| /* | |
| * preproc.c: Preprocessing of style operations | |
| * | |
| * References: | |
| * http://www.w3.org/TR/1999/REC-xslt-19991116 | |
| * | |
| * Michael Kay "XSLT Programmer's Reference" pp 637-643 | |
| * Writing Multiple Output Files | |
| * | |
| * XSLT-1.1 Working Draft | |
| * http://www.w3.org/TR/xslt11#multiple-output | |
| * | |
| * See Copyright for the status of this software. | |
| * | |
| * [email protected] | |
| */ | |
| #define IN_LIBXSLT | |
| #include "libxslt.h" | |
| #include <string.h> | |
| #include <libxml/xmlmemory.h> | |
| #include <libxml/parser.h> | |
| #include <libxml/tree.h> | |
| #include <libxml/valid.h> | |
| #include <libxml/hash.h> | |
| #include <libxml/uri.h> | |
| #include <libxml/encoding.h> | |
| #include <libxml/xmlerror.h> | |
| #include "xslt.h" | |
| #include "xsltutils.h" | |
| #include "xsltInternals.h" | |
| #include "transform.h" | |
| #include "templates.h" | |
| #include "variables.h" | |
| #include "numbersInternals.h" | |
| #include "preproc.h" | |
| #include "extra.h" | |
| #include "imports.h" | |
| #include "extensions.h" | |
| #ifdef WITH_XSLT_DEBUG | |
| #define WITH_XSLT_DEBUG_PREPROC | |
| #endif | |
| const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; | |
| /************************************************************************ | |
| * * | |
| * Grammar checks * | |
| * * | |
| ************************************************************************/ | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * Grammar checks are now performed in xslt.c. | |
| */ | |
| #else | |
| /** | |
| * xsltCheckTopLevelElement: | |
| * @style: the XSLT stylesheet | |
| * @inst: the XSLT instruction | |
| * @err: raise an error or not | |
| * | |
| * Check that the instruction is instanciated as a top level element. | |
| * | |
| * Returns -1 in case of error, 0 if failed and 1 in case of success | |
| */ | |
| static int | |
| xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) { | |
| xmlNodePtr parent; | |
| if ((style == NULL) || (inst == NULL) || (inst->ns == NULL)) | |
| return(-1); | |
| parent = inst->parent; | |
| if (parent == NULL) { | |
| if (err) { | |
| xsltTransformError(NULL, style, inst, | |
| "internal problem: element has no parent\n"); | |
| style->errors++; | |
| } | |
| return(0); | |
| } | |
| if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) || | |
| ((parent->ns != inst->ns) && | |
| (!xmlStrEqual(parent->ns->href, inst->ns->href))) || | |
| ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) && | |
| (!xmlStrEqual(parent->name, BAD_CAST "transform")))) { | |
| if (err) { | |
| xsltTransformError(NULL, style, inst, | |
| "element %s only allowed as child of stylesheet\n", | |
| inst->name); | |
| style->errors++; | |
| } | |
| return(0); | |
| } | |
| return(1); | |
| } | |
| /** | |
| * xsltCheckInstructionElement: | |
| * @style: the XSLT stylesheet | |
| * @inst: the XSLT instruction | |
| * | |
| * Check that the instruction is instanciated as an instruction element. | |
| */ | |
| static void | |
| xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| xmlNodePtr parent; | |
| int has_ext; | |
| if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || | |
| (style->literal_result)) | |
| return; | |
| has_ext = (style->extInfos != NULL); | |
| parent = inst->parent; | |
| if (parent == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "internal problem: element has no parent\n"); | |
| style->errors++; | |
| return; | |
| } | |
| while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { | |
| if (((parent->ns == inst->ns) || | |
| ((parent->ns != NULL) && | |
| (xmlStrEqual(parent->ns->href, inst->ns->href)))) && | |
| ((xmlStrEqual(parent->name, BAD_CAST "template")) || | |
| (xmlStrEqual(parent->name, BAD_CAST "param")) || | |
| (xmlStrEqual(parent->name, BAD_CAST "attribute")) || | |
| (xmlStrEqual(parent->name, BAD_CAST "variable")))) { | |
| return; | |
| } | |
| /* | |
| * if we are within an extension element all bets are off | |
| * about the semantic there e.g. xsl:param within func:function | |
| */ | |
| if ((has_ext) && (parent->ns != NULL) && | |
| (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) | |
| return; | |
| parent = parent->parent; | |
| } | |
| xsltTransformError(NULL, style, inst, | |
| "element %s only allowed within a template, variable or param\n", | |
| inst->name); | |
| style->errors++; | |
| } | |
| /** | |
| * xsltCheckParentElement: | |
| * @style: the XSLT stylesheet | |
| * @inst: the XSLT instruction | |
| * @allow1: allowed parent1 | |
| * @allow2: allowed parent2 | |
| * | |
| * Check that the instruction is instanciated as the childre of one of the | |
| * possible parents. | |
| */ | |
| static void | |
| xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, | |
| const xmlChar *allow1, const xmlChar *allow2) { | |
| xmlNodePtr parent; | |
| if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || | |
| (style->literal_result)) | |
| return; | |
| parent = inst->parent; | |
| if (parent == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "internal problem: element has no parent\n"); | |
| style->errors++; | |
| return; | |
| } | |
| if (((parent->ns == inst->ns) || | |
| ((parent->ns != NULL) && | |
| (xmlStrEqual(parent->ns->href, inst->ns->href)))) && | |
| ((xmlStrEqual(parent->name, allow1)) || | |
| (xmlStrEqual(parent->name, allow2)))) { | |
| return; | |
| } | |
| if (style->extInfos != NULL) { | |
| while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { | |
| /* | |
| * if we are within an extension element all bets are off | |
| * about the semantic there e.g. xsl:param within func:function | |
| */ | |
| if ((parent->ns != NULL) && | |
| (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) | |
| return; | |
| parent = parent->parent; | |
| } | |
| } | |
| xsltTransformError(NULL, style, inst, | |
| "element %s is not allowed within that context\n", | |
| inst->name); | |
| style->errors++; | |
| } | |
| #endif | |
| /************************************************************************ | |
| * * | |
| * handling of precomputed data * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltNewStylePreComp: | |
| * @style: the XSLT stylesheet | |
| * @type: the construct type | |
| * | |
| * Create a new XSLT Style precomputed block | |
| * | |
| * Returns the newly allocated specialized structure | |
| * or NULL in case of error | |
| */ | |
| static xsltStylePreCompPtr | |
| xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) { | |
| xsltStylePreCompPtr cur; | |
| #ifdef XSLT_REFACTORED | |
| size_t size; | |
| #endif | |
| if (style == NULL) | |
| return(NULL); | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * URGENT TODO: Use specialized factory functions in order | |
| * to avoid this ugliness. | |
| */ | |
| switch (type) { | |
| case XSLT_FUNC_COPY: | |
| size = sizeof(xsltStyleItemCopy); break; | |
| case XSLT_FUNC_SORT: | |
| size = sizeof(xsltStyleItemSort); break; | |
| case XSLT_FUNC_TEXT: | |
| size = sizeof(xsltStyleItemText); break; | |
| case XSLT_FUNC_ELEMENT: | |
| size = sizeof(xsltStyleItemElement); break; | |
| case XSLT_FUNC_ATTRIBUTE: | |
| size = sizeof(xsltStyleItemAttribute); break; | |
| case XSLT_FUNC_COMMENT: | |
| size = sizeof(xsltStyleItemComment); break; | |
| case XSLT_FUNC_PI: | |
| size = sizeof(xsltStyleItemPI); break; | |
| case XSLT_FUNC_COPYOF: | |
| size = sizeof(xsltStyleItemCopyOf); break; | |
| case XSLT_FUNC_VALUEOF: | |
| size = sizeof(xsltStyleItemValueOf); break;; | |
| case XSLT_FUNC_NUMBER: | |
| size = sizeof(xsltStyleItemNumber); break; | |
| case XSLT_FUNC_APPLYIMPORTS: | |
| size = sizeof(xsltStyleItemApplyImports); break; | |
| case XSLT_FUNC_CALLTEMPLATE: | |
| size = sizeof(xsltStyleItemCallTemplate); break; | |
| case XSLT_FUNC_APPLYTEMPLATES: | |
| size = sizeof(xsltStyleItemApplyTemplates); break; | |
| case XSLT_FUNC_CHOOSE: | |
| size = sizeof(xsltStyleItemChoose); break; | |
| case XSLT_FUNC_IF: | |
| size = sizeof(xsltStyleItemIf); break; | |
| case XSLT_FUNC_FOREACH: | |
| size = sizeof(xsltStyleItemForEach); break; | |
| case XSLT_FUNC_DOCUMENT: | |
| size = sizeof(xsltStyleItemDocument); break; | |
| case XSLT_FUNC_WITHPARAM: | |
| size = sizeof(xsltStyleItemWithParam); break; | |
| case XSLT_FUNC_PARAM: | |
| size = sizeof(xsltStyleItemParam); break; | |
| case XSLT_FUNC_VARIABLE: | |
| size = sizeof(xsltStyleItemVariable); break; | |
| case XSLT_FUNC_WHEN: | |
| size = sizeof(xsltStyleItemWhen); break; | |
| case XSLT_FUNC_OTHERWISE: | |
| size = sizeof(xsltStyleItemOtherwise); break; | |
| default: | |
| xsltTransformError(NULL, style, NULL, | |
| "xsltNewStylePreComp : invalid type %d\n", type); | |
| style->errors++; | |
| return(NULL); | |
| } | |
| /* | |
| * Create the structure. | |
| */ | |
| cur = (xsltStylePreCompPtr) xmlMalloc(size); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, style, NULL, | |
| "xsltNewStylePreComp : malloc failed\n"); | |
| style->errors++; | |
| return(NULL); | |
| } | |
| memset(cur, 0, size); | |
| #else /* XSLT_REFACTORED */ | |
| /* | |
| * Old behaviour. | |
| */ | |
| cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp)); | |
| if (cur == NULL) { | |
| xsltTransformError(NULL, style, NULL, | |
| "xsltNewStylePreComp : malloc failed\n"); | |
| style->errors++; | |
| return(NULL); | |
| } | |
| memset(cur, 0, sizeof(xsltStylePreComp)); | |
| #endif /* XSLT_REFACTORED */ | |
| /* | |
| * URGENT TODO: Better to move this to spezialized factory functions. | |
| */ | |
| cur->type = type; | |
| switch (cur->type) { | |
| case XSLT_FUNC_COPY: | |
| cur->func = (xsltTransformFunction) xsltCopy;break; | |
| case XSLT_FUNC_SORT: | |
| cur->func = (xsltTransformFunction) xsltSort;break; | |
| case XSLT_FUNC_TEXT: | |
| cur->func = (xsltTransformFunction) xsltText;break; | |
| case XSLT_FUNC_ELEMENT: | |
| cur->func = (xsltTransformFunction) xsltElement;break; | |
| case XSLT_FUNC_ATTRIBUTE: | |
| cur->func = (xsltTransformFunction) xsltAttribute;break; | |
| case XSLT_FUNC_COMMENT: | |
| cur->func = (xsltTransformFunction) xsltComment;break; | |
| case XSLT_FUNC_PI: | |
| cur->func = (xsltTransformFunction) xsltProcessingInstruction; | |
| break; | |
| case XSLT_FUNC_COPYOF: | |
| cur->func = (xsltTransformFunction) xsltCopyOf;break; | |
| case XSLT_FUNC_VALUEOF: | |
| cur->func = (xsltTransformFunction) xsltValueOf;break; | |
| case XSLT_FUNC_NUMBER: | |
| cur->func = (xsltTransformFunction) xsltNumber;break; | |
| case XSLT_FUNC_APPLYIMPORTS: | |
| cur->func = (xsltTransformFunction) xsltApplyImports;break; | |
| case XSLT_FUNC_CALLTEMPLATE: | |
| cur->func = (xsltTransformFunction) xsltCallTemplate;break; | |
| case XSLT_FUNC_APPLYTEMPLATES: | |
| cur->func = (xsltTransformFunction) xsltApplyTemplates;break; | |
| case XSLT_FUNC_CHOOSE: | |
| cur->func = (xsltTransformFunction) xsltChoose;break; | |
| case XSLT_FUNC_IF: | |
| cur->func = (xsltTransformFunction) xsltIf;break; | |
| case XSLT_FUNC_FOREACH: | |
| cur->func = (xsltTransformFunction) xsltForEach;break; | |
| case XSLT_FUNC_DOCUMENT: | |
| cur->func = (xsltTransformFunction) xsltDocumentElem;break; | |
| case XSLT_FUNC_WITHPARAM: | |
| case XSLT_FUNC_PARAM: | |
| case XSLT_FUNC_VARIABLE: | |
| case XSLT_FUNC_WHEN: | |
| break; | |
| default: | |
| if (cur->func == NULL) { | |
| xsltTransformError(NULL, style, NULL, | |
| "xsltNewStylePreComp : no function for type %d\n", type); | |
| style->errors++; | |
| } | |
| } | |
| cur->next = style->preComps; | |
| style->preComps = (xsltElemPreCompPtr) cur; | |
| return(cur); | |
| } | |
| /** | |
| * xsltFreeStylePreComp: | |
| * @comp: an XSLT Style precomputed block | |
| * | |
| * Free up the memory allocated by @comp | |
| */ | |
| static void | |
| xsltFreeStylePreComp(xsltStylePreCompPtr comp) { | |
| if (comp == NULL) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| /* | |
| * URGENT TODO: Implement destructors. | |
| */ | |
| switch (comp->type) { | |
| case XSLT_FUNC_LITERAL_RESULT_ELEMENT: | |
| break; | |
| case XSLT_FUNC_COPY: | |
| break; | |
| case XSLT_FUNC_SORT: { | |
| xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; | |
| if (item->locale != (xsltLocale)0) | |
| xsltFreeLocale(item->locale); | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_TEXT: | |
| break; | |
| case XSLT_FUNC_ELEMENT: | |
| break; | |
| case XSLT_FUNC_ATTRIBUTE: | |
| break; | |
| case XSLT_FUNC_COMMENT: | |
| break; | |
| case XSLT_FUNC_PI: | |
| break; | |
| case XSLT_FUNC_COPYOF: { | |
| xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_VALUEOF: { | |
| xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_NUMBER: | |
| break; | |
| case XSLT_FUNC_APPLYIMPORTS: | |
| break; | |
| case XSLT_FUNC_CALLTEMPLATE: | |
| break; | |
| case XSLT_FUNC_APPLYTEMPLATES: { | |
| xsltStyleItemApplyTemplatesPtr item = | |
| (xsltStyleItemApplyTemplatesPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_CHOOSE: | |
| break; | |
| case XSLT_FUNC_IF: { | |
| xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_FOREACH: { | |
| xsltStyleItemForEachPtr item = | |
| (xsltStyleItemForEachPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_DOCUMENT: | |
| break; | |
| case XSLT_FUNC_WITHPARAM: { | |
| xsltStyleItemWithParamPtr item = | |
| (xsltStyleItemWithParamPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_PARAM: { | |
| xsltStyleItemParamPtr item = | |
| (xsltStyleItemParamPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_VARIABLE: { | |
| xsltStyleItemVariablePtr item = | |
| (xsltStyleItemVariablePtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_WHEN: { | |
| xsltStyleItemWhenPtr item = | |
| (xsltStyleItemWhenPtr) comp; | |
| if (item->comp != NULL) | |
| xmlXPathFreeCompExpr(item->comp); | |
| } | |
| break; | |
| case XSLT_FUNC_OTHERWISE: | |
| case XSLT_FUNC_FALLBACK: | |
| case XSLT_FUNC_MESSAGE: | |
| case XSLT_FUNC_INCLUDE: | |
| case XSLT_FUNC_ATTRSET: | |
| break; | |
| default: | |
| /* TODO: Raise error. */ | |
| break; | |
| } | |
| #else | |
| if (comp->locale != (xsltLocale)0) | |
| xsltFreeLocale(comp->locale); | |
| if (comp->comp != NULL) | |
| xmlXPathFreeCompExpr(comp->comp); | |
| if (comp->nsList != NULL) | |
| xmlFree(comp->nsList); | |
| #endif | |
| xmlFree(comp); | |
| } | |
| /************************************************************************ | |
| * * | |
| * XSLT-1.1 extensions * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltDocumentComp: | |
| * @style: the XSLT stylesheet | |
| * @inst: the instruction in the stylesheet | |
| * @function: unused | |
| * | |
| * Pre process an XSLT-1.1 document element | |
| * | |
| * Returns a precompiled data structure for the element | |
| */ | |
| xsltElemPreCompPtr | |
| xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, | |
| xsltTransformFunction function ATTRIBUTE_UNUSED) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemDocumentPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| const xmlChar *filename = NULL; | |
| /* | |
| * As of 2006-03-30, this function is currently defined in Libxslt | |
| * to be used for: | |
| * (in libxslt/extra.c) | |
| * "output" in XSLT_SAXON_NAMESPACE | |
| * "write" XSLT_XALAN_NAMESPACE | |
| * "document" XSLT_XT_NAMESPACE | |
| * "document" XSLT_NAMESPACE (from the abandoned old working | |
| * draft of XSLT 1.1) | |
| * (in libexslt/common.c) | |
| * "document" in EXSLT_COMMON_NAMESPACE | |
| */ | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemDocumentPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); | |
| #endif | |
| if (comp == NULL) | |
| return (NULL); | |
| comp->inst = inst; | |
| comp->ver11 = 0; | |
| if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { | |
| #ifdef WITH_XSLT_DEBUG_EXTRA | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Found saxon:output extension\n"); | |
| #endif | |
| /* | |
| * The element "output" is in the namespace XSLT_SAXON_NAMESPACE | |
| * (http://icl.com/saxon) | |
| * The @file is in no namespace; it is an AVT. | |
| * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output) | |
| * | |
| * TODO: Do we need not to check the namespace here? | |
| */ | |
| filename = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"file", | |
| NULL, &comp->has_filename); | |
| } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { | |
| #ifdef WITH_XSLT_DEBUG_EXTRA | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Found xalan:write extension\n"); | |
| #endif | |
| /* the filename need to be interpreted */ | |
| /* | |
| * TODO: Is "filename need to be interpreted" meant to be a todo? | |
| * Where will be the filename of xalan:write be processed? | |
| * | |
| * TODO: Do we need not to check the namespace here? | |
| * The extension ns is "http://xml.apache.org/xalan/redirect". | |
| * See http://xml.apache.org/xalan-j/extensionslib.html. | |
| */ | |
| } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { | |
| if (inst->ns != NULL) { | |
| if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) { | |
| /* | |
| * Mark the instruction as being of | |
| * XSLT version 1.1 (abandoned). | |
| */ | |
| comp->ver11 = 1; | |
| #ifdef WITH_XSLT_DEBUG_EXTRA | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Found xslt11:document construct\n"); | |
| #endif | |
| } else { | |
| if (xmlStrEqual(inst->ns->href, | |
| (const xmlChar *)"http://exslt.org/common")) { | |
| /* EXSLT. */ | |
| #ifdef WITH_XSLT_DEBUG_EXTRA | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Found exslt:document extension\n"); | |
| #endif | |
| } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) { | |
| /* James Clark's XT. */ | |
| #ifdef WITH_XSLT_DEBUG_EXTRA | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "Found xt:document extension\n"); | |
| #endif | |
| } | |
| } | |
| } | |
| /* | |
| * The element "document" is used in conjunction with the | |
| * following namespaces: | |
| * | |
| * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1) | |
| * <!ELEMENT xsl:document %template;> | |
| * <!ATTLIST xsl:document | |
| * href %avt; #REQUIRED | |
| * @href is an AVT | |
| * IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft, | |
| * it was removed and isn't available in XSLT 1.1 anymore. | |
| * In XSLT 2.0 it was renamed to xsl:result-document. | |
| * | |
| * All other attributes are identical to the attributes | |
| * on xsl:output | |
| * | |
| * 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common) | |
| * <exsl:document | |
| * href = { uri-reference } | |
| * TODO: is @href is an AVT? | |
| * | |
| * 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt) | |
| * Example: <xt:document method="xml" href="myFile.xml"> | |
| * TODO: is @href is an AVT? | |
| * | |
| * In all cases @href is in no namespace. | |
| */ | |
| filename = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"href", NULL, &comp->has_filename); | |
| } | |
| if (!comp->has_filename) { | |
| goto error; | |
| } | |
| comp->filename = filename; | |
| error: | |
| return ((xsltElemPreCompPtr) comp); | |
| } | |
| /************************************************************************ | |
| * * | |
| * Most of the XSLT-1.0 transformations * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltSortComp: | |
| * @style: the XSLT stylesheet | |
| * @inst: the xslt sort node | |
| * | |
| * Process the xslt sort node on the source node | |
| */ | |
| static void | |
| xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemSortPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->stype = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"data-type", | |
| NULL, &comp->has_stype); | |
| if (comp->stype != NULL) { | |
| if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) | |
| comp->number = 0; | |
| else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) | |
| comp->number = 1; | |
| else { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltSortComp: no support for data-type = %s\n", comp->stype); | |
| comp->number = 0; /* use default */ | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| comp->order = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"order", | |
| NULL, &comp->has_order); | |
| if (comp->order != NULL) { | |
| if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) | |
| comp->descending = 0; | |
| else if (xmlStrEqual(comp->order, (const xmlChar *) "descending")) | |
| comp->descending = 1; | |
| else { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltSortComp: invalid value %s for order\n", comp->order); | |
| comp->descending = 0; /* use default */ | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"case-order", | |
| NULL, &comp->has_use); | |
| if (comp->case_order != NULL) { | |
| if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first")) | |
| comp->lower_first = 0; | |
| else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first")) | |
| comp->lower_first = 1; | |
| else { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltSortComp: invalid value %s for order\n", comp->order); | |
| comp->lower_first = 0; /* use default */ | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| comp->lang = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"lang", | |
| NULL, &comp->has_lang); | |
| if (comp->lang != NULL) { | |
| comp->locale = xsltNewLocale(comp->lang); | |
| } | |
| else { | |
| comp->locale = (xsltLocale)0; | |
| } | |
| comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE); | |
| if (comp->select == NULL) { | |
| /* | |
| * The default value of the select attribute is ., which will | |
| * cause the string-value of the current node to be used as | |
| * the sort key. | |
| */ | |
| comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1); | |
| } | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltSortComp: could not compile select expression '%s'\n", | |
| comp->select); | |
| if (style != NULL) style->errors++; | |
| } | |
| if (inst->children != NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:sort : is not empty\n"); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| /** | |
| * xsltCopyComp: | |
| * @style: the XSLT stylesheet | |
| * @inst: the xslt copy node | |
| * | |
| * Process the xslt copy node on the source node | |
| */ | |
| static void | |
| xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemCopyPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets", | |
| XSLT_NAMESPACE); | |
| if (comp->use == NULL) | |
| comp->has_use = 0; | |
| else | |
| comp->has_use = 1; | |
| } | |
| #ifdef XSLT_REFACTORED | |
| /* Enable if ever needed for xsl:text. */ | |
| #else | |
| /** | |
| * xsltTextComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt text node | |
| * | |
| * TODO: This function is obsolete, since xsl:text won't | |
| * be compiled, but removed from the tree. | |
| * | |
| * Process the xslt text node on the source node | |
| */ | |
| static void | |
| xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemTextPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| const xmlChar *prop; | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->noescape = 0; | |
| prop = xsltGetCNsProp(style, inst, | |
| (const xmlChar *)"disable-output-escaping", | |
| XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| if (xmlStrEqual(prop, (const xmlChar *)"yes")) { | |
| comp->noescape = 1; | |
| } else if (!xmlStrEqual(prop, | |
| (const xmlChar *)"no")){ | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:text: disable-output-escaping allows only yes or no\n"); | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| } | |
| #endif /* else of XSLT_REFACTORED */ | |
| /** | |
| * xsltElementComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt element node | |
| * | |
| * Process the xslt element node on the source node | |
| */ | |
| static void | |
| xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemElementPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| /* | |
| * <xsl:element | |
| * name = { qname } | |
| * namespace = { uri-reference } | |
| * use-attribute-sets = qnames> | |
| * <!-- Content: template --> | |
| * </xsl:element> | |
| */ | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "name". | |
| */ | |
| /* | |
| * TODO: Precompile the AVT. See bug #344894. | |
| */ | |
| comp->name = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"name", NULL, &comp->has_name); | |
| if (! comp->has_name) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:element: The attribute 'name' is missing.\n"); | |
| style->errors++; | |
| goto error; | |
| } | |
| /* | |
| * Attribute "namespace". | |
| */ | |
| /* | |
| * TODO: Precompile the AVT. See bug #344894. | |
| */ | |
| comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"namespace", NULL, &comp->has_ns); | |
| if (comp->name != NULL) { | |
| if (xmlValidateQName(comp->name, 0)) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:element: The value '%s' of the attribute 'name' is " | |
| "not a valid QName.\n", comp->name); | |
| style->errors++; | |
| } else { | |
| const xmlChar *prefix = NULL, *name; | |
| name = xsltSplitQName(style->dict, comp->name, &prefix); | |
| if (comp->has_ns == 0) { | |
| xmlNsPtr ns; | |
| /* | |
| * SPEC XSLT 1.0: | |
| * "If the namespace attribute is not present, then the QName is | |
| * expanded into an expanded-name using the namespace declarations | |
| * in effect for the xsl:element element, including any default | |
| * namespace declaration. | |
| */ | |
| ns = xmlSearchNs(inst->doc, inst, prefix); | |
| if (ns != NULL) { | |
| comp->ns = xmlDictLookup(style->dict, ns->href, -1); | |
| comp->has_ns = 1; | |
| #ifdef XSLT_REFACTORED | |
| comp->nsPrefix = prefix; | |
| comp->name = name; | |
| #endif | |
| } else if (prefix != NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:element: The prefixed QName '%s' " | |
| "has no namespace binding in scope in the " | |
| "stylesheet; this is an error, since the namespace was " | |
| "not specified by the instruction itself.\n", comp->name); | |
| style->errors++; | |
| } | |
| } | |
| if ((prefix != NULL) && | |
| (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) | |
| { | |
| /* | |
| * Mark is to be skipped. | |
| */ | |
| comp->has_name = 0; | |
| } | |
| } | |
| } | |
| /* | |
| * Attribute "use-attribute-sets", | |
| */ | |
| comp->use = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"use-attribute-sets", | |
| NULL, &comp->has_use); | |
| error: | |
| return; | |
| } | |
| /** | |
| * xsltAttributeComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt attribute node | |
| * | |
| * Process the xslt attribute node on the source node | |
| */ | |
| static void | |
| xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemAttributePtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| /* | |
| * <xsl:attribute | |
| * name = { qname } | |
| * namespace = { uri-reference }> | |
| * <!-- Content: template --> | |
| * </xsl:attribute> | |
| */ | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, | |
| XSLT_FUNC_ATTRIBUTE); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "name". | |
| */ | |
| /* | |
| * TODO: Precompile the AVT. See bug #344894. | |
| */ | |
| comp->name = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"name", | |
| NULL, &comp->has_name); | |
| if (! comp->has_name) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-attribute: The attribute 'name' is missing.\n"); | |
| style->errors++; | |
| return; | |
| } | |
| /* | |
| * Attribute "namespace". | |
| */ | |
| /* | |
| * TODO: Precompile the AVT. See bug #344894. | |
| */ | |
| comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"namespace", | |
| NULL, &comp->has_ns); | |
| if (comp->name != NULL) { | |
| if (xmlValidateQName(comp->name, 0)) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:attribute: The value '%s' of the attribute 'name' is " | |
| "not a valid QName.\n", comp->name); | |
| style->errors++; | |
| } else { | |
| const xmlChar *prefix = NULL, *name; | |
| name = xsltSplitQName(style->dict, comp->name, &prefix); | |
| if (prefix != NULL) { | |
| if (comp->has_ns == 0) { | |
| xmlNsPtr ns; | |
| /* | |
| * SPEC XSLT 1.0: | |
| * "If the namespace attribute is not present, then the | |
| * QName is expanded into an expanded-name using the | |
| * namespace declarations in effect for the xsl:element | |
| * element, including any default namespace declaration. | |
| */ | |
| ns = xmlSearchNs(inst->doc, inst, prefix); | |
| if (ns != NULL) { | |
| comp->ns = xmlDictLookup(style->dict, ns->href, -1); | |
| comp->has_ns = 1; | |
| #ifdef XSLT_REFACTORED | |
| comp->nsPrefix = prefix; | |
| comp->name = name; | |
| #endif | |
| } else { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:attribute: The prefixed QName '%s' " | |
| "has no namespace binding in scope in the " | |
| "stylesheet; this is an error, since the " | |
| "namespace was not specified by the instruction " | |
| "itself.\n", comp->name); | |
| style->errors++; | |
| } | |
| } | |
| if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) { | |
| /* | |
| * SPEC XSLT 1.0: | |
| * "It is an error if the string that results from | |
| * instantiating the attribute value template is not a | |
| * QName or is the string xmlns. An XSLT processor may | |
| * signal the error; if it does not signal the error, | |
| * it must recover by not adding the attribute to the | |
| * result tree." | |
| * | |
| * Reject a prefix of "xmlns". Mark to be skipped. | |
| */ | |
| comp->has_name = 0; | |
| #ifdef WITH_XSLT_DEBUG_PARSING | |
| xsltGenericDebug(xsltGenericDebugContext, | |
| "xsltAttribute: xmlns prefix forbidden\n"); | |
| #endif | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * xsltCommentComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt comment node | |
| * | |
| * Process the xslt comment node on the source node | |
| */ | |
| static void | |
| xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemCommentPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| } | |
| /** | |
| * xsltProcessingInstructionComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt processing-instruction node | |
| * | |
| * Process the xslt processing-instruction node on the source node | |
| */ | |
| static void | |
| xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemPIPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_PI); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->name = xsltEvalStaticAttrValueTemplate(style, inst, | |
| (const xmlChar *)"name", | |
| XSLT_NAMESPACE, &comp->has_name); | |
| } | |
| /** | |
| * xsltCopyOfComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt copy-of node | |
| * | |
| * Process the xslt copy-of node on the source node | |
| */ | |
| static void | |
| xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemCopyOfPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:copy-of : select is missing\n"); | |
| if (style != NULL) style->errors++; | |
| return; | |
| } | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:copy-of : could not compile select expression '%s'\n", | |
| comp->select); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| /** | |
| * xsltValueOfComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt value-of node | |
| * | |
| * Process the xslt value-of node on the source node | |
| */ | |
| static void | |
| xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemValueOfPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| const xmlChar *prop; | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| prop = xsltGetCNsProp(style, inst, | |
| (const xmlChar *)"disable-output-escaping", | |
| XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| if (xmlStrEqual(prop, (const xmlChar *)"yes")) { | |
| comp->noescape = 1; | |
| } else if (!xmlStrEqual(prop, | |
| (const xmlChar *)"no")){ | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:value-of : disable-output-escaping allows only yes or no\n"); | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:value-of : select is missing\n"); | |
| if (style != NULL) style->errors++; | |
| return; | |
| } | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:value-of : could not compile select expression '%s'\n", | |
| comp->select); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| static void | |
| xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst, | |
| const xmlChar *propName, | |
| int mandatory, | |
| int *hasProp, const xmlChar **nsName, | |
| const xmlChar** localName) | |
| { | |
| const xmlChar *prop; | |
| if (nsName) | |
| *nsName = NULL; | |
| if (localName) | |
| *localName = NULL; | |
| if (hasProp) | |
| *hasProp = 0; | |
| prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE); | |
| if (prop == NULL) { | |
| if (mandatory) { | |
| xsltTransformError(NULL, style, inst, | |
| "The attribute '%s' is missing.\n", propName); | |
| style->errors++; | |
| return; | |
| } | |
| } else { | |
| const xmlChar *URI; | |
| if (xmlValidateQName(prop, 0)) { | |
| xsltTransformError(NULL, style, inst, | |
| "The value '%s' of the attribute " | |
| "'%s' is not a valid QName.\n", prop, propName); | |
| style->errors++; | |
| return; | |
| } else { | |
| /* | |
| * @prop will be in the string dict afterwards, @URI not. | |
| */ | |
| URI = xsltGetQNameURI2(style, inst, &prop); | |
| if (prop == NULL) { | |
| style->errors++; | |
| } else { | |
| *localName = prop; | |
| if (hasProp) | |
| *hasProp = 1; | |
| if (URI != NULL) { | |
| /* | |
| * Fixes bug #308441: Put the ns-name in the dict | |
| * in order to pointer compare names during XPath's | |
| * variable lookup. | |
| */ | |
| if (nsName) | |
| *nsName = xmlDictLookup(style->dict, URI, -1); | |
| /* comp->has_ns = 1; */ | |
| } | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| /** | |
| * xsltWithParamComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt with-param node | |
| * | |
| * Process the xslt with-param node on the source node | |
| * Allowed parents: xsl:call-template, xsl:apply-templates. | |
| * <xsl:with-param | |
| * name = qname | |
| * select = expression> | |
| * <!-- Content: template --> | |
| * </xsl:with-param> | |
| */ | |
| static void | |
| xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemWithParamPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "name". | |
| */ | |
| xsltGetQNameProperty(style, inst, BAD_CAST "name", | |
| 1, &(comp->has_name), &(comp->ns), &(comp->name)); | |
| if (comp->ns) | |
| comp->has_ns = 1; | |
| /* | |
| * Attribute "select". | |
| */ | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select != NULL) { | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-with-param: Failed to compile select " | |
| "expression '%s'\n", comp->select); | |
| style->errors++; | |
| } | |
| if (inst->children != NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-with-param: The content should be empty since " | |
| "the attribute select is present.\n"); | |
| style->warnings++; | |
| } | |
| } | |
| } | |
| /** | |
| * xsltNumberComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @cur: the xslt number node | |
| * | |
| * Process the xslt number node on the source node | |
| */ | |
| static void | |
| xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemNumberPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| const xmlChar *prop; | |
| if ((style == NULL) || (cur == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| cur->psvi = comp; | |
| if ((style == NULL) || (cur == NULL)) | |
| return; | |
| comp->numdata.doc = cur->doc; | |
| comp->numdata.node = cur; | |
| comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", | |
| XSLT_NAMESPACE); | |
| prop = xsltEvalStaticAttrValueTemplate(style, cur, | |
| (const xmlChar *)"format", | |
| XSLT_NAMESPACE, &comp->numdata.has_format); | |
| if (comp->numdata.has_format == 0) { | |
| comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0); | |
| } else { | |
| comp->numdata.format = prop; | |
| } | |
| comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count", | |
| XSLT_NAMESPACE); | |
| comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from", | |
| XSLT_NAMESPACE); | |
| prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| if (xmlStrEqual(prop, BAD_CAST("single")) || | |
| xmlStrEqual(prop, BAD_CAST("multiple")) || | |
| xmlStrEqual(prop, BAD_CAST("any"))) { | |
| comp->numdata.level = prop; | |
| } else { | |
| xsltTransformError(NULL, style, cur, | |
| "xsl:number : invalid value %s for level\n", prop); | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| xsltTransformError(NULL, style, cur, | |
| "xsl:number : lang attribute not implemented\n"); | |
| XSLT_TODO; /* xsl:number lang attribute */ | |
| } | |
| prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) { | |
| xsltTransformError(NULL, style, cur, | |
| "xsl:number : letter-value 'alphabetic' not implemented\n"); | |
| if (style != NULL) style->warnings++; | |
| XSLT_TODO; /* xsl:number letter-value attribute alphabetic */ | |
| } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) { | |
| xsltTransformError(NULL, style, cur, | |
| "xsl:number : letter-value 'traditional' not implemented\n"); | |
| if (style != NULL) style->warnings++; | |
| XSLT_TODO; /* xsl:number letter-value attribute traditional */ | |
| } else { | |
| xsltTransformError(NULL, style, cur, | |
| "xsl:number : invalid value %s for letter-value\n", prop); | |
| if (style != NULL) style->warnings++; | |
| } | |
| } | |
| prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator", | |
| XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| comp->numdata.groupingCharacterLen = xmlStrlen(prop); | |
| comp->numdata.groupingCharacter = | |
| xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen)); | |
| } | |
| prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); | |
| if (prop != NULL) { | |
| sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup); | |
| } else { | |
| comp->numdata.groupingCharacter = 0; | |
| } | |
| /* Set default values */ | |
| if (comp->numdata.value == NULL) { | |
| if (comp->numdata.level == NULL) { | |
| comp->numdata.level = xmlDictLookup(style->dict, | |
| BAD_CAST"single", 6); | |
| } | |
| } | |
| } | |
| /** | |
| * xsltApplyImportsComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt apply-imports node | |
| * | |
| * Process the xslt apply-imports node on the source node | |
| */ | |
| static void | |
| xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemApplyImportsPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| } | |
| /** | |
| * xsltCallTemplateComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt call-template node | |
| * | |
| * Process the xslt call-template node on the source node | |
| */ | |
| static void | |
| xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemCallTemplatePtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemCallTemplatePtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "name". | |
| */ | |
| xsltGetQNameProperty(style, inst, BAD_CAST "name", | |
| 1, &(comp->has_name), &(comp->ns), &(comp->name)); | |
| if (comp->ns) | |
| comp->has_ns = 1; | |
| } | |
| /** | |
| * xsltApplyTemplatesComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the apply-templates node | |
| * | |
| * Process the apply-templates node on the source node | |
| */ | |
| static void | |
| xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemApplyTemplatesPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemApplyTemplatesPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "mode". | |
| */ | |
| xsltGetQNameProperty(style, inst, BAD_CAST "mode", | |
| 0, NULL, &(comp->modeURI), &(comp->mode)); | |
| /* | |
| * Attribute "select". | |
| */ | |
| comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select", | |
| XSLT_NAMESPACE); | |
| if (comp->select != NULL) { | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-apply-templates: could not compile select " | |
| "expression '%s'\n", comp->select); | |
| style->errors++; | |
| } | |
| } | |
| /* TODO: handle (or skip) the xsl:sort and xsl:with-param */ | |
| } | |
| /** | |
| * xsltChooseComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt choose node | |
| * | |
| * Process the xslt choose node on the source node | |
| */ | |
| static void | |
| xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemChoosePtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemChoosePtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| } | |
| /** | |
| * xsltIfComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt if node | |
| * | |
| * Process the xslt if node on the source node | |
| */ | |
| static void | |
| xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemIfPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemIfPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_IF); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_IF); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); | |
| if (comp->test == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:if : test is not defined\n"); | |
| if (style != NULL) style->errors++; | |
| return; | |
| } | |
| comp->comp = xsltXPathCompile(style, comp->test); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:if : could not compile test expression '%s'\n", | |
| comp->test); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| /** | |
| * xsltWhenComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt if node | |
| * | |
| * Process the xslt if node on the source node | |
| */ | |
| static void | |
| xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemWhenPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemWhenPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_WHEN); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); | |
| if (comp->test == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:when : test is not defined\n"); | |
| if (style != NULL) style->errors++; | |
| return; | |
| } | |
| comp->comp = xsltXPathCompile(style, comp->test); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:when : could not compile test expression '%s'\n", | |
| comp->test); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| /** | |
| * xsltForEachComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt for-each node | |
| * | |
| * Process the xslt for-each node on the source node | |
| */ | |
| static void | |
| xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemForEachPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemForEachPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:for-each : select is missing\n"); | |
| if (style != NULL) style->errors++; | |
| } else { | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "xsl:for-each : could not compile select expression '%s'\n", | |
| comp->select); | |
| if (style != NULL) style->errors++; | |
| } | |
| } | |
| /* TODO: handle and skip the xsl:sort */ | |
| } | |
| /** | |
| * xsltVariableComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt variable node | |
| * | |
| * Process the xslt variable node on the source node | |
| */ | |
| static void | |
| xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemVariablePtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemVariablePtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * The full template resolution can be done statically | |
| */ | |
| /* | |
| * Attribute "name". | |
| */ | |
| xsltGetQNameProperty(style, inst, BAD_CAST "name", | |
| 1, &(comp->has_name), &(comp->ns), &(comp->name)); | |
| if (comp->ns) | |
| comp->has_ns = 1; | |
| /* | |
| * Attribute "select". | |
| */ | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select != NULL) { | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-variable: Failed to compile the XPath expression '%s'.\n", | |
| comp->select); | |
| style->errors++; | |
| } | |
| if (inst->children != NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-variable: The must be no child nodes, since the " | |
| "attribute 'select' was specified.\n"); | |
| style->errors++; | |
| } | |
| } | |
| } | |
| /** | |
| * xsltParamComp: | |
| * @style: an XSLT compiled stylesheet | |
| * @inst: the xslt param node | |
| * | |
| * Process the xslt param node on the source node | |
| */ | |
| static void | |
| xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| #ifdef XSLT_REFACTORED | |
| xsltStyleItemParamPtr comp; | |
| #else | |
| xsltStylePreCompPtr comp; | |
| #endif | |
| if ((style == NULL) || (inst == NULL)) | |
| return; | |
| #ifdef XSLT_REFACTORED | |
| comp = (xsltStyleItemParamPtr) | |
| xsltNewStylePreComp(style, XSLT_FUNC_PARAM); | |
| #else | |
| comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM); | |
| #endif | |
| if (comp == NULL) | |
| return; | |
| inst->psvi = comp; | |
| comp->inst = inst; | |
| /* | |
| * Attribute "name". | |
| */ | |
| xsltGetQNameProperty(style, inst, BAD_CAST "name", | |
| 1, &(comp->has_name), &(comp->ns), &(comp->name)); | |
| if (comp->ns) | |
| comp->has_ns = 1; | |
| /* | |
| * Attribute "select". | |
| */ | |
| comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", | |
| XSLT_NAMESPACE); | |
| if (comp->select != NULL) { | |
| comp->comp = xsltXPathCompile(style, comp->select); | |
| if (comp->comp == NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-param: could not compile select expression '%s'.\n", | |
| comp->select); | |
| style->errors++; | |
| } | |
| if (inst->children != NULL) { | |
| xsltTransformError(NULL, style, inst, | |
| "XSLT-param: The content should be empty since the " | |
| "attribute 'select' is present.\n"); | |
| style->warnings++; | |
| } | |
| } | |
| } | |
| /************************************************************************ | |
| * * | |
| * Generic interface * | |
| * * | |
| ************************************************************************/ | |
| /** | |
| * xsltFreeStylePreComps: | |
| * @style: an XSLT transformation context | |
| * | |
| * Free up the memory allocated by all precomputed blocks | |
| */ | |
| void | |
| xsltFreeStylePreComps(xsltStylesheetPtr style) { | |
| xsltElemPreCompPtr cur, next; | |
| if (style == NULL) | |
| return; | |
| cur = style->preComps; | |
| while (cur != NULL) { | |
| next = cur->next; | |
| if (cur->type == XSLT_FUNC_EXTENSION) | |
| cur->free(cur); | |
| else | |
| xsltFreeStylePreComp((xsltStylePreCompPtr) cur); | |
| cur = next; | |
| } | |
| } | |
| #ifdef XSLT_REFACTORED | |
| /** | |
| * xsltStylePreCompute: | |
| * @style: the XSLT stylesheet | |
| * @node: the element in the XSLT namespace | |
| * | |
| * Precompute an XSLT element. | |
| * This expects the type of the element to be already | |
| * set in style->compCtxt->inode->type; | |
| */ | |
| void | |
| xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) { | |
| /* | |
| * The xsltXSLTElemMarker marker was set beforehand by | |
| * the parsing mechanism for all elements in the XSLT namespace. | |
| */ | |
| if (style == NULL) { | |
| if (node != NULL) | |
| node->psvi = NULL; | |
| return; | |
| } | |
| if (node == NULL) | |
| return; | |
| if (! IS_XSLT_ELEM_FAST(node)) | |
| return; | |
| node->psvi = NULL; | |
| if (XSLT_CCTXT(style)->inode->type != 0) { | |
| switch (XSLT_CCTXT(style)->inode->type) { | |
| case XSLT_FUNC_APPLYTEMPLATES: | |
| xsltApplyTemplatesComp(style, node); | |
| break; | |
| case XSLT_FUNC_WITHPARAM: | |
| xsltWithParamComp(style, node); | |
| break; | |
| case XSLT_FUNC_VALUEOF: | |
| xsltValueOfComp(style, node); | |
| break; | |
| case XSLT_FUNC_COPY: | |
| xsltCopyComp(style, node); | |
| break; | |
| case XSLT_FUNC_COPYOF: | |
| xsltCopyOfComp(style, node); | |
| break; | |
| case XSLT_FUNC_IF: | |
| xsltIfComp(style, node); | |
| break; | |
| case XSLT_FUNC_CHOOSE: | |
| xsltChooseComp(style, node); | |
| break; | |
| case XSLT_FUNC_WHEN: | |
| xsltWhenComp(style, node); | |
| break; | |
| case XSLT_FUNC_OTHERWISE: | |
| /* NOP yet */ | |
| return; | |
| case XSLT_FUNC_FOREACH: | |
| xsltForEachComp(style, node); | |
| break; | |
| case XSLT_FUNC_APPLYIMPORTS: | |
| xsltApplyImportsComp(style, node); | |
| break; | |
| case XSLT_FUNC_ATTRIBUTE: | |
| xsltAttributeComp(style, node); | |
| break; | |
| case XSLT_FUNC_ELEMENT: | |
| xsltElementComp(style, node); | |
| break; | |
| case XSLT_FUNC_SORT: | |
| xsltSortComp(style, node); | |
| break; | |
| case XSLT_FUNC_COMMENT: | |
| xsltCommentComp(style, node); | |
| break; | |
| case XSLT_FUNC_NUMBER: | |
| xsltNumberComp(style, node); | |
| break; | |
| case XSLT_FUNC_PI: | |
| xsltProcessingInstructionComp(style, node); | |
| break; | |
| case XSLT_FUNC_CALLTEMPLATE: | |
| xsltCallTemplateComp(style, node); | |
| break; | |
| case XSLT_FUNC_PARAM: | |
| xsltParamComp(style, node); | |
| break; | |
| case XSLT_FUNC_VARIABLE: | |
| xsltVariableComp(style, node); | |
| break; | |
| case XSLT_FUNC_FALLBACK: | |
| /* NOP yet */ | |
| return; | |
| case XSLT_FUNC_DOCUMENT: | |
| /* The extra one */ | |
| node->psvi = (void *) xsltDocumentComp(style, node, | |
| (xsltTransformFunction) xsltDocumentElem); | |
| break; | |
| case XSLT_FUNC_MESSAGE: | |
| /* NOP yet */ | |
| return; | |
| default: | |
| /* | |
| * NOTE that xsl:text, xsl:template, xsl:stylesheet, | |
| * xsl:transform, xsl:import, xsl:include are not expected | |
| * to be handed over to this function. | |
| */ | |
| xsltTransformError(NULL, style, node, | |
| "Internal error: (xsltStylePreCompute) cannot handle " | |
| "the XSLT element '%s'.\n", node->name); | |
| style->errors++; | |
| return; | |
| } | |
| } else { | |
| /* | |
| * Fallback to string comparison. | |
| */ | |
| if (IS_XSLT_NAME(node, "apply-templates")) { | |
| xsltApplyTemplatesComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "with-param")) { | |
| xsltWithParamComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "value-of")) { | |
| xsltValueOfComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "copy")) { | |
| xsltCopyComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "copy-of")) { | |
| xsltCopyOfComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "if")) { | |
| xsltIfComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "choose")) { | |
| xsltChooseComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "when")) { | |
| xsltWhenComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "otherwise")) { | |
| /* NOP yet */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "for-each")) { | |
| xsltForEachComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "apply-imports")) { | |
| xsltApplyImportsComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "attribute")) { | |
| xsltAttributeComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "element")) { | |
| xsltElementComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "sort")) { | |
| xsltSortComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "comment")) { | |
| xsltCommentComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "number")) { | |
| xsltNumberComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "processing-instruction")) { | |
| xsltProcessingInstructionComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "call-template")) { | |
| xsltCallTemplateComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "param")) { | |
| xsltParamComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "variable")) { | |
| xsltVariableComp(style, node); | |
| } else if (IS_XSLT_NAME(node, "fallback")) { | |
| /* NOP yet */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "document")) { | |
| /* The extra one */ | |
| node->psvi = (void *) xsltDocumentComp(style, node, | |
| (xsltTransformFunction) xsltDocumentElem); | |
| } else if (IS_XSLT_NAME(node, "output")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "preserve-space")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "strip-space")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "key")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "message")) { | |
| return; | |
| } else if (IS_XSLT_NAME(node, "attribute-set")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "namespace-alias")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "decimal-format")) { | |
| /* Top-level */ | |
| return; | |
| } else if (IS_XSLT_NAME(node, "include")) { | |
| /* Top-level */ | |
| } else { | |
| /* | |
| * NOTE that xsl:text, xsl:template, xsl:stylesheet, | |
| * xsl:transform, xsl:import, xsl:include are not expected | |
| * to be handed over to this function. | |
| */ | |
| xsltTransformError(NULL, style, node, | |
| "Internal error: (xsltStylePreCompute) cannot handle " | |
| "the XSLT element '%s'.\n", node->name); | |
| style->errors++; | |
| return; | |
| } | |
| } | |
| /* | |
| * Assign the current list of in-scope namespaces to the | |
| * item. This is needed for XPath expressions. | |
| */ | |
| if (node->psvi != NULL) { | |
| ((xsltStylePreCompPtr) node->psvi)->inScopeNs = | |
| XSLT_CCTXT(style)->inode->inScopeNs; | |
| } | |
| } | |
| #else | |
| /** | |
| * xsltStylePreCompute: | |
| * @style: the XSLT stylesheet | |
| * @inst: the instruction in the stylesheet | |
| * | |
| * Precompute an XSLT stylesheet element | |
| */ | |
| void | |
| xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { | |
| /* | |
| * URGENT TODO: Normally inst->psvi Should never be reserved here, | |
| * BUT: since if we include the same stylesheet from | |
| * multiple imports, then the stylesheet will be parsed | |
| * again. We simply must not try to compute the stylesheet again. | |
| * TODO: Get to the point where we don't need to query the | |
| * namespace- and local-name of the node, but can evaluate this | |
| * using cctxt->style->inode->category; | |
| */ | |
| if (inst->psvi != NULL) | |
| return; | |
| if (IS_XSLT_ELEM(inst)) { | |
| xsltStylePreCompPtr cur; | |
| if (IS_XSLT_NAME(inst, "apply-templates")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltApplyTemplatesComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "with-param")) { | |
| xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", | |
| BAD_CAST "call-template"); | |
| xsltWithParamComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "value-of")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltValueOfComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "copy")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltCopyComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "copy-of")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltCopyOfComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "if")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltIfComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "when")) { | |
| xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); | |
| xsltWhenComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "choose")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltChooseComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "for-each")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltForEachComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "apply-imports")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltApplyImportsComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "attribute")) { | |
| xmlNodePtr parent = inst->parent; | |
| if ((parent == NULL) || (parent->ns == NULL) || | |
| ((parent->ns != inst->ns) && | |
| (!xmlStrEqual(parent->ns->href, inst->ns->href))) || | |
| (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) { | |
| xsltCheckInstructionElement(style, inst); | |
| } | |
| xsltAttributeComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "element")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltElementComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "text")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltTextComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "sort")) { | |
| xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", | |
| BAD_CAST "for-each"); | |
| xsltSortComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "comment")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltCommentComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "number")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltNumberComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "processing-instruction")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltProcessingInstructionComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "call-template")) { | |
| xsltCheckInstructionElement(style, inst); | |
| xsltCallTemplateComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "param")) { | |
| if (xsltCheckTopLevelElement(style, inst, 0) == 0) | |
| xsltCheckInstructionElement(style, inst); | |
| xsltParamComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "variable")) { | |
| if (xsltCheckTopLevelElement(style, inst, 0) == 0) | |
| xsltCheckInstructionElement(style, inst); | |
| xsltVariableComp(style, inst); | |
| } else if (IS_XSLT_NAME(inst, "otherwise")) { | |
| xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); | |
| xsltCheckInstructionElement(style, inst); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "template")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "output")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "preserve-space")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "strip-space")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if ((IS_XSLT_NAME(inst, "stylesheet")) || | |
| (IS_XSLT_NAME(inst, "transform"))) { | |
| xmlNodePtr parent = inst->parent; | |
| if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) { | |
| xsltTransformError(NULL, style, inst, | |
| "element %s only allowed only as root element\n", | |
| inst->name); | |
| style->errors++; | |
| } | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "key")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "message")) { | |
| xsltCheckInstructionElement(style, inst); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "attribute-set")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "namespace-alias")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "include")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "import")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "decimal-format")) { | |
| xsltCheckTopLevelElement(style, inst, 1); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "fallback")) { | |
| xsltCheckInstructionElement(style, inst); | |
| return; | |
| } else if (IS_XSLT_NAME(inst, "document")) { | |
| xsltCheckInstructionElement(style, inst); | |
| inst->psvi = (void *) xsltDocumentComp(style, inst, | |
| (xsltTransformFunction) xsltDocumentElem); | |
| } else { | |
| xsltTransformError(NULL, style, inst, | |
| "xsltStylePreCompute: unknown xsl:%s\n", inst->name); | |
| if (style != NULL) style->warnings++; | |
| } | |
| cur = (xsltStylePreCompPtr) inst->psvi; | |
| /* | |
| * A ns-list is build for every XSLT item in the | |
| * node-tree. This is needed for XPath expressions. | |
| */ | |
| if (cur != NULL) { | |
| int i = 0; | |
| cur->nsList = xmlGetNsList(inst->doc, inst); | |
| if (cur->nsList != NULL) { | |
| while (cur->nsList[i] != NULL) | |
| i++; | |
| } | |
| cur->nsNr = i; | |
| } | |
| } else { | |
| inst->psvi = | |
| (void *) xsltPreComputeExtModuleElement(style, inst); | |
| /* | |
| * Unknown element, maybe registered at the context | |
| * level. Mark it for later recognition. | |
| */ | |
| if (inst->psvi == NULL) | |
| inst->psvi = (void *) xsltExtMarker; | |
| } | |
| } | |
| #endif /* XSLT_REFACTORED */ |