From: Kasimier T. Buchcik Date: Fri, 5 May 2006 21:18:25 +0000 (+0000) Subject: Next step of refactoring (plus some bug-fixes). For more details see X-Git-Tag: v1.1.28~251 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eb037ebd811cbf68dd36a9d5732529aed2e3f2e5;p=platform%2Fupstream%2Flibxslt.git Next step of refactoring (plus some bug-fixes). For more details see * libxslt/xsltInternals.h libxslt/attributes.c libxslt/documents.c libxslt/extensions.c libxslt/extensions.h libxslt/functions.c libxslt/imports.c libxslt/keys.c libxslt/preproc.c libxslt/transform.c libxslt/variables.c libxslt/xslt.c libxslt/xsltutils.c libxslt/xsltutils.h libexslt/functions.c: Next step of refactoring (plus some bug-fixes). For more details see #340780. --- diff --git a/ChangeLog b/ChangeLog index 1feee53..a55491e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Fri May 5 23:10:47 CEST 2006 Kasimier Buchcik + + * libxslt/xsltInternals.h libxslt/attributes.c + libxslt/documents.c libxslt/extensions.c + libxslt/extensions.h libxslt/functions.c + libxslt/imports.c libxslt/keys.c libxslt/preproc.c + libxslt/transform.c libxslt/variables.c libxslt/xslt.c + libxslt/xsltutils.c libxslt/xsltutils.h libexslt/functions.c: + Next step of refactoring (plus some bug-fixes). + For more details see #340780. + Fri May 5 14:31:53 CEST 2006 Kasimier Buchcik * tests/exslt/common/node-set.5.out diff --git a/libexslt/functions.c b/libexslt/functions.c index 57e90c4..51f7d44 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -128,6 +128,10 @@ exsltFuncRegisterImportFunc (exsltFuncFunctionData *data, * @URI: the namespace URI for the extension * * Initializes the EXSLT - Functions module. + * Called at transformation-time; merges all + * functions declared in the import tree taking + * import precedence into account, i.e. overriding + * functions with lower import precedence. * * Returns the data for this transformation */ @@ -170,8 +174,9 @@ exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension * @data: the module data to free up - * + * * Shutdown the EXSLT - Functions module + * Called at transformation-time. */ static void exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, @@ -188,6 +193,7 @@ exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, * @URI: the namespace URI for the extension * * Allocates the stylesheet data for EXSLT - Function + * Called at compile-time. * * Returns the allocated data */ @@ -201,9 +207,10 @@ exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, * exsltFuncStyleShutdown: * @style: an XSLT stylesheet * @URI: the namespace URI for the extension - * @data: the stylesheet data to free up + * @data: the stylesheet data to free up * * Shutdown the EXSLT - Function module + * Called at compile-time. */ static void exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, @@ -431,8 +438,19 @@ exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { * Register the function data such that it can be retrieved * by exslFuncFunctionFunction */ - data = (xmlHashTablePtr) xsltStyleGetExtData (style, - EXSLT_FUNCTIONS_NAMESPACE); +#ifdef XSLT_REFACTORED + /* + * Ensure that the hash table will be stored in the *current* + * stylesheet level in order to correctly evaluate the + * import precedence. + */ + data = (xmlHashTablePtr) + xsltStyleStylesheetLevelGetExtData(style, + EXSLT_FUNCTIONS_NAMESPACE); +#else + data = (xmlHashTablePtr) + xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); +#endif if (data == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncFunctionComp: no stylesheet data\n"); @@ -441,9 +459,10 @@ exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { } if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { - xsltGenericError(xsltGenericErrorContext, - "Failed to register function {%s}%s\n", + xsltTransformError(NULL, style, inst, + "Failed to register function {%s}%s\n", ns->href, name); + style->errors++; } else { xsltGenericDebug(xsltGenericDebugContext, "exsltFuncFunctionComp: register {%s}%s\n", diff --git a/libxslt/attributes.c b/libxslt/attributes.c index 9e6dbb4..849b2f6 100644 --- a/libxslt/attributes.c +++ b/libxslt/attributes.c @@ -46,6 +46,7 @@ #include "templates.h" #include "imports.h" #include "transform.h" +#include "preproc.h" #define WITH_XSLT_DEBUG_ATTRIBUTES #ifdef WITH_XSLT_DEBUG @@ -143,6 +144,11 @@ xsltFreeAttrElemList(xsltAttrElemPtr list) { } } +#ifdef XSLT_REFACTORED + /* + * This was moved to xsltParseStylesheetAttributeSet(). + */ +#else /** * xsltAddAttrElemList: * @list: an XSLT AttrElem list @@ -161,7 +167,7 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { if (list == NULL) return(xsltNewAttrElem(attr)); cur = list; - while (cur != NULL) { + while (cur != NULL) { next = cur->next; if (cur->attr == attr) return(cur); @@ -173,6 +179,7 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { } return(list); } +#endif /* XSLT_REFACTORED */ /** * xsltMergeAttrElemList: @@ -185,7 +192,8 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { * Returns the new list pointer */ static xsltAttrElemPtr -xsltMergeAttrElemList(xsltAttrElemPtr list, xsltAttrElemPtr old) { +xsltMergeAttrElemList(xsltStylesheetPtr style, + xsltAttrElemPtr list, xsltAttrElemPtr old) { xsltAttrElemPtr cur; int add; @@ -233,19 +241,23 @@ xsltMergeAttrElemList(xsltAttrElemPtr list, xsltAttrElemPtr old) { } if (add == 1) { + /* + * Changed to use the string-dict, rather than duplicating + * @set and @ns; this fixes bug #340400. + */ if (cur == NULL) { list = xsltNewAttrElem(old->attr); if (old->set != NULL) { - list->set = xmlStrdup(old->set); + list->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) - list->ns = xmlStrdup(old->ns); + list->ns = xmlDictLookup(style->dict, old->ns, -1); } } else if (add) { cur->next = xsltNewAttrElem(old->attr); if (old->set != NULL) { - cur->next->set = xmlStrdup(old->set); + cur->next->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) - cur->next->ns = xmlStrdup(old->ns); + cur->next->ns = xmlDictLookup(style->dict, old->ns, -1); } } } @@ -273,24 +285,23 @@ void xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { const xmlChar *ncname; const xmlChar *prefix; - const xmlChar *attrib, *endattr; - xmlChar *prop; - xmlChar *attributes; - xmlNodePtr list; - xsltAttrElemPtr values; + xmlChar *value; + xmlNodePtr child; + xsltAttrElemPtr attrItems; if ((cur == NULL) || (style == NULL)) return; - prop = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); - if (prop == NULL) { + value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); + if (value == NULL) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : name is missing\n"); return; } - ncname = xsltSplitQName(style->dict, prop, &prefix); - xmlFree(prop); + ncname = xsltSplitQName(style->dict, value, &prefix); + xmlFree(value); + value = NULL; if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES @@ -302,80 +313,141 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { if (style->attributeSets == NULL) return; - values = xmlHashLookup2(style->attributeSets, ncname, prefix); + attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix); /* - * check the children list - */ - list = cur->children; - while (list != NULL) { - if (IS_XSLT_ELEM(list)) { - if (!IS_XSLT_NAME(list, "attribute")) { - xsltGenericError(xsltGenericErrorContext, - "xsl:attribute-set : unexpected child xsl:%s\n", - list->name); - } else { + * Parse the content. Only xsl:attribute elements are allowed. + */ + child = cur->children; + while (child != NULL) { + /* + * Report invalid nodes. + */ + if ((child->type != XML_ELEMENT_NODE) || + (child->ns == NULL) || + (! IS_XSLT_ELEM(child))) + { + if (child->type == XML_ELEMENT_NODE) + xsltTransformError(NULL, style, child, + "xsl:attribute-set : unexpected child %s\n", + child->name); + else + xsltTransformError(NULL, style, child, + "xsl:attribute-set : child of unexpected type\n"); + } else if (!IS_XSLT_NAME(child, "attribute")) { + xsltTransformError(NULL, style, child, + "xsl:attribute-set : unexpected child xsl:%s\n", + child->name); + } else { +#ifdef XSLT_REFACTORED + xsltAttrElemPtr nextAttr, curAttr; + + /* + * Process xsl:attribute + * --------------------- + */ + #ifdef WITH_XSLT_DEBUG_ATTRIBUTES - xsltGenericDebug(xsltGenericDebugContext, - "add attribute to list %s\n", ncname); + xsltGenericDebug(xsltGenericDebugContext, + "add attribute to list %s\n", ncname); #endif - values = xsltAddAttrElemList(values, list); + /* + * The following was taken over from + * xsltAddAttrElemList(). + */ + if (attrItems == NULL) { + attrItems = xsltNewAttrElem(child); + } else { + curAttr = attrItems; + while (curAttr != NULL) { + nextAttr = curAttr->next; + if (curAttr->attr == child) { + /* + * URGENT TODO: Can somebody explain + * why attrItems is set to curAttr + * here? Is this somehow related to + * avoidance of recursions? + */ + attrItems = curAttr; + goto next_child; + } + if (curAttr->next == NULL) + curAttr->next = xsltNewAttrElem(child); + curAttr = nextAttr; + } } - } else { - xsltGenericError(xsltGenericErrorContext, - "xsl:attribute-set : unexpected child %s\n", list->name); + /* + * Parse the xsl:attribute and its content. + */ + xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); +#else +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "add attribute to list %s\n", ncname); +#endif + /* + * OLD behaviour: + */ + attrItems = xsltAddAttrElemList(attrItems, child); +#endif } - list = list->next; + +#ifdef XSLT_REFACTORED +next_child: +#endif + child = child->next; } /* - * Check a possible use-attribute-sets definition - */ - /* TODO check recursion */ - - attributes = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets", + * Process attribue "use-attribute-sets". + */ + /* TODO check recursion */ + value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets", NULL); - if (attributes == NULL) { - goto done; - } - - attrib = attributes; - while (*attrib != 0) { - while (IS_BLANK(*attrib)) attrib++; - if (*attrib == 0) - break; - endattr = attrib; - while ((*endattr != 0) && (!IS_BLANK(*endattr))) endattr++; - attrib = xmlDictLookup(style->dict, attrib, endattr - attrib); - if (attrib) { - const xmlChar *ncname2 = NULL; - const xmlChar *prefix2 = NULL; - xsltAttrElemPtr values2; - + if (value != NULL) { + const xmlChar *curval, *endval; + curval = value; + while (*curval != 0) { + while (IS_BLANK(*curval)) curval++; + if (*curval == 0) + break; + endval = curval; + while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; + curval = xmlDictLookup(style->dict, curval, endval - curval); + if (curval) { + const xmlChar *ncname2 = NULL; + const xmlChar *prefix2 = NULL; + xsltAttrElemPtr refAttrItems; + #ifdef WITH_XSLT_DEBUG_ATTRIBUTES - xsltGenericDebug(xsltGenericDebugContext, - "xsl:attribute-set : %s adds use %s\n", ncname, attrib); + xsltGenericDebug(xsltGenericDebugContext, + "xsl:attribute-set : %s adds use %s\n", ncname, curval); #endif - ncname2 = xsltSplitQName(style->dict, attrib, &prefix2); - values2 = xsltNewAttrElem(NULL); - if (values2 != NULL) { - values2->set = ncname2; - values2->ns = prefix2; - values = xsltMergeAttrElemList(values, values2); - xsltFreeAttrElem(values2); + ncname2 = xsltSplitQName(style->dict, curval, &prefix2); + refAttrItems = xsltNewAttrElem(NULL); + if (refAttrItems != NULL) { + refAttrItems->set = ncname2; + refAttrItems->ns = prefix2; + attrItems = xsltMergeAttrElemList(style, + attrItems, refAttrItems); + xsltFreeAttrElem(refAttrItems); + } } + curval = endval; } - attrib = endattr; + xmlFree(value); + value = NULL; } - xmlFree(attributes); -done: /* * Update the value */ - if (values == NULL) - values = xsltNewAttrElem(NULL); - xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, values, NULL); + /* + * TODO: Why is this dummy entry needed.? + */ + if (attrItems == NULL) + attrItems = xsltNewAttrElem(NULL); + xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL); #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "updated attribute list %s\n", ncname); @@ -447,15 +519,12 @@ xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, /* * Then merge */ - xsltMergeAttrElemList(values, refs); + xsltMergeAttrElemList(style, values, refs); /* * Then suppress the reference */ - xmlFree((char *)tmp->set); tmp->set = NULL; - if (tmp->ns != NULL) { - xmlFree((char *)tmp->ns); - } + tmp->ns = NULL; } } } @@ -492,7 +561,7 @@ xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, "xsl:attribute-set : logic error merging from imports for" " attribute-set %s\n", name); } else { - topSet = xsltMergeAttrElemList(topSet, values); + topSet = xsltMergeAttrElemList(style, topSet, values); xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL); } xsltFreeAttrElemList(values); diff --git a/libxslt/documents.c b/libxslt/documents.c index b6ee9b0..0963e1c 100644 --- a/libxslt/documents.c +++ b/libxslt/documents.c @@ -192,18 +192,42 @@ xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { /** * xsltFreeStyleDocuments: - * @style: an XSLT style sheet + * @style: an XSLT stylesheet (representing a stylesheet-level) * - * Free up all the space used by the loaded documents + * Frees the node-trees (and xsltDocument structures) of all + * stylesheet-modules of the stylesheet-level represented by + * the given @style. */ void xsltFreeStyleDocuments(xsltStylesheetPtr style) { xsltDocumentPtr doc, cur; +#ifdef XSLT_REFACTORED + xsltNsMapPtr nsMap; +#endif + + if (style == NULL) + return; + +#ifdef XSLT_REFACTORED + if (XSLT_HAS_INTERNAL_NSMAP(style)) + nsMap = XSLT_GET_INTERNAL_NSMAP(style); + else + nsMap = NULL; +#endif cur = style->docList; while (cur != NULL) { doc = cur; cur = cur->next; + +#ifdef XSLT_REFACTORED + /* + * Restore all changed namespace URIs of ns-decls. + */ + if (nsMap) + xsltRestoreDocumentNamespaces(nsMap, doc->doc); +#endif + xsltFreeDocumentKeys(doc); if (!doc->main) xmlFreeDoc(doc->doc); diff --git a/libxslt/extensions.c b/libxslt/extensions.c index 450474a..b7dad9b 100644 --- a/libxslt/extensions.c +++ b/libxslt/extensions.c @@ -469,12 +469,19 @@ xsltFreeExts(xsltStylesheetPtr style) /** * xsltRegisterExtPrefix: * @style: an XSLT stylesheet - * @prefix: the prefix used + * @prefix: the prefix used (optional) * @URI: the URI associated to the extension - * + * * Registers an extension namespace - * - * Returns 0 in case of success, -1 in case of failure + * This is called from xslt.c during compile-time. + * The given prefix is not needed. + * Called by: + * xsltParseExtElemPrefixes() (new function) + * xsltRegisterExtPrefix() (old function) + * + * Returns 0 in case of success, 1 if the @URI was already + * registered as an extension namespace and + * -1 in case of failure */ int xsltRegisterExtPrefix(xsltStylesheetPtr style, @@ -482,7 +489,7 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style, { xsltExtDefPtr def, ret; - if ((style == NULL) || (prefix == NULL) | (URI == NULL)) + if ((style == NULL) || (URI == NULL)) return (-1); #ifdef WITH_XSLT_DEBUG_EXTENSIONS @@ -491,11 +498,22 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style, URI); #endif def = (xsltExtDefPtr) style->nsDefs; +#ifdef XSLT_REFACTORED + /* + * The extension is associated with a namespace name. + */ + while (def != NULL) { + if (xmlStrEqual(URI, def->URI)) + return (1); + def = def->next; + } +#else while (def != NULL) { if (xmlStrEqual(prefix, def->prefix)) return (-1); def = def->next; } +#endif ret = xsltNewExtDef(prefix, URI); if (ret == NULL) return (-1); @@ -506,6 +524,12 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style, * check wether there is an extension module with a stylesheet * initialization function. */ +#ifdef XSLT_REFACTORED + /* + * Don't initialize modules based on specified namespaced via + * the attribute "[xsl:]extension-element-prefixes". + */ +#else if (xsltExtensionsHash != NULL) { xsltExtModulePtr module; @@ -515,11 +539,11 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style, module = xmlHashLookup(xsltExtensionsHash, URI); } } - if (module != NULL) { xsltStyleGetExtData(style, URI); } } +#endif return (0); } @@ -600,82 +624,197 @@ xsltFreeCtxtExts(xsltTransformContextPtr ctxt) } /** - * xsltStyleGetExtData: + * xsltStyleGetStylesheetExtData: * @style: an XSLT stylesheet * @URI: the URI associated to the exension module * - * Retrieve the data associated to the extension module in this given - * stylesheet. + * Fires the compile-time initialization callback + * of an extension module and returns a container + * holding the user-data (retrieved via the callback). * - * Returns the pointer or NULL if not present + * Returns the create module-data container + * or NULL if such a module was not registered. */ -void * -xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) +static xsltExtDataPtr +xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style, + const xmlChar * URI) { - xsltExtDataPtr data = NULL; - xsltStylesheetPtr tmp; - - - if ((style == NULL) || (URI == NULL)) - return (NULL); + xsltExtDataPtr dataContainer; + void *userData = NULL; + xsltExtModulePtr module; + + if ((style == NULL) || (URI == NULL)) + return(NULL); - tmp = style; - while (tmp != NULL) { - if (tmp->extInfos != NULL) { - data = (xsltExtDataPtr) xmlHashLookup(tmp->extInfos, URI); - if (data != NULL) - break; - } - tmp = xsltNextImport(tmp); - } - if (data == NULL) { - if (style->extInfos == NULL) { - style->extInfos = xmlHashCreate(10); - if (style->extInfos == NULL) - return (NULL); - } + if (xsltExtensionsHash == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return(NULL); } - if (data == NULL) { - void *extData; - xsltExtModulePtr module; - module = xmlHashLookup(xsltExtensionsHash, URI); - if (module == NULL) { + module = xmlHashLookup(xsltExtensionsHash, URI); + if (module == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS - xsltGenericDebug(xsltGenericDebugContext, - "Not registered extension module: %s\n", URI); + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); #endif - return (NULL); - } else { - if (module->styleInitFunc == NULL) { + return (NULL); + } + /* + * The specified module was registered so initialize it. + */ + if (style->extInfos == NULL) { + style->extInfos = xmlHashCreate(10); + if (style->extInfos == NULL) + return (NULL); + } + /* + * Fire the initialization callback if available. + */ + if (module->styleInitFunc == NULL) { #ifdef WITH_XSLT_DEBUG_EXTENSIONS - xsltGenericDebug(xsltGenericDebugContext, - "Registering style module: %s\n", URI); + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module with *no* callback: %s\n", URI); #endif - extData = NULL; - } else { + } else { #ifdef WITH_XSLT_DEBUG_EXTENSIONS - xsltGenericDebug(xsltGenericDebugContext, - "Initializing module: %s\n", URI); + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module with callback: %s\n", URI); #endif - extData = module->styleInitFunc(style, URI); - } + /* + * Fire the initialization callback. + */ + userData = module->styleInitFunc(style, URI); + } + /* + * Store the user-data in the context of the given stylesheet. + */ + dataContainer = xsltNewExtData(module, userData); + if (dataContainer == NULL) + return (NULL); + + if (xmlHashAddEntry(style->extInfos, URI, + (void *) dataContainer) < 0) + { + xsltTransformError(NULL, style, NULL, + "Failed to register module '%s'.\n", URI); + style->errors++; + if (module->styleShutdownFunc) + module->styleShutdownFunc(style, URI, userData); + xsltFreeExtData(dataContainer); + return (NULL); + } - data = xsltNewExtData(module, extData); - if (data == NULL) - return (NULL); - if (xmlHashAddEntry(style->extInfos, URI, (void *) data) < 0) { - xsltGenericError(xsltGenericErrorContext, - "Failed to register module data: %s\n", - URI); - if (module->styleShutdownFunc) - module->styleShutdownFunc(style, URI, extData); - xsltFreeExtData(data); - return (NULL); - } - } + return(dataContainer); +} + +/** + * xsltStyleGetExtData: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module + * in this given stylesheet. + * Called by: + * xsltRegisterExtPrefix(), + * ( xsltExtElementPreCompTest(), xsltExtInitTest ) + * + * Returns the pointer or NULL if not present + */ +void * +xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) +{ + xsltExtDataPtr dataContainer = NULL; + xsltStylesheetPtr tmpStyle; + + if ((style == NULL) || (URI == NULL) || + (xsltExtensionsHash == NULL)) + return (NULL); + + +#ifdef XSLT_REFACTORED + /* + * This is intended for global storage, so only the main + * stylesheet will hold the data. + */ + tmpStyle = style; + while (tmpStyle->parent != NULL) + tmpStyle = tmpStyle->parent; + if (tmpStyle->extInfos != NULL) { + dataContainer = + (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); + if (dataContainer != NULL) { + /* + * The module was already initialized in the context + * of this stylesheet; just return the user-data that + * comes with it. + */ + return(dataContainer->extData); + } } - return (data->extData); +#else + /* + * Old behaviour. + */ + tmpStyle = style; + while (tmpStyle != NULL) { + if (tmpStyle->extInfos != NULL) { + dataContainer = + (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); + if (dataContainer != NULL) { + return(dataContainer->extData); + } + } + tmpStyle = xsltNextImport(tmpStyle); + } + tmpStyle = style; +#endif + + dataContainer = + xsltStyleInitializeStylesheetModule(tmpStyle, URI); + if (dataContainer != NULL) + return (dataContainer->extData); + return(NULL); +} + +/** + * xsltStyleGetExtDataPerStylesheetLevel: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module in this given + * stylesheet. + * + * Returns the pointer or NULL if not present + */ +void * +xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style, + const xmlChar * URI) +{ + xsltExtDataPtr dataContainer = NULL; + + if ((style == NULL) || (URI == NULL) || + (xsltExtensionsHash == NULL)) + return (NULL); + + if (style->extInfos != NULL) { + dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI); + /* + * The module was already initialized in the context + * of this stylesheet; just return the user-data that + * comes with it. + */ + if (dataContainer) + return(dataContainer->extData); + } + + dataContainer = + xsltStyleInitializeStylesheetModule(style, URI); + if (dataContainer != NULL) + return (dataContainer->extData); + return(NULL); } /** @@ -939,8 +1078,13 @@ xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style, "Shutting down module : %s\n", URI); #endif module->styleShutdownFunc(style, URI, data->extData); - xmlHashRemoveEntry(style->extInfos, URI, - (xmlHashDeallocator) xsltFreeExtData); + /* + * Don't remove the entry from the hash table here, since + * this will produce segfaults - this fixes bug #340624. + * + * xmlHashRemoveEntry(style->extInfos, URI, + * (xmlHashDeallocator) xsltFreeExtData); + */ } /** @@ -964,29 +1108,59 @@ xsltShutdownExts(xsltStylesheetPtr style) /** * xsltCheckExtPrefix: * @style: the stylesheet - * @prefix: the namespace prefix (possibly NULL) + * @URI: the namespace URI (possibly NULL) * - * Check if the given prefix is one of the declared extensions + * Check if the given prefix is one of the declared extensions. + * This is intended to be called only at compile-time. + * Called by: + * xsltGetInheritedNsList() (xslt.c) + * xsltParseTemplateContent (xslt.c) * * Returns 1 if this is an extension, 0 otherwise */ int -xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * prefix) -{ +xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI) +{ +#ifdef XSLT_REFACTORED + if ((style == NULL) || (style->compCtxt == NULL) || + (XSLT_CCTXT(style)->inode == NULL) || + (XSLT_CCTXT(style)->inode->extElemNs == NULL)) + return (0); + /* + * Lookup the extension namespaces registered + * at the current node in the stylesheet's tree. + */ + if (XSLT_CCTXT(style)->inode->extElemNs != NULL) { + int i; + xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs; + + for (i = 0; i < list->number; i++) { + if (xmlStrEqual((const xmlChar *) list->items[i], + URI)) + { + return(1); + } + } + } +#else xsltExtDefPtr cur; if ((style == NULL) || (style->nsDefs == NULL)) return (0); - - if (prefix == NULL) - prefix = BAD_CAST "#default"; - + if (URI == NULL) + URI = BAD_CAST "#default"; cur = (xsltExtDefPtr) style->nsDefs; while (cur != NULL) { - if (xmlStrEqual(prefix, cur->prefix)) + /* + * TODO: This is the old behaviour and it won't work + * correctly, since it works with the namespace prefix, + * but it should work with the namespace name. + */ + if (xmlStrEqual(URI, cur->prefix)) return (1); cur = cur->next; } +#endif return (0); } @@ -1281,13 +1455,39 @@ xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst) ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href); + /* + * EXT TODO: Now what? + */ if (ext == NULL) return (NULL); - if (ext->precomp != NULL) + if (ext->precomp != NULL) { + /* + * REVISIT TODO: Check if the text below is correct. + * This will return a xsltElemPreComp structure or NULL. + * 1) If the the author of the extension needs a + * custom structure to hold the specific values of + * this extension, he will derive a structure based on + * xsltElemPreComp; thus we obviously *cannot* refactor + * the xsltElemPreComp structure, since all already derived + * user-defined strucures will break. + * Example: For the extension xsl:document, + * in xsltDocumentComp() (preproc.c), the structure + * xsltStyleItemDocument is allocated, filled with + * specific values and returned. + * 2) If the author needs no values to be stored in + * this structure, then he'll return NULL; + */ comp = ext->precomp(style, inst, ext->transform); - if (comp == NULL) + } + if (comp == NULL) { + /* + * Default creation of a xsltElemPreComp structure, if + * the author of this extension did not create a custom + * structure. + */ comp = xsltNewElemPreComp(style, inst, ext->transform); + } return (comp); } @@ -1553,6 +1753,13 @@ xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI) { xsltExtDataPtr data; + /* + * TODO: Why do we have a return type of xmlHashTablePtr? + * Is the user-allocated data for extension modules expected + * to be a xmlHashTablePtr only? Or is this intended for + * the EXSLT module only? + */ + if (style != NULL && style->extInfos != NULL) { data = xmlHashLookup(style->extInfos, URI); if (data != NULL && data->extData != NULL) diff --git a/libxslt/extensions.h b/libxslt/extensions.h index 79130e4..1036fae 100644 --- a/libxslt/extensions.h +++ b/libxslt/extensions.h @@ -93,7 +93,12 @@ XSLTPUBFUN void * XSLTCALL XSLTPUBFUN void * XSLTCALL xsltStyleGetExtData (xsltStylesheetPtr style, const xmlChar *URI); - +#ifdef XSLT_REFACTORED +XSLTPUBFUN void * XSLTCALL + xsltStyleStylesheetLevelGetExtData( + xsltStylesheetPtr style, + const xmlChar * URI); +#endif XSLTPUBFUN void XSLTCALL xsltShutdownCtxtExts (xsltTransformContextPtr ctxt); @@ -210,7 +215,7 @@ XSLTPUBFUN int XSLTCALL const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltCheckExtPrefix (xsltStylesheetPtr style, - const xmlChar *prefix); + const xmlChar *URI); XSLTPUBFUN int XSLTCALL xsltInitCtxtExts (xsltTransformContextPtr ctxt); XSLTPUBFUN void XSLTCALL diff --git a/libxslt/imports.c b/libxslt/imports.c index 1a2b12d..8ff9f3d 100644 --- a/libxslt/imports.c +++ b/libxslt/imports.c @@ -41,6 +41,7 @@ #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" +#include "preproc.h" #include "imports.h" #include "documents.h" #include "security.h" @@ -229,7 +230,16 @@ xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) { "xsl:include : unable to load %s\n", URI); goto error; } - +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) { + ((xsltStyleItemIncludePtr) cur->psvi)->include = include; + } else { + xsltTransformError(NULL, style, cur, + "Internal error: (xsltParseStylesheetInclude) " + "The xsl:include element was not compiled.\n", URI); + style->errors++; + } +#endif oldDoc = style->doc; style->doc = include->doc; /* chain to stylesheet for recursion checking */ @@ -237,6 +247,12 @@ xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) { style->includes = include; oldNopreproc = style->nopreproc; style->nopreproc = include->preproc; + /* + * TODO: This will change some values of the + * including stylesheet with every included module + * (e.g. excluded-result-prefixes) + * We need to strictly seperate such stylesheet-owned values. + */ result = xsltParseStylesheetProcess(style, include->doc); style->nopreproc = oldNopreproc; include->preproc = 1; @@ -359,6 +375,13 @@ xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) { * @nameURI: the template name URI * * Finds the named template, apply import precedence rule. + * REVISIT TODO: We'll change the nameURI fields of + * templates to be in the string dict, so if the + * specified @nameURI is in the same dict, then use pointer + * comparison. Check if this can be done in a sane way. + * Maybe this function is not needed internally at + * transformation-time if we hard-wire the called templates + * to the caller. * * Returns the xsltTemplatePtr or NULL if not found */ diff --git a/libxslt/keys.c b/libxslt/keys.c index cb7c998..c03d172 100644 --- a/libxslt/keys.c +++ b/libxslt/keys.c @@ -369,6 +369,14 @@ xsltAddKey(xsltStylesheetPtr style, const xmlChar *name, xsltGenericDebug(xsltGenericDebugContext, " resulting pattern %s\n", pattern); #endif + /* + * XSLT-1: "It is an error for the value of either the use + * attribute or the match attribute to contain a + * VariableReference." + * TODO: We should report a variable-reference at compile-time. + * Maybe a search for "$", if it occurs outside of quotation + * marks, could be sufficient. + */ key->comp = xsltXPathCompile(style, pattern); if (key->comp == NULL) { xsltTransformError(NULL, style, inst, diff --git a/libxslt/preproc.c b/libxslt/preproc.c index 899c5fa..3e2d70c 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -52,6 +52,11 @@ const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; * * ************************************************************************/ +#ifdef XSLT_REFACTORED + /* + * Grammar checks are now performed in xslt.c. + */ +#else /** * xsltCheckTopLevelElement: * @style: the XSLT stylesheet @@ -197,6 +202,7 @@ xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, inst->name); style->errors++; } +#endif /************************************************************************ * * @@ -350,7 +356,6 @@ xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) { case XSLT_FUNC_PARAM: case XSLT_FUNC_VARIABLE: case XSLT_FUNC_WHEN: - case XSLT_FUNC_OTHERWISE: break; default: if (cur->func == NULL) { @@ -518,7 +523,8 @@ xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, * "output" in XSLT_SAXON_NAMESPACE * "write" XSLT_XALAN_NAMESPACE * "document" XSLT_XT_NAMESPACE - * "document" XSLT_NAMESPACE + * "document" XSLT_NAMESPACE (from the abandoned old working + * draft of XSLT 1.1) * (in libexslt/common.c) * "document" in EXSLT_COMMON_NAMESPACE */ @@ -544,6 +550,8 @@ xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, * (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", @@ -557,6 +565,10 @@ xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, /* * 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) { @@ -770,11 +782,17 @@ xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { 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 @@ -807,13 +825,14 @@ xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { if (xmlStrEqual(prop, (const xmlChar *)"yes")) { comp->noescape = 1; } else if (!xmlStrEqual(prop, - (const xmlChar *)"no")){ + (const xmlChar *)"no")){ xsltTransformError(NULL, style, inst, -"xsl:text: disable-output-escaping allows only yes or no\n"); + "xsl:text: disable-output-escaping allows only yes or no\n"); if (style != NULL) style->warnings++; } } } +#endif /* else of XSLT_REFACTORED */ /** * xsltElementComp: @@ -1774,85 +1793,6 @@ xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { } } -#ifdef XSLT_REFACTORED - -/* -* xsltCompilerGetInScopeNSInfo: -* -* Create and store the list of in-scope namespaces for the given -* node in the stylesheet. If there are no changes in the in-scope -* namespaces then the last ns-info of the ancestor axis will be returned. -* Compilation-time only. -* -* Returns the ns-info or NULL if there are no namespaces in scope. -*/ -xsltNsListPtr -xsltCompilerGetInScopeNSInfo(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) -{ - xsltNsListPtr nsi = NULL; - xmlNsPtr *list = NULL; - /* - * Create a new ns-list for this position in the node-tree. - * xmlGetNsList() will return NULL, if there are no ns-decls in the - * tree. Note that the ns-decl for the XML namespace is not added - * to the resulting list; the XPath module handles the XML namespace - * internally. - */ - list = xmlGetNsList(node->doc, node); - if (list == NULL) - return(NULL); - /* - * Initialize the list hold by the stylesheet. - */ - if (cctxt->sheet->inScopeNamespaces == NULL) { - cctxt->sheet->inScopeNamespaces = xsltPointerListCreate(); - if (cctxt->sheet->inScopeNamespaces == NULL) { - xsltTransformError(NULL, cctxt->sheet, NULL, - "xsltCompilerGetInScopeNSInfo: malloc failed.\n"); - goto internal_err; - } - } - /* - * Create the info-structure. - */ - nsi = (xsltNsListPtr) xmlMalloc(sizeof(xsltNsList)); - if (nsi == NULL) { - xsltTransformError(NULL, cctxt->sheet, NULL, - "xsltCompilerGetInScopeNSInfo: malloc failed.\n"); - goto internal_err; - } - memset(nsi, 0, sizeof(xsltNsList)); - nsi->list = list; - /* - * Eval the number of ns-decls; this is used to speed up - * XPath-context initialization. - */ - while (list[nsi->number] != NULL) - nsi->number++; - /* - * Store the ns-list in the stylesheet. - */ - if (xsltPointerListAdd( - (xsltPointerListPtr)cctxt->sheet->inScopeNamespaces, - (void *) nsi) == -1) - { - xmlFree(nsi); - nsi = NULL; - xsltTransformError(NULL, cctxt->sheet, NULL, - "xsltCompilerGetInScopeNSInfo: failed to add ns-info.\n"); - goto internal_err; - } - - return(nsi); - -internal_err: - if (list != NULL) - xmlFree(list); - cctxt->sheet->errors++; - return(NULL); -} -#endif /* XSLT_REFACTORED */ - /************************************************************************ * * * Generic interface * @@ -1870,10 +1810,11 @@ xsltFreeStylePreComps(xsltStylesheetPtr style) { xsltElemPreCompPtr cur, next; if (style == NULL) - return; + return; + cur = style->preComps; while (cur != NULL) { - next = cur->next; + next = cur->next; if (cur->type == XSLT_FUNC_EXTENSION) cur->free(cur); else @@ -1882,6 +1823,221 @@ xsltFreeStylePreComps(xsltStylesheetPtr style) { } } +#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 @@ -1895,10 +2051,14 @@ 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. + * 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 (inst->psvi != NULL) + return; + if (IS_XSLT_ELEM(inst)) { xsltStylePreCompPtr cur; @@ -1965,7 +2125,7 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { } else if (IS_XSLT_NAME(inst, "call-template")) { xsltCheckInstructionElement(style, inst); xsltCallTemplateComp(style, inst); - } else if (IS_XSLT_NAME(inst, "param")) { + } else if (IS_XSLT_NAME(inst, "param")) { if (xsltCheckTopLevelElement(style, inst, 0) == 0) xsltCheckInstructionElement(style, inst); xsltParamComp(style, inst); @@ -2034,18 +2194,7 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { if (style != NULL) style->warnings++; } - cur = (xsltStylePreCompPtr) inst->psvi; - -#ifdef XSLT_REFACTORED - /* - * Assign the current list of in-scope namespaces to the - * item. This is needed for XPath expressions. - */ - if (cur != NULL) { - cur->inScopeNS = XSLT_CCTXT(style)->inode->inScopeNS; - } -#else /* * A ns-list is build for every XSLT item in the * node-tree. This is needed for XPath expressions. @@ -2060,7 +2209,6 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { } cur->nsNr = i; } -#endif } else { inst->psvi = (void *) xsltPreComputeExtModuleElement(style, inst); @@ -2073,3 +2221,4 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { inst->psvi = (void *) xsltExtMarker; } } +#endif /* XSLT_REFACTORED */ diff --git a/libxslt/transform.c b/libxslt/transform.c index f3b392f..ae66aa0 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -1624,7 +1624,11 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node, xslHandleDebugger(cur, node, templ, ctxt); #endif +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(cur)) { +#else if (IS_XSLT_ELEM(cur)) { +#endif /* * This is an XSLT node */ @@ -2949,9 +2953,9 @@ xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3065,9 +3069,9 @@ xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3232,7 +3236,11 @@ xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, * structure. Avoid to "search" for params dynamically * in the XML tree every time. */ +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(cur)) { +#else if (IS_XSLT_ELEM(cur)) { +#endif if (IS_XSLT_NAME(cur, "with-param")) { param = xsltParseStylesheetCallerParam(ctxt, cur); if (param != NULL) { @@ -3345,9 +3353,9 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3500,7 +3508,11 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, #endif #endif if (ctxt->state == XSLT_STATE_STOPPED) break; +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(cur)) { +#else if (IS_XSLT_ELEM(cur)) { +#endif if (IS_XSLT_NAME(cur, "with-param")) { param = xsltParseStylesheetCallerParam(ctxt, cur); if (param != NULL) { @@ -3620,13 +3632,23 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node, "xsl:choose: empty content not allowed\n"); goto error; } - if (((!IS_XSLT_ELEM(replacement)) || (!IS_XSLT_NAME(replacement, "when"))) +#ifdef XSLT_REFACTORED + if (((!IS_XSLT_ELEM_FAST(replacement)) || +#else + if (((!IS_XSLT_ELEM(replacement)) || +#endif + (!IS_XSLT_NAME(replacement, "when"))) && (!xmlIsBlankNode(replacement))) { xsltTransformError(ctxt, NULL, inst, "xsl:choose: xsl:when expected first\n"); goto error; } - while ((IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "when"))) +#ifdef XSLT_REFACTORED + while ((IS_XSLT_ELEM_FAST(replacement) && +#else + while ((IS_XSLT_ELEM(replacement) && +#endif + (IS_XSLT_NAME(replacement, "when"))) || xmlIsBlankNode(replacement)) { #ifdef XSLT_REFACTORED xsltStyleItemWhenPtr wcomp = @@ -3669,9 +3691,9 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node, oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (wcomp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = wcomp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = wcomp->inScopeNS->number; + if (wcomp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = wcomp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3715,7 +3737,12 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node, res = NULL; replacement = replacement->next; } - if (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "otherwise"))) { +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(replacement) && +#else + if (IS_XSLT_ELEM(replacement) && +#endif + (IS_XSLT_NAME(replacement, "otherwise"))) { #ifdef WITH_DEBUGGER if (xslDebugStatus != XSLT_DEBUG_NONE) #ifdef XSLT_REFACTORED @@ -3791,9 +3818,9 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3886,9 +3913,9 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node, oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -3933,7 +3960,12 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node, * handle and skip the xsl:sort */ replacement = inst->children; - while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) { +#ifdef XSLT_REFACTORED + while (IS_XSLT_ELEM_FAST(replacement) && +#else + while (IS_XSLT_ELEM(replacement) && +#endif + (IS_XSLT_NAME(replacement, "sort"))) { if (nbsorts >= XSLT_MAX_SORT) { xsltGenericError(xsltGenericErrorContext, "xsl:for-each: too many sorts\n"); diff --git a/libxslt/variables.c b/libxslt/variables.c index 88caf17..8bb8771 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -467,9 +467,9 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, if (precomp != NULL) { ctxt->inst = precomp->inst; #ifdef XSLT_REFACTORED - if (precomp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = precomp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = precomp->inScopeNS->number; + if (precomp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -628,9 +628,9 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) if (precomp != NULL) { ctxt->inst = precomp->inst; #ifdef XSLT_REFACTORED - if (precomp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = precomp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = precomp->inScopeNS->number; + if (precomp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; @@ -1389,10 +1389,12 @@ xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, /** * xsltParseStylesheetCallerParam: * @ctxt: the XSLT transformation context - * @cur: the "param" element + * @cur: the "xsl:with-param" element * * parse an XSLT transformation param declaration, compute * its value but doesn't record it. + * NOTE that this is also called with an *xsl:param* element + * from exsltFuncFunctionFunction(). * * Returns the new xsltStackElemPtr or NULL */ @@ -1417,19 +1419,19 @@ xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) #endif if (comp == NULL) { xsltTransformError(ctxt, NULL, cur, - "xsl:param : compilation error\n"); + "xsl:with-param : compilation error\n"); return(NULL); } if (comp->name == NULL) { xsltTransformError(ctxt, NULL, cur, - "xsl:param : missing name attribute\n"); + "xsl:with-param : missing name attribute\n"); return(NULL); } #ifdef WITH_XSLT_DEBUG_VARIABLE XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, - "Handling param %s\n", comp->name)); + "Handling xsl:with-param %s\n", comp->name)); #endif if (comp->select == NULL) { @@ -1467,11 +1469,15 @@ xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) if ((cur == NULL) || (style == NULL)) return; - - xsltStylePreCompute(style, cur); + #ifdef XSLT_REFACTORED + /* + * Note that xsltStylePreCompute() will be called from + * xslt.c only. + */ comp = (xsltStyleItemVariablePtr) cur->psvi; #else + xsltStylePreCompute(style, cur); comp = (xsltStylePreCompPtr) cur->psvi; #endif if (comp == NULL) { @@ -1486,8 +1492,15 @@ xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) return; } + /* + * Parse the content (a sequence constructor) of xsl:variable. + */ if (cur->children != NULL) { +#ifdef XSLT_REFACTORED + xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); +#else xsltParseTemplateContent(style, cur); +#endif } #ifdef WITH_XSLT_DEBUG_VARIABLE xsltGenericDebug(xsltGenericDebugContext, @@ -1518,11 +1531,15 @@ xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { if ((cur == NULL) || (style == NULL)) return; - - xsltStylePreCompute(style, cur); + #ifdef XSLT_REFACTORED + /* + * Note that xsltStylePreCompute() will be called from + * xslt.c only. + */ comp = (xsltStyleItemParamPtr) cur->psvi; #else + xsltStylePreCompute(style, cur); comp = (xsltStylePreCompPtr) cur->psvi; #endif if (comp == NULL) { @@ -1537,8 +1554,15 @@ xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { return; } + /* + * Parse the content (a sequence constructor) of xsl:param. + */ if (cur->children != NULL) { +#ifdef XSLT_REFACTORED + xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); +#else xsltParseTemplateContent(style, cur); +#endif } #ifdef WITH_XSLT_DEBUG_VARIABLE diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 63a7ed8..8d1dd03 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -51,6 +51,40 @@ const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA; const int xsltLibxsltVersion = LIBXSLT_VERSION; const int xsltLibxmlVersion = LIBXML_VERSION; +#ifdef XSLT_REFACTORED + +const xmlChar *xsltConstNamespaceNameXSLT= (const xmlChar *) XSLT_NAMESPACE; + +static const xmlChar *xsltLibxsltDataElementNameMeta = + (const xmlChar *) "meta"; + +static const xmlChar *xsltLibxsltDataElementNamespaceMeta = + (const xmlChar *) XSLT_DEFAULT_URL; + +static const xmlChar *xsltUserDataElemMarker = + (const xmlChar *) "User Data Element"; + +/* +* xsltLiteralResultMarker: +* Marker for Literal result elements, in order to avoid multiple attempts +* to recognize such elements in the stylesheet's tree. +* This marker is set on node->psvi during the initial traversal +* of a stylesheet's node tree. +* +const xmlChar *xsltLiteralResultMarker = + (const xmlChar *) "Literal Result Element"; +*/ + +/* +* xsltXSLTTextMarker: +* Marker for xsl:text elements. Used to recognize xsl:text elements +* for post-processing of the stylesheet's tree, where those +* elements are removed from the tree. +*/ +const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element"; + +#endif + /* * Harmless but avoiding a problem when compiling against a * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED @@ -75,11 +109,39 @@ double xmlXPathStringEvalNumber(const xmlChar *str); (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) /** + * xsltParseContentError: + * + * @style: the stylesheet + * @node: the node where the error occured + * + * Compile-time error function. + */ +static void +xsltParseContentError(xsltStylesheetPtr style, + xmlNodePtr node) +{ + if ((style == NULL) || (node == NULL)) + return; + + if (IS_XSLT_ELEM(node)) + xsltTransformError(NULL, style, node, + "The XSLT-element '%s' is not allowed at this position.\n", + node->name); + else + xsltTransformError(NULL, style, node, + "The element '%s' is not allowed at this position.\n", + node->name); + style->errors++; +} + +#ifdef XSLT_REFACTORED +#else +/** * exclPrefixPush: * @style: the transformation stylesheet - * @value: the excluded prefix to push on the stack + * @value: the excluded namespace name to push on the stack * - * Push an excluded prefix on the stack + * Push an excluded namespace name on the stack * * Returns the new index in the stack or 0 in case of error */ @@ -135,6 +197,7 @@ exclPrefixPop(xsltStylesheetPtr style) style->exclPrefixTab[style->exclPrefixNr] = 0; return (ret); } +#endif /************************************************************************ * * @@ -270,7 +333,7 @@ xsltFreeDecimalFormatList(xsltStylesheetPtr self) /** * xsltDecimalFormatGetByName: - * @sheet: the XSLT stylesheet + * @style: the XSLT stylesheet * @name: the decimal-format name to find * * Find decimal-format by name @@ -278,21 +341,21 @@ xsltFreeDecimalFormatList(xsltStylesheetPtr self) * Returns the xsltDecimalFormatPtr */ xsltDecimalFormatPtr -xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name) +xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name) { xsltDecimalFormatPtr result = NULL; if (name == NULL) - return sheet->decimalFormat; + return style->decimalFormat; - while (sheet != NULL) { - for (result = sheet->decimalFormat->next; + while (style != NULL) { + for (result = style->decimalFormat->next; result != NULL; result = result->next) { if (xmlStrEqual(name, result->name)) return result; } - sheet = xsltNextImport(sheet); + style = xsltNextImport(style); } return result; } @@ -331,8 +394,11 @@ xsltFreeTemplate(xsltTemplatePtr template) { if (template == NULL) return; if (template->match) xmlFree(template->match); - if (template->name) xmlFree(template->name); - if (template->nameURI) xmlFree(template->nameURI); +/* +* NOTE: @name and @nameURI are put into the string dict now. +* if (template->name) xmlFree(template->name); +* if (template->nameURI) xmlFree(template->nameURI); +*/ /* if (template->mode) xmlFree(template->mode); if (template->modeURI) xmlFree(template->modeURI); @@ -359,69 +425,247 @@ xsltFreeTemplateList(xsltTemplatePtr template) { } } +#ifdef XSLT_REFACTORED /** - * xsltNewStylesheet: + * xsltCompilerCreate: * - * Create a new XSLT Stylesheet + * Create an XSLT compiler context. * - * Returns the newly allocated xsltStylesheetPtr or NULL in case of error + * Returns the allocated xsltCompilerCtxtPtr or NULL in case of error. */ -xsltStylesheetPtr -xsltNewStylesheet(void) { - xsltStylesheetPtr cur; -#ifdef XSLT_REFACTORED - xsltCompilerCtxtPtr cctxt; -#endif +static xsltCompilerCtxtPtr +xsltCompilerCreate(xsltStylesheetPtr style) { + xsltCompilerCtxtPtr ret; - cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet)); - if (cur == NULL) { - xsltTransformError(NULL, NULL, NULL, - "xsltNewStylesheet : malloc failed\n"); + ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt)); + if (ret == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltCompilerCreate: allocation of compiler " + "context failed.\n"); return(NULL); } - memset(cur, 0, sizeof(xsltStylesheet)); -#ifdef XSLT_REFACTORED + memset(ret, 0, sizeof(xsltCompilerCtxt)); + + ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR; + + style->compCtxt = (void *) ret; + ret->style = style; + ret->tmpList = xsltPointerListCreate(20); + if (ret->tmpList == NULL) { + xmlFree(ret); + return(NULL); + } + ret->dict = style->dict; + return(ret); +} + +static void +xsltCompilerCtxtFree(xsltCompilerCtxtPtr cctxt) +{ + if (cctxt == NULL) + return; /* - * Create the compiler context. + * Free node-infos. */ - cctxt = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt)); - if (cctxt == NULL) { - xmlFree(cur); + if (cctxt->inodeList != NULL) { + xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList; + while (cur != NULL) { + tmp = cur; + cur = cur->next; + xmlFree(tmp); + } + } + if (cctxt->tmpList != NULL) + xsltPointerListFree(cctxt->tmpList); + xmlFree(cctxt); +} + +static void +xsltFreeNamespaceMap(xsltNsMapPtr item) +{ + xsltNsMapPtr tmp; + + while (item) { + tmp = item; + item = item->next; + xmlFree(tmp); + } + return; +} + +static xsltNsMapPtr +xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt, + xmlDocPtr doc, + xmlNodePtr elem, + xmlNsPtr ns) +{ + xsltNsMapPtr ret; + + if ((cctxt == NULL) || (doc == NULL) || (elem == NULL) || + (ns == NULL)) + return(NULL); + + ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap)); + if (ret == NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "Internal error: (xsltNewNamespaceMapItem) " + "memory allocation failed.\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltNsMap)); + ret->doc = doc; + ret->ns = ns; + ret->origNsName = ns->href; + /* + * Store the item at current stylesheet-level. + */ + if (cctxt->psData->nsMap != NULL) + ret->next = cctxt->psData->nsMap; + cctxt->psData->nsMap = ret; + + return(ret); +} + +static void +xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data) +{ + if (data == NULL) + return; + + if (data->inScopeNamespaces != NULL) { + int i; + xsltNsListPtr nsi; + xsltPointerListPtr list = + (xsltPointerListPtr) data->inScopeNamespaces; + + for (i = 0; i < list->number; i++) { + /* + * REVISIT TODO: Free info of in-scope namespaces. + */ + nsi = (xsltNsListPtr) list->items[i]; + if (nsi->list != NULL) + xmlFree(nsi->list); + xmlFree(nsi); + } + xsltPointerListFree(list); + data->inScopeNamespaces = NULL; + } + + if (data->exclResultNamespaces != NULL) { + int i; + xsltPointerListPtr list = (xsltPointerListPtr) + data->exclResultNamespaces; + + for (i = 0; i < list->number; i++) + xsltPointerListFree((xsltPointerListPtr) list->items[i]); + + xsltPointerListFree(list); + data->exclResultNamespaces = NULL; + } + + if (data->extElemNamespaces != NULL) { + xsltPointerListPtr list = (xsltPointerListPtr) + data->extElemNamespaces; + int i; + + for (i = 0; i < list->number; i++) + xsltPointerListFree((xsltPointerListPtr) list->items[i]); + + xsltPointerListFree(list); + data->extElemNamespaces = NULL; + } + xsltFreeNamespaceMap(data->nsMap); + xmlFree(data); +} + +static xsltPrincipalStylesheetDataPtr +xsltNewPrincipalStylesheetData(void) +{ + xsltPrincipalStylesheetDataPtr ret; + + ret = (xsltPrincipalStylesheetDataPtr) + xmlMalloc(sizeof(xsltPrincipalStylesheetData)); + if (ret == NULL) { xsltTransformError(NULL, NULL, NULL, - "xsltNewStylesheet : malloc of compilation context failed\n"); + "xsltNewPrincipalStylesheetData: memory allocation failed.\n"); return(NULL); } - memset(cctxt, 0, sizeof(xsltCompilerCtxt)); - cur->compCtxt = (void *) cctxt; - cctxt->sheet = cur; -#endif + memset(ret, 0, sizeof(xsltPrincipalStylesheetData)); + /* - * TODO: This here seems to be the best place where to create - * the compilation context, right? - */ - - cur->omitXmlDeclaration = -1; - cur->standalone = -1; - cur->decimalFormat = xsltNewDecimalFormat(NULL); - cur->indent = -1; - cur->errors = 0; - cur->warnings = 0; - cur->exclPrefixNr = 0; - cur->exclPrefixMax = 0; - cur->exclPrefixTab = NULL; - cur->extInfos = NULL; - cur->extrasNr = 0; - cur->internalized = 1; - cur->literal_result = 0; - cur->dict = xmlDictCreate(); + * Global list of in-scope namespaces. + */ + ret->inScopeNamespaces = xsltPointerListCreate(-1); + if (ret->inScopeNamespaces == NULL) + goto internal_err; + /* + * Global list of excluded result ns-decls. + */ + ret->exclResultNamespaces = xsltPointerListCreate(-1); + if (ret->exclResultNamespaces == NULL) + goto internal_err; + /* + * Global list of extension element namespace names. + */ + ret->extElemNamespaces = xsltPointerListCreate(-1); + if (ret->extElemNamespaces == NULL) + goto internal_err; + + return(ret); + +internal_err: + + return(NULL); +} + +#endif + +/** + * xsltNewStylesheet: + * + * Create a new XSLT Stylesheet + * + * Returns the newly allocated xsltStylesheetPtr or NULL in case of error + */ +xsltStylesheetPtr +xsltNewStylesheet(void) { + xsltStylesheetPtr ret = NULL; + + ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewStylesheet : malloc failed\n"); + goto internal_err; + } + memset(ret, 0, sizeof(xsltStylesheet)); + + ret->omitXmlDeclaration = -1; + ret->standalone = -1; + ret->decimalFormat = xsltNewDecimalFormat(NULL); + ret->indent = -1; + ret->errors = 0; + ret->warnings = 0; + ret->exclPrefixNr = 0; + ret->exclPrefixMax = 0; + ret->exclPrefixTab = NULL; + ret->extInfos = NULL; + ret->extrasNr = 0; + ret->internalized = 1; + ret->literal_result = 0; + ret->dict = xmlDictCreate(); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, - "creating dictionary for stylesheet\n"); + "creating dictionary for stylesheet\n"); #endif xsltInit(); - return(cur); + return(ret); + +internal_err: + if (ret != NULL) + xsltFreeStylesheet(ret); + return(NULL); } /** @@ -495,149 +739,190 @@ xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt) /** * xsltFreeStylesheetList: - * @sheet: an XSLT stylesheet list + * @style: an XSLT stylesheet list * - * Free up the memory allocated by the list @sheet + * Free up the memory allocated by the list @style */ static void -xsltFreeStylesheetList(xsltStylesheetPtr sheet) { +xsltFreeStylesheetList(xsltStylesheetPtr style) { xsltStylesheetPtr next; - while (sheet != NULL) { - next = sheet->next; - xsltFreeStylesheet(sheet); - sheet = next; + while (style != NULL) { + next = style->next; + xsltFreeStylesheet(style); + style = next; } } -#ifdef XSLT_REFACTORED /** - * xsltFreeInScopeNamespaces: - * @sheet: an XSLT stylesheet + * xsltCleanupStylesheetTree: + * + * @doc: the document-node + * @node: the element where the stylesheet is rooted at * - * Frees the list of in-scope namespace lists. + * Actually @node need not be the document-element, but + * currently Libxslt does not support embedeed stylesheets. + * + * Returns 0 if OK, -1 on API or internal errors. */ -static void -xsltFreeInScopeNamespaces(xsltStylesheetPtr sheet) +static int +xsltCleanupStylesheetTree(xmlDocPtr doc, xmlNodePtr rootElem) { - if (sheet->inScopeNamespaces == NULL) - return; - else { - int i; - xsltNsListPtr nsi; - xsltPointerListPtr list = sheet->inScopeNamespaces; + xmlNodePtr cur; - for (i = 0; i < list->number; i++) { + if ((doc == NULL) || (rootElem == NULL) || + (rootElem->type != XML_ELEMENT_NODE) || + (doc != rootElem->doc)) + return(-1); + + /* + * Cleanup was suggested by Aleksey Sanin: + * Clear the PSVI field to avoid problems if the + * node-tree of the stylesheet is intended to be used for + * further processing by the user (e.g. for compiling it + * once again - although not recommended). + */ + + cur = rootElem; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { /* - * REVISIT TODO: Free info of in-scope namespaces. + * Clear the PSVI field. */ - nsi = (xsltNsListPtr) list->items[i]; - if (nsi->list != NULL) - xmlFree(nsi->list); - xmlFree(nsi); + cur->psvi = NULL; + if (cur->children) { + cur = cur->children; + continue; + } } - xsltPointerListFree(list); - sheet->inScopeNamespaces = NULL; - } - return; -} -static void -xsltCompilerCtxtFree(xsltCompilerCtxtPtr cctxt) -{ - if (cctxt == NULL) - return; - /* - * Free node-infos. - */ - if (cctxt->inodeList != NULL) { - xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList; - while (cur != NULL) { - tmp = cur; +leave_node: + if (cur == rootElem) + break; + if (cur->next != NULL) cur = cur->next; - xmlFree(tmp); + else { + cur = cur->parent; + if (cur == NULL) + break; + goto leave_node; } } - xmlFree(cctxt); + return(0); } -#endif /** * xsltFreeStylesheet: - * @sheet: an XSLT stylesheet + * @style: an XSLT stylesheet * - * Free up the memory allocated by @sheet + * Free up the memory allocated by @style */ void -xsltFreeStylesheet(xsltStylesheetPtr sheet) +xsltFreeStylesheet(xsltStylesheetPtr style) { - if (sheet == NULL) + if (style == NULL) return; - - xsltFreeKeys(sheet); - xsltFreeExts(sheet); - xsltFreeTemplateHashes(sheet); - xsltFreeDecimalFormatList(sheet); - xsltFreeTemplateList(sheet->templates); - xsltFreeAttributeSetsHashes(sheet); - xsltFreeNamespaceAliasHashes(sheet); + #ifdef XSLT_REFACTORED - if (sheet->inScopeNamespaces != NULL) - xsltFreeInScopeNamespaces(sheet); + /* + * Start with a cleanup of the main stylesheet's doc. + */ + if ((style->principal == style) && (style->doc)) + xsltCleanupStylesheetTree(style->doc, + xmlDocGetRootElement(style->doc)); + /* + * Restore changed ns-decls before freeing the document. + */ + if ((style->doc != NULL) && + XSLT_HAS_INTERNAL_NSMAP(style)) + { + xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style), + style->doc); + } +#else + /* + * Start with a cleanup of the main stylesheet's doc. + */ + if ((style->parent == NULL) && (style->doc)) + xsltCleanupStylesheetTree(style->doc, + xmlDocGetRootElement(style->doc)); #endif - xsltFreeStyleDocuments(sheet); - xsltFreeStylePreComps(sheet); - xsltShutdownExts(sheet); - if (sheet->doc != NULL) - xmlFreeDoc(sheet->doc); - if (sheet->variables != NULL) - xsltFreeStackElemList(sheet->variables); - if (sheet->cdataSection != NULL) - xmlHashFree(sheet->cdataSection, NULL); - if (sheet->stripSpaces != NULL) - xmlHashFree(sheet->stripSpaces, NULL); - if (sheet->nsHash != NULL) - xmlHashFree(sheet->nsHash, NULL); - - if (sheet->exclPrefixTab != NULL) - xmlFree(sheet->exclPrefixTab); - if (sheet->method != NULL) - xmlFree(sheet->method); - if (sheet->methodURI != NULL) - xmlFree(sheet->methodURI); - if (sheet->version != NULL) - xmlFree(sheet->version); - if (sheet->encoding != NULL) - xmlFree(sheet->encoding); - if (sheet->doctypePublic != NULL) - xmlFree(sheet->doctypePublic); - if (sheet->doctypeSystem != NULL) - xmlFree(sheet->doctypeSystem); - if (sheet->mediaType != NULL) - xmlFree(sheet->mediaType); - if (sheet->attVTs) - xsltFreeAVTList(sheet->attVTs); - - if (sheet->imports != NULL) - xsltFreeStylesheetList(sheet->imports); + + xsltFreeKeys(style); + xsltFreeExts(style); + xsltFreeTemplateHashes(style); + xsltFreeDecimalFormatList(style); + xsltFreeTemplateList(style->templates); + xsltFreeAttributeSetsHashes(style); + xsltFreeNamespaceAliasHashes(style); + xsltFreeStylePreComps(style); + /* + * Free documents of all included stylsheet modules of this + * stylesheet level. + */ + xsltFreeStyleDocuments(style); + /* + * TODO: Best time to shutdown extension stuff? + */ + xsltShutdownExts(style); + + if (style->variables != NULL) + xsltFreeStackElemList(style->variables); + if (style->cdataSection != NULL) + xmlHashFree(style->cdataSection, NULL); + if (style->stripSpaces != NULL) + xmlHashFree(style->stripSpaces, NULL); + if (style->nsHash != NULL) + xmlHashFree(style->nsHash, NULL); + if (style->exclPrefixTab != NULL) + xmlFree(style->exclPrefixTab); + if (style->method != NULL) + xmlFree(style->method); + if (style->methodURI != NULL) + xmlFree(style->methodURI); + if (style->version != NULL) + xmlFree(style->version); + if (style->encoding != NULL) + xmlFree(style->encoding); + if (style->doctypePublic != NULL) + xmlFree(style->doctypePublic); + if (style->doctypeSystem != NULL) + xmlFree(style->doctypeSystem); + if (style->mediaType != NULL) + xmlFree(style->mediaType); + if (style->attVTs) + xsltFreeAVTList(style->attVTs); + if (style->imports != NULL) + xsltFreeStylesheetList(style->imports); + #ifdef XSLT_REFACTORED /* - * TODO: Just a paranoid cleanup, in case the compilation - * context was not freed after the compilation. + * If this is the principal stylesheet, then + * free its internal data. */ - if (sheet->compCtxt != NULL) { - xsltCompilerCtxtFree((xsltCompilerCtxtPtr) sheet->compCtxt); - } + if (style->principal == style) { + if (style->principalData) { + xsltFreePrincipalStylesheetData(style->principalData); + style->principalData = NULL; + } + } #endif + /* + * Better to free the main document of this stylesheet level + * at the end - so here. + */ + if (style->doc != NULL) { + xmlFreeDoc(style->doc); + } #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, "freeing dictionary from stylesheet\n"); #endif - xmlDictFree(sheet->dict); + xmlDictFree(style->dict); - memset(sheet, -1, sizeof(xsltStylesheet)); - xmlFree(sheet); + memset(style, -1, sizeof(xsltStylesheet)); + xmlFree(style); } /************************************************************************ @@ -646,6 +931,11 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) * * ************************************************************************/ +#ifdef XSLT_REFACTORED + /* + * This is now performed in an optimized way in xsltParseXSLTTemplate. + */ +#else /** * xsltGetInheritedNsList: * @style: the stylesheet @@ -676,7 +966,7 @@ xsltGetInheritedNsList(xsltStylesheetPtr style, * * Will have foo="urn:test:foo" in the list. - * Is this a bug? + * Is this OK? */ if ((style == NULL) || (template == NULL) || (node == NULL) || @@ -688,6 +978,7 @@ xsltGetInheritedNsList(xsltStylesheetPtr style, while (cur != NULL) { if (xmlStrEqual(cur->href, XSLT_NAMESPACE)) goto skip_ns; + if ((cur->prefix != NULL) && (xsltCheckExtPrefix(style, cur->prefix))) goto skip_ns; @@ -751,6 +1042,7 @@ skip_ns: } return (nbns); } +#endif /* else of XSLT_REFACTORED */ /** * xsltParseStylesheetOutput: @@ -842,7 +1134,7 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) } else { xsltTransformError(NULL, style, cur, "invalid value for standalone: %s\n", prop); - if (style != NULL) style->warnings++; + style->errors++; } xmlFree(prop); } @@ -856,7 +1148,7 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) } else { xsltTransformError(NULL, style, cur, "invalid value for indent: %s\n", prop); - if (style != NULL) style->warnings++; + style->errors++; } xmlFree(prop); } @@ -871,7 +1163,7 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) xsltTransformError(NULL, style, cur, "invalid value for omit-xml-declaration: %s\n", prop); - if (style != NULL) style->warnings++; + style->errors++; } xmlFree(prop); } @@ -894,34 +1186,51 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) while ((*end != 0) && (!IS_BLANK(*end))) end++; element = xmlStrndup(element, end - element); - if (element) { - const xmlChar *URI; + if (element) { #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "add cdata section output element %s\n", element); #endif - - URI = xsltGetQNameURI(cur, &element); - if (element == NULL) { - if (style != NULL) style->errors++; + if (xmlValidateQName(BAD_CAST element, 0) != 0) { + xsltTransformError(NULL, style, cur, + "Attribute 'cdata-section-elements': The value " + "'%s' is not a valid QName.\n", element); + xmlFree(element); + style->errors++; } else { - xmlNsPtr ns; - - xmlHashAddEntry2(style->cdataSection, element, URI, - (void *) "cdata"); - /* - * if prefix is NULL, we must check whether it's - * necessary to also put in the name of the default - * namespace. - */ - if (URI == NULL) { - ns = xmlSearchNs(style->doc, cur, NULL); - if (ns != NULL) - xmlHashAddEntry2(style->cdataSection, element, - ns->href, (void *) "cdata"); + const xmlChar *URI; + + URI = xsltGetQNameURI(cur, &element); + if (element == NULL) { + /* + * TODO: We'll report additionally an error + * via the stylesheet's error handling. + */ + xsltTransformError(NULL, style, cur, + "Attribute 'cdata-section-elements': The value " + "'%s' is not a valid QName.\n", element); + style->errors++; + } else { + xmlNsPtr ns; + + /* + * XSLT-1.0 "Each QName is expanded into an + * expanded-name using the namespace declarations in + * effect on the xsl:output element in which the QName + * occurs; if there is a default namespace, it is used + * for QNames that do not have a prefix" + * NOTE: Fix of bug #339570. + */ + if (URI == NULL) { + ns = xmlSearchNs(style->doc, cur, NULL); + if (ns != NULL) + URI = ns->href; + } + xmlHashAddEntry2(style->cdataSection, element, URI, + (void *) "cdata"); + xmlFree(element); } - xmlFree(element); } } element = end; @@ -935,6 +1244,9 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) xmlFree(style->mediaType); style->mediaType = prop; } + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } } /** @@ -1046,6 +1358,9 @@ xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur) if (format->patternSeparator != NULL) xmlFree(format->patternSeparator); format->patternSeparator = prop; } + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } } /** @@ -1106,8 +1421,13 @@ xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { element = end; } xmlFree(elements); + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } } +#ifdef XSLT_REFACTORED +#else /** * xsltParseStylesheetExtPrefix: * @style: the XSLT stylesheet @@ -1122,7 +1442,6 @@ xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { * literal result element * 3) TODO: an extension element." */ - static void xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur, int isXsltElem) { @@ -1178,6 +1497,7 @@ xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur, } xmlFree(prefixes); } +#endif /* else of XSLT_REFACTORED */ /** * xsltParseStylesheetStripSpace: @@ -1237,8 +1557,13 @@ xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { element = end; } xmlFree(elements); + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } } +#ifdef XSLT_REFACTORED +#else /** * xsltParseStylesheetExcludePrefix: * @style: the XSLT stylesheet @@ -1307,55 +1632,109 @@ xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur, xmlFree(prefixes); return(nb); } +#endif /* else of XSLT_REFACTORED */ #ifdef XSLT_REFACTORED -static xsltCompilerNodeInfoPtr -xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +/* +* xsltCompilerNodePush: +* +* @cctxt: the compilation context +* @node: the node to be pushed (this can also be the doc-node) +* +* Returns the current node info structure or +* NULL in case of an internal error. +*/ +xsltCompilerNodeInfoPtr +xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { + xsltCompilerNodeInfoPtr inode; + if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) { - cctxt->inode = cctxt->inode->next; + inode = cctxt->inode->next; } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) { - cctxt->inode = cctxt->inodeList; + inode = cctxt->inodeList; } else { /* * Create a new node-info. */ - cctxt->inode = (xsltCompilerNodeInfoPtr) + inode = (xsltCompilerNodeInfoPtr) xmlMalloc(sizeof(xsltCompilerNodeInfo)); - if (cctxt->inode == NULL) { - xsltTransformError(NULL, cctxt->sheet, NULL, + if (inode == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, "xsltCompilerNodePush: malloc failed.\n"); return(NULL); } - memset(cctxt->inode, 0, sizeof(xsltCompilerNodeInfo)); + memset(inode, 0, sizeof(xsltCompilerNodeInfo)); if (cctxt->inodeList == NULL) - cctxt->inodeList = cctxt->inode; + cctxt->inodeList = inode; else { - cctxt->inodeLast->next = cctxt->inode; - cctxt->inode->prev = cctxt->inodeLast; + cctxt->inodeLast->next = inode; + inode->prev = cctxt->inodeLast; } - cctxt->inodeLast = cctxt->inode; + cctxt->inodeLast = inode; + cctxt->maxNodeInfos++; } /* * REVISIT TODO: Keep the reset always complete. */ cctxt->depth++; - cctxt->inode->depth = cctxt->depth; - cctxt->inode->templ = NULL; - cctxt->inode->item = NULL; - cctxt->inode->node = node; + /* - * Inherit the list of in-scope namespaces. + * NOTE: Be carefull with the @node, since it might be + * a doc-node. */ - if (cctxt->inode->prev != NULL) - cctxt->inode->inScopeNS = cctxt->inode->prev->inScopeNS; - else - cctxt->inode->inScopeNS = NULL; + inode->node = node; + + inode->depth = cctxt->depth; + inode->templ = NULL; + inode->category = XSLT_ELEMENT_CATEGORY_XSLT; + inode->type = 0; + inode->item = NULL; + inode->curChildType = 0; + inode->extContentHandled = 0; + inode->isRoot = 0; - return(cctxt->inode); + if (inode->prev != NULL) { + /* + * Inherit the following information: + */ + inode->inScopeNs = inode->prev->inScopeNs; + /* + * in-scope namespaces + */ + inode->exclResultNs = inode->prev->exclResultNs; + /* + * extension-element namespaces + */ + inode->extElemNs = inode->prev->extElemNs; + /* + * whitespace perservation + */ + inode->preserveWhitespace = inode->prev->preserveWhitespace; + /* + * forwards-compatible mode + */ + inode->forwardsCompat = inode->prev->forwardsCompat; + } else { + inode->inScopeNs = NULL; + inode->exclResultNs = NULL; + inode->extElemNs = NULL; + inode->preserveWhitespace = 0; + inode->forwardsCompat = 0; + } + cctxt->inode = inode; + return(inode); } +/* +* xsltCompilerNodePop: +* +* @cctxt: the compilation context +* @node: the node to be pushed (this can also be the doc-node) +* +* Pops the current node info. +*/ static void xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { @@ -1363,134 +1742,931 @@ xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Top-node mismatch.\n"); return; - } - if (cctxt->inode->node != node) + } + /* + * NOTE: Be carefull with the @node, since it might be + * a doc-node. + */ + if (cctxt->inode->node != node) { xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Node mismatch.\n"); - if (cctxt->inode->depth != cctxt->depth) + goto mismatch; + } + if (cctxt->inode->depth != cctxt->depth) { xmlGenericError(xmlGenericErrorContext, "xsltCompilerNodePop: Depth mismatch.\n"); + goto mismatch; + } cctxt->depth--; cctxt->inode = cctxt->inode->prev; + if (cctxt->inode != NULL) + cctxt->inode->curChildType = 0; + return; + +mismatch: + { + const xmlChar *nsName = NULL, *name = NULL; + const xmlChar *infnsName = NULL, *infname = NULL; + + if (node) { + if (node->type == XML_ELEMENT_NODE) { + name = node->name; + if (node->ns != NULL) + nsName = node->ns->href; + else + nsName = BAD_CAST ""; + } else { + name = BAD_CAST "#document"; + nsName = BAD_CAST ""; + } + } else + name = BAD_CAST "Not given"; + + if (cctxt->inode->node) { + if (node->type == XML_ELEMENT_NODE) { + infname = cctxt->inode->node->name; + if (cctxt->inode->node->ns != NULL) + infnsName = cctxt->inode->node->ns->href; + else + infnsName = BAD_CAST ""; + } else { + infname = BAD_CAST "#document"; + infnsName = BAD_CAST ""; + } + } else + infname = BAD_CAST "Not given"; + + + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Given : '%s' URI '%s'\n", + name, nsName); + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Expected: '%s' URI '%s'\n", + infname, infnsName); + } +} + +/* +* xsltCompilerBuildInScopeNsList: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltNsListPtr +xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xsltNsListPtr nsi = NULL; + xmlNsPtr *list = NULL; + /* + * Create a new ns-list for this position in the node-tree. + * xmlGetNsList() will return NULL, if there are no ns-decls in the + * tree. Note that the ns-decl for the XML namespace is not added + * to the resulting list; the XPath module handles the XML namespace + * internally. + */ + list = xmlGetNsList(node->doc, node); + if (list == NULL) + return(NULL); + /* + * Create the info-structure. + */ + nsi = (xsltNsListPtr) xmlMalloc(sizeof(xsltNsList)); + if (nsi == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: malloc failed.\n"); + goto internal_err; + } + memset(nsi, 0, sizeof(xsltNsList)); + nsi->list = list; + /* + * Eval the number of ns-decls; this is used to speed up + * XPath-context initialization. + */ + while (list[nsi->number] != NULL) + nsi->number++; + /* + * Store the ns-list in the stylesheet. + */ + if (xsltPointerListAddSize( + (xsltPointerListPtr)cctxt->psData->inScopeNamespaces, + (void *) nsi, 5) == -1) + { + xmlFree(nsi); + nsi = NULL; + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n"); + goto internal_err; + } + + return(nsi); + +internal_err: + if (list != NULL) + xmlFree(list); + cctxt->style->errors++; + return(NULL); } +static int +xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt, + xsltPointerListPtr list, + xmlNodePtr node, + const xmlChar *value) +{ + xmlChar *cur, *end; + xmlNsPtr ns; + + if ((cctxt == NULL) || (value == NULL) || (list == NULL)) + return(-1); + + list->number = 0; + + cur = (xmlChar *) value; + while (*cur != 0) { + while (IS_BLANK(*cur)) cur++; + if (*cur == 0) + break; + end = cur; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + cur = xmlStrndup(cur, end - cur); + if (cur == NULL) { + cur = end; + continue; + } + /* + * TODO: Export and use xmlSearchNsByPrefixStrict() + * in Libxml2, tree.c, since xmlSearchNs() is in most + * cases not efficient and in some cases not correct. + * + * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value. + */ + if ((cur[0] == '#') && + xmlStrEqual(cur, (const xmlChar *)"#default")) + ns = xmlSearchNs(cctxt->style->doc, node, NULL); + else + ns = xmlSearchNs(cctxt->style->doc, node, cur); + + if (ns == NULL) { + /* + * TODO: Better to report the attr-node, otherwise + * the user won't know which attribute was invalid. + */ + xsltTransformError(NULL, cctxt->style, node, + "No namespace binding in scope for prefix '%s'.\n", cur); + /* + * XSLT-1.0: "It is an error if there is no namespace + * bound to the prefix on the element bearing the + * exclude-result-prefixes or xsl:exclude-result-prefixes + * attribute." + */ + cctxt->style->errors++; + } else { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "resolved prefix '%s'\n", cur); #endif + /* + * Note that we put the namespace name into the dict. + */ + if (xsltPointerListAddSize(list, + (void *) xmlDictLookup(cctxt->style->dict, + ns->href, -1), 5) == -1) + { + xmlFree(cur); + goto internal_err; + } + } + xmlFree(cur); + + cur = end; + } + return(0); + +internal_err: + cctxt->style->errors++; + return(-1); +} /** - * xsltPrecomputeStylesheet: - * @style: the XSLT stylesheet - * @cur: the current child list - * - * Clean-up the stylesheet content from unwanted ignorable blank nodes - * and run the preprocessing of all XSLT constructs. + * xsltCompilerUtilsCreateMergedList: + * @dest: the destination list (optional) + * @first: the first list + * @second: the second list (optional) * - * and process xslt:text + * Appends the content of @second to @first into @destination. + * If @destination is NULL a new list will be created. * - * URGENT TODO: In order to avoid separation of the parsing of the stylesheet's - * node-tree, this should either only strip whitespace-only text-nodes, - * or it should be merged completely with the stylesheet-parsing - * functions (e.g. xsltParseStylesheetTop()). + * Returns the merged list of items or NULL if there's nothing to merge. */ -static void -xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { - xmlNodePtr delete; - int internalize = 0; -#ifdef XSLT_REFACTORED - xsltCompilerCtxtPtr cctxt; -#endif +static xsltPointerListPtr +xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first, + xsltPointerListPtr second) +{ + xsltPointerListPtr ret; + size_t num; - if ((style == NULL) || (cur == NULL) -#ifdef XSLT_REFACTORED - ||(style->compCtxt == NULL) -#endif - ) - return; + if (first) + num = first->number; + else + num = 0; + if (second) + num += second->number; + if (num == 0) + return(NULL); + ret = xsltPointerListCreate(num); + if (ret == NULL) + return(NULL); + /* + * Copy contents. + */ + if ((first != NULL) && (first->number != 0)) { + memcpy(ret->items, first->items, + first->number * sizeof(void *)); + if ((second != NULL) && (second->number != 0)) + memcpy(ret->items + first->number, second->items, + second->number * sizeof(void *)); + } else if ((second != NULL) && (second->number != 0)) + memcpy(ret->items, (void *) second->items, + second->number * sizeof(void *)); + ret->number = num; + return(ret); +} - if ((cur->doc != NULL) && (style->dict != NULL) && - (cur->doc->dict == style->dict)) +/* +* xsltParseExclResultPrefixes: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltPointerListPtr +xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + xsltPointerListPtr def, + int isXsltElem) +{ + xsltPointerListPtr list = NULL; + xmlChar *value = NULL; + + if ((cctxt == NULL) || (node == NULL)) + return(NULL); + + if (isXsltElem) + value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes", NULL); + else + value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes", + XSLT_NAMESPACE); + + if (value == NULL) + return(def); + + if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, + BAD_CAST value) != 0) + goto exit; + if (cctxt->tmpList->number == 0) + goto exit; + /* + * Merge the list with the inherited list. + */ + list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); + if (list == NULL) + goto exit; + /* + * Store the list in the stylesheet. + */ + if (xsltPointerListAddSize( + cctxt->psData->exclResultNamespaces, list, 5) == -1) + { + xsltPointerListFree(list); + list = NULL; + goto exit; + } + +exit: + if (value != NULL) + xmlFree(value); + if (list != NULL) + return(list); + else + return(def); +} + +/* +* xsltParseExtElemPrefixes: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltPointerListPtr +xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + xsltPointerListPtr def, + int isXsltElem) +{ + xsltPointerListPtr list = NULL; + xmlChar *value; + int i; + + if ((cctxt == NULL) || (node == NULL)) + return(NULL); + + if (isXsltElem) + value = xmlGetNsProp(node, BAD_CAST "extension-element-prefixes", NULL); + else + value = xmlGetNsProp(node, BAD_CAST "extension-element-prefixes", + XSLT_NAMESPACE); + + if (value == NULL) + return(def); + + if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, + BAD_CAST value) != 0) + goto exit; + + if (cctxt->tmpList->number == 0) + goto exit; + /* + * REVISIT: Register the extension namespaces. + */ + for (i = 0; i < cctxt->tmpList->number; i++) + xsltRegisterExtPrefix(cctxt->style, NULL, + BAD_CAST cctxt->tmpList->items[i]); + /* + * Merge the list with the inherited list. + */ + list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); + if (list == NULL) + goto exit; + /* + * Store the list in the stylesheet. + */ + if (xsltPointerListAddSize( + cctxt->psData->extElemNamespaces, list, 5) == -1) + { + xsltPointerListFree(list); + list = NULL; + goto exit; + } + +exit: + if (value != NULL) + xmlFree(value); + if (list != NULL) + return(list); + else + return(def); +} + + +/* +* xsltParseAttrXSLTVersion: +* +* @cctxt: the compilation context +* @node: the element-node +* @isXsltElem: whether this is an XSLT element +* +* Parses the attribute xsl:version. +* +* Returns 1 if there was such an attribute, 0 if not and +* -1 if an internal or API error occured. +*/ +static int +xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + int isXsltElem) +{ + xmlChar *value; + + if ((cctxt == NULL) || (node == NULL)) + return(-1); + + if (isXsltElem) + value = xmlGetNsProp(node, BAD_CAST "version", NULL); + else + value = xmlGetNsProp(node, BAD_CAST "version", XSLT_NAMESPACE); + + if (value == NULL) + return(0); + + if (! xmlStrEqual(value, (const xmlChar *)"1.0")) { + cctxt->inode->forwardsCompat = 1; + /* + * TODO: To what extent do we support the + * forwards-compatible mode? + */ + /* + * Report this only once per compilation episode. + */ + if (! cctxt->hasForwardsCompat) { + cctxt->hasForwardsCompat = 1; + cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING; + xsltTransformError(NULL, cctxt->style, node, + "Warning: the attribute xsl:version specifies a value " + "different from '1.0'. Switching to forwards-compatible " + "mode. Only features of XSLT 1.0 are supported by this " + "processor.\n"); + cctxt->style->warnings++; + cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR; + } + } else { + cctxt->inode->forwardsCompat = 0; + } + xmlFree(value); + return(1); +} + +static int +xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xmlNodePtr deleteNode, cur, txt, textNode = NULL; + xmlDocPtr doc; + xsltStylesheetPtr style; + int internalize = 0, findSpaceAttr; + int xsltStylesheetElemDepth; + xmlAttrPtr attr; + xmlChar *value; + const xmlChar *name, *nsNameXSLT = NULL; + int strictWhitespace, inXSLText = 0; + xsltNsMapPtr nsMapItem; + + if ((cctxt == NULL) || (cctxt->style == NULL) || + (node == NULL) || (node->type != XML_ELEMENT_NODE)) + return(-1); + + doc = node->doc; + if (doc == NULL) + return(-1); + + style = cctxt->style; + if ((style->dict != NULL) && (doc->dict == style->dict)) internalize = 1; else style->internalized = 0; -#ifdef XSLT_REFACTORED - cctxt = (xsltCompilerCtxtPtr) style->compCtxt; -#endif + /* - * This content comes from the stylesheet - * For stylesheets, the set of whitespace-preserving - * element names consists of just xsl:text. - */ - delete = NULL; + * Init value of xml:space. Since this might be an embedded + * stylesheet, this is needed to be performed on the element + * where the stylesheet is rooted at, taking xml:space of + * ancestors into account. + */ + if (! cctxt->simplified) + xsltStylesheetElemDepth = cctxt->depth +1; + else + xsltStylesheetElemDepth = 0; + + if (xmlNodeGetSpacePreserve(node) != 1) + cctxt->inode->preserveWhitespace = 0; + else + cctxt->inode->preserveWhitespace = 1; + + /* + * Eval if we should keep the old incorrect behaviour. + */ + strictWhitespace = (cctxt->strict != 0) ? 1 : 0; + + nsNameXSLT = xsltConstNamespaceNameXSLT; + + deleteNode = NULL; + cur = node; while (cur != NULL) { - if (delete != NULL) { + if (deleteNode != NULL) { + #ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, - "xsltPrecomputeStylesheet: removing ignorable blank node\n"); + "xsltParsePreprocessStylesheetTree: removing node\n"); #endif - xmlUnlinkNode(delete); - xmlFreeNode(delete); - delete = NULL; + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; } if (cur->type == XML_ELEMENT_NODE) { - int exclPrefixes; + + /* + * Clear the PSVI field. + */ + cur->psvi = NULL; -#ifdef XSLT_REFACTORED xsltCompilerNodePush(cctxt, cur); -#endif + + inXSLText = 0; + textNode = NULL; + findSpaceAttr = 1; + cctxt->inode->stripWhitespace = 0; /* - * Internalize attributes values. - */ - if ((internalize) && (cur->properties != NULL)) { - xmlAttrPtr prop = cur->properties; - xmlNodePtr txt; + * TODO: I'd love to use a string pointer comparison here :-/ + */ + if (IS_XSLT_ELEM(cur)) { + if (cur->ns->href != nsNameXSLT) { + nsMapItem = xsltNewNamespaceMapItem(cctxt, + doc, cur, cur->ns); + if (nsMapItem == NULL) + goto internal_err; + cur->ns->href = nsNameXSLT; + } - while (prop != NULL) { - txt = prop->children; - if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && - (txt->content != NULL) && - (!xmlDictOwns(style->dict, txt->content))) { - xmlChar *tmp; + if (cur->name == NULL) + goto process_attributes; + /* + * Mark the XSLT element for later recognition. + * TODO: Using the marker is still too dangerous, since if + * the parsing mechanism leaves out an XSLT element, then + * this might hit the transformation-mechanism, which + * will break if it doesn't expect such a marker. + */ + /* cur->psvi = (void *) xsltXSLTElemMarker; */ - /* - * internalize the text string, goal is to speed - * up operations and minimize used space by compiled - * stylesheets. - */ - tmp = (xmlChar *) xmlDictLookup(style->dict, - txt->content, -1); - if (tmp != txt->content) { - xmlNodeSetContent(txt, NULL); - txt->content = tmp; + /* + * XSLT 2.0: "Any whitespace text node whose parent is + * one of the following elements is removed from the " + * tree, regardless of any xml:space attributes:..." + * xsl:apply-imports, + * xsl:apply-templates, + * xsl:attribute-set, + * xsl:call-template, + * xsl:choose, + * xsl:stylesheet, xsl:transform. + * XSLT 2.0: xsl:analyze-string, + * xsl:character-map, + * xsl:next-match + * + * TODO: I'd love to use a string pointer comparison here :-/ + */ + name = cur->name; + switch (*name) { + case 't': + if ((name[0] == 't') && (name[1] == 'e') && + (name[2] == 'x') && (name[3] == 't') && + (name[4] == 0)) + { + /* + * Process the xsl:text element. + * ---------------------------- + * Mark it for later recognition. + */ + cur->psvi = (void *) xsltXSLTTextMarker; + /* + * For stylesheets, the set of + * whitespace-preserving element names + * consists of just xsl:text. + */ + findSpaceAttr = 0; + cctxt->inode->preserveWhitespace = 1; + inXSLText = 1; + } + break; + case 'c': + if (xmlStrEqual(name, BAD_CAST "choose") || + xmlStrEqual(name, BAD_CAST "call-template")) + cctxt->inode->stripWhitespace = 1; + break; + case 'a': + if (xmlStrEqual(name, BAD_CAST "apply-templates") || + xmlStrEqual(name, BAD_CAST "apply-imports") || + xmlStrEqual(name, BAD_CAST "attribute-set")) + + cctxt->inode->stripWhitespace = 1; + break; + default: + if (xsltStylesheetElemDepth == cctxt->depth) { + /* + * This is a xsl:stylesheet/xsl:transform. + */ + cctxt->inode->stripWhitespace = 1; + break; } - } - prop = prop->next; + + if ((cur->prev != NULL) && + (cur->prev->type == XML_TEXT_NODE)) + { + /* + * XSLT 2.0 : "Any whitespace text node whose + * following-sibling node is an xsl:param or + * xsl:sort element is removed from the tree, + * regardless of any xml:space attributes." + */ + if (((*name == 'p') || (*name == 's')) && + (xmlStrEqual(name, BAD_CAST "param") || + xmlStrEqual(name, BAD_CAST "sort"))) + { + do { + if (IS_BLANK_NODE(cur->prev)) { + txt = cur->prev; + xmlUnlinkNode(txt); + xmlFreeNode(txt); + } else { + /* + * This will result in a content + * error, when hitting the parsing + * functions. + */ + break; + } + } while (cur->prev); + } + } + break; } } + +process_attributes: /* - * TODO: "exclude-result-prefixes" - * SPEC 1.0: - * "exclude-result-prefixes" is only allowed on literal - * result elements and "xsl:exclude-result-prefixes" only - * on xsl:stylesheet/xsl:transform. - * SPEC 2.0: - * "There are a number of standard attributes - * that may appear on any XSLT element: specifically version, - * exclude-result-prefixes, extension-element-prefixes, - * xpath-default-namespace, default-collation, and use-when." + * Process attributes. + * ------------------ */ - if (IS_XSLT_ELEM(cur)) { - exclPrefixes = 0; -#ifdef XSLT_REFACTORED - if ((cctxt->depth == 0) && (cur->nsDef != NULL)) { - /* - * In every case, we need the in-scope namespaces of the - * element, where the stylesheet is rooted at. - * Otherwise we need to pre-compute the in-scope namespaces - * only if there's a new ns-decl. + if (cur->properties != NULL) { + if (cur->children == NULL) + findSpaceAttr = 0; + attr = cur->properties; + do { + if (internalize) { + /* + * Internalize the attribute's value; the goal is to + * speed up operations and minimize used space by + * compiled stylesheets. + */ + txt = attr->children; + /* + * NOTE that this assumes only one + * text-node in the attribute's content. + */ + if ((txt != NULL) && (txt->content != NULL) && + (!xmlDictOwns(style->dict, txt->content))) + { + value = (xmlChar *) xmlDictLookup(style->dict, + txt->content, -1); + xmlNodeSetContent(txt, NULL); + txt->content = value; + } + } + /* + * Process xml:space attributes. + * ---------------------------- */ - cctxt->inode->inScopeNS = - xsltCompilerGetInScopeNSInfo(cctxt, cur); + if ((findSpaceAttr != 0) && + (attr->ns != NULL) && + (attr->name != NULL) && + (attr->name[0] == 's') && + (attr->ns->prefix != NULL) && + (attr->ns->prefix[0] == 'x') && + (attr->ns->prefix[1] == 'm') && + (attr->ns->prefix[2] == 'l') && + (attr->ns->prefix[3] == 0)) + { + value = xmlGetNsProp(cur, BAD_CAST "space", + XML_XML_NAMESPACE); + if (value != NULL) { + if (xmlStrEqual(value, BAD_CAST "preserve")) { + cctxt->inode->preserveWhitespace = 1; + } else if (xmlStrEqual(value, BAD_CAST "default")) { + cctxt->inode->preserveWhitespace = 0; + } else { + /* Invalid value for xml:space. */ + xsltTransformError(NULL, style, cur, + "Attribute xml:space: Invalid value.\n"); + cctxt->style->warnings++; + } + findSpaceAttr = 0; + xmlFree(value); + } + + } + attr = attr->next; + } while (attr != NULL); + } + /* + * We'll descend into the children of element nodes only. + */ + if (cur->children != NULL) { + cur = cur->children; + continue; + } + } else if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) + { + /* + * Merge adjacent text/CDATA-section-nodes + * --------------------------------------- + * In order to avoid breaking of existing stylesheets, + * if the old behaviour is wanted (strictWhitespace == 0), + * then we *won't* merge adjacent text-nodes + * (except in xsl:text); this will ensure that whitespace-only + * text nodes are (incorrectly) not stripped in some cases. + * + * Example: : zoo + * Corrent (strict) result: zoo + * Incorrect (old) result : zoo + * + * NOTE that we *will* merge adjacent text-nodes if + * they are in xsl:text. + * Example, the following: + * zoo + * will result in both cases in: + * zoo + */ + cur->type = XML_TEXT_NODE; + if ((strictWhitespace != 0) || (inXSLText != 0)) { + /* + * New behaviour; merge nodes. + */ + if (textNode == NULL) + textNode = cur; + else { + if (cur->content != NULL) + xmlNodeAddContent(textNode, cur->content); + deleteNode = cur; + } + if ((cur->next == NULL) || + (cur->next->type == XML_ELEMENT_NODE)) + goto end_of_text; + else + goto next_sibling; + } else { + /* + * Old behaviour. + */ + if (textNode == NULL) + textNode = cur; + goto end_of_text; + } + } else if ((cur->type == XML_COMMENT_NODE) || + (cur->type == XML_PI_NODE)) + { + /* + * Remove processing instructions and comments. + */ + deleteNode = cur; + if ((cur->next == NULL) || + (cur->next->type == XML_ELEMENT_NODE)) + goto end_of_text; + else + goto next_sibling; + } else { + textNode = NULL; + /* + * Invalid node-type for this data-model. + */ + xsltTransformError(NULL, style, cur, + "Invalid type of node for the XSLT data model.\n"); + cctxt->style->errors++; + goto next_sibling; + } + +end_of_text: + if (textNode) { + value = textNode->content; + /* + * At this point all adjacent text/CDATA-section nodes + * have been merged. + * + * Strip whitespace-only text-nodes. + * (cctxt->inode->stripWhitespace) + */ + if ((value == NULL) || (*value == 0) || + (((cctxt->inode->stripWhitespace) || + (! cctxt->inode->preserveWhitespace)) && + IS_BLANK(*value) && + xsltIsBlank(value))) + { + if (textNode != cur) { + xmlUnlinkNode(textNode); + xmlFreeNode(textNode); + } else + deleteNode = textNode; + textNode = NULL; + goto next_sibling; + } + /* + * Convert CDATA-section nodes to text-nodes. + * TODO: Can this produce problems? + */ + if (textNode->type != XML_TEXT_NODE) { + textNode->type = XML_TEXT_NODE; + textNode->name = xmlStringText; + } + if (internalize && + (textNode->content != NULL) && + (!xmlDictOwns(style->dict, textNode->content))) + { + /* + * Internalize the string. + */ + value = (xmlChar *) xmlDictLookup(style->dict, + textNode->content, -1); + xmlNodeSetContent(textNode, NULL); + textNode->content = value; + } + textNode = NULL; + /* + * Note that "disable-output-escaping" of the xsl:text + * element will be applied at a later level, when + * XSLT elements are processed. + */ + } + +next_sibling: + if (cur->type == XML_ELEMENT_NODE) { + xsltCompilerNodePop(cctxt, cur); + } + if (cur == node) + break; + if (cur->next != NULL) { + cur = cur->next; + } else { + cur = cur->parent; + inXSLText = 0; + goto next_sibling; + }; + } + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParsePreprocessStylesheetTree: removing node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + } + return(0); + +internal_err: + return(-1); +} + +#endif /* XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED +#else +static void +xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) +{ + xmlNodePtr deleteNode; + int internalize = 0; + + if ((style == NULL) || (cur == NULL)) + return; + + if ((cur->doc != NULL) && (style->dict != NULL) && + (cur->doc->dict == style->dict)) + internalize = 1; + else + style->internalized = 0; + /* + * This content comes from the stylesheet + * For stylesheets, the set of whitespace-preserving + * element names consists of just xsl:text. + */ + deleteNode = NULL; + while (cur != NULL) { + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltPrecomputeStylesheet: removing ignorable blank node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } + if (cur->type == XML_ELEMENT_NODE) { + int exclPrefixes; + /* + * Internalize attributes values. + */ + if ((internalize) && (cur->properties != NULL)) { + xmlAttrPtr attr = cur->properties; + xmlNodePtr txt; + + while (attr != NULL) { + txt = attr->children; + if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && + (txt->content != NULL) && + (!xmlDictOwns(style->dict, txt->content))) + { + xmlChar *tmp; + + /* + * internalize the text string, goal is to speed + * up operations and minimize used space by compiled + * stylesheets. + */ + tmp = (xmlChar *) xmlDictLookup(style->dict, + txt->content, -1); + if (tmp != txt->content) { + xmlNodeSetContent(txt, NULL); + txt->content = tmp; + } + } + attr = attr->next; } -#endif + } + if (IS_XSLT_ELEM(cur)) { + exclPrefixes = 0; xsltStylePreCompute(style, cur); if (IS_XSLT_NAME(cur, "text")) { for (;exclPrefixes > 0;exclPrefixes--) @@ -1498,25 +2674,9 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { goto skip_children; } } else { -#ifdef XSLT_REFACTORED - if (cctxt->depth == 0) - cctxt->inode->inScopeNS = - xsltCompilerGetInScopeNSInfo(cctxt, cur); -#endif exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0); } - - /* - * Remove excluded prefixes - * TODO BUG: - * This will incorrectly apply excluded-result-prefixes - * of the including stylesheet to the included stylesheet. - * We need to localize the list of excluded-prefixes for - * every processed stylesheet. - * SPEC 1.0: "a subtree rooted at an xsl:stylesheet element - * does not include any stylesheets imported or included by - * children of that xsl:stylesheet element." - */ + if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) { xmlNsPtr ns = cur->nsDef, prev = NULL, next; xmlNodePtr root = NULL; @@ -1547,188 +2707,1093 @@ xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) { break; } } - if (moved == 0) - prev = ns; - ns = next; + if (moved == 0) + prev = ns; + ns = next; + } + } + } + /* + * If we have prefixes locally, recurse and pop them up when + * going back + */ + if (exclPrefixes > 0) { + xsltPrecomputeStylesheet(style, cur->children); + for (;exclPrefixes > 0;exclPrefixes--) + exclPrefixPop(style); + goto skip_children; + } + } else if (cur->type == XML_TEXT_NODE) { + if (IS_BLANK_NODE(cur)) { + if (xmlNodeGetSpacePreserve(cur) != 1) { + deleteNode = cur; + } + } else if ((cur->content != NULL) && (internalize) && + (!xmlDictOwns(style->dict, cur->content))) { + xmlChar *tmp; + + /* + * internalize the text string, goal is to speed + * up operations and minimize used space by compiled + * stylesheets. + */ + tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1); + xmlNodeSetContent(cur, NULL); + cur->content = tmp; + } + } else if ((cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_CDATA_SECTION_NODE)) { + deleteNode = cur; + goto skip_children; + } + + /* + * Skip to next node + */ + if (cur->children != NULL) { + if ((cur->children->type != XML_ENTITY_DECL) && + (cur->children->type != XML_ENTITY_REF_NODE) && + (cur->children->type != XML_ENTITY_NODE)) { + cur = cur->children; + continue; + } + } + +skip_children: + if (cur->next != NULL) { + cur = cur->next; + continue; + } + do { + + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) style->doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltPrecomputeStylesheet: removing ignorable blank node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + } +} +#endif /* end of else XSLT_REFACTORED */ + +/** + * xsltGatherNamespaces: + * @style: the XSLT stylesheet + * + * Browse the stylesheet and build the namspace hash table which + * will be used for XPath interpretation. If needed do a bit of normalization + */ + +static void +xsltGatherNamespaces(xsltStylesheetPtr style) { + xmlNodePtr cur; + const xmlChar *URI; + + if (style == NULL) + return; + /* + * TODO: basically if the stylesheet uses the same prefix for different + * patterns, well they may be in problem, hopefully they will get + * a warning first. + */ + /* + * TODO: Eliminate the use of the hash for XPath expressions. + * An expression should be evaluated in the context of the in-scope + * namespaces; eliminate the restriction of an XML document to contain + * no duplicate prefixes for different namespace names. + * + */ + cur = xmlDocGetRootElement(style->doc); + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + xmlNsPtr ns = cur->nsDef; + while (ns != NULL) { + if (ns->prefix != NULL) { + if (style->nsHash == NULL) { + style->nsHash = xmlHashCreate(10); + if (style->nsHash == NULL) { + xsltTransformError(NULL, style, cur, + "xsltGatherNamespaces: failed to create hash table\n"); + style->errors++; + return; + } + } + URI = xmlHashLookup(style->nsHash, ns->prefix); + if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) { + xsltTransformError(NULL, style, cur, + "Namespaces prefix %s used for multiple namespaces\n",ns->prefix); + style->warnings++; + } else if (URI == NULL) { + xmlHashUpdateEntry(style->nsHash, ns->prefix, + (void *) ns->href, (xmlHashDeallocator)xmlFree); + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "Added namespace: %s mapped to %s\n", ns->prefix, ns->href); +#endif + } + } + ns = ns->next; + } + } + + /* + * Skip to next node + */ + if (cur->children != NULL) { + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) style->doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } +} + +#ifdef XSLT_REFACTORED + +static xsltStyleType +xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node) +{ + if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || + (node->name == NULL)) + return(0); + + if (node->name[0] == 'a') { + if (IS_XSLT_NAME(node, "apply-templates")) + return(XSLT_FUNC_APPLYTEMPLATES); + else if (IS_XSLT_NAME(node, "attribute")) + return(XSLT_FUNC_ATTRIBUTE); + else if (IS_XSLT_NAME(node, "apply-imports")) + return(XSLT_FUNC_APPLYIMPORTS); + else if (IS_XSLT_NAME(node, "attribute-set")) + return(0); + + } else if (node->name[0] == 'c') { + if (IS_XSLT_NAME(node, "choose")) + return(XSLT_FUNC_CHOOSE); + else if (IS_XSLT_NAME(node, "copy")) + return(XSLT_FUNC_COPY); + else if (IS_XSLT_NAME(node, "copy-of")) + return(XSLT_FUNC_COPYOF); + else if (IS_XSLT_NAME(node, "call-template")) + return(XSLT_FUNC_CALLTEMPLATE); + else if (IS_XSLT_NAME(node, "comment")) + return(XSLT_FUNC_COMMENT); + + } else if (node->name[0] == 'd') { + if (IS_XSLT_NAME(node, "document")) + return(XSLT_FUNC_DOCUMENT); + else if (IS_XSLT_NAME(node, "decimal-format")) + return(0); + + } else if (node->name[0] == 'e') { + if (IS_XSLT_NAME(node, "element")) + return(XSLT_FUNC_ELEMENT); + + } else if (node->name[0] == 'f') { + if (IS_XSLT_NAME(node, "for-each")) + return(XSLT_FUNC_FOREACH); + else if (IS_XSLT_NAME(node, "fallback")) + return(XSLT_FUNC_FALLBACK); + + } else if (*(node->name) == 'i') { + if (IS_XSLT_NAME(node, "if")) + return(XSLT_FUNC_IF); + else if (IS_XSLT_NAME(node, "include")) + return(0); + else if (IS_XSLT_NAME(node, "import")) + return(0); + + } else if (*(node->name) == 'k') { + if (IS_XSLT_NAME(node, "key")) + return(0); + + } else if (*(node->name) == 'm') { + if (IS_XSLT_NAME(node, "message")) + return(XSLT_FUNC_MESSAGE); + + } else if (*(node->name) == 'n') { + if (IS_XSLT_NAME(node, "number")) + return(XSLT_FUNC_NUMBER); + else if (IS_XSLT_NAME(node, "namespace-alias")) + return(0); + + } else if (*(node->name) == 'o') { + if (IS_XSLT_NAME(node, "otherwise")) + return(XSLT_FUNC_OTHERWISE); + else if (IS_XSLT_NAME(node, "output")) + return(0); + + } else if (*(node->name) == 'p') { + if (IS_XSLT_NAME(node, "param")) + return(XSLT_FUNC_PARAM); + else if (IS_XSLT_NAME(node, "processing-instruction")) + return(XSLT_FUNC_PI); + else if (IS_XSLT_NAME(node, "preserve-space")) + return(0); + + } else if (*(node->name) == 's') { + if (IS_XSLT_NAME(node, "sort")) + return(XSLT_FUNC_SORT); + else if (IS_XSLT_NAME(node, "strip-space")) + return(0); + else if (IS_XSLT_NAME(node, "stylesheet")) + return(0); + + } else if (node->name[0] == 't') { + if (IS_XSLT_NAME(node, "text")) + return(XSLT_FUNC_TEXT); + else if (IS_XSLT_NAME(node, "template")) + return(0); + else if (IS_XSLT_NAME(node, "transform")) + return(0); + + } else if (*(node->name) == 'v') { + if (IS_XSLT_NAME(node, "value-of")) + return(XSLT_FUNC_VALUEOF); + else if (IS_XSLT_NAME(node, "variable")) + return(XSLT_FUNC_VARIABLE); + + } else if (*(node->name) == 'w') { + if (IS_XSLT_NAME(node, "when")) + return(XSLT_FUNC_WHEN); + if (IS_XSLT_NAME(node, "with-param")) + return(XSLT_FUNC_WITHPARAM); + } + return(0); +} + +int +xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem) +{ + if ((cctxt == NULL) || (elem == NULL) || + (elem->type != XML_ELEMENT_NODE)) + return(-1); + + elem->psvi = NULL; + + if (! (IS_IN_XSLT_NS(elem))) + return(-1); + /* + * Detection of handled content of extension elements. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + + xsltCompilerNodePush(cctxt, elem); + /* + * URGENT TODO: Find a way to speed up this annoying redundant + * textual node-name and namespace comparison. + */ + if (cctxt->inode->prev->curChildType != 0) + cctxt->inode->type = cctxt->inode->prev->curChildType; + else + cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem); + /* + * Update the in-scope namespaces if needed. + */ + if (elem->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, elem); + /* + * xsltStylePreCompute(): Precompute the XSLT-instruction. + * This will compile the information found on the current + * element's attributes. NOTE that this won't process the + * children of the current element. + */ + xsltStylePreCompute(cctxt->style, elem); + /* + * Validate the content model of the XSLT-element. + */ + switch (cctxt->inode->type) { + case XSLT_FUNC_APPLYIMPORTS: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_APPLYTEMPLATES: + /* */ + goto apply_templates; + case XSLT_FUNC_ATTRIBUTE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_CALLTEMPLATE: + /* */ + goto call_template; + case XSLT_FUNC_CHOOSE: + /* */ + goto choose; + case XSLT_FUNC_COMMENT: + /* */ + goto sequence_constructor; + case XSLT_FUNC_COPY: + /* */ + goto sequence_constructor; + case XSLT_FUNC_COPYOF: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_DOCUMENT: /* Extra one */ + /* ?? template ?? */ + goto sequence_constructor; + case XSLT_FUNC_ELEMENT: + /* */ + goto sequence_constructor; + case XSLT_FUNC_FALLBACK: + /* */ + goto sequence_constructor; + case XSLT_FUNC_FOREACH: + /* */ + goto for_each; + case XSLT_FUNC_IF: + /* */ + goto sequence_constructor; + case XSLT_FUNC_OTHERWISE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_MESSAGE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_NUMBER: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_PARAM: + /* */ + goto sequence_constructor; + case XSLT_FUNC_PI: + /* */ + goto sequence_constructor; + case XSLT_FUNC_SORT: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_TEXT: + /* */ + goto text; + case XSLT_FUNC_VALUEOF: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_VARIABLE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_WHEN: + /* */ + goto sequence_constructor; + case XSLT_FUNC_WITHPARAM: + /* */ + goto sequence_constructor; + default: +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n", + elem->name); +#endif + xsltTransformError(NULL, cctxt->style, elem, + "xsltParseXSLTNode: Internal error; " + "unhandled XSLT element '%s'.\n", elem->name); + cctxt->style->errors++; + goto internal_err; + } + +apply_templates: + /* */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_IN_XSLT_NS(child)) { + xsltStyleType type; + + type = xsltGetXSLTElementTypeByNode(cctxt, child); + if ((type == XSLT_FUNC_WITHPARAM) || + (type == XSLT_FUNC_SORT)) + { + /* cctxt->inode->type = type; */ + xsltParseAnyXSLTElem(cctxt, child); + } else { + xsltParseContentError(cctxt->style, child); + } + } else + xsltParseContentError(cctxt->style, child); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +call_template: + /* */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_IN_XSLT_NS(child)) { + xsltStyleType type; + + type = xsltGetXSLTElementTypeByNode(cctxt, child); + if (type == XSLT_FUNC_WITHPARAM) { + cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; + xsltParseAnyXSLTElem(cctxt, child); + } else { + xsltParseContentError(cctxt->style, child); + } + } else + xsltParseContentError(cctxt->style, child); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +text: + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if ((child->type != XML_TEXT_NODE) && + (child->type != XML_CDATA_SECTION_NODE)) + { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT 'text' element must have only character " + "data as content.\n"); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +empty_content: + if (elem->children != NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "This XSLT element must have no content.\n"); + cctxt->style->errors++; + } + goto exit; + +choose: + /* */ + /* + * TODO: text-nodes in between are *not* allowed in XSLT 1.0. + * The old behaviour did not check this. + * NOTE: In XSLT 2.0 they are stripped beforehand + * if whitespace-only (regardless of xml:space). + */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + int nbWhen = 0, nbOtherwise = 0, err = 0; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_IN_XSLT_NS(child)) { + xsltStyleType type; + + type = xsltGetXSLTElementTypeByNode(cctxt, child); + if (type == XSLT_FUNC_WHEN) { + nbWhen++; + if (nbOtherwise) { + xsltParseContentError(cctxt->style, child); + err = 1; + break; + } + cctxt->inode->curChildType = XSLT_FUNC_WHEN; + xsltParseAnyXSLTElem(cctxt, child); + } else if (type == XSLT_FUNC_OTHERWISE) { + if (! nbWhen) { + xsltParseContentError(cctxt->style, child); + err = 1; + break; + } + if (nbOtherwise) { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT 'choose' element must not contain " + "more than one XSLT 'otherwise' element.\n"); + cctxt->style->errors++; + err = 1; + break; + } + nbOtherwise++; + cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE; + xsltParseAnyXSLTElem(cctxt, child); + } else + xsltParseContentError(cctxt->style, child); + } else + xsltParseContentError(cctxt->style, child); + } + /* + else + xsltParseContentError(cctxt, child); + */ + child = child->next; + } while (child != NULL); + if ((! err) && (! nbWhen)) { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT element 'choose' must contain at least one " + "XSLT element 'when'.\n"); + cctxt->style->errors++; + } + } + goto exit; + +for_each: + /* */ + /* + * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0. + * The old behaviour did not allow this, but it catched this + * only at transformation-time. + * In XSLT 2.0 they are stripped beforehand if whitespace-only + * (regardless of xml:space). + */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + /* + * Parse xsl:sort first. + */ + do { + if ((child->type == XML_ELEMENT_NODE) && + IS_IN_XSLT_NS(child)) + { + if (xsltGetXSLTElementTypeByNode(cctxt, child) == + XSLT_FUNC_SORT) + { + cctxt->inode->curChildType = XSLT_FUNC_SORT; + xsltParseAnyXSLTElem(cctxt, child); + } else + break; + } else + break; + child = child->next; + } while (child != NULL); + /* + * Parse the sequece constructor. + */ + if (child != NULL) + xsltParseSequenceConstructor(cctxt, child); + } + goto exit; + +sequence_constructor: + if (elem->children != NULL) + xsltParseSequenceConstructor(cctxt, elem->children); + +exit: + xsltCompilerNodePop(cctxt, elem); + return(0); + +internal_err: + xsltCompilerNodePop(cctxt, elem); + return(-1); +} + +static int +xsltParseForwardsCompatUnexpectedXSLTElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node) +{ + if ((cctxt == NULL) || (node == NULL)) + return(-1); + + /* + * Detection of handled content of extension elements. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + + node->psvi = NULL; + if (node->children == NULL) + return(0); + else { + xmlNodePtr child = node->children; + + xsltCompilerNodePush(cctxt, node); + /* + * Update the in-scope namespaces if needed. + */ + if (node->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + /* + * Parse all xsl:fallback children. + */ + do { + if ((child->type == XML_ELEMENT_NODE) && + IS_IN_XSLT_NS(child) && + IS_XSLT_NAME(child, "fallback")) + { + cctxt->inode->curChildType = XSLT_FUNC_FALLBACK; + xsltParseAnyXSLTElem(cctxt, child); + } + child = child->next; + } while (child != NULL); + xsltCompilerNodePop(cctxt, node); + } + return(0); +} +/** + * xsltParseSequenceConstructor: + * + * @cctxt: the compilation context + * @cur: the start-node of the content to be parsed + * + * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms). + * This will additionally remove xsl:text elements from the tree. + */ +void +xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur) +{ + xsltStyleType type; + xmlNodePtr deleteNode = NULL; + + if (cctxt == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltParseSequenceConstructor: Bad arguments\n"); + cctxt->style->errors++; + return; + } + /* + * Detection of handled content of extension elements. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + if (cur == NULL) + return; + /* + * This is the content reffered to as a "template". + * E.g. an xsl:element has such content model: + * + * + * + * NOTE that in XSLT-2 the term "template" was abandoned due to + * confusion with xsl:template and the term "sequence constructor" + * was introduced instead. + * + * The following XSLT-instructions are allowed to appear: + * xsl:apply-templates, xsl:call-template, xsl:apply-imports, + * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number, + * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable, + * xsl:message, xsl:fallback, + * xsl:processing-instruction, xsl:comment, xsl:element + * xsl:attribute. + * Additional allowed content: + * 1) extension elements + * 2) literal result elements + * 3) PCDATA + * + * NOTE that this content model does *not* allow xsl:param. + */ + while (cur != NULL) { + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseSequenceConstructor: removing xsl:text element\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } + if (cur->type == XML_ELEMENT_NODE) { + + if (cur->psvi == xsltXSLTTextMarker) { + /* + * Process xsl:text elements. + * ========================== + */ + xmlNodePtr tmp; + + cur->psvi = NULL; + /* + * Mark the xsl:text element for later deletion. + */ + deleteNode = cur; + /* + * Validate content. + */ + tmp = cur->children; + if (tmp) { + /* + * We don't expect more than one text-node in the + * content, since we already merged adjacent + * text/CDATA-nodes and eliminated PI/comment-nodes. + */ + if ((tmp->type == XML_TEXT_NODE) || + (tmp->next == NULL)) + { + /* + * Leave the contained text-node in the tree. + */ + xmlUnlinkNode(tmp); + xmlAddPrevSibling(cur, tmp); + } else { + tmp = NULL; + xsltTransformError(NULL, cctxt->style, cur, + "Element 'xsl:text': Invalid type " + "of node found in content.\n"); + cctxt->style->errors++; + } + } + if (cur->properties) { + xmlAttrPtr attr; + /* + * TODO: We need to report errors for + * invalid attrs. + */ + attr = cur->properties; + do { + if ((attr->ns == NULL) && + (attr->name != NULL) && + (attr->name[0] == 'd') && + xmlStrEqual(attr->name, + BAD_CAST "disable-output-escaping")) + { + /* + * Attr "disable-output-escaping". + * XSLT-2: This attribute is deprecated. + */ + if ((attr->children != NULL) && + xmlStrEqual(attr->children->content, + BAD_CAST "yes")) + { + /* + * Disable output escaping for this + * text node. + */ + if (tmp) + tmp->name = xmlStringTextNoenc; + } else if ((attr->children == NULL) || + (attr->children->content == NULL) || + (!xmlStrEqual(attr->children->content, + BAD_CAST "no"))) + { + xsltTransformError(NULL, cctxt->style, + cur, + "Attribute 'disable-output-escaping': " + "Invalid value. Expected is " + "'yes' or 'no'.\n"); + cctxt->style->errors++; + } + break; + } + attr = attr->next; + } while (attr != NULL); + } + } else if (IS_IN_XSLT_NS(cur)) { + /* + * TODO: Using the XSLT-marker is still not stable yet. + */ + /* if (cur->psvi == xsltXSLTElemMarker) { */ + /* + * This is element in the XSLT namespace. + * ===================================== + */ + type = xsltGetXSLTElementTypeByNode(cctxt, cur); + switch (type) { + case XSLT_FUNC_APPLYIMPORTS: + case XSLT_FUNC_APPLYTEMPLATES: + case XSLT_FUNC_ATTRIBUTE: + case XSLT_FUNC_CALLTEMPLATE: + case XSLT_FUNC_CHOOSE: + case XSLT_FUNC_COMMENT: + case XSLT_FUNC_COPY: + case XSLT_FUNC_COPYOF: + case XSLT_FUNC_DOCUMENT: /* Extra one */ + case XSLT_FUNC_ELEMENT: + case XSLT_FUNC_FALLBACK: + case XSLT_FUNC_FOREACH: + case XSLT_FUNC_IF: + case XSLT_FUNC_MESSAGE: + case XSLT_FUNC_NUMBER: + case XSLT_FUNC_PI: + case XSLT_FUNC_TEXT: + case XSLT_FUNC_VALUEOF: + case XSLT_FUNC_VARIABLE: + /* cctxt->inode->type = type; */ + /* + * Parse the XSLT element. + */ + cctxt->inode->curChildType = type; + xsltParseAnyXSLTElem(cctxt, cur); + break; + default: + cur->psvi = NULL; + /* + * Ignore unknown elements in the + * XSLT namespace if in forwards-compatible + * mode. + */ + if (cctxt->inode->forwardsCompat) { + /* + * This will parse xsl:fallback elements. + */ + xsltParseForwardsCompatUnexpectedXSLTElem( + cctxt, cur); + } else { + xsltParseContentError(cctxt->style, cur); + } + cur = cur->next; + continue; + } + } else { + /* + * This is a non-XSLT element. + * ========================== + */ + xsltCompilerNodePush(cctxt, cur); + /* + * The current element is either a literal result element + * or an extension element. + * + * Process attr "xsl:extension-element-prefixes". + * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be + * processed by the implementor of the extension function; + * i.e., it won't be handled by the XSLT processor. + */ + /* SPEC 1.0: + * "exclude-result-prefixes" is only allowed on literal + * result elements and "xsl:exclude-result-prefixes" + * on xsl:stylesheet/xsl:transform. + * SPEC 2.0: + * "There are a number of standard attributes + * that may appear on any XSLT element: specifically + * version, exclude-result-prefixes, + * extension-element-prefixes, xpath-default-namespace, + * default-collation, and use-when." + * + * SPEC 2.0: + * For literal result elements: + * "xsl:version, xsl:exclude-result-prefixes, + * xsl:extension-element-prefixes, + * xsl:xpath-default-namespace, + * xsl:default-collation, or xsl:use-when." + */ + if (cur->properties) + cctxt->inode->extElemNs = + xsltParseExtElemPrefixes(cctxt, + cur, cctxt->inode->extElemNs, 0); + /* + * Eval if we have an extension element here. + */ + if ((cur->ns != NULL) && + (cctxt->inode->extElemNs != NULL) && + (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1)) + { + /* + * This is an extension element. + * ============================ + * Mark the node information. + */ + cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION; + cctxt->inode->extContentHandled = 0; + if (cur->psvi != NULL) { + cur->psvi = NULL; + /* + * TODO: Temporary sanity check. + */ + xsltTransformError(NULL, cctxt->style, cur, + "Internal error: (xsltParseNonXSLTElement) " + " Occupied psvi field.\n"); + cctxt->style->errors++; + cur = cur->next; + continue; + } + cur->psvi = (void *) + xsltPreComputeExtModuleElement(cctxt->style, cur); + + if (cur->psvi == NULL) { + /* + * OLD COMMENT: "Unknown element, maybe registered at the + * context level. Mark it for later recognition." + * QUESTION: What does the xsltExtMarker mean? + * ANSWER: It is used in xsltApplyOneTemplateInt() at + * transformation-time to look out for extension + * registered in the transformation context. + */ + cur->psvi = (void *) xsltExtMarker; + } + /* + * BIG NOTE: Now the ugly part. In previous versions + * of Libxslt (until 1.1.16), all the content of an + * extension element was processed and compiled without + * the need of the extension-author to explicitely call + * such a processing;.We now need to mimic this old + * behaviour in order to avoid breaking old code + * on the extension-author's side. + * The mechanism: + * 1) If the author does *not* set the + * compile-time-flag @extContentHandled, then we'll + * parse the content assuming that it's a "template" + * (or "sequence constructor in XSLT 2.0 terms). + * NOTE: If the extension is registered at + * transformation-time only, then there's no way of + * knowing that content shall be valid, and we'll + * process the content the same way. + * 2) If author *does* set the flag, then we'll assume + * that the author has handled the parsing him/herself + * (e.g. called xsltParseSequenceConstructor(), etc. + * explicitely in his/her code). + */ + if ((cur->children != NULL) && + (cctxt->inode->extContentHandled == 0)) + { + /* + * Default parsing of the content using the + * sequence-constructor model. + */ + xsltParseSequenceConstructor(cctxt, cur->children); + } + } else { + /* + * This is a literal result element. + * ================================ + * Allowed XSLT attributes: + * xsl:extension-element-prefixes CDATA #IMPLIED + * xsl:exclude-result-prefixes CDATA #IMPLIED + * TODO: xsl:use-attribute-sets %qnames; #IMPLIED + * xsl:version NMTOKEN #IMPLIED + */ + cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LR; + if (cur->properties != NULL) { + /* + * Attribute "xsl:exclude-result-prefixes". + */ + cctxt->inode->exclResultNs = + xsltParseExclResultPrefixes(cctxt, cur, + cctxt->inode->exclResultNs, 0); + /* + * Attribute "xsl:version". + */ + xsltParseAttrXSLTVersion(cctxt, cur, 0); + } + /* + * TODO: Create the literal result item. + * TODO: Check what this *defaultAlias* mechanism does. Do we + * need to create the compiled item after such namespace + * conversion? + */ + if ((cur->ns == NULL) && (cctxt->style->defaultAlias != NULL) && + (cur->type == XML_ELEMENT_NODE)) + { + + cur->ns = xmlSearchNsByHref(cur->doc, cur, + cctxt->style->defaultAlias); + } + if (cur->properties) { + xmlAttrPtr attr = cur->properties; + + while (attr != NULL) { + xsltCompileAttr(cctxt->style, attr); + attr = attr->next; + } + } + /* + * Parse the content, which is defined to be a "template" + * (or "sequence constructor" in XSLT 2.0 terms). + */ + if (cur->children != NULL) { + xsltParseSequenceConstructor(cctxt, cur->children); } } - } - - /* - * If we have prefixes locally, recurse and pop them up when - * going back - */ - if (exclPrefixes > 0) { - xsltPrecomputeStylesheet(style, cur->children); - for (;exclPrefixes > 0;exclPrefixes--) - exclPrefixPop(style); - goto skip_children; - } - - } else if (cur->type == XML_TEXT_NODE) { - if (IS_BLANK_NODE(cur)) { - if (xmlNodeGetSpacePreserve(cur) != 1) { - delete = cur; - } - } else if ((cur->content != NULL) && (internalize) && - (!xmlDictOwns(style->dict, cur->content))) { - xmlChar *tmp; - /* - * internalize the text string, goal is to speed - * up operations and minimize used space by compiled - * stylesheets. - */ - tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1); - xmlNodeSetContent(cur, NULL); - cur->content = tmp; - } - } else if ((cur->type != XML_ELEMENT_NODE) && - (cur->type != XML_CDATA_SECTION_NODE)) { - delete = cur; - goto skip_children; - } - - /* - * Skip to next node - */ - if (cur->children != NULL) { - if ((cur->children->type != XML_ENTITY_DECL) && - (cur->children->type != XML_ENTITY_REF_NODE) && - (cur->children->type != XML_ENTITY_NODE)) { - cur = cur->children; - continue; + * Leave the non-XSLT element. + */ + xsltCompilerNodePop(cctxt, cur); } } -#ifdef XSLT_REFACTORED - if (cur->type == XML_ELEMENT_NODE) { - /* Leaving the scope of an element-node. */ - xsltCompilerNodePop(cctxt, cur); - } -#endif - -skip_children: - if (cur->next != NULL) { - cur = cur->next; - continue; - } - do { - - cur = cur->parent; - if (cur == NULL) - break; - if (cur == (xmlNodePtr) style->doc) { - cur = NULL; - break; - } - if (cur->next != NULL) { - cur = cur->next; - break; - } - } while (cur != NULL); + cur = cur->next; } - if (delete != NULL) { -#ifdef WITH_XSLT_DEBUG_PARSING + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS xsltGenericDebug(xsltGenericDebugContext, - "xsltPrecomputeStylesheet: removing ignorable blank node\n"); + "xsltParseSequenceConstructor: removing xsl:text element\n"); #endif - xmlUnlinkNode(delete); - xmlFreeNode(delete); - delete = NULL; + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; } } /** - * xsltGatherNamespaces: + * xsltParseTemplateContent: * @style: the XSLT stylesheet + * @templ: the node containing the content to be parsed * - * Browse the stylesheet and build the namspace hash table which - * will be used for XPath interpretation. If needed do a bit of normalization + * Parses and compiles the content-model of an xsl:template element. + * Note that this is *not* the "template" (or "sequence constructor" + * in XSLT 2.0) content model. Since it allows addional xsl:param + * elements as immediate children of @templ. + * + * Called by: + * exsltFuncFunctionComp() (EXSLT, functions.c) + * So this is intended to be called from extension functions. */ +void +xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { + if ((style == NULL) || (templ == NULL)) + return; -static void -xsltGatherNamespaces(xsltStylesheetPtr style) { - xmlNodePtr cur; - const xmlChar *URI; - - if (style == NULL) - return; - /* - * TODO: basically if the stylesheet uses the same prefix for different - * patterns, well they may be in problem, hopefully they will get - * a warning first. - */ /* - * TODO: Eliminate the use of the hash for XPath expressions. - * An expression should be evaluated in the context of the in-scope - * namespaces; eliminate the restriction of an XML document to contain - * no duplicate prefixes for different namespace names. - * + * Detection of handled content of extension elements. */ - cur = xmlDocGetRootElement(style->doc); - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) { - xmlNsPtr ns = cur->nsDef; - while (ns != NULL) { - if (ns->prefix != NULL) { - if (style->nsHash == NULL) { - style->nsHash = xmlHashCreate(10); - if (style->nsHash == NULL) { - xsltTransformError(NULL, style, cur, - "xsltGatherNamespaces: failed to create hash table\n"); - style->errors++; - return; - } - } - URI = xmlHashLookup(style->nsHash, ns->prefix); - if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) { - xsltTransformError(NULL, style, cur, - "Namespaces prefix %s used for multiple namespaces\n",ns->prefix); - style->warnings++; - } else if (URI == NULL) { - xmlHashUpdateEntry(style->nsHash, ns->prefix, - (void *) ns->href, (xmlHashDeallocator)xmlFree); - -#ifdef WITH_XSLT_DEBUG_PARSING - xsltGenericDebug(xsltGenericDebugContext, - "Added namespace: %s mapped to %s\n", ns->prefix, ns->href); -#endif - } - } - ns = ns->next; - } - } + if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + XSLT_CCTXT(style)->inode->extContentHandled = 1; + } + if (templ->children != NULL) { + xmlNodePtr child = templ->children; /* - * Skip to next node - */ - if (cur->children != NULL) { - if (cur->children->type != XML_ENTITY_DECL) { - cur = cur->children; - continue; - } - } - if (cur->next != NULL) { - cur = cur->next; - continue; - } - + * Process xsl:param elements, which can only occur as the + * immediate children of xsl:template (well, and of any + * user-defined extension element if needed). + */ do { - cur = cur->parent; - if (cur == NULL) - break; - if (cur == (xmlNodePtr) style->doc) { - cur = NULL; - break; - } - if (cur->next != NULL) { - cur = cur->next; + if ((child->type == XML_ELEMENT_NODE) && + IS_IN_XSLT_NS(child) && IS_XSLT_NAME(child, "param")) + { + XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM; + xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); + } else break; - } - } while (cur != NULL); + child = child->next; + } while (child != NULL); + /* + * Parse the content and register the pattern. + */ + xsltParseSequenceConstructor(XSLT_CCTXT(style), child); } } +#else /* XSLT_REFACTORED */ + /** * xsltParseTemplateContent: * @style: the XSLT stylesheet @@ -1738,7 +3803,6 @@ xsltGatherNamespaces(xsltStylesheetPtr style) { * Clean-up the template content from unwanted ignorable blank nodes * and process xslt:text */ - void xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { xmlNodePtr cur, delete; @@ -1761,6 +3825,13 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { } if (IS_XSLT_ELEM(cur)) { if (IS_XSLT_NAME(cur, "text")) { + /* + * TODO: Processing of xsl:text should be moved to + * xsltPrecomputeStylesheet(), since otherwise this + * will be performed for every multiply included + * stylesheet; i.e. this here is not skipped with + * the use of the style->nopreproc flag. + */ if (cur->children != NULL) { xmlChar *prop; xmlNodePtr text = cur->children, next; @@ -1837,8 +3908,10 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { delete = cur; goto skip_children; } - } else if ((cur->ns != NULL) && (style->nsDefs != NULL) && - (xsltCheckExtPrefix(style, cur->ns->prefix))) { + } + else if ((cur->ns != NULL) && (style->nsDefs != NULL) && + (xsltCheckExtPrefix(style, cur->ns->prefix))) + { /* * okay this is an extension element compile it too */ @@ -1862,7 +3935,6 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { } } } - /* * Skip to next node */ @@ -1930,6 +4002,8 @@ skip_children: } } +#endif /* else XSLT_REFACTORED */ + /** * xsltParseStylesheetKey: * @style: the XSLT stylesheet @@ -1949,7 +4023,7 @@ xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) { xmlChar *name = NULL; xmlChar *nameURI = NULL; - if (key == NULL) + if ((style == NULL) || (key == NULL)) return; /* @@ -1996,22 +4070,234 @@ xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) { } /* - * register the keys - */ - xsltAddKey(style, name, nameURI, match, use, key); + * register the keys + */ + xsltAddKey(style, name, nameURI, match, use, key); + + +error: + if (use != NULL) + xmlFree(use); + if (match != NULL) + xmlFree(match); + if (name != NULL) + xmlFree(name); + if (nameURI != NULL) + xmlFree(nameURI); + + if (key->children != NULL) { + xsltParseContentError(style, key->children); + } +} + +#ifdef XSLT_REFACTORED +/** + * xsltParseXSLTTemplate: + * @style: the XSLT stylesheet + * @template: the "template" element + * + * parse an XSLT stylesheet template building the associated structures + * TODO: Is @style ever expected to be NULL? + * + * Called from: + * xsltParseXSLTStylesheet() + * xsltParseStylesheetTop() + */ + +static void +xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) { + xsltTemplatePtr templ; + xmlChar *prop; + double priority; + + if ((cctxt == NULL) || (templNode == NULL)) + return; + + /* + * Create and link the structure + */ + templ = xsltNewTemplate(); + if (templ == NULL) + return; + + xsltCompilerNodePush(cctxt, templNode); + if (templNode->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, templNode); + + templ->next = cctxt->style->templates; + cctxt->style->templates = templ; + templ->style = cctxt->style; + + + /* + * Get inherited namespaces. + */ + if (cctxt->inode->inScopeNs != NULL) { + int i, j; + xmlNsPtr ns; + xsltPointerListPtr extElemList = cctxt->inode->extElemNs; + xsltPointerListPtr exclResultList = cctxt->inode->exclResultNs; + xsltNsListPtr inScopeNs = cctxt->inode->inScopeNs; + + for (i = 0; i < inScopeNs->number; i++) { + ns = inScopeNs->list[i]; + /* + * Exclude the XSLT namespace. + */ + if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) + goto skip_ns; + /* + * Exclude excluded result namespaces. + */ + if (exclResultList) { + for (j = 0; j < exclResultList->number; j++) + if (xmlStrEqual(ns->href, + BAD_CAST exclResultList->items[j])) + goto skip_ns; + } + /* + * Exclude extension-element namespaces. + */ + if (extElemList) { + for (j = 0; j < extElemList->number; j++) + if (xmlStrEqual(ns->href, BAD_CAST extElemList->items[j])) + goto skip_ns; + } + /* + * Add the xmlNs item. + */ + if (templ->inheritedNs == NULL) { + templ->inheritedNs = (xmlNsPtr *) xmlMalloc( + inScopeNs->number * sizeof(xmlNsPtr)); + if (templ->inheritedNs == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltGetInheritedNsList : out of memory!\n"); + cctxt->style->errors++; + goto error; + } + memset(templ->inheritedNs, 0, + inScopeNs->number * sizeof(xmlNsPtr)); + } + templ->inheritedNs[templ->inheritedNsNr++] = ns; +skip_ns: + {} + } +#ifdef WITH_XSLT_DEBUG_PARSING + if (templ->inheritedNsNr != 0) { + xsltGenericDebug(xsltGenericDebugContext, + "xsl:template has %d inherited namespaces\n", + templ->inheritedNsNr); + } +#endif + } + + /* + * Attribute "mode". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL); + if (prop != NULL) { + const xmlChar *modeURI; + /* + * TODO: We need a standardized function for extraction + * of namespace names and local names from QNames. + */ + modeURI = xsltGetQNameURI(templNode, &prop); + if (prop == NULL) { + cctxt->style->errors++; + goto error; + } + templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1); + xmlFree(prop); + prop = NULL; + if (xmlValidateNCName(templ->mode, 0)) { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: Attribute 'mode': The local part '%s' " + "of the value is not a valid NCName.\n", templ->name); + cctxt->style->errors++; + goto error; + } + if (modeURI != NULL) + templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseXSLTTemplate: mode %s\n", templ->mode); +#endif + } + /* + * Attribute "match". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL); + if (prop != NULL) { + templ->match = prop; + prop = NULL; + } + /* + * Attribute "priority". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL); + if (prop != NULL) { + priority = xmlXPathStringEvalNumber(prop); + templ->priority = (float) priority; + xmlFree(prop); + prop = NULL; + } + /* + * Attribute "name". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL); + if (prop != NULL) { + const xmlChar *nameURI; + xsltTemplatePtr curTempl; + + nameURI = xsltGetQNameURI(templNode, &prop); + if (prop == NULL) { + cctxt->style->errors++; + goto error; + } + templ->name = xmlDictLookup(cctxt->style->dict, prop, -1); + xmlFree(prop); + prop = NULL; + if (xmlValidateNCName(templ->name, 0)) { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: Attribute 'name': The local part '%s' of " + "the value is not a valid NCName.\n", templ->name); + cctxt->style->errors++; + goto error; + } + if (nameURI != NULL) + templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1); + curTempl = templ->next; + while (curTempl != NULL) { + if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) && + xmlStrEqual(curTempl->nameURI, nameURI) ) || + (nameURI == NULL && curTempl->nameURI == NULL && + xmlStrEqual(curTempl->name, templ->name))) + { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: error duplicate name '%s'\n", templ->name); + cctxt->style->errors++; + goto error; + } + curTempl = curTempl->next; + } + } + if (templNode->children != NULL) + xsltParseTemplateContent(cctxt->style, templNode); + + templ->elem = templNode; + templ->content = templNode->children; + xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI); error: - if (use != NULL) - xmlFree(use); - if (match != NULL) - xmlFree(match); - if (name != NULL) - xmlFree(name); - if (nameURI != NULL) - xmlFree(nameURI); + xsltCompilerNodePop(cctxt, templNode); + + return; } +#else /* XSLT_REFACTORED */ + /** * xsltParseStylesheetTemplate: * @style: the XSLT stylesheet @@ -2092,16 +4378,7 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { if (prop != NULL) { const xmlChar *URI; xsltTemplatePtr cur; - - if (ret->name != NULL) { - xmlFree(ret->name); - ret->name = NULL; - } - if (ret->nameURI != NULL) { - xmlFree(ret->nameURI); - ret->nameURI = NULL; - } - + URI = xsltGetQNameURI(template, &prop); if (prop == NULL) { if (style != NULL) style->errors++; @@ -2112,119 +4389,727 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { "xsl:template : error invalid name '%s'\n", prop); if (style != NULL) style->errors++; goto error; - } - ret->name = prop; + } + ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1); + xmlFree(prop); + prop = NULL; if (URI != NULL) - ret->nameURI = xmlStrdup(URI); + ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1); else ret->nameURI = NULL; cur = ret->next; while (cur != NULL) { - if ((URI != NULL && xmlStrEqual(cur->name, prop) && + if ((URI != NULL && xmlStrEqual(cur->name, ret->name) && xmlStrEqual(cur->nameURI, URI) ) || (URI == NULL && cur->nameURI == NULL && - xmlStrEqual(cur->name, prop))) { + xmlStrEqual(cur->name, ret->name))) { xsltTransformError(NULL, style, template, - "xsl:template: error duplicate name '%s'\n", prop); + "xsl:template: error duplicate name '%s'\n", ret->name); + style->errors++; + goto error; + } + cur = cur->next; + } + } + } + + /* + * parse the content and register the pattern + */ + xsltParseTemplateContent(style, template); + ret->elem = template; + ret->content = template->children; + xsltAddTemplate(style, ret, ret->mode, ret->modeURI); + +error: + return; +} + +#endif /* else XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED + +/** + * xsltIncludeComp: + * @cctxt: the compilation contenxt + * @node: the xsl:include node + * + * Process the xslt include node on the source node + */ +static xsltStyleItemIncludePtr +xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { + xsltStyleItemIncludePtr item; + + if ((cctxt == NULL) || (node == NULL)) + return(NULL); + + node->psvi = NULL; + item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude)); + if (item == NULL) { + xsltTransformError(NULL, cctxt->style, node, + "xsltIncludeComp : malloc failed\n"); + cctxt->style->errors++; + return(NULL); + } + memset(item, 0, sizeof(xsltStyleItemInclude)); + + node->psvi = item; + item->inst = node; + item->type = XSLT_FUNC_INCLUDE; + + item->next = cctxt->style->preComps; + cctxt->style->preComps = (xsltElemPreCompPtr) item; + + return(item); +} + +/** + * xsltParseFindTopLevelElem: + */ +static int +xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr cur, + const xmlChar *name, + const xmlChar *namespaceURI, + int breakOnOtherElem, + xmlNodePtr *resultNode) +{ + if (name == NULL) + return(-1); + + *resultNode = NULL; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if ((cur->ns != NULL) && (cur->name != NULL)) { + if ((*(cur->name) == *name) && + xmlStrEqual(cur->name, name) && + xmlStrEqual(cur->ns->href, namespaceURI)) + { + *resultNode = cur; + return(1); + } + } + if (breakOnOtherElem) + break; + } + cur = cur->next; + } + *resultNode = cur; + return(0); +} + +static int +xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node, + xsltStyleType type) +{ + int ret = 0; + + /* + * TODO: The reason why this function exists: + * due to historical reasons some of the + * top-level declarations are processed by functions + * in other files. Since we need still to set + * up the node-info and generate information like + * in-scope namespaces, this is a wrapper around + * those old parsing functions. + */ + xsltCompilerNodePush(cctxt, node); + if (node->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + cctxt->inode->type = type; + + switch (type) { + case XSLT_FUNC_INCLUDE: + { + int oldIsInclude; + + if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL) + goto exit; + /* + * Mark this stylesheet tree as being currently included. + */ + oldIsInclude = cctxt->isInclude; + cctxt->isInclude = 1; + + if (xsltParseStylesheetInclude(cctxt->style, node) != 0) { + cctxt->style->errors++; + } + cctxt->isInclude = oldIsInclude; + } + break; + case XSLT_FUNC_PARAM: + xsltStylePreCompute(cctxt->style, node); + xsltParseGlobalParam(cctxt->style, node); + break; + case XSLT_FUNC_VARIABLE: + xsltStylePreCompute(cctxt->style, node); + xsltParseGlobalVariable(cctxt->style, node); + break; + case XSLT_FUNC_ATTRSET: + xsltParseStylesheetAttributeSet(cctxt->style, node); + break; + default: + xsltTransformError(NULL, cctxt->style, node, + "Internal error: (xsltParseTopLevelXSLTElem) " + "Cannot handle this top-level declaration.\n"); + cctxt->style->errors++; + ret = -1; + } + +exit: + xsltCompilerNodePop(cctxt, node); + + return(ret); +} + +static int +xsltParseRemoveWhitespace(xmlNodePtr node) +{ + if ((node == NULL) || (node->children == NULL)) + return(0); + else { + xmlNodePtr delNode = NULL, child = node->children; + + do { + if (delNode) { + xmlUnlinkNode(delNode); + xmlFreeNode(delNode); + delNode = NULL; + } + if (((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) && + (IS_BLANK_NODE(child))) + delNode = child; + child = child->next; + } while (child != NULL); + if (delNode) { + xmlUnlinkNode(delNode); + xmlFreeNode(delNode); + delNode = NULL; + } + } + return(0); +} + +static int +xsltParseMetaInfo(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ +#define XSLT_MODULE_SCOPE_GLOBAL 0 +#define XSLT_MODULE_SCOPE_SSLEVEL 1 + xmlNodePtr cur; + xmlChar *value = NULL, *value2 = NULL; + int moduleScope; + + if ((cctxt == NULL) || (node == NULL) || (node->children == NULL)) + return(-1); + + /* + * Remove whitespace in case we had a xml:space. + */ + xsltParseRemoveWhitespace(node); + + cur = node->children; + while (cur != NULL) { + if (value != NULL) { + xmlFree(value); + value = NULL; + } + if (value2 != NULL) { + xmlFree(value2); + value2 = NULL; + } + /* + * Process the module-registration specific elements. + */ + if ((cur->type == XML_ELEMENT_NODE) && + (cur->ns == NULL)) + { + if (xmlStrEqual(cur->name, "initialize-module")) { + /* + * TODO: Validation of attributes. + */ + value = xmlGetNsProp(cur, "namespace", NULL); + if (value != NULL) { + moduleScope = XSLT_MODULE_SCOPE_GLOBAL; + value2 = xmlGetNsProp(cur, "scope", NULL); + if (value != NULL) { + if (xmlStrEqual(value2, "global")) + moduleScope = XSLT_MODULE_SCOPE_GLOBAL; + else if (xmlStrEqual(value2, "stylesheet-level")) + moduleScope = XSLT_MODULE_SCOPE_SSLEVEL; + else { + xsltTransformError(NULL, cctxt->style, cur, + "Attribute 'scope': Invalid value. " + "Only the values 'global' and " + "'stylesheet-level' are expected.\n"); + } + } + /* + * Call the module initialization. + */ + if (moduleScope == XSLT_MODULE_SCOPE_GLOBAL) { + /* + * Initialize the modle using global user-data + * storage. This means that this module + * will be initialized only *once* (regardless + * of the number of stylesheet-modules) and the + * user-data will be only stored in the main + * stylesheet. + */ + xsltStyleGetExtData(cctxt->style, BAD_CAST value); + } else { + /* + * Initialize the modle using per-stylesheet + * user-data storage. This means that this module + * will be initialized (and user-data is stored) + * in the stylesheet at the current stylesheet-level. + */ + xsltStyleStylesheetLevelGetExtData(cctxt->style, + BAD_CAST value); + } + goto next_item; + } + } + } + xsltParseContentError(cctxt->style, cur); + +next_item: + cur = cur->next; + } + if (value != NULL) { + xmlFree(value); + value = NULL; + } + if (value2 != NULL) { + xmlFree(value2); + value2 = NULL; + } + + return(0); +} + +static int +xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ +#ifdef WITH_XSLT_DEBUG_PARSING + int templates = 0; +#endif + xmlNodePtr cur, start = NULL; + xsltStylesheetPtr style; + + if ((cctxt == NULL) || (node == NULL) || + (node->type != XML_ELEMENT_NODE)) + return(-1); + + style = cctxt->style; + /* + * At this stage all import declarations of all stylesheet modules + * with the same stylesheet level have been processed. + * Now we can safely parse the rest of the declarations. + */ + if (IS_IN_XSLT_NS(node) && IS_XSLT_NAME(node, "include")) + { + xsltDocumentPtr include; + /* + * URGENT TODO: Make this work with simplified stylesheets! + * I.e., when we won't find an xsl:stylesheet element. + */ + /* + * This is as include declaration. + */ + include = ((xsltStyleItemIncludePtr) node->psvi)->include; + if (include == NULL) { + /* TODO: raise error? */ + return(-1); + } + /* + * TODO: Actually an xsl:include should locate an embedded + * stylesheet as well; so the document-element won't always + * be the element where the actual stylesheet is rooted at. + * But such embedded stylesheets are not supported by Libxslt yet. + */ + node = xmlDocGetRootElement(include->doc); + if (node == NULL) { + return(-1); + } + } + + if (node->children == NULL) + return(0); + /* + * Push the xsl:stylesheet/xsl:transform element. + */ + xsltCompilerNodePush(cctxt, node); + cctxt->inode->isRoot = 1; + + /* + * In every case, we need to have + * the in-scope namespaces of the element, where the + * stylesheet is rooted at, regardless if it's an XSLT + * instruction or a literal result instruction (or if + * this is an embedded stylesheet). + */ + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + + /* + * Process attributes of xsl:stylesheet/xsl:transform. + * -------------------------------------------------- + * Allowed are: + * id = id + * extension-element-prefixes = tokens + * exclude-result-prefixes = tokens + * version = number (mandatory) + */ + if (xsltParseAttrXSLTVersion(cctxt, node, 1) == 0) { + /* + * Attribute "version". + * XSLT 1.0: "An xsl:stylesheet element *must* have a version + * attribute, indicating the version of XSLT that the + * stylesheet requires". + * The root element of a simplified stylesheet must also have + * this attribute. + */ +#ifdef XSLT_REFACTORED_MANDATORY_VERSION + if (isXsltElem) + xsltTransformError(NULL, cctxt->style, node, + "The attribute 'version' is missing.\n"); + cctxt->style->errors++; +#else + /* OLD behaviour. */ +xsltTransformError(NULL, cctxt->style, node, + "xsl:version is missing: document may not be a stylesheet\n"); + cctxt->style->warnings++; +#endif + } + /* + * The namespaces declared by the attributes + * "extension-element-prefixes" and + * "exclude-result-prefixes" are local to *this* + * stylesheet tree; i.e., they are *not* visible to + * other stylesheet-modules, whether imported or included. + * + * Attribute "extension-element-prefixes". + */ + cctxt->inode->extElemNs = + xsltParseExtElemPrefixes(cctxt, node, NULL, 1); + /* + * Attribute "exclude-result-prefixes". + */ + cctxt->inode->exclResultNs = + xsltParseExclResultPrefixes(cctxt, node, NULL, 1); + + /* + * Processed top-level elements: + * ---------------------------- + * xsl:variable, xsl:param (QName, in-scope ns, + * expression (vars allowed)) + * xsl:attribute-set (QName, in-scope ns) + * xsl:strip-space, xsl:preserve-space (XPath NameTests, + * in-scope ns) + * I *think* global scope, merge with includes + * xsl:output (QName, in-scope ns) + * xsl:key (QName, in-scope ns, pattern, + * expression (vars *not* allowed)) + * xsl:decimal-format (QName, needs in-scope ns) + * xsl:namespace-alias (in-scope ns) + * global scope, merge with includes + * xsl:template (last, QName, pattern) + * + * (whitespace-only text-nodes have *not* been removed + * yet; this will be done in xsltParseSequenceConstructor) + * + * Report misplaced child-nodes first. + */ + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_TEXT_NODE) { + xsltTransformError(NULL, style, cur, + "Misplaced text node (content: '%s').\n", + (cur->content != NULL) ? cur->content : BAD_CAST ""); + style->errors++; + } else if (cur->type != XML_ELEMENT_NODE) { + xsltTransformError(NULL, style, cur, "Misplaced node.\n"); + style->errors++; + } + cur = cur->next; + } + /* + * Skip xsl:import elements; they have been processed + * already. + */ + cur = node->children; + while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) + cur = cur->next; + if (cur == NULL) + goto exit; + + start = cur; + /* + * Process all top-level xsl:param elements. + */ + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); + cur = cur->next; + } + /* + * Process all top-level xsl:variable elements. + */ + cur = start; + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE); + cur = cur->next; + } + /* + * REVISIT TODO: Process Libxslt's module handling user-defined + * data element. + */ + cur = start; + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + xsltLibxsltDataElementNameMeta, + xsltLibxsltDataElementNamespaceMeta, 0, &cur) == 1) + { + if (xsltParseMetaInfo(cctxt, cur) == -1) + goto internal_err; + cur->psvi = (void *) xsltUserDataElemMarker; + cur = cur->next; + } + /* + * Process all the rest of top-level elements. + */ + cur = start; + while (cur != NULL) { + /* + * Process element nodes. + */ + if (cur->type == XML_ELEMENT_NODE) { + if (cur->ns == NULL) { + xsltTransformError(NULL, style, cur, + "Unexpected top-level element in no namespace.\n"); + style->errors++; + cur = cur->next; + continue; + } + if (cur->psvi == xsltUserDataElemMarker) { + cur->psvi = NULL; + cur = cur->next; + continue; + } + /* + * Process all XSLT elements. + */ + if (IS_IN_XSLT_NS(cur)) { + /* + * xsl:import is only allowed at the beginning. + */ + if (IS_XSLT_NAME(cur, "import")) { + xsltTransformError(NULL, style, cur, + "Misplaced xsl:import element.\n"); style->errors++; - goto error; + cur = cur->next; + continue; } - cur = cur->next; + /* + * TODO: Change the return type of the parsing functions + * to int. + */ + if (IS_XSLT_NAME(cur, "template")) { +#ifdef WITH_XSLT_DEBUG_PARSING + templates++; +#endif + /* + * TODO: Is the position of xsl:template in the + * tree significant? If not it would be easier to + * parse them at a later stage. + */ + xsltParseXSLTTemplate(cctxt, cur); + } else if (IS_XSLT_NAME(cur, "variable")) { + /* NOP; done already */ + } else if (IS_XSLT_NAME(cur, "param")) { + /* NOP; done already */ + } else if (IS_XSLT_NAME(cur, "include")) { + if (cur->psvi != NULL) + xsltParseXSLTStylesheetElemCore(cctxt, cur); + else { + xsltTransformError(NULL, style, cur, + "Internal error: " + "(xsltParseXSLTStylesheetElemCore) " + "The xsl:include element was not compiled.\n"); + style->errors++; + } + } else if (IS_XSLT_NAME(cur, "strip-space")) { + /* No node info needed. */ + xsltParseStylesheetStripSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "preserve-space")) { + /* No node info needed. */ + xsltParseStylesheetPreserveSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "output")) { + /* No node-info needed. */ + xsltParseStylesheetOutput(style, cur); + } else if (IS_XSLT_NAME(cur, "key")) { + /* TODO: node-info needed for expressions ? */ + xsltParseStylesheetKey(style, cur); + } else if (IS_XSLT_NAME(cur, "decimal-format")) { + /* No node-info needed. */ + xsltParseStylesheetDecimalFormat(style, cur); + } else if (IS_XSLT_NAME(cur, "attribute-set")) { + xsltParseTopLevelXSLTElem(cctxt, cur, + XSLT_FUNC_ATTRSET); + } else if (IS_XSLT_NAME(cur, "namespace-alias")) { + xsltNamespaceAlias(style, cur); + } else { + if (cctxt->inode->forwardsCompat) { + /* + * Forwards-compatible mode: + * + * XSLT-1: "if it is a top-level element and + * XSLT 1.0 does not allow such elements as top-level + * elements, then the element must be ignored along + * with its content;" + */ + /* + * TODO: I don't think we should generate a warning. + */ + xsltTransformError(NULL, style, cur, + "Forwards-compatible mode: Ignoring unknown XSLT " + "element '%s'.\n", cur->name); + style->warnings++; + } else { + xsltTransformError(NULL, style, cur, + "Unknown XSLT element '%s'.\n", cur->name); + style->errors++; + } + } + } else { + xsltTopLevelFunction function; + + /* + * Process non-XSLT elements, which are in a + * non-NULL namespace. + */ + /* + * QUESTION: What does xsltExtModuleTopLevelLookup() + * do exactly? + */ + function = xsltExtModuleTopLevelLookup(cur->name, + cur->ns->href); + if (function != NULL) + function(style, cur); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetTop : found foreign element %s\n", + cur->name); +#endif } } + cur = cur->next; } - /* - * parse the content and register the pattern - */ - xsltParseTemplateContent(style, template); - ret->elem = template; - ret->content = template->children; - xsltAddTemplate(style, ret, ret->mode, ret->modeURI); +exit: + xsltCompilerNodePop(cctxt, node); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "parsed %d templates\n", templates); +#endif + return(0); -error: - return; +internal_err: + xsltCompilerNodePop(cctxt, node); + return(-1); } -#ifdef XSLT_REFACTORED_PARSING -/* -* xsltParseStylesheetTreeNew: -* -* Parses and compiles an XSLT stylesheet's XML tree. -* -* TODO: Adjust error report text. -*/ +/** + * xsltParseXSLTStylesheet: + * @cctxt: the compiler context + * @node: the xsl:stylesheet/xsl:transform element-node + * + * Parses the xsl:stylesheet and xsl:transform element. + * + * + * + * + * + * BIG TODO: The xsl:include stuff. + * + * Called by xsltParseStylesheetTree() + * + * Returns 0 on success, a positive result on errors and + * -1 on API or internal errors. + */ static int -xsltParseStylesheetTreeNew(xsltStylesheetPtr sheet, xmlNodePtr cur) +xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { - xsltCompilerCtxtPtr cctxt; - xmlNodePtr top = cur; - int depth = 0, simpleSyntax = 0; + xmlNodePtr cur; - if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE) || - (sheet == NULL) || (sheet->compCtxt == NULL)) + if ((cctxt == NULL) || (node == NULL)) return(-1); - cctxt = (xsltCompilerCtxtPtr) sheet->compCtxt; - + + if (node->children == NULL) + goto exit; /* - * Evalute if we have a simplified syntax. + * Process top-level elements: + * xsl:import (must be first) + * xsl:include (this is just a pre-processing) */ - if ((IS_XSLT_ELEM(cur)) && - ((IS_XSLT_NAME(cur, "stylesheet")) || - (IS_XSLT_NAME(cur, "transform")))) - { -#ifdef WITH_XSLT_DEBUG_PARSING - xsltGenericDebug(xsltGenericDebugContext, - "xsltParseStylesheetProcess : found stylesheet\n"); -#endif - /* - * TODO: Initialize. - */ - } else { - simpleSyntax = 1; - /* - * TODO: Create the initial template. - * TODO: Initialize. - */ - } + cur = node->children; /* - * Reset the compiler context. - */ - cctxt->depth = 0; - cctxt->inode = NULL; + * Process xsl:import elements. + * XSLT 1.0: "The xsl:import element children must precede all + * other element children of an xsl:stylesheet element, + * including any xsl:include element children." + */ + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) + { + if (xsltParseStylesheetImport(cctxt->style, cur) != 0) { + cctxt->style->errors++; + } + cur = cur->next; + } + if (cur == NULL) + goto exit; /* - * Initialize the in-scope namespaces. We need to have - * the in-scope ns-decls of the first given node, regardless - * if it's a XSLT instruction or a literal result element. + * Pre-process all xsl:include elements. */ - xsltCompilerNodePush(cctxt, cur); - xsltCompilerGetInScopeNSInfo(cctxt, cur); - goto next_sibling; - - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) { - - } - -next_sibling: - if (cur->type == XML_ELEMENT_NODE) { - /* - * Leaving an element. - */ - xsltCompilerNodePop(cctxt, cur); - } - if (cur == top) - break; - if (cur->next != NULL) - cur = cur->next; - else { - cur = cur->parent; - goto next_sibling; - } + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE); + cur = cur->next; } + + if (cctxt->isInclude) { + /* + * If this stylesheet is intended for inclusion, then + * we will process only imports and includes. + */ + goto exit; + } + /* + * Now parse the rest of the top-level elements. + */ + xsltParseXSLTStylesheetElemCore(cctxt, node); +exit: return(0); } -#endif /* XSLT_REFACTORED_PARSING */ + +#else /* XSLT_REFACTORED */ /** * xsltParseStylesheetTop: @@ -2289,7 +5174,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { if (cur->type == XML_TEXT_NODE) { if (cur->content != NULL) { xsltTransformError(NULL, style, cur, - "misplaced text element: '%s'\n", cur->content); + "misplaced text node: '%s'\n", cur->content); } if (style != NULL) style->errors++; cur = cur->next; @@ -2350,6 +5235,10 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { } else if (IS_XSLT_NAME(cur, "namespace-alias")) { xsltNamespaceAlias(style, cur); } else { + /* + * BUG TODO: The version of the *doc* is irrelevant for + * the forwards-compatible mode. + */ if ((style != NULL) && (style->doc->version != NULL) && (!strncmp((const char *) style->doc->version, "1.0", 3))) { xsltTransformError(NULL, style, cur, @@ -2373,16 +5262,176 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { #endif } +#endif /* else of XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED +/** + * xsltParseSimplifiedStylesheetTree: + * + * @style: the stylesheet (TODO: Change this to the compiler context) + * @doc: the document containing the stylesheet. + * @node: the node where the stylesheet is rooted at + * + * Returns 0 in case of success, a positive result if an error occurred + * and -1 on API and internal errors. + */ +static int +xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt, + xmlDocPtr doc, + xmlNodePtr node) +{ + xsltTemplatePtr templ; + + if ((cctxt == NULL) || (node == NULL)) + return(-1); + /* + * + */ + if (xsltParseAttrXSLTVersion(cctxt, node, 0) == 0) { + /* + * TODO: Adjust report, since this might be an + * embedded stylesheet. + */ + xsltTransformError(NULL, cctxt->style, node, + "The attribute 'xsl:version' is missing; cannot identify " + "this document as an XSLT stylesheet document.\n"); + cctxt->style->errors++; + return(1); + } + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseSimplifiedStylesheetTree: document is stylesheet\n"); +#endif + + /* + * Create and link the template + */ + templ = xsltNewTemplate(); + if (templ == NULL) { + return(-1); + } + templ->next = cctxt->style->templates; + cctxt->style->templates = templ; + templ->match = xmlStrdup(BAD_CAST "/"); + + /* + * Note that we push the document-node in this special case. + */ + xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); + /* + * In every case, we need to have + * the in-scope namespaces of the element, where the + * stylesheet is rooted at, regardless if it's an XSLT + * instruction or a literal result instruction (or if + * this is an embedded stylesheet). + */ + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + /* + * Parse the content and register the match-pattern. + */ + xsltParseSequenceConstructor(cctxt, node); + xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); + + templ->elem = (xmlNodePtr) doc; + templ->content = node; + xsltAddTemplate(cctxt->style, templ, NULL, NULL); + cctxt->style->literal_result = 1; + return(0); +} + +int +xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc) +{ + if (doc == NULL) + return(-1); + /* + * Revert the changes we have applied to the namespace-URIs of + * ns-decls. + */ + while (ns != NULL) { + if ((ns->doc == doc) && (ns->ns != NULL)) { + ns->ns->href = ns->origNsName; + ns->ns = NULL; + ns->origNsName = NULL; + } + ns = ns->next; + } + return(0); +} + /** * xsltParseStylesheetProcess: - * @ret: the XSLT stylesheet + * @style: the XSLT stylesheet (the current stylesheet-level) * @doc: and xmlDoc parsed XML * - * parse an XSLT stylesheet adding the associated structures + * Parses an XSLT stylesheet, adding the associated structures. + * Called by: + * xsltParseStylesheetImportedDoc() (xslt.c) + * xsltParseStylesheetInclude() (imports.c) * - * Returns the value of the 'ret' parameter if everything + * Returns the value of the @style parameter if everything * went right, NULL if something went amiss. */ +xsltStylesheetPtr +xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc) +{ + xsltCompilerCtxtPtr cctxt; + xmlNodePtr cur; + int oldIsSimplifiedStylesheet; + + + if ((style == NULL) || (doc == NULL)) + return(NULL); + + cctxt = XSLT_CCTXT(style); + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xsltTransformError(NULL, style, (xmlNodePtr) doc, + "xsltParseStylesheetProcess : empty stylesheet\n"); + return(NULL); + } + oldIsSimplifiedStylesheet = cctxt->simplified; + + if ((IS_XSLT_ELEM(cur)) && + ((IS_XSLT_NAME(cur, "stylesheet")) || + (IS_XSLT_NAME(cur, "transform")))) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetProcess : found stylesheet\n"); +#endif + cctxt->simplified = 0; + style->literal_result = 0; + } else { + cctxt->simplified = 1; + style->literal_result = 1; + } + /* + * Pre-process the stylesheet if not already done before. + * This will remove PIs and comments, merge adjacent + * text nodes, internalize strings, etc. + */ + if (! style->nopreproc) + xsltParsePreprocessStylesheetTree(cctxt, cur); + /* + * Parse and compile the stylesheet. + */ + if (style->literal_result == 0) { + if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0) + return(NULL); + } else { + if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0) + return(NULL); + } + + cctxt->simplified = oldIsSimplifiedStylesheet; + + return(style); +} + +#else /* XSLT_REFACTORED */ xsltStylesheetPtr xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { @@ -2403,7 +5452,8 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { xsltTransformError(NULL, ret, (xmlNodePtr) doc, "xsltParseStylesheetProcess : empty stylesheet\n"); return(NULL); - } + } + if ((IS_XSLT_ELEM(cur)) && ((IS_XSLT_NAME(cur, "stylesheet")) || (IS_XSLT_NAME(cur, "transform")))) { @@ -2420,22 +5470,8 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { ret->literal_result = 1; } if (!ret->nopreproc) { -#ifdef XSLT_REFACTORED - /* - * Reset the compiler context. - * TODO: This all looks ugly; but note that this will go - * into an other function; it's just temporarily here. - */ - XSLT_CCTXT(ret)->depth = -1; - XSLT_CCTXT(ret)->inode = NULL; -#endif xsltPrecomputeStylesheet(ret, cur); -#ifdef XSLT_REFACTORED - XSLT_CCTXT(ret)->depth = -1; - XSLT_CCTXT(ret)->inode = NULL; -#endif } - if (ret->literal_result == 0) { xsltParseStylesheetTop(ret, cur); } else { @@ -2483,16 +5519,18 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { template->elem = (xmlNodePtr) doc; template->content = doc->children; xsltAddTemplate(ret, template, NULL, NULL); - ret->literal_result = 1; + ret->literal_result = 1; } return(ret); } +#endif /* else of XSLT_REFACTORED */ + /** * xsltParseStylesheetImportedDoc: * @doc: an xmlDoc parsed XML - * @style: pointer to parent stylesheet + * @style: pointer to the parent stylesheet (if it exists) * * parse an XSLT stylesheet building the associated structures * except the processing not needed for imported documents. @@ -2501,44 +5539,156 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { */ xsltStylesheetPtr -xsltParseStylesheetImportedDoc(xmlDocPtr doc, xsltStylesheetPtr style) { - xsltStylesheetPtr ret; +xsltParseStylesheetImportedDoc(xmlDocPtr doc, + xsltStylesheetPtr parentStyle) { + xsltStylesheetPtr retStyle; if (doc == NULL) return(NULL); - ret = xsltNewStylesheet(); - if (ret == NULL) + retStyle = xsltNewStylesheet(); + if (retStyle == NULL) return(NULL); - + /* + * Set the importing stylesheet module; also used to detect recursion. + */ + retStyle->parent = parentStyle; + /* + * Adjust the string dict. + */ if (doc->dict != NULL) { - xmlDictFree(ret->dict); - ret->dict = doc->dict; + xmlDictFree(retStyle->dict); + retStyle->dict = doc->dict; #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, - "reusing dictionary from %s for stylesheet\n", - doc->URL); + "reusing dictionary from %s for stylesheet\n", + doc->URL); #endif - xmlDictReference(ret->dict); - } + xmlDictReference(retStyle->dict); + } - ret->doc = doc; - ret->parent = style; /* needed to prevent loops */ - xsltGatherNamespaces(ret); - if (xsltParseStylesheetProcess(ret, doc) == NULL) { - ret->doc = NULL; - xsltFreeStylesheet(ret); - ret = NULL; + /* + * TODO: Eliminate xsltGatherNamespaces(); we must not restrict + * the stylesheet to containt distinct namespace prefixes. + */ + xsltGatherNamespaces(retStyle); + +#ifdef XSLT_REFACTORED + { + xsltCompilerCtxtPtr cctxt; + xsltStylesheetPtr oldCurSheet; + + if (parentStyle == NULL) { + xsltPrincipalStylesheetDataPtr principalData; + /* + * Principal stylesheet + * -------------------- + */ + retStyle->principal = retStyle; + /* + * Create extra data for the principal stylesheet. + */ + principalData = xsltNewPrincipalStylesheetData(); + if (principalData == NULL) { + xsltFreeStylesheet(retStyle); + return(NULL); + } + retStyle->principalData = principalData; + /* + * Create the compilation context (only once; for the + * principal stylesheet). + * This is currently the only function where the + * compilation context is created. + */ + if (xsltCompilerCreate(retStyle) == NULL) { + xsltFreeStylesheet(retStyle); + return(NULL); + } + cctxt = XSLT_CCTXT(retStyle); + cctxt->psData = principalData; + /* + * Push initial dummy node info. + */ + cctxt->depth = -1; + xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); + } else { + /* + * Imported stylesheet. + */ + retStyle->principal = parentStyle->principal; + cctxt = parentStyle->compCtxt; + retStyle->compCtxt = cctxt; + } + /* + * Save the old and set the current stylesheet structure in the + * compilation context. + */ + oldCurSheet = cctxt->style; + cctxt->style = retStyle; + + retStyle->doc = doc; + xsltParseStylesheetProcess(retStyle, doc); + + cctxt->style = oldCurSheet; + if (parentStyle == NULL) { + /* + * Pop the initial dummy node info. + */ + xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); + } else { + /* + * Clear the compilation context of imported + * stylesheets. + * TODO: really? + */ + /* retStyle->compCtxt = NULL; */ + } + /* + * Free the stylesheet if there were errors. + */ + if (retStyle != NULL) { + if (retStyle->errors != 0) { + /* + * Restore all changes made to namespace URIs of ns-decls. + */ + if (cctxt->psData->nsMap) + xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc); + /* + * Detach the doc from the stylesheet; otherwise the doc + * will be freed in xsltFreeStylesheet(). + */ + retStyle->doc = NULL; + /* + * Cleanup the doc if its the main doc. + */ + if (parentStyle == NULL) + xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc)); + + xsltFreeStylesheet(retStyle); + retStyle = NULL; + } + } } - if (ret != NULL) { - if (ret->errors != 0) { - ret->doc = NULL; - xsltFreeStylesheet(ret); - ret = NULL; + +#else /* XSLT_REFACTORED */ + /* + * Old behaviour. + */ + retStyle->doc = doc; + xsltParseStylesheetProcess(retStyle, doc); + if (retStyle != NULL) { + if (retStyle->errors != 0) { + retStyle->doc = NULL; + if (parentStyle == NULL) + xsltCleanupStylesheetTree(doc, + xmlDocGetRootElement(doc)); + xsltFreeStylesheet(retStyle); + retStyle = NULL; } } - - return(ret); +#endif /* else of XSLT_REFACTORED */ + + return(retStyle); } /** @@ -2566,6 +5716,8 @@ xsltParseStylesheetDoc(xmlDocPtr doc) { * xsltParseStylesheetImportedDoc(). */ if (ret->compCtxt != NULL) { + /* TEST TODO: REMOVE test output*/ + /* printf("MAX NODE INFO: %d\n", XSLT_CCTXT(ret)->maxNodeInfos); */ xsltCompilerCtxtFree(XSLT_CCTXT(ret)); ret->compCtxt = NULL; } diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index a79096d..7fb8940 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -26,7 +26,6 @@ extern "C" { #endif - /** * XSLT_REFACTORED: * @@ -35,6 +34,54 @@ extern "C" { */ /* #define XSLT_REFACTORED */ +#ifdef XSLT_REFACTORED + +extern const xmlChar *xsltConstNamespaceNameXSLT; + +/** + * IS_XSLT_ELEM_FAST: + * + * Checks that the element pertains to XSLT namespace. + */ +#define IS_XSLT_ELEM_FAST(e) \ + (((e) != NULL) && ((e)->type == XML_ELEMENT_NODE) && \ + ((e)->ns != NULL) && ((e)->ns->href == xsltConstNamespaceNameXSLT)) + +#define IS_IN_XSLT_NS(e) \ + (((e)->ns != NULL) && ((e)->ns->href == xsltConstNamespaceNameXSLT)) + +#define XSLT_HAS_INTERNAL_NSMAP(s) \ + (((s) != NULL) && ((s)->principal) && \ + ((s)->principal->principalData) && \ + ((s)->principal->principalData->nsMap)) + +#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap) + +/** + * XSLT_REFACTORED_MANDATORY_VERSION: + * + * TODO: Currently disabled to surpress regression test failures, since + * the old behaviour was that a missing version attribute + * produced a only a warning and not an error, which was incerrect. + * So the regression tests need to be fixed if this is enabled. + */ +/* #define XSLT_REFACTORED_MANDATORY_VERSION */ + +/** + * xsltPointerList: + * + * Pointer-list for various purposes. + */ +typedef struct _xsltPointerList xsltPointerList; +typedef xsltPointerList *xsltPointerListPtr; +struct _xsltPointerList { + void **items; + int number; + int size; +}; + +#endif + /** * XSLT_REFACTORED_PARSING: * @@ -110,8 +157,8 @@ struct _xsltTemplate { struct _xsltStylesheet *style;/* the containing stylesheet */ xmlChar *match; /* the matching string */ float priority; /* as given from the stylesheet, not computed */ - xmlChar *name; /* the local part of the name QName */ - xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ const xmlChar *mode;/* the local part of the mode QName */ const xmlChar *modeURI;/* the URI part of the mode QName */ xmlNodePtr content; /* the template replacement value */ @@ -236,7 +283,13 @@ typedef enum { XSLT_FUNC_VARIABLE, XSLT_FUNC_WHEN, XSLT_FUNC_EXTENSION, +#ifdef XSLT_REFACTORED XSLT_FUNC_OTHERWISE, + XSLT_FUNC_FALLBACK, + XSLT_FUNC_MESSAGE, + XSLT_FUNC_INCLUDE, + XSLT_FUNC_ATTRSET +#endif } xsltStyleType; /** @@ -258,7 +311,7 @@ typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp); struct _xsltElemPreComp { xsltElemPreCompPtr next; /* next item in the global chained list hold by xsltStylesheet. */ - xsltStyleType type; /* type of the element */ + xsltStyleType type; /* type of the element */ xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the node in the stylesheet's tree corresponding to this item */ @@ -270,51 +323,44 @@ struct _xsltElemPreComp { /** * xsltStylePreComp: * - * The abstract basic structure for items of the - * AST of the XSLT processor. - * The AST includes: + * The abstract basic structure for items of the XSLT processor. + * This includes: * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.) * 2) compiled forms of literal result elements + * 3) compiled forms of extension elements */ typedef struct _xsltStylePreComp xsltStylePreComp; typedef xsltStylePreComp *xsltStylePreCompPtr; -/************************* - * Refactored structures * - *************************/ #ifdef XSLT_REFACTORED -typedef struct _xsltNsList xsltNsList; +/* +* Some pointer-list utility functions. +*/ +XSLTPUBFUN xsltPointerListPtr XSLTCALL + xsltPointerListCreate (int initialSize); +XSLTPUBFUN void XSLTCALL + xsltPointerListFree (xsltPointerListPtr list); +XSLTPUBFUN void XSLTCALL + xsltPointerListClear (xsltPointerListPtr list); +XSLTPUBFUN int XSLTCALL + xsltPointerListAddSize (xsltPointerListPtr list, + void *item, + int initialSize); + +/************************************************************************ + * * + * Refactored structures * + * * + ************************************************************************/ +typedef struct _xsltNsList xsltNsList; typedef xsltNsList *xsltNsListPtr; struct _xsltNsList { xmlNsPtr *list; int number; }; -#if 0 -/* - * TODO: xsltBasicItem is not used yet; maybe never will be used, since - * xsltElemPreCompPtr is acting as the base type for the compiled - * items of a stylesheet. It seems not practical to try to change - * this type to xsltBasicItemPtr, since xsltElemPreCompPtr is - * used already used too massively (e.g. xsltStylesheet->preComps) and - * for extension functions. - */ -/** - * xsltBasicItem: - * - * The basic structure for all items of the AST of the XSLT processor. - */ -typedef struct _xsltBasicItem xsltBasicItem; - -typedef xsltBasicItem *xsltBasicItemPtr; -struct _xsltBasicItem { - xsltBasicASTItemPtr next; - xsltStyleType type; -}; -#endif - /** * XSLT_ITEM_COMPATIBILITY_FIELDS: * @@ -346,7 +392,7 @@ struct _xsltBasicItem { * * The in-scope namespaces. */ -#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListPtr inScopeNS; +#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListPtr inScopeNs; /** * XSLT_ITEM_COMMON_FIELDS: @@ -378,8 +424,8 @@ struct _xsltStylePreComp { xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the node in the stylesheet's tree corresponding to this item. */ - /* Currenlty to navigational fields. */ - xsltNsListPtr inScopeNS; + /* Currently no navigational fields. */ + xsltNsListPtr inScopeNs; }; /** @@ -868,14 +914,72 @@ struct _xsltStyleItemOtherwise { XSLT_ITEM_COMMON_FIELDS }; +typedef struct _xsltStyleItemInclude xsltStyleItemInclude; +typedef xsltStyleItemInclude *xsltStyleItemIncludePtr; + +struct _xsltStyleItemInclude { + XSLT_ITEM_COMMON_FIELDS + xsltDocumentPtr include; +}; + +/************************************************************************ + * * + * Extension elements * + * * + ************************************************************************/ + +/* + * xsltStyleItemExtElement: + * + * Reflects extension elements. + * + * NOTE: Due to the fact that the structure xsltElemPreComp is most + * probably already heavily in use out there by users, so we cannot + * easily change it, we'll create an intermediate structure which will + * hold an xsltElemPreCompPtr. + * BIG NOTE: The only problem I see here is that the user processes the + * content of the stylesheet tree, possibly he'll lookup the node->psvi + * fields in order to find subsequent extension functions. + * In this case, the user's code will break, since the node->psvi + * field will hold now the xsltStyleItemExtElementPtr and not + * the xsltElemPreCompPtr. + * However the place where the structure is anchored in the node-tree, + * namely node->psvi, has beed already once been moved from node->_private + * to node->psvi, so we have a precedent here, which, I think, should allow + * us to change such semantics without headaches. + */ +typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement; +typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr; +struct _xsltStyleItemExtElement { + XSLT_ITEM_COMMON_FIELDS + xsltElemPreCompPtr item; +}; + +/************************************************************************ + * * + * Literal result elements * + * * + ************************************************************************/ + /* * Literal result elements. - * TODO: Not used yet. */ -typedef struct _xsltStyleItemLRE xsltStyleItemLRE; -typedef xsltStyleItemLRE *xsltStyleItemLREPtr; -struct _xsltStyleItemLRE { +typedef struct _xsltStyleItemLRElement xsltStyleItemLRElement; +typedef xsltStyleItemLRElement *xsltStyleItemLRElementPtr; +struct _xsltStyleItemLRElement { XSLT_ITEM_COMMON_FIELDS + xsltPointerListPtr exclResultNs; +}; + +typedef struct _xsltNsMap xsltNsMap; +typedef xsltNsMap *xsltNsMapPtr; +struct _xsltNsMap { + xsltNsMapPtr next; /* next in the list */ + xmlDocPtr doc; + xmlNodePtr elem; /* the element holding the ns-decl */ + xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */ + const xmlChar *origNsName; /* the original XML namespace name */ + const xmlChar *newNsName; /* the mapped XML namespace name */ }; /************************************************************************ @@ -884,6 +988,13 @@ struct _xsltStyleItemLRE { * * ************************************************************************/ +typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData; +typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr; + +#define XSLT_ELEMENT_CATEGORY_XSLT 0 +#define XSLT_ELEMENT_CATEGORY_EXTENSION 1 +#define XSLT_ELEMENT_CATEGORY_LR 2 + /** * xsltCompilerNodeInfo: * @@ -896,29 +1007,68 @@ struct _xsltCompilerNodeInfo { xsltCompilerNodeInfoPtr prev; xmlNodePtr node; int depth; - xsltNsListPtr inScopeNS; /* The in-scope namespaces for the current - position in the node-tree */ xsltTemplatePtr templ; /* The owning template */ + int category; /* XSLT element, LR-element or + extension element */ + xsltStyleType type; xsltElemPreCompPtr item; /* The compiled information */ + xsltNsListPtr inScopeNs; /* The in-scope namespaces for the current + position in the node-tree */ + xsltPointerListPtr exclResultNs; /* The current excluded + result namespaces */ + xsltPointerListPtr extElemNs; + int preserveWhitespace; + int stripWhitespace; + int isRoot; /* whether this is the stylesheet's root node */ + int forwardsCompat; /* whether forwards-compatible mode is enabled */ + /* whether the content of an extension element was processed */ + int extContentHandled; + /* the type of the current child */ + xsltStyleType curChildType; }; -#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) +#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) + +typedef enum { + XSLT_ERROR_SEVERITY_ERROR = 0, + XSLT_ERROR_SEVERITY_WARNING +} xsltErrorSeverityType; typedef struct _xsltCompilerCtxt xsltCompilerCtxt; typedef xsltCompilerCtxt *xsltCompilerCtxtPtr; struct _xsltCompilerCtxt { - void *errorCtxt; /* user specific error context */ + void *errorCtxt; /* user specific error context */ + /* + * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */ + xsltErrorSeverityType errSeverity; int warnings; /* TODO: number of warnings found at compilation */ int errors; /* TODO: number of errors found at compilation */ - xsltStylesheetPtr sheet; + xmlDictPtr dict; + xsltStylesheetPtr style; + int simplified; /* whether this is a simplified stylesheet */ /* TODO: structured/unstructured error contexts. */ - int depth; /* TODO: current depth in the stylesheets node-tree */ + int depth; /* Current depth of processing */ xsltCompilerNodeInfoPtr inode; xsltCompilerNodeInfoPtr inodeList; xsltCompilerNodeInfoPtr inodeLast; + xsltPointerListPtr tmpList; /* Used for various purposes */ + /* + * The XSLT version as specified by the stylesheet's root element. + */ + int isInclude; + int hasForwardsCompat; /* whether forwards-compatible mode was used + in a parsing episode */ + int maxNodeInfos; /* just for the interest */ + /* + * In order to keep the old behaviour, applying strict rules of + * the spec can be turned off. This has effect only on special + * mechanisms like whitespace-stripping in the stylesheet. + */ + int strict; + xsltPrincipalStylesheetDataPtr psData; }; #else /* XSLT_REFACTORED */ @@ -1002,10 +1152,39 @@ struct _xsltStackElem { xmlXPathObjectPtr value; /* The value if computed */ }; +#ifdef XSLT_REFACTORED + +struct _xsltPrincipalStylesheetData { + /* + * Namespace dictionary for ns-prefixes and ns-names: + * TODO: Shared between stylesheets, and XPath mechanisms. + * Not used yet. + */ + xmlDictPtr namespaceDict; + /* + * Global list of in-scope namespaces. + */ + void *inScopeNamespaces; + /* + * Global list of information for [xsl:]excluded-result-prefixes. + */ + void *exclResultNamespaces; + /* + * Global list of information for [xsl:]extension-element-prefixes. + */ + void *extElemNamespaces; + /* + * Namespace name map to get rid of string comparison of namespace names. + */ + xsltNsMapPtr nsMap; +}; + + +#endif /* - * TODO: We need a field to anchor an stylesheet compilation context, since, - * due to historical reasons, various compile-time function take only the - * stylesheet as argument and not a compilation context. + * Note that we added a @compCtxt field to anchor an stylesheet compilation + * context, since, due to historical reasons, various compile-time function + * take only the stylesheet as argument and not a compilation context. */ struct _xsltStylesheet { /* @@ -1059,13 +1238,22 @@ struct _xsltStylesheet { /* * Namespaces. */ - xmlHashTablePtr nsHash; /* the set of namespaces in use */ - void *nsDefs; /* the namespaces defined */ + xmlHashTablePtr nsHash; /* the set of namespaces in use: + ATTENTION: This is used for + execution of XPath expressions; unfortunately + it restricts the stylesheet to have distinct + prefixes. + TODO: We need to get rid of this. + */ + void *nsDefs; /* ATTENTION TODO: This is currently used to store + xsltExtDefPtr (in extensions.c) and + *not* xmlNsPtr. + */ /* * Key definitions. */ - void *keys; /* key definitions */ + void *keys; /* key definitions */ /* * Output related stuff. @@ -1112,7 +1300,7 @@ struct _xsltStylesheet { xsltDocumentPtr includes; /* points to last nested include */ /* - * dictionnary: shared between stylesheet, context and documents. + * dictionary: shared between stylesheet, context and documents. */ xmlDictPtr dict; /* @@ -1135,16 +1323,18 @@ struct _xsltStylesheet { * Literal Result Element as Stylesheet c.f. section 2.3 */ int literal_result; -#ifdef XSLT_REFACTORED /* - * Compilation context used during compile-time. + * The principal stylesheet */ - void * compCtxt; + xsltStylesheetPtr principal; +#ifdef XSLT_REFACTORED /* - * Namespace lists. + * Compilation context used during compile-time. */ - void *inScopeNamespaces; -#endif + xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */ + + xsltPrincipalStylesheetDataPtr principalData; +#endif }; /* @@ -1323,13 +1513,13 @@ XSLTPUBFUN xsltStylesheetPtr XSLTCALL XSLTPUBFUN xsltStylesheetPtr XSLTCALL xsltParseStylesheetFile (const xmlChar* filename); XSLTPUBFUN void XSLTCALL - xsltFreeStylesheet (xsltStylesheetPtr sheet); + xsltFreeStylesheet (xsltStylesheetPtr style); XSLTPUBFUN int XSLTCALL xsltIsBlank (xmlChar *str); XSLTPUBFUN void XSLTCALL xsltFreeStackElemList (xsltStackElemPtr elem); XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL - xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, + xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name); XSLTPUBFUN xsltStylesheetPtr XSLTCALL @@ -1389,23 +1579,32 @@ XSLTPUBFUN xmlChar * XSLTCALL XSLTPUBFUN void XSLTCALL xsltFreeAVTList (void *avt); +/* + * Extra function for successful xsltCleanupGlobals / xsltInit sequence. + */ + +XSLTPUBFUN void XSLTCALL + xsltUninit (void); + /************************************************************************ * * * Compile-time functions for *internal* use only * * * ************************************************************************/ -#ifdef XSLT_REFACTORED -XSLTPUBFUN xsltNsListPtr XSLTCALL - xsltCompilerGetInScopeNSInfo(xsltCompilerCtxtPtr cctxt, - xmlNodePtr node); -#endif /* XSLT_REFACTORED */ -/* - * Extra function for successful xsltCleanupGlobals / xsltInit sequence. - */ - +#ifdef XSLT_REFACTORED XSLTPUBFUN void XSLTCALL - xsltUninit (void); + xsltParseSequenceConstructor( + xsltCompilerCtxtPtr cctxt, + xmlNodePtr start); +XSLTPUBFUN int XSLTCALL + xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt, + xmlNodePtr elem); +XSLTPUBFUN int XSLTCALL + xsltRestoreDocumentNamespaces( + xsltNsMapPtr ns, + xmlDocPtr doc); +#endif /* XSLT_REFACTORED */ #ifdef __cplusplus } diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index f7ee731..723962f 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -303,6 +303,49 @@ error: #ifdef XSLT_REFACTORED /** + * xsltPointerListAddSize: + * @list: the pointer list structure + * @item: the item to be stored + * @initialSize: the initial size of the list + * + * Adds an item to the list. + * + * Returns the position of the added item in the list or + * -1 in case of an error. + */ +int +xsltPointerListAddSize(xsltPointerListPtr list, + void *item, + int initialSize) +{ + if (list->items == NULL) { + if (initialSize <= 0) + initialSize = 1; + list->items = (void **) xmlMalloc( + initialSize * sizeof(void *)); + if (list->items == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPointerListAddSize: memory allocation failure.\n"); + return(-1); + } + list->number = 0; + list->size = initialSize; + } else if (list->size <= list->number) { + list->size *= 2; + list->items = (void **) xmlRealloc(list->items, + list->size * sizeof(void *)); + if (list->items == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPointerListAddSize: memory re-allocation failure.\n"); + list->size = 0; + return(-1); + } + } + list->items[list->number++] = item; + return(0); +} + +/** * xsltPointerListCreate: * * Creates an xsltPointerList structure. @@ -310,7 +353,7 @@ error: * Returns a xsltPointerList structure or NULL in case of an error. */ xsltPointerListPtr -xsltPointerListCreate(void) +xsltPointerListCreate(int initialSize) { xsltPointerListPtr ret; @@ -321,6 +364,10 @@ xsltPointerListCreate(void) return (NULL); } memset(ret, 0, sizeof(xsltPointerList)); + if (initialSize > 0) { + xsltPointerListAddSize(ret, NULL, initialSize); + ret->number = 0; + } return (ret); } @@ -357,76 +404,6 @@ xsltPointerListClear(xsltPointerListPtr list) list->size = 0; } -/** - * xsltPointerListAdd: - * - * Adds an item to the list. - * - * Returns the position of the added item in the list or - * -1 in case of an error. - */ -int -xsltPointerListAdd(xsltPointerListPtr list, void *item) -{ - if (list->items == NULL) { - list->items = (void **) xmlMalloc( - 20 * sizeof(void *)); - if (list->items == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltPointerListAdd: memory allocation failure.\n"); - return(-1); - } - list->number = 0; - list->size = 20; - } else if (list->size <= list->number) { - list->size *= 2; - list->items = (void **) xmlRealloc(list->items, - list->size * sizeof(void *)); - if (list->items == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltPointerListAdd: memory re-allocation failure.\n"); - list->size = 0; - return(-1); - } - } - list->items[list->number++] = item; - return(0); -} - -#if 0 /* TODO: Not used yet. Enable if ever needed. */ -static int -xsltPointerListAddSize(xsltPointerListPtr list, - int initialSize, - void *item) -{ - if (list->items == NULL) { - if (initialSize <= 0) - initialSize = 1; - list->items = (void **) xmlMalloc( - initialSize * sizeof(void *)); - if (list->items == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltPointerListAddSize: memory allocation failure.\n"); - return(-1); - } - list->number = 0; - list->size = initialSize; - } else if (list->size <= list->number) { - list->size *= 2; - list->items = (void **) xmlRealloc(list->items, - list->size * sizeof(void *)); - if (list->items == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltPointerListAddSize: memory re-allocation failure.\n"); - list->size = 0; - return(-1); - } - } - list->items[list->number++] = item; - return(0); -} -#endif - #endif /* XSLT_REFACTORED */ /************************************************************************ @@ -650,8 +627,16 @@ xsltPrintErrorContext(xsltTransformContextPtr ctxt, if (ctxt != NULL) type = "runtime error"; - else if (style != NULL) + else if (style != NULL) { +#ifdef XSLT_REFACTORED + if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING) + type = "compilation warning"; + else + type = "compilation error"; +#else type = "compilation error"; +#endif + } if ((file != NULL) && (line != 0) && (name != NULL)) error(errctx, "%s: file %s line %d element %s\n", @@ -1008,9 +993,9 @@ xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) { ctxt->node = list->nodeTab[i]; ctxt->xpathCtxt->node = ctxt->node; #ifdef XSLT_REFACTORED - if (comp->inScopeNS != NULL) { - ctxt->xpathCtxt->namespaces = comp->inScopeNS->list; - ctxt->xpathCtxt->nsNr = comp->inScopeNS->number; + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->number; } else { ctxt->xpathCtxt->namespaces = NULL; ctxt->xpathCtxt->nsNr = 0; diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h index c4e3ae9..058d143 100644 --- a/libxslt/xsltutils.h +++ b/libxslt/xsltutils.h @@ -298,31 +298,6 @@ XSLTPUBFUN int XSLTCALL XSLTPUBFUN void XSLTCALL xslDropCall (void); -#ifdef XSLT_REFACTORED -/** - * xsltPointerList: - * - * Pointer-list for various purposes. - */ -typedef struct _xsltPointerList xsltPointerList; -typedef xsltPointerList *xsltPointerListPtr; -struct _xsltPointerList { - void **items; - int number; - int size; -}; - -XSLTPUBFUN xsltPointerListPtr XSLTCALL - xsltPointerListCreate (void); -XSLTPUBFUN void XSLTCALL - xsltPointerListFree (xsltPointerListPtr list); -XSLTPUBFUN void XSLTCALL - xsltPointerListClear (xsltPointerListPtr list); -XSLTPUBFUN int XSLTCALL - xsltPointerListAdd (xsltPointerListPtr list, - void *item); -#endif /* XSLT_REFACTOR */ - #ifdef __cplusplus } #endif