| /* |
| * 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. |
| * |
| * daniel@veillard.com |
| */ |
| |
| #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 */ |