Index: third_party/libxslt/libxslt/transform.c |
diff --git a/third_party/libxslt/libxslt/transform.c b/third_party/libxslt/libxslt/transform.c |
deleted file mode 100644 |
index 85ad3a20d41023ac558ddfd6bf4e04f70614cf40..0000000000000000000000000000000000000000 |
--- a/third_party/libxslt/libxslt/transform.c |
+++ /dev/null |
@@ -1,6464 +0,0 @@ |
-/* |
- * transform.c: Implementation of the XSL Transformation 1.0 engine |
- * transform part, i.e. applying a Stylesheet to a document |
- * |
- * References: |
- * http://www.w3.org/TR/1999/REC-xslt-19991116 |
- * |
- * Michael Kay "XSLT Programmer's Reference" pp 637-643 |
- * Writing Multiple Output Files |
- * |
- * XSLT-1.1 Working Draft |
- * http://www.w3.org/TR/xslt11#multiple-output |
- * |
- * See Copyright for the status of this software. |
- * |
- * daniel@veillard.com |
- */ |
- |
-#define IN_LIBXSLT |
-#include "libxslt.h" |
- |
-#include <string.h> |
-#include <stdio.h> |
- |
-#include <libxml/xmlmemory.h> |
-#include <libxml/parser.h> |
-#include <libxml/tree.h> |
-#include <libxml/valid.h> |
-#include <libxml/hash.h> |
-#include <libxml/encoding.h> |
-#include <libxml/xmlerror.h> |
-#include <libxml/xpath.h> |
-#include <libxml/parserInternals.h> |
-#include <libxml/xpathInternals.h> |
-#include <libxml/HTMLtree.h> |
-#include <libxml/debugXML.h> |
-#include <libxml/uri.h> |
-#include "xslt.h" |
-#include "xsltInternals.h" |
-#include "xsltutils.h" |
-#include "pattern.h" |
-#include "transform.h" |
-#include "variables.h" |
-#include "numbersInternals.h" |
-#include "namespaces.h" |
-#include "attributes.h" |
-#include "templates.h" |
-#include "imports.h" |
-#include "keys.h" |
-#include "documents.h" |
-#include "extensions.h" |
-#include "extra.h" |
-#include "preproc.h" |
-#include "security.h" |
- |
-#ifdef WITH_XSLT_DEBUG |
-#define WITH_XSLT_DEBUG_EXTRA |
-#define WITH_XSLT_DEBUG_PROCESS |
-#define WITH_XSLT_DEBUG_VARIABLE |
-#endif |
- |
-#define XSLT_GENERATE_HTML_DOCTYPE |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
-static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, |
- const xmlChar **systemID); |
-#endif |
- |
-int xsltMaxDepth = 3000; |
-int xsltMaxVars = 15000; |
- |
-/* |
- * Useful macros |
- */ |
- |
-#ifndef FALSE |
-# define FALSE (0 == 1) |
-# define TRUE (!FALSE) |
-#endif |
- |
-#define IS_BLANK_NODE(n) \ |
- (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) |
- |
- |
-/* |
-* Forward declarations |
-*/ |
- |
-static xmlNsPtr |
-xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); |
- |
-static xmlNodePtr |
-xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, |
- xmlNodePtr node, xmlNodePtr insert, int isLRE, |
- int topElemVisited); |
- |
-static void |
-xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, xmlNodePtr list, |
- xsltTemplatePtr templ); |
- |
-static void |
-xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, |
- xmlNodePtr list, |
- xsltTemplatePtr templ, |
- xsltStackElemPtr withParams); |
- |
-/** |
- * templPush: |
- * @ctxt: the transformation context |
- * @value: the template to push on the stack |
- * |
- * Push a template on the stack |
- * |
- * Returns the new index in the stack or 0 in case of error |
- */ |
-static int |
-templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) |
-{ |
- if (ctxt->templMax == 0) { |
- ctxt->templMax = 4; |
- ctxt->templTab = |
- (xsltTemplatePtr *) xmlMalloc(ctxt->templMax * |
- sizeof(ctxt->templTab[0])); |
- if (ctxt->templTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); |
- return (0); |
- } |
- } |
- else if (ctxt->templNr >= ctxt->templMax) { |
- ctxt->templMax *= 2; |
- ctxt->templTab = |
- (xsltTemplatePtr *) xmlRealloc(ctxt->templTab, |
- ctxt->templMax * |
- sizeof(ctxt->templTab[0])); |
- if (ctxt->templTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); |
- return (0); |
- } |
- } |
- ctxt->templTab[ctxt->templNr] = value; |
- ctxt->templ = value; |
- return (ctxt->templNr++); |
-} |
-/** |
- * templPop: |
- * @ctxt: the transformation context |
- * |
- * Pop a template value from the stack |
- * |
- * Returns the stored template value |
- */ |
-static xsltTemplatePtr |
-templPop(xsltTransformContextPtr ctxt) |
-{ |
- xsltTemplatePtr ret; |
- |
- if (ctxt->templNr <= 0) |
- return (0); |
- ctxt->templNr--; |
- if (ctxt->templNr > 0) |
- ctxt->templ = ctxt->templTab[ctxt->templNr - 1]; |
- else |
- ctxt->templ = (xsltTemplatePtr) 0; |
- ret = ctxt->templTab[ctxt->templNr]; |
- ctxt->templTab[ctxt->templNr] = 0; |
- return (ret); |
-} |
- |
-/** |
- * xsltLocalVariablePop: |
- * @ctxt: the transformation context |
- * @limitNr: number of variables which should remain |
- * @level: the depth in the xsl:template's tree |
- * |
- * Pops all variable values at the given @depth from the stack. |
- * |
- * Returns the stored variable value |
- * **NOTE:** |
- * This is an internal routine and should not be called by users! |
- */ |
-void |
-xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level) |
-{ |
- xsltStackElemPtr variable; |
- |
- if (ctxt->varsNr <= 0) |
- return; |
- |
- do { |
- if (ctxt->varsNr <= limitNr) |
- break; |
- variable = ctxt->varsTab[ctxt->varsNr - 1]; |
- if (variable->level <= level) |
- break; |
- if (variable->level >= 0) |
- xsltFreeStackElemList(variable); |
- ctxt->varsNr--; |
- } while (ctxt->varsNr != 0); |
- if (ctxt->varsNr > 0) |
- ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; |
- else |
- ctxt->vars = NULL; |
-} |
- |
-/** |
- * xsltTemplateParamsCleanup: |
- * |
- * Removes xsl:param and xsl:with-param items from the |
- * variable-stack. Only xsl:with-param items are not freed. |
- */ |
-static void |
-xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt) |
-{ |
- xsltStackElemPtr param; |
- |
- for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) { |
- param = ctxt->varsTab[ctxt->varsNr -1]; |
- /* |
- * Free xsl:param items. |
- * xsl:with-param items will have a level of -1 or -2. |
- */ |
- if (param->level >= 0) { |
- xsltFreeStackElemList(param); |
- } |
- } |
- if (ctxt->varsNr > 0) |
- ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; |
- else |
- ctxt->vars = NULL; |
-} |
- |
-/** |
- * profPush: |
- * @ctxt: the transformation context |
- * @value: the profiling value to push on the stack |
- * |
- * Push a profiling value on the stack |
- * |
- * Returns the new index in the stack or 0 in case of error |
- */ |
-static int |
-profPush(xsltTransformContextPtr ctxt, long value) |
-{ |
- if (ctxt->profMax == 0) { |
- ctxt->profMax = 4; |
- ctxt->profTab = |
- (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0])); |
- if (ctxt->profTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); |
- return (0); |
- } |
- } |
- else if (ctxt->profNr >= ctxt->profMax) { |
- ctxt->profMax *= 2; |
- ctxt->profTab = |
- (long *) xmlRealloc(ctxt->profTab, |
- ctxt->profMax * sizeof(ctxt->profTab[0])); |
- if (ctxt->profTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); |
- return (0); |
- } |
- } |
- ctxt->profTab[ctxt->profNr] = value; |
- ctxt->prof = value; |
- return (ctxt->profNr++); |
-} |
-/** |
- * profPop: |
- * @ctxt: the transformation context |
- * |
- * Pop a profiling value from the stack |
- * |
- * Returns the stored profiling value |
- */ |
-static long |
-profPop(xsltTransformContextPtr ctxt) |
-{ |
- long ret; |
- |
- if (ctxt->profNr <= 0) |
- return (0); |
- ctxt->profNr--; |
- if (ctxt->profNr > 0) |
- ctxt->prof = ctxt->profTab[ctxt->profNr - 1]; |
- else |
- ctxt->prof = (long) 0; |
- ret = ctxt->profTab[ctxt->profNr]; |
- ctxt->profTab[ctxt->profNr] = 0; |
- return (ret); |
-} |
- |
-static void |
-profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent) |
-{ |
- int i; |
- |
- if (templ->templMax == 0) { |
- templ->templMax = 4; |
- templ->templCalledTab = |
- (xsltTemplatePtr *) xmlMalloc(templ->templMax * |
- sizeof(templ->templCalledTab[0])); |
- templ->templCountTab = |
- (int *) xmlMalloc(templ->templMax * |
- sizeof(templ->templCountTab[0])); |
- if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); |
- return; |
- } |
- } |
- else if (templ->templNr >= templ->templMax) { |
- templ->templMax *= 2; |
- templ->templCalledTab = |
- (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab, |
- templ->templMax * |
- sizeof(templ->templCalledTab[0])); |
- templ->templCountTab = |
- (int *) xmlRealloc(templ->templCountTab, |
- templ->templMax * |
- sizeof(templ->templCountTab[0])); |
- if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); |
- return; |
- } |
- } |
- |
- for (i = 0; i < templ->templNr; i++) { |
- if (templ->templCalledTab[i] == parent) { |
- templ->templCountTab[i]++; |
- break; |
- } |
- } |
- if (i == templ->templNr) { |
- /* not found, add new one */ |
- templ->templCalledTab[templ->templNr] = parent; |
- templ->templCountTab[templ->templNr] = 1; |
- templ->templNr++; |
- } |
-} |
- |
-/** |
- * xsltPreCompEval: |
- * @ctxt: transform context |
- * @node: context node |
- * @comp: precompiled expression |
- * |
- * Evaluate a precompiled XPath expression. |
- */ |
-static xmlXPathObjectPtr |
-xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xsltStylePreCompPtr comp) { |
- xmlXPathObjectPtr res; |
- xmlXPathContextPtr xpctxt; |
- xmlNodePtr oldXPContextNode; |
- xmlNsPtr *oldXPNamespaces; |
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; |
- |
- xpctxt = ctxt->xpathCtxt; |
- oldXPContextNode = xpctxt->node; |
- oldXPProximityPosition = xpctxt->proximityPosition; |
- oldXPContextSize = xpctxt->contextSize; |
- oldXPNsNr = xpctxt->nsNr; |
- oldXPNamespaces = xpctxt->namespaces; |
- |
- xpctxt->node = node; |
-#ifdef XSLT_REFACTORED |
- if (comp->inScopeNs != NULL) { |
- xpctxt->namespaces = comp->inScopeNs->list; |
- xpctxt->nsNr = comp->inScopeNs->xpathNumber; |
- } else { |
- xpctxt->namespaces = NULL; |
- xpctxt->nsNr = 0; |
- } |
-#else |
- xpctxt->namespaces = comp->nsList; |
- xpctxt->nsNr = comp->nsNr; |
-#endif |
- |
- res = xmlXPathCompiledEval(comp->comp, xpctxt); |
- |
- xpctxt->node = oldXPContextNode; |
- xpctxt->proximityPosition = oldXPProximityPosition; |
- xpctxt->contextSize = oldXPContextSize; |
- xpctxt->nsNr = oldXPNsNr; |
- xpctxt->namespaces = oldXPNamespaces; |
- |
- return(res); |
-} |
- |
-/** |
- * xsltPreCompEvalToBoolean: |
- * @ctxt: transform context |
- * @node: context node |
- * @comp: precompiled expression |
- * |
- * Evaluate a precompiled XPath expression as boolean. |
- */ |
-static int |
-xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xsltStylePreCompPtr comp) { |
- int res; |
- xmlXPathContextPtr xpctxt; |
- xmlNodePtr oldXPContextNode; |
- xmlNsPtr *oldXPNamespaces; |
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; |
- |
- xpctxt = ctxt->xpathCtxt; |
- oldXPContextNode = xpctxt->node; |
- oldXPProximityPosition = xpctxt->proximityPosition; |
- oldXPContextSize = xpctxt->contextSize; |
- oldXPNsNr = xpctxt->nsNr; |
- oldXPNamespaces = xpctxt->namespaces; |
- |
- xpctxt->node = node; |
-#ifdef XSLT_REFACTORED |
- if (comp->inScopeNs != NULL) { |
- xpctxt->namespaces = comp->inScopeNs->list; |
- xpctxt->nsNr = comp->inScopeNs->xpathNumber; |
- } else { |
- xpctxt->namespaces = NULL; |
- xpctxt->nsNr = 0; |
- } |
-#else |
- xpctxt->namespaces = comp->nsList; |
- xpctxt->nsNr = comp->nsNr; |
-#endif |
- |
- res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt); |
- |
- xpctxt->node = oldXPContextNode; |
- xpctxt->proximityPosition = oldXPProximityPosition; |
- xpctxt->contextSize = oldXPContextSize; |
- xpctxt->nsNr = oldXPNsNr; |
- xpctxt->namespaces = oldXPNamespaces; |
- |
- return(res); |
-} |
- |
-/************************************************************************ |
- * * |
- * XInclude default settings * |
- * * |
- ************************************************************************/ |
- |
-static int xsltDoXIncludeDefault = 0; |
- |
-/** |
- * xsltSetXIncludeDefault: |
- * @xinclude: whether to do XInclude processing |
- * |
- * Set whether XInclude should be processed on document being loaded by default |
- */ |
-void |
-xsltSetXIncludeDefault(int xinclude) { |
- xsltDoXIncludeDefault = (xinclude != 0); |
-} |
- |
-/** |
- * xsltGetXIncludeDefault: |
- * |
- * Provides the default state for XInclude processing |
- * |
- * Returns 0 if there is no processing 1 otherwise |
- */ |
-int |
-xsltGetXIncludeDefault(void) { |
- return(xsltDoXIncludeDefault); |
-} |
- |
-static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; |
- |
-/** |
- * xsltDebugSetDefaultTrace: |
- * @val: tracing level mask |
- * |
- * Set the default debug tracing level mask |
- */ |
-void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) { |
- xsltDefaultTrace = val; |
-} |
- |
-/** |
- * xsltDebugGetDefaultTrace: |
- * |
- * Get the current default debug tracing level mask |
- * |
- * Returns the current default debug tracing level mask |
- */ |
-xsltDebugTraceCodes xsltDebugGetDefaultTrace() { |
- return xsltDefaultTrace; |
-} |
- |
-/************************************************************************ |
- * * |
- * Handling of Transformation Contexts * |
- * * |
- ************************************************************************/ |
- |
-static xsltTransformCachePtr |
-xsltTransformCacheCreate(void) |
-{ |
- xsltTransformCachePtr ret; |
- |
- ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache)); |
- if (ret == NULL) { |
- xsltTransformError(NULL, NULL, NULL, |
- "xsltTransformCacheCreate : malloc failed\n"); |
- return(NULL); |
- } |
- memset(ret, 0, sizeof(xsltTransformCache)); |
- return(ret); |
-} |
- |
-static void |
-xsltTransformCacheFree(xsltTransformCachePtr cache) |
-{ |
- if (cache == NULL) |
- return; |
- /* |
- * Free tree fragments. |
- */ |
- if (cache->RVT) { |
- xmlDocPtr tmp, cur = cache->RVT; |
- while (cur) { |
- tmp = cur; |
- cur = (xmlDocPtr) cur->next; |
- if (tmp->_private != NULL) { |
- /* |
- * Tree the document info. |
- */ |
- xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); |
- xmlFree(tmp->_private); |
- } |
- xmlFreeDoc(tmp); |
- } |
- } |
- /* |
- * Free vars/params. |
- */ |
- if (cache->stackItems) { |
- xsltStackElemPtr tmp, cur = cache->stackItems; |
- while (cur) { |
- tmp = cur; |
- cur = cur->next; |
- /* |
- * REVISIT TODO: Should be call a destruction-function |
- * instead? |
- */ |
- xmlFree(tmp); |
- } |
- } |
- xmlFree(cache); |
-} |
- |
-/** |
- * xsltNewTransformContext: |
- * @style: a parsed XSLT stylesheet |
- * @doc: the input document |
- * |
- * Create a new XSLT TransformContext |
- * |
- * Returns the newly allocated xsltTransformContextPtr or NULL in case of error |
- */ |
-xsltTransformContextPtr |
-xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { |
- xsltTransformContextPtr cur; |
- xsltDocumentPtr docu; |
- int i; |
- |
- xsltInitGlobals(); |
- |
- cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext)); |
- if (cur == NULL) { |
- xsltTransformError(NULL, NULL, (xmlNodePtr)doc, |
- "xsltNewTransformContext : malloc failed\n"); |
- return(NULL); |
- } |
- memset(cur, 0, sizeof(xsltTransformContext)); |
- |
- cur->cache = xsltTransformCacheCreate(); |
- if (cur->cache == NULL) |
- goto internal_err; |
- /* |
- * setup of the dictionary must be done early as some of the |
- * processing later like key handling may need it. |
- */ |
- cur->dict = xmlDictCreateSub(style->dict); |
- cur->internalized = ((style->internalized) && (cur->dict != NULL)); |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Creating sub-dictionary from stylesheet for transformation\n"); |
-#endif |
- |
- /* |
- * initialize the template stack |
- */ |
- cur->templTab = (xsltTemplatePtr *) |
- xmlMalloc(10 * sizeof(xsltTemplatePtr)); |
- if (cur->templTab == NULL) { |
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc, |
- "xsltNewTransformContext: out of memory\n"); |
- goto internal_err; |
- } |
- cur->templNr = 0; |
- cur->templMax = 5; |
- cur->templ = NULL; |
- cur->maxTemplateDepth = xsltMaxDepth; |
- |
- /* |
- * initialize the variables stack |
- */ |
- cur->varsTab = (xsltStackElemPtr *) |
- xmlMalloc(10 * sizeof(xsltStackElemPtr)); |
- if (cur->varsTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, |
- "xsltNewTransformContext: out of memory\n"); |
- goto internal_err; |
- } |
- cur->varsNr = 0; |
- cur->varsMax = 10; |
- cur->vars = NULL; |
- cur->varsBase = 0; |
- cur->maxTemplateVars = xsltMaxVars; |
- |
- /* |
- * the profiling stack is not initialized by default |
- */ |
- cur->profTab = NULL; |
- cur->profNr = 0; |
- cur->profMax = 0; |
- cur->prof = 0; |
- |
- cur->style = style; |
- xmlXPathInit(); |
- cur->xpathCtxt = xmlXPathNewContext(doc); |
- if (cur->xpathCtxt == NULL) { |
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc, |
- "xsltNewTransformContext : xmlXPathNewContext failed\n"); |
- goto internal_err; |
- } |
- /* |
- * Create an XPath cache. |
- */ |
- if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1) |
- goto internal_err; |
- /* |
- * Initialize the extras array |
- */ |
- if (style->extrasNr != 0) { |
- cur->extrasMax = style->extrasNr + 20; |
- cur->extras = (xsltRuntimeExtraPtr) |
- xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra)); |
- if (cur->extras == NULL) { |
- xmlGenericError(xmlGenericErrorContext, |
- "xsltNewTransformContext: out of memory\n"); |
- goto internal_err; |
- } |
- cur->extrasNr = style->extrasNr; |
- for (i = 0;i < cur->extrasMax;i++) { |
- cur->extras[i].info = NULL; |
- cur->extras[i].deallocate = NULL; |
- cur->extras[i].val.ptr = NULL; |
- } |
- } else { |
- cur->extras = NULL; |
- cur->extrasNr = 0; |
- cur->extrasMax = 0; |
- } |
- |
- XSLT_REGISTER_VARIABLE_LOOKUP(cur); |
- XSLT_REGISTER_FUNCTION_LOOKUP(cur); |
- cur->xpathCtxt->nsHash = style->nsHash; |
- /* |
- * Initialize the registered external modules |
- */ |
- xsltInitCtxtExts(cur); |
- /* |
- * Setup document element ordering for later efficiencies |
- * (bug 133289) |
- */ |
- if (xslDebugStatus == XSLT_DEBUG_NONE) |
- xmlXPathOrderDocElems(doc); |
- /* |
- * Must set parserOptions before calling xsltNewDocument |
- * (bug 164530) |
- */ |
- cur->parserOptions = XSLT_PARSE_OPTIONS; |
- docu = xsltNewDocument(cur, doc); |
- if (docu == NULL) { |
- xsltTransformError(cur, NULL, (xmlNodePtr)doc, |
- "xsltNewTransformContext : xsltNewDocument failed\n"); |
- goto internal_err; |
- } |
- docu->main = 1; |
- cur->document = docu; |
- cur->inst = NULL; |
- cur->outputFile = NULL; |
- cur->sec = xsltGetDefaultSecurityPrefs(); |
- cur->debugStatus = xslDebugStatus; |
- cur->traceCode = (unsigned long*) &xsltDefaultTrace; |
- cur->xinclude = xsltGetXIncludeDefault(); |
- cur->keyInitLevel = 0; |
- |
- return(cur); |
- |
-internal_err: |
- if (cur != NULL) |
- xsltFreeTransformContext(cur); |
- return(NULL); |
-} |
- |
-/** |
- * xsltFreeTransformContext: |
- * @ctxt: an XSLT parser context |
- * |
- * Free up the memory allocated by @ctxt |
- */ |
-void |
-xsltFreeTransformContext(xsltTransformContextPtr ctxt) { |
- if (ctxt == NULL) |
- return; |
- |
- /* |
- * Shutdown the extension modules associated to the stylesheet |
- * used if needed. |
- */ |
- xsltShutdownCtxtExts(ctxt); |
- |
- if (ctxt->xpathCtxt != NULL) { |
- ctxt->xpathCtxt->nsHash = NULL; |
- xmlXPathFreeContext(ctxt->xpathCtxt); |
- } |
- if (ctxt->templTab != NULL) |
- xmlFree(ctxt->templTab); |
- if (ctxt->varsTab != NULL) |
- xmlFree(ctxt->varsTab); |
- if (ctxt->profTab != NULL) |
- xmlFree(ctxt->profTab); |
- if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) { |
- int i; |
- |
- for (i = 0;i < ctxt->extrasNr;i++) { |
- if ((ctxt->extras[i].deallocate != NULL) && |
- (ctxt->extras[i].info != NULL)) |
- ctxt->extras[i].deallocate(ctxt->extras[i].info); |
- } |
- xmlFree(ctxt->extras); |
- } |
- xsltFreeGlobalVariables(ctxt); |
- xsltFreeDocuments(ctxt); |
- xsltFreeCtxtExts(ctxt); |
- xsltFreeRVTs(ctxt); |
- xsltTransformCacheFree(ctxt->cache); |
- xmlDictFree(ctxt->dict); |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "freeing transformation dictionary\n"); |
-#endif |
- memset(ctxt, -1, sizeof(xsltTransformContext)); |
- xmlFree(ctxt); |
-} |
- |
-/************************************************************************ |
- * * |
- * Copy of Nodes in an XSLT fashion * |
- * * |
- ************************************************************************/ |
- |
-/** |
- * xsltAddChild: |
- * @parent: the parent node |
- * @cur: the child node |
- * |
- * Wrapper version of xmlAddChild with a more consistent behaviour on |
- * error. One expect the use to be child = xsltAddChild(parent, child); |
- * and the routine will take care of not leaking on errors or node merge |
- * |
- * Returns the child is successfully attached or NULL if merged or freed |
- */ |
-static xmlNodePtr |
-xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { |
- xmlNodePtr ret; |
- |
- if (cur == NULL) |
- return(NULL); |
- if (parent == NULL) { |
- xmlFreeNode(cur); |
- return(NULL); |
- } |
- ret = xmlAddChild(parent, cur); |
- |
- return(ret); |
-} |
- |
-/** |
- * xsltAddTextString: |
- * @ctxt: a XSLT process context |
- * @target: the text node where the text will be attached |
- * @string: the text string |
- * @len: the string length in byte |
- * |
- * Extend the current text node with the new string, it handles coalescing |
- * |
- * Returns: the text node |
- */ |
-static xmlNodePtr |
-xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, |
- const xmlChar *string, int len) { |
- /* |
- * optimization |
- */ |
- if ((len <= 0) || (string == NULL) || (target == NULL)) |
- return(target); |
- |
- if (ctxt->lasttext == target->content) { |
- int minSize; |
- |
- /* Check for integer overflow accounting for NUL terminator. */ |
- if (len >= INT_MAX - ctxt->lasttuse) { |
- xsltTransformError(ctxt, NULL, target, |
- "xsltCopyText: text allocation failed\n"); |
- return(NULL); |
- } |
- minSize = ctxt->lasttuse + len + 1; |
- |
- if (ctxt->lasttsize < minSize) { |
- xmlChar *newbuf; |
- int size; |
- int extra; |
- |
- /* Double buffer size but increase by at least 100 bytes. */ |
- extra = minSize < 100 ? 100 : minSize; |
- |
- /* Check for integer overflow. */ |
- if (extra > INT_MAX - ctxt->lasttsize) { |
- size = INT_MAX; |
- } |
- else { |
- size = ctxt->lasttsize + extra; |
- } |
- |
- newbuf = (xmlChar *) xmlRealloc(target->content,size); |
- if (newbuf == NULL) { |
- xsltTransformError(ctxt, NULL, target, |
- "xsltCopyText: text allocation failed\n"); |
- return(NULL); |
- } |
- ctxt->lasttsize = size; |
- ctxt->lasttext = newbuf; |
- target->content = newbuf; |
- } |
- memcpy(&(target->content[ctxt->lasttuse]), string, len); |
- ctxt->lasttuse += len; |
- target->content[ctxt->lasttuse] = 0; |
- } else { |
- xmlNodeAddContent(target, string); |
- ctxt->lasttext = target->content; |
- len = xmlStrlen(target->content); |
- ctxt->lasttsize = len; |
- ctxt->lasttuse = len; |
- } |
- return(target); |
-} |
- |
-/** |
- * xsltCopyTextString: |
- * @ctxt: a XSLT process context |
- * @target: the element where the text will be attached |
- * @string: the text string |
- * @noescape: should disable-escaping be activated for this text node. |
- * |
- * Adds @string to a newly created or an existent text node child of |
- * @target. |
- * |
- * Returns: the text node, where the text content of @cur is copied to. |
- * NULL in case of API or internal errors. |
- */ |
-xmlNodePtr |
-xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, |
- const xmlChar *string, int noescape) |
-{ |
- xmlNodePtr copy; |
- int len; |
- |
- if (string == NULL) |
- return(NULL); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyTextString: copy text %s\n", |
- string)); |
-#endif |
- |
- /* |
- * Play safe and reset the merging mechanism for every new |
- * target node. |
- */ |
- if ((target == NULL) || (target->children == NULL)) { |
- ctxt->lasttext = NULL; |
- } |
- |
- /* handle coalescing of text nodes here */ |
- len = xmlStrlen(string); |
- if ((ctxt->type == XSLT_OUTPUT_XML) && |
- (ctxt->style->cdataSection != NULL) && |
- (target != NULL) && |
- (target->type == XML_ELEMENT_NODE) && |
- (((target->ns == NULL) && |
- (xmlHashLookup2(ctxt->style->cdataSection, |
- target->name, NULL) != NULL)) || |
- ((target->ns != NULL) && |
- (xmlHashLookup2(ctxt->style->cdataSection, |
- target->name, target->ns->href) != NULL)))) |
- { |
- /* |
- * Process "cdata-section-elements". |
- */ |
- if ((target->last != NULL) && |
- (target->last->type == XML_CDATA_SECTION_NODE)) |
- { |
- return(xsltAddTextString(ctxt, target->last, string, len)); |
- } |
- copy = xmlNewCDataBlock(ctxt->output, string, len); |
- } else if (noescape) { |
- /* |
- * Process "disable-output-escaping". |
- */ |
- if ((target != NULL) && (target->last != NULL) && |
- (target->last->type == XML_TEXT_NODE) && |
- (target->last->name == xmlStringTextNoenc)) |
- { |
- return(xsltAddTextString(ctxt, target->last, string, len)); |
- } |
- copy = xmlNewTextLen(string, len); |
- if (copy != NULL) |
- copy->name = xmlStringTextNoenc; |
- } else { |
- /* |
- * Default processing. |
- */ |
- if ((target != NULL) && (target->last != NULL) && |
- (target->last->type == XML_TEXT_NODE) && |
- (target->last->name == xmlStringText)) { |
- return(xsltAddTextString(ctxt, target->last, string, len)); |
- } |
- copy = xmlNewTextLen(string, len); |
- } |
- if (copy != NULL && target != NULL) |
- copy = xsltAddChild(target, copy); |
- if (copy != NULL) { |
- ctxt->lasttext = copy->content; |
- ctxt->lasttsize = len; |
- ctxt->lasttuse = len; |
- } else { |
- xsltTransformError(ctxt, NULL, target, |
- "xsltCopyTextString: text copy failed\n"); |
- ctxt->lasttext = NULL; |
- } |
- return(copy); |
-} |
- |
-/** |
- * xsltCopyText: |
- * @ctxt: a XSLT process context |
- * @target: the element where the text will be attached |
- * @cur: the text or CDATA node |
- * @interned: the string is in the target doc dictionary |
- * |
- * Copy the text content of @cur and append it to @target's children. |
- * |
- * Returns: the text node, where the text content of @cur is copied to. |
- * NULL in case of API or internal errors. |
- */ |
-static xmlNodePtr |
-xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target, |
- xmlNodePtr cur, int interned) |
-{ |
- xmlNodePtr copy; |
- |
- if ((cur->type != XML_TEXT_NODE) && |
- (cur->type != XML_CDATA_SECTION_NODE)) |
- return(NULL); |
- if (cur->content == NULL) |
- return(NULL); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->type == XML_CDATA_SECTION_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyText: copy CDATA text %s\n", |
- cur->content)); |
- } else if (cur->name == xmlStringTextNoenc) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyText: copy unescaped text %s\n", |
- cur->content)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyText: copy text %s\n", |
- cur->content)); |
- } |
-#endif |
- |
- /* |
- * Play save and reset the merging mechanism for every new |
- * target node. |
- */ |
- if ((target == NULL) || (target->children == NULL)) { |
- ctxt->lasttext = NULL; |
- } |
- |
- if ((ctxt->style->cdataSection != NULL) && |
- (ctxt->type == XSLT_OUTPUT_XML) && |
- (target != NULL) && |
- (target->type == XML_ELEMENT_NODE) && |
- (((target->ns == NULL) && |
- (xmlHashLookup2(ctxt->style->cdataSection, |
- target->name, NULL) != NULL)) || |
- ((target->ns != NULL) && |
- (xmlHashLookup2(ctxt->style->cdataSection, |
- target->name, target->ns->href) != NULL)))) |
- { |
- /* |
- * Process "cdata-section-elements". |
- */ |
- /* |
- * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. |
- */ |
- /* |
- * TODO: Since this doesn't merge adjacent CDATA-section nodes, |
- * we'll get: <![CDATA[x]]><!CDATA[y]]>. |
- * TODO: Reported in #321505. |
- */ |
- if ((target->last != NULL) && |
- (target->last->type == XML_CDATA_SECTION_NODE)) |
- { |
- /* |
- * Append to existing CDATA-section node. |
- */ |
- copy = xsltAddTextString(ctxt, target->last, cur->content, |
- xmlStrlen(cur->content)); |
- goto exit; |
- } else { |
- unsigned int len; |
- |
- len = xmlStrlen(cur->content); |
- copy = xmlNewCDataBlock(ctxt->output, cur->content, len); |
- if (copy == NULL) |
- goto exit; |
- ctxt->lasttext = copy->content; |
- ctxt->lasttsize = len; |
- ctxt->lasttuse = len; |
- } |
- } else if ((target != NULL) && |
- (target->last != NULL) && |
- /* both escaped or both non-escaped text-nodes */ |
- (((target->last->type == XML_TEXT_NODE) && |
- (target->last->name == cur->name)) || |
- /* non-escaped text nodes and CDATA-section nodes */ |
- (((target->last->type == XML_CDATA_SECTION_NODE) && |
- (cur->name == xmlStringTextNoenc))))) |
- { |
- /* |
- * we are appending to an existing text node |
- */ |
- copy = xsltAddTextString(ctxt, target->last, cur->content, |
- xmlStrlen(cur->content)); |
- goto exit; |
- } else if ((interned) && (target != NULL) && |
- (target->doc != NULL) && |
- (target->doc->dict == ctxt->dict)) |
- { |
- /* |
- * TODO: DO we want to use this also for "text" output? |
- */ |
- copy = xmlNewTextLen(NULL, 0); |
- if (copy == NULL) |
- goto exit; |
- if (cur->name == xmlStringTextNoenc) |
- copy->name = xmlStringTextNoenc; |
- |
- /* |
- * Must confirm that content is in dict (bug 302821) |
- * TODO: This check should be not needed for text coming |
- * from the stylesheets |
- */ |
- if (xmlDictOwns(ctxt->dict, cur->content)) |
- copy->content = cur->content; |
- else { |
- if ((copy->content = xmlStrdup(cur->content)) == NULL) |
- return NULL; |
- } |
- } else { |
- /* |
- * normal processing. keep counters to extend the text node |
- * in xsltAddTextString if needed. |
- */ |
- unsigned int len; |
- |
- len = xmlStrlen(cur->content); |
- copy = xmlNewTextLen(cur->content, len); |
- if (copy == NULL) |
- goto exit; |
- if (cur->name == xmlStringTextNoenc) |
- copy->name = xmlStringTextNoenc; |
- ctxt->lasttext = copy->content; |
- ctxt->lasttsize = len; |
- ctxt->lasttuse = len; |
- } |
- if (copy != NULL) { |
- if (target != NULL) { |
- copy->doc = target->doc; |
- /* |
- * MAYBE TODO: Maybe we should reset the ctxt->lasttext here |
- * to ensure that the optimized text-merging mechanism |
- * won't interfere with normal node-merging in any case. |
- */ |
- copy = xsltAddChild(target, copy); |
- } |
- } else { |
- xsltTransformError(ctxt, NULL, target, |
- "xsltCopyText: text copy failed\n"); |
- } |
- |
-exit: |
- if ((copy == NULL) || (copy->content == NULL)) { |
- xsltTransformError(ctxt, NULL, target, |
- "Internal error in xsltCopyText(): " |
- "Failed to copy the string.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- } |
- return(copy); |
-} |
- |
-/** |
- * xsltShallowCopyAttr: |
- * @ctxt: a XSLT process context |
- * @invocNode: responsible node in the stylesheet; used for error reports |
- * @target: the element where the attribute will be grafted |
- * @attr: the attribute to be copied |
- * |
- * Do a copy of an attribute. |
- * Called by: |
- * - xsltCopyTree() |
- * - xsltCopyOf() |
- * - xsltCopy() |
- * |
- * Returns: a new xmlAttrPtr, or NULL in case of error. |
- */ |
-static xmlAttrPtr |
-xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, |
- xmlNodePtr target, xmlAttrPtr attr) |
-{ |
- xmlAttrPtr copy; |
- xmlChar *value; |
- |
- if (attr == NULL) |
- return(NULL); |
- |
- if (target->type != XML_ELEMENT_NODE) { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "Cannot add an attribute node to a non-element node.\n"); |
- return(NULL); |
- } |
- |
- if (target->children != NULL) { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "Attribute nodes must be added before " |
- "any child nodes to an element.\n"); |
- return(NULL); |
- } |
- |
- value = xmlNodeListGetString(attr->doc, attr->children, 1); |
- if (attr->ns != NULL) { |
- xmlNsPtr ns; |
- |
- ns = xsltGetSpecialNamespace(ctxt, invocNode, |
- attr->ns->href, attr->ns->prefix, target); |
- if (ns == NULL) { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "Namespace fixup error: Failed to acquire an in-scope " |
- "namespace binding of the copied attribute '{%s}%s'.\n", |
- attr->ns->href, attr->name); |
- /* |
- * TODO: Should we just stop here? |
- */ |
- } |
- /* |
- * Note that xmlSetNsProp() will take care of duplicates |
- * and assigns the new namespace even to a duplicate. |
- */ |
- copy = xmlSetNsProp(target, ns, attr->name, value); |
- } else { |
- copy = xmlSetNsProp(target, NULL, attr->name, value); |
- } |
- if (value != NULL) |
- xmlFree(value); |
- |
- if (copy == NULL) |
- return(NULL); |
- |
-#if 0 |
- /* |
- * NOTE: This was optimized according to bug #342695. |
- * TODO: Can this further be optimized, if source and target |
- * share the same dict and attr->children is just 1 text node |
- * which is in the dict? How probable is such a case? |
- */ |
- /* |
- * TODO: Do we need to create an empty text node if the value |
- * is the empty string? |
- */ |
- value = xmlNodeListGetString(attr->doc, attr->children, 1); |
- if (value != NULL) { |
- txtNode = xmlNewDocText(target->doc, NULL); |
- if (txtNode == NULL) |
- return(NULL); |
- if ((target->doc != NULL) && |
- (target->doc->dict != NULL)) |
- { |
- txtNode->content = |
- (xmlChar *) xmlDictLookup(target->doc->dict, |
- BAD_CAST value, -1); |
- xmlFree(value); |
- } else |
- txtNode->content = value; |
- copy->children = txtNode; |
- } |
-#endif |
- |
- return(copy); |
-} |
- |
-/** |
- * xsltCopyAttrListNoOverwrite: |
- * @ctxt: a XSLT process context |
- * @invocNode: responsible node in the stylesheet; used for error reports |
- * @target: the element where the new attributes will be grafted |
- * @attr: the first attribute in the list to be copied |
- * |
- * Copies a list of attribute nodes, starting with @attr, over to the |
- * @target element node. |
- * |
- * Called by: |
- * - xsltCopyTree() |
- * |
- * Returns 0 on success and -1 on errors and internal errors. |
- */ |
-static int |
-xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt, |
- xmlNodePtr invocNode, |
- xmlNodePtr target, xmlAttrPtr attr) |
-{ |
- xmlAttrPtr copy; |
- xmlNsPtr origNs = NULL, copyNs = NULL; |
- xmlChar *value; |
- |
- /* |
- * Don't use xmlCopyProp() here, since it will try to |
- * reconciliate namespaces. |
- */ |
- while (attr != NULL) { |
- /* |
- * Find a namespace node in the tree of @target. |
- * Avoid searching for the same ns. |
- */ |
- if (attr->ns != origNs) { |
- origNs = attr->ns; |
- if (attr->ns != NULL) { |
- copyNs = xsltGetSpecialNamespace(ctxt, invocNode, |
- attr->ns->href, attr->ns->prefix, target); |
- if (copyNs == NULL) |
- return(-1); |
- } else |
- copyNs = NULL; |
- } |
- /* |
- * If attribute has a value, we need to copy it (watching out |
- * for possible entities) |
- */ |
- if ((attr->children) && (attr->children->type == XML_TEXT_NODE) && |
- (attr->children->next == NULL)) { |
- copy = xmlNewNsProp(target, copyNs, attr->name, |
- attr->children->content); |
- } else if (attr->children != NULL) { |
- value = xmlNodeListGetString(attr->doc, attr->children, 1); |
- copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value); |
- xmlFree(value); |
- } else { |
- copy = xmlNewNsProp(target, copyNs, attr->name, NULL); |
- } |
- |
- if (copy == NULL) |
- return(-1); |
- |
- attr = attr->next; |
- } |
- return(0); |
-} |
- |
-/** |
- * xsltShallowCopyElem: |
- * @ctxt: the XSLT process context |
- * @node: the element node in the source tree |
- * or the Literal Result Element |
- * @insert: the parent in the result tree |
- * @isLRE: if @node is a Literal Result Element |
- * |
- * Make a copy of the element node @node |
- * and insert it as last child of @insert. |
- * |
- * URGENT TODO: The problem with this one (for the non-refactored code) |
- * is that it is used for both, Literal Result Elements *and* |
- * copying input nodes. |
- * |
- * BIG NOTE: This is only called for XML_ELEMENT_NODEs. |
- * |
- * Called from: |
- * xsltApplySequenceConstructor() |
- * (for Literal Result Elements - which is a problem) |
- * xsltCopy() (for shallow-copying elements via xsl:copy) |
- * |
- * Returns a pointer to the new node, or NULL in case of error |
- */ |
-static xmlNodePtr |
-xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr insert, int isLRE) |
-{ |
- xmlNodePtr copy; |
- |
- if ((node->type == XML_DTD_NODE) || (insert == NULL)) |
- return(NULL); |
- if ((node->type == XML_TEXT_NODE) || |
- (node->type == XML_CDATA_SECTION_NODE)) |
- return(xsltCopyText(ctxt, insert, node, 0)); |
- |
- copy = xmlDocCopyNode(node, insert->doc, 0); |
- if (copy != NULL) { |
- copy->doc = ctxt->output; |
- copy = xsltAddChild(insert, copy); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltShallowCopyElem: copy failed\n"); |
- return (copy); |
- } |
- |
- if (node->type == XML_ELEMENT_NODE) { |
- /* |
- * Add namespaces as they are needed |
- */ |
- if (node->nsDef != NULL) { |
- /* |
- * TODO: Remove the LRE case in the refactored code |
- * gets enabled. |
- */ |
- if (isLRE) |
- xsltCopyNamespaceList(ctxt, copy, node->nsDef); |
- else |
- xsltCopyNamespaceListInternal(copy, node->nsDef); |
- } |
- |
- /* |
- * URGENT TODO: The problem with this is that it does not |
- * copy over all namespace nodes in scope. |
- * The damn thing about this is, that we would need to |
- * use the xmlGetNsList(), for every single node; this is |
- * also done in xsltCopyTree(), but only for the top node. |
- */ |
- if (node->ns != NULL) { |
- if (isLRE) { |
- /* |
- * REVISIT TODO: Since the non-refactored code still does |
- * ns-aliasing, we need to call xsltGetNamespace() here. |
- * Remove this when ready. |
- */ |
- copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy); |
- } else { |
- copy->ns = xsltGetSpecialNamespace(ctxt, |
- node, node->ns->href, node->ns->prefix, copy); |
- |
- } |
- } else if ((insert->type == XML_ELEMENT_NODE) && |
- (insert->ns != NULL)) |
- { |
- /* |
- * "Undeclare" the default namespace. |
- */ |
- xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy); |
- } |
- } |
- } else { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltShallowCopyElem: copy %s failed\n", node->name); |
- } |
- return(copy); |
-} |
- |
-/** |
- * xsltCopyTreeList: |
- * @ctxt: a XSLT process context |
- * @invocNode: responsible node in the stylesheet; used for error reports |
- * @list: the list of element nodes in the source tree. |
- * @insert: the parent in the result tree. |
- * @isLRE: is this a literal result element list |
- * @topElemVisited: indicates if a top-most element was already processed |
- * |
- * Make a copy of the full list of tree @list |
- * and insert it as last children of @insert |
- * |
- * NOTE: Not to be used for Literal Result Elements. |
- * |
- * Used by: |
- * - xsltCopyOf() |
- * |
- * Returns a pointer to the new list, or NULL in case of error |
- */ |
-static xmlNodePtr |
-xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, |
- xmlNodePtr list, |
- xmlNodePtr insert, int isLRE, int topElemVisited) |
-{ |
- xmlNodePtr copy, ret = NULL; |
- |
- while (list != NULL) { |
- copy = xsltCopyTree(ctxt, invocNode, |
- list, insert, isLRE, topElemVisited); |
- if (copy != NULL) { |
- if (ret == NULL) { |
- ret = copy; |
- } |
- } |
- list = list->next; |
- } |
- return(ret); |
-} |
- |
-/** |
- * xsltCopyNamespaceListInternal: |
- * @node: the target node |
- * @cur: the first namespace |
- * |
- * Do a copy of a namespace list. If @node is non-NULL the |
- * new namespaces are added automatically. |
- * Called by: |
- * xsltCopyTree() |
- * |
- * QUESTION: What is the exact difference between this function |
- * and xsltCopyNamespaceList() in "namespaces.c"? |
- * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases. |
- * |
- * Returns: a new xmlNsPtr, or NULL in case of error. |
- */ |
-static xmlNsPtr |
-xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) { |
- xmlNsPtr ret = NULL; |
- xmlNsPtr p = NULL, q, luNs; |
- |
- if (ns == NULL) |
- return(NULL); |
- /* |
- * One can add namespaces only on element nodes |
- */ |
- if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) |
- elem = NULL; |
- |
- do { |
- if (ns->type != XML_NAMESPACE_DECL) |
- break; |
- /* |
- * Avoid duplicating namespace declarations on the tree. |
- */ |
- if (elem != NULL) { |
- if ((elem->ns != NULL) && |
- xmlStrEqual(elem->ns->prefix, ns->prefix) && |
- xmlStrEqual(elem->ns->href, ns->href)) |
- { |
- ns = ns->next; |
- continue; |
- } |
- luNs = xmlSearchNs(elem->doc, elem, ns->prefix); |
- if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href))) |
- { |
- ns = ns->next; |
- continue; |
- } |
- } |
- q = xmlNewNs(elem, ns->href, ns->prefix); |
- if (p == NULL) { |
- ret = p = q; |
- } else if (q != NULL) { |
- p->next = q; |
- p = q; |
- } |
- ns = ns->next; |
- } while (ns != NULL); |
- return(ret); |
-} |
- |
-/** |
- * xsltShallowCopyNsNode: |
- * @ctxt: the XSLT transformation context |
- * @invocNode: responsible node in the stylesheet; used for error reports |
- * @insert: the target element node in the result tree |
- * @ns: the namespace node |
- * |
- * This is used for copying ns-nodes with xsl:copy-of and xsl:copy. |
- * |
- * Returns a new/existing ns-node, or NULL. |
- */ |
-static xmlNsPtr |
-xsltShallowCopyNsNode(xsltTransformContextPtr ctxt, |
- xmlNodePtr invocNode, |
- xmlNodePtr insert, |
- xmlNsPtr ns) |
-{ |
- /* |
- * TODO: Contrary to header comments, this is declared as int. |
- * be modified to return a node pointer, or NULL if any error |
- */ |
- xmlNsPtr tmpns; |
- |
- if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE)) |
- return(NULL); |
- |
- if (insert->children != NULL) { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "Namespace nodes must be added before " |
- "any child nodes are added to an element.\n"); |
- return(NULL); |
- } |
- /* |
- * BIG NOTE: Xalan-J simply overwrites any ns-decls with |
- * an equal prefix. We definitively won't do that. |
- * |
- * MSXML 4.0 and the .NET ignores ns-decls for which an |
- * equal prefix is already in use. |
- * |
- * Saxon raises an error like: |
- * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace |
- * nodes with the same name". |
- * |
- * NOTE: We'll currently follow MSXML here. |
- * REVISIT TODO: Check if it's better to follow Saxon here. |
- */ |
- if (ns->prefix == NULL) { |
- /* |
- * If we are adding ns-nodes to an element using e.g. |
- * <xsl:copy-of select="/foo/namespace::*">, then we need |
- * to ensure that we don't incorrectly declare a default |
- * namespace on an element in no namespace, which otherwise |
- * would move the element incorrectly into a namespace, if |
- * the node tree is serialized. |
- */ |
- if (insert->ns == NULL) |
- goto occupied; |
- } else if ((ns->prefix[0] == 'x') && |
- xmlStrEqual(ns->prefix, BAD_CAST "xml")) |
- { |
- /* |
- * The XML namespace is built in. |
- */ |
- return(NULL); |
- } |
- |
- if (insert->nsDef != NULL) { |
- tmpns = insert->nsDef; |
- do { |
- if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { |
- if ((tmpns->prefix == ns->prefix) || |
- xmlStrEqual(tmpns->prefix, ns->prefix)) |
- { |
- /* |
- * Same prefix. |
- */ |
- if (xmlStrEqual(tmpns->href, ns->href)) |
- return(NULL); |
- goto occupied; |
- } |
- } |
- tmpns = tmpns->next; |
- } while (tmpns != NULL); |
- } |
- tmpns = xmlSearchNs(insert->doc, insert, ns->prefix); |
- if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href)) |
- return(NULL); |
- /* |
- * Declare a new namespace. |
- * TODO: The problem (wrt efficiency) with this xmlNewNs() is |
- * that it will again search the already declared namespaces |
- * for a duplicate :-/ |
- */ |
- return(xmlNewNs(insert, ns->href, ns->prefix)); |
- |
-occupied: |
- /* |
- * TODO: We could as well raise an error here (like Saxon does), |
- * or at least generate a warning. |
- */ |
- return(NULL); |
-} |
- |
-/** |
- * xsltCopyTree: |
- * @ctxt: the XSLT transformation context |
- * @invocNode: responsible node in the stylesheet; used for error reports |
- * @node: the element node in the source tree |
- * @insert: the parent in the result tree |
- * @isLRE: indicates if @node is a Literal Result Element |
- * @topElemVisited: indicates if a top-most element was already processed |
- * |
- * Make a copy of the full tree under the element node @node |
- * and insert it as last child of @insert |
- * |
- * NOTE: Not to be used for Literal Result Elements. |
- * |
- * Used by: |
- * - xsltCopyOf() |
- * |
- * Returns a pointer to the new tree, or NULL in case of error |
- */ |
-static xmlNodePtr |
-xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, |
- xmlNodePtr node, xmlNodePtr insert, int isLRE, |
- int topElemVisited) |
-{ |
- xmlNodePtr copy; |
- |
- if (node == NULL) |
- return(NULL); |
- switch (node->type) { |
- case XML_ELEMENT_NODE: |
- case XML_ENTITY_REF_NODE: |
- case XML_ENTITY_NODE: |
- case XML_PI_NODE: |
- case XML_COMMENT_NODE: |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
-#ifdef LIBXML_DOCB_ENABLED |
- case XML_DOCB_DOCUMENT_NODE: |
-#endif |
- break; |
- case XML_TEXT_NODE: { |
- int noenc = (node->name == xmlStringTextNoenc); |
- return(xsltCopyTextString(ctxt, insert, node->content, noenc)); |
- } |
- case XML_CDATA_SECTION_NODE: |
- return(xsltCopyTextString(ctxt, insert, node->content, 0)); |
- case XML_ATTRIBUTE_NODE: |
- return((xmlNodePtr) |
- xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)); |
- case XML_NAMESPACE_DECL: |
- return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode, |
- insert, (xmlNsPtr) node)); |
- |
- case XML_DOCUMENT_TYPE_NODE: |
- case XML_DOCUMENT_FRAG_NODE: |
- case XML_NOTATION_NODE: |
- case XML_DTD_NODE: |
- case XML_ELEMENT_DECL: |
- case XML_ATTRIBUTE_DECL: |
- case XML_ENTITY_DECL: |
- case XML_XINCLUDE_START: |
- case XML_XINCLUDE_END: |
- return(NULL); |
- } |
- if (XSLT_IS_RES_TREE_FRAG(node)) { |
- if (node->children != NULL) |
- copy = xsltCopyTreeList(ctxt, invocNode, |
- node->children, insert, 0, 0); |
- else |
- copy = NULL; |
- return(copy); |
- } |
- copy = xmlDocCopyNode(node, insert->doc, 0); |
- if (copy != NULL) { |
- copy->doc = ctxt->output; |
- copy = xsltAddChild(insert, copy); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "xsltCopyTree: Copying of '%s' failed.\n", node->name); |
- return (copy); |
- } |
- /* |
- * The node may have been coalesced into another text node. |
- */ |
- if (insert->last != copy) |
- return(insert->last); |
- copy->next = NULL; |
- |
- if (node->type == XML_ELEMENT_NODE) { |
- /* |
- * Copy in-scope namespace nodes. |
- * |
- * REVISIT: Since we try to reuse existing in-scope ns-decls by |
- * using xmlSearchNsByHref(), this will eventually change |
- * the prefix of an original ns-binding; thus it might |
- * break QNames in element/attribute content. |
- * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation |
- * context, plus a ns-lookup function, which writes directly |
- * to a given list, then we wouldn't need to create/free the |
- * nsList every time. |
- */ |
- if ((topElemVisited == 0) && |
- (node->parent != NULL) && |
- (node->parent->type != XML_DOCUMENT_NODE) && |
- (node->parent->type != XML_HTML_DOCUMENT_NODE)) |
- { |
- xmlNsPtr *nsList, *curns, ns; |
- |
- /* |
- * If this is a top-most element in a tree to be |
- * copied, then we need to ensure that all in-scope |
- * namespaces are copied over. For nodes deeper in the |
- * tree, it is sufficient to reconcile only the ns-decls |
- * (node->nsDef entries). |
- */ |
- |
- nsList = xmlGetNsList(node->doc, node); |
- if (nsList != NULL) { |
- curns = nsList; |
- do { |
- /* |
- * Search by prefix first in order to break as less |
- * QNames in element/attribute content as possible. |
- */ |
- ns = xmlSearchNs(insert->doc, insert, |
- (*curns)->prefix); |
- |
- if ((ns == NULL) || |
- (! xmlStrEqual(ns->href, (*curns)->href))) |
- { |
- ns = NULL; |
- /* |
- * Search by namespace name. |
- * REVISIT TODO: Currently disabled. |
- */ |
-#if 0 |
- ns = xmlSearchNsByHref(insert->doc, |
- insert, (*curns)->href); |
-#endif |
- } |
- if (ns == NULL) { |
- /* |
- * Declare a new namespace on the copied element. |
- */ |
- ns = xmlNewNs(copy, (*curns)->href, |
- (*curns)->prefix); |
- /* TODO: Handle errors */ |
- } |
- if (node->ns == *curns) { |
- /* |
- * If this was the original's namespace then set |
- * the generated counterpart on the copy. |
- */ |
- copy->ns = ns; |
- } |
- curns++; |
- } while (*curns != NULL); |
- xmlFree(nsList); |
- } |
- } else if (node->nsDef != NULL) { |
- /* |
- * Copy over all namespace declaration attributes. |
- */ |
- if (node->nsDef != NULL) { |
- if (isLRE) |
- xsltCopyNamespaceList(ctxt, copy, node->nsDef); |
- else |
- xsltCopyNamespaceListInternal(copy, node->nsDef); |
- } |
- } |
- /* |
- * Set the namespace. |
- */ |
- if (node->ns != NULL) { |
- if (copy->ns == NULL) { |
- /* |
- * This will map copy->ns to one of the newly created |
- * in-scope ns-decls, OR create a new ns-decl on @copy. |
- */ |
- copy->ns = xsltGetSpecialNamespace(ctxt, invocNode, |
- node->ns->href, node->ns->prefix, copy); |
- } |
- } else if ((insert->type == XML_ELEMENT_NODE) && |
- (insert->ns != NULL)) |
- { |
- /* |
- * "Undeclare" the default namespace on @copy with xmlns="". |
- */ |
- xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy); |
- } |
- /* |
- * Copy attribute nodes. |
- */ |
- if (node->properties != NULL) { |
- xsltCopyAttrListNoOverwrite(ctxt, invocNode, |
- copy, node->properties); |
- } |
- if (topElemVisited == 0) |
- topElemVisited = 1; |
- } |
- /* |
- * Copy the subtree. |
- */ |
- if (node->children != NULL) { |
- xsltCopyTreeList(ctxt, invocNode, |
- node->children, copy, isLRE, topElemVisited); |
- } |
- } else { |
- xsltTransformError(ctxt, NULL, invocNode, |
- "xsltCopyTree: Copying of '%s' failed.\n", node->name); |
- } |
- return(copy); |
-} |
- |
-/************************************************************************ |
- * * |
- * Error/fallback processing * |
- * * |
- ************************************************************************/ |
- |
-/** |
- * xsltApplyFallbacks: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the node generating the error |
- * |
- * Process possible xsl:fallback nodes present under @inst |
- * |
- * Returns the number of xsl:fallback element found and processed |
- */ |
-static int |
-xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst) { |
- |
- xmlNodePtr child; |
- int ret = 0; |
- |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || |
- (inst->children == NULL)) |
- return(0); |
- |
- child = inst->children; |
- while (child != NULL) { |
- if ((IS_XSLT_ELEM(child)) && |
- (xmlStrEqual(child->name, BAD_CAST "fallback"))) { |
-#ifdef WITH_XSLT_DEBUG_PARSING |
- xsltGenericDebug(xsltGenericDebugContext, |
- "applying xsl:fallback\n"); |
-#endif |
- ret++; |
- xsltApplySequenceConstructor(ctxt, node, child->children, |
- NULL); |
- } |
- child = child->next; |
- } |
- return(ret); |
-} |
- |
-/************************************************************************ |
- * * |
- * Default processing * |
- * * |
- ************************************************************************/ |
- |
-/** |
- * xsltDefaultProcessOneNode: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @params: extra parameters passed to the template if any |
- * |
- * Process the source node with the default built-in template rule: |
- * <xsl:template match="*|/"> |
- * <xsl:apply-templates/> |
- * </xsl:template> |
- * |
- * and |
- * |
- * <xsl:template match="text()|@*"> |
- * <xsl:value-of select="."/> |
- * </xsl:template> |
- * |
- * Note also that namespace declarations are copied directly: |
- * |
- * the built-in template rule is the only template rule that is applied |
- * for namespace nodes. |
- */ |
-static void |
-xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xsltStackElemPtr params) { |
- xmlNodePtr copy; |
- xmlNodePtr delete = NULL, cur; |
- int nbchild = 0, oldSize; |
- int childno = 0, oldPos; |
- xsltTemplatePtr template; |
- |
- CHECK_STOPPED; |
- /* |
- * Handling of leaves |
- */ |
- switch (node->type) { |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- case XML_ELEMENT_NODE: |
- break; |
- case XML_CDATA_SECTION_NODE: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy CDATA %s\n", |
- node->content)); |
-#endif |
- copy = xsltCopyText(ctxt, ctxt->insert, node, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltDefaultProcessOneNode: cdata copy failed\n"); |
- } |
- return; |
- case XML_TEXT_NODE: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (node->content == NULL) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy empty text\n")); |
- return; |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy text %s\n", |
- node->content)); |
- } |
-#endif |
- copy = xsltCopyText(ctxt, ctxt->insert, node, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltDefaultProcessOneNode: text copy failed\n"); |
- } |
- return; |
- case XML_ATTRIBUTE_NODE: |
- cur = node->children; |
- while ((cur != NULL) && (cur->type != XML_TEXT_NODE)) |
- cur = cur->next; |
- if (cur == NULL) { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltDefaultProcessOneNode: no text for attribute\n"); |
- } else { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->content == NULL) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy empty text\n")); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy text %s\n", |
- cur->content)); |
- } |
-#endif |
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, node, |
- "xsltDefaultProcessOneNode: text copy failed\n"); |
- } |
- } |
- return; |
- default: |
- return; |
- } |
- /* |
- * Handling of Elements: first pass, cleanup and counting |
- */ |
- cur = node->children; |
- while (cur != NULL) { |
- switch (cur->type) { |
- case XML_TEXT_NODE: |
- case XML_CDATA_SECTION_NODE: |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- case XML_ELEMENT_NODE: |
- case XML_PI_NODE: |
- case XML_COMMENT_NODE: |
- nbchild++; |
- break; |
- case XML_DTD_NODE: |
- /* Unlink the DTD, it's still reachable using doc->intSubset */ |
- if (cur->next != NULL) |
- cur->next->prev = cur->prev; |
- if (cur->prev != NULL) |
- cur->prev->next = cur->next; |
- break; |
- default: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: skipping node type %d\n", |
- cur->type)); |
-#endif |
- delete = cur; |
- } |
- cur = cur->next; |
- if (delete != NULL) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); |
-#endif |
- xmlUnlinkNode(delete); |
- xmlFreeNode(delete); |
- delete = NULL; |
- } |
- } |
- if (delete != NULL) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); |
-#endif |
- xmlUnlinkNode(delete); |
- xmlFreeNode(delete); |
- delete = NULL; |
- } |
- |
- /* |
- * Handling of Elements: second pass, actual processing |
- * |
- * Note that params are passed to the next template. This matches |
- * XSLT 2.0 behavior but doesn't conform to XSLT 1.0. |
- */ |
- oldSize = ctxt->xpathCtxt->contextSize; |
- oldPos = ctxt->xpathCtxt->proximityPosition; |
- cur = node->children; |
- while (cur != NULL) { |
- childno++; |
- switch (cur->type) { |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- case XML_ELEMENT_NODE: |
- ctxt->xpathCtxt->contextSize = nbchild; |
- ctxt->xpathCtxt->proximityPosition = childno; |
- xsltProcessOneNode(ctxt, cur, params); |
- break; |
- case XML_CDATA_SECTION_NODE: |
- template = xsltGetTemplate(ctxt, cur, NULL); |
- if (template) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: applying template for CDATA %s\n", |
- cur->content)); |
-#endif |
- /* |
- * Instantiate the xsl:template. |
- */ |
- xsltApplyXSLTTemplate(ctxt, cur, template->content, |
- template, params); |
- } else /* if (ctxt->mode == NULL) */ { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy CDATA %s\n", |
- cur->content)); |
-#endif |
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, cur, |
- "xsltDefaultProcessOneNode: cdata copy failed\n"); |
- } |
- } |
- break; |
- case XML_TEXT_NODE: |
- template = xsltGetTemplate(ctxt, cur, NULL); |
- if (template) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: applying template for text %s\n", |
- cur->content)); |
-#endif |
- ctxt->xpathCtxt->contextSize = nbchild; |
- ctxt->xpathCtxt->proximityPosition = childno; |
- /* |
- * Instantiate the xsl:template. |
- */ |
- xsltApplyXSLTTemplate(ctxt, cur, template->content, |
- template, params); |
- } else /* if (ctxt->mode == NULL) */ { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->content == NULL) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy empty text\n")); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: copy text %s\n", |
- cur->content)); |
- } |
-#endif |
- copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, cur, |
- "xsltDefaultProcessOneNode: text copy failed\n"); |
- } |
- } |
- break; |
- case XML_PI_NODE: |
- case XML_COMMENT_NODE: |
- template = xsltGetTemplate(ctxt, cur, NULL); |
- if (template) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->type == XML_PI_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: template found for PI %s\n", |
- cur->name)); |
- } else if (cur->type == XML_COMMENT_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltDefaultProcessOneNode: template found for comment\n")); |
- } |
-#endif |
- ctxt->xpathCtxt->contextSize = nbchild; |
- ctxt->xpathCtxt->proximityPosition = childno; |
- /* |
- * Instantiate the xsl:template. |
- */ |
- xsltApplyXSLTTemplate(ctxt, cur, template->content, |
- template, params); |
- } |
- break; |
- default: |
- break; |
- } |
- cur = cur->next; |
- } |
- ctxt->xpathCtxt->contextSize = oldSize; |
- ctxt->xpathCtxt->proximityPosition = oldPos; |
-} |
- |
-/** |
- * xsltProcessOneNode: |
- * @ctxt: a XSLT process context |
- * @contextNode: the "current node" in the source tree |
- * @withParams: extra parameters (e.g. xsl:with-param) passed to the |
- * template if any |
- * |
- * Process the source node. |
- */ |
-void |
-xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, |
- xsltStackElemPtr withParams) |
-{ |
- xsltTemplatePtr templ; |
- xmlNodePtr oldNode; |
- |
- templ = xsltGetTemplate(ctxt, contextNode, NULL); |
- /* |
- * If no template is found, apply the default rule. |
- */ |
- if (templ == NULL) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (contextNode->type == XML_DOCUMENT_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: no template found for /\n")); |
- } else if (contextNode->type == XML_CDATA_SECTION_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: no template found for CDATA\n")); |
- } else if (contextNode->type == XML_ATTRIBUTE_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: no template found for attribute %s\n", |
- ((xmlAttrPtr) contextNode)->name)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: no template found for %s\n", contextNode->name)); |
- } |
-#endif |
- oldNode = ctxt->node; |
- ctxt->node = contextNode; |
- xsltDefaultProcessOneNode(ctxt, contextNode, withParams); |
- ctxt->node = oldNode; |
- return; |
- } |
- |
- if (contextNode->type == XML_ATTRIBUTE_NODE) { |
- xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; |
- /* |
- * Set the "current template rule". |
- */ |
- ctxt->currentTemplateRule = templ; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: applying template '%s' for attribute %s\n", |
- templ->match, contextNode->name)); |
-#endif |
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); |
- |
- ctxt->currentTemplateRule = oldCurTempRule; |
- } else { |
- xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; |
- /* |
- * Set the "current template rule". |
- */ |
- ctxt->currentTemplateRule = templ; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (contextNode->type == XML_DOCUMENT_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: applying template '%s' for /\n", |
- templ->match)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessOneNode: applying template '%s' for %s\n", |
- templ->match, contextNode->name)); |
- } |
-#endif |
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); |
- |
- ctxt->currentTemplateRule = oldCurTempRule; |
- } |
-} |
- |
-static xmlNodePtr |
-xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, |
- xmlNodePtr list, |
- xsltTemplatePtr templ, |
- int *addCallResult) |
-{ |
- xmlNodePtr debugedNode = NULL; |
- |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) { |
- if (templ) { |
- *addCallResult = xslAddCall(templ, templ->elem); |
- } else { |
- *addCallResult = xslAddCall(NULL, list); |
- } |
- switch (ctxt->debugStatus) { |
- case XSLT_DEBUG_RUN_RESTART: |
- case XSLT_DEBUG_QUIT: |
- if (*addCallResult) |
- xslDropCall(); |
- return(NULL); |
- } |
- if (templ) { |
- xslHandleDebugger(templ->elem, contextNode, templ, ctxt); |
- debugedNode = templ->elem; |
- } else if (list) { |
- xslHandleDebugger(list, contextNode, templ, ctxt); |
- debugedNode = list; |
- } else if (ctxt->inst) { |
- xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt); |
- debugedNode = ctxt->inst; |
- } |
- } |
- return(debugedNode); |
-} |
- |
-/** |
- * xsltLocalVariablePush: |
- * @ctxt: the transformation context |
- * @variable: variable to be pushed to the variable stack |
- * @level: new value for variable's level |
- * |
- * Places the variable onto the local variable stack |
- * |
- * Returns: 0 for success, -1 for any error |
- * **NOTE:** |
- * This is an internal routine and should not be called by users! |
- */ |
-int |
-xsltLocalVariablePush(xsltTransformContextPtr ctxt, |
- xsltStackElemPtr variable, |
- int level) |
-{ |
- if (ctxt->varsMax == 0) { |
- ctxt->varsMax = 10; |
- ctxt->varsTab = |
- (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * |
- sizeof(ctxt->varsTab[0])); |
- if (ctxt->varsTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); |
- return (-1); |
- } |
- } |
- if (ctxt->varsNr >= ctxt->varsMax) { |
- ctxt->varsMax *= 2; |
- ctxt->varsTab = |
- (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, |
- ctxt->varsMax * |
- sizeof(ctxt->varsTab[0])); |
- if (ctxt->varsTab == NULL) { |
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); |
- return (-1); |
- } |
- } |
- ctxt->varsTab[ctxt->varsNr++] = variable; |
- ctxt->vars = variable; |
- variable->level = level; |
- return(0); |
-} |
- |
-/** |
- * xsltReleaseLocalRVTs: |
- * |
- * Fragments which are results of extension instructions |
- * are preserved; all other fragments are freed/cached. |
- */ |
-static void |
-xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) |
-{ |
- xmlDocPtr cur = ctxt->localRVT, tmp; |
- |
- if (cur == base) |
- return; |
- if (cur->prev != NULL) |
- xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n"); |
- |
- do { |
- tmp = cur; |
- cur = (xmlDocPtr) cur->next; |
- if (tmp->psvi == XSLT_RVT_LOCAL) { |
- xsltReleaseRVT(ctxt, tmp); |
- } else if (tmp->psvi == XSLT_RVT_GLOBAL) { |
- xsltRegisterPersistRVT(ctxt, tmp); |
- } else if (tmp->psvi != XSLT_RVT_FUNC_RESULT) { |
- xmlGenericError(xmlGenericErrorContext, |
- "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", |
- tmp->psvi); |
- } |
- } while (cur != base); |
- |
- if (base != NULL) |
- base->prev = NULL; |
- ctxt->localRVT = base; |
-} |
- |
-/** |
- * xsltApplySequenceConstructor: |
- * @ctxt: a XSLT process context |
- * @contextNode: the "current node" in the source tree |
- * @list: the nodes of a sequence constructor; |
- * (plus leading xsl:param elements) |
- * @templ: the compiled xsl:template (optional) |
- * |
- * Processes a sequence constructor. |
- * |
- * NOTE: ctxt->currentTemplateRule was introduced to reflect the |
- * semantics of "current template rule". I.e. the field ctxt->templ |
- * is not intended to reflect this, thus always pushed onto the |
- * template stack. |
- */ |
-static void |
-xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, xmlNodePtr list, |
- xsltTemplatePtr templ) |
-{ |
- xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; |
- xmlNodePtr cur, insert, copy = NULL; |
- int level = 0, oldVarsNr; |
- xmlDocPtr oldLocalFragmentTop; |
- |
-#ifdef XSLT_REFACTORED |
- xsltStylePreCompPtr info; |
-#endif |
- |
-#ifdef WITH_DEBUGGER |
- int addCallResult = 0; |
- xmlNodePtr debuggedNode = NULL; |
-#endif |
- |
- if (ctxt == NULL) |
- return; |
- |
-#ifdef WITH_DEBUGGER |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) { |
- debuggedNode = |
- xsltDebuggerStartSequenceConstructor(ctxt, contextNode, |
- list, templ, &addCallResult); |
- if (debuggedNode == NULL) |
- return; |
- } |
-#endif |
- |
- if (list == NULL) |
- return; |
- CHECK_STOPPED; |
- |
- /* |
- * Check for infinite recursion: stop if the maximum of nested templates |
- * is excceeded. Adjust xsltMaxDepth if you need more. |
- */ |
- if (ctxt->depth >= ctxt->maxTemplateDepth) { |
- xsltTransformError(ctxt, NULL, list, |
- "xsltApplySequenceConstructor: A potential infinite template " |
- "recursion was detected.\n" |
- "You can adjust xsltMaxDepth (--maxdepth) in order to " |
- "raise the maximum number of nested template calls and " |
- "variables/params (currently set to %d).\n", |
- ctxt->maxTemplateDepth); |
- xsltDebug(ctxt, contextNode, list, NULL); |
- ctxt->state = XSLT_STATE_STOPPED; |
- return; |
- } |
- ctxt->depth++; |
- |
- oldLocalFragmentTop = ctxt->localRVT; |
- oldInsert = insert = ctxt->insert; |
- oldInst = oldCurInst = ctxt->inst; |
- oldContextNode = ctxt->node; |
- /* |
- * Save current number of variables on the stack; new vars are popped when |
- * exiting. |
- */ |
- oldVarsNr = ctxt->varsNr; |
- /* |
- * Process the sequence constructor. |
- */ |
- cur = list; |
- while (cur != NULL) { |
- ctxt->inst = cur; |
- |
-#ifdef WITH_DEBUGGER |
- switch (ctxt->debugStatus) { |
- case XSLT_DEBUG_RUN_RESTART: |
- case XSLT_DEBUG_QUIT: |
- break; |
- |
- } |
-#endif |
- /* |
- * Test; we must have a valid insertion point. |
- */ |
- if (insert == NULL) { |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: insert == NULL !\n")); |
-#endif |
- goto error; |
- } |
- |
-#ifdef WITH_DEBUGGER |
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur)) |
- xslHandleDebugger(cur, contextNode, templ, ctxt); |
-#endif |
- |
-#ifdef XSLT_REFACTORED |
- if (cur->type == XML_ELEMENT_NODE) { |
- info = (xsltStylePreCompPtr) cur->psvi; |
- /* |
- * We expect a compiled representation on: |
- * 1) XSLT instructions of this XSLT version (1.0) |
- * (with a few exceptions) |
- * 2) Literal result elements |
- * 3) Extension instructions |
- * 4) XSLT instructions of future XSLT versions |
- * (forwards-compatible mode). |
- */ |
- if (info == NULL) { |
- /* |
- * Handle the rare cases where we don't expect a compiled |
- * representation on an XSLT element. |
- */ |
- if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) { |
- xsltMessage(ctxt, contextNode, cur); |
- goto skip_children; |
- } |
- /* |
- * Something really went wrong: |
- */ |
- xsltTransformError(ctxt, NULL, cur, |
- "Internal error in xsltApplySequenceConstructor(): " |
- "The element '%s' in the stylesheet has no compiled " |
- "representation.\n", |
- cur->name); |
- goto skip_children; |
- } |
- |
- if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) { |
- xsltStyleItemLRElementInfoPtr lrInfo = |
- (xsltStyleItemLRElementInfoPtr) info; |
- /* |
- * Literal result elements |
- * -------------------------------------------------------- |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, |
- xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy literal result " |
- "element '%s'\n", cur->name)); |
-#endif |
- /* |
- * Copy the raw element-node. |
- * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert)) |
- * == NULL) |
- * goto error; |
- */ |
- copy = xmlDocCopyNode(cur, insert->doc, 0); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, cur, |
- "Internal error in xsltApplySequenceConstructor(): " |
- "Failed to copy literal result element '%s'.\n", |
- cur->name); |
- goto error; |
- } else { |
- /* |
- * Add the element-node to the result tree. |
- */ |
- copy->doc = ctxt->output; |
- copy = xsltAddChild(insert, copy); |
- /* |
- * Create effective namespaces declarations. |
- * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef); |
- */ |
- if (lrInfo->effectiveNs != NULL) { |
- xsltEffectiveNsPtr effNs = lrInfo->effectiveNs; |
- xmlNsPtr ns, lastns = NULL; |
- |
- while (effNs != NULL) { |
- /* |
- * Avoid generating redundant namespace |
- * declarations; thus lookup if there is already |
- * such a ns-decl in the result. |
- */ |
- ns = xmlSearchNs(copy->doc, copy, effNs->prefix); |
- if ((ns != NULL) && |
- (xmlStrEqual(ns->href, effNs->nsName))) |
- { |
- effNs = effNs->next; |
- continue; |
- } |
- ns = xmlNewNs(copy, effNs->nsName, effNs->prefix); |
- if (ns == NULL) { |
- xsltTransformError(ctxt, NULL, cur, |
- "Internal error in " |
- "xsltApplySequenceConstructor(): " |
- "Failed to copy a namespace " |
- "declaration.\n"); |
- goto error; |
- } |
- |
- if (lastns == NULL) |
- copy->nsDef = ns; |
- else |
- lastns->next =ns; |
- lastns = ns; |
- |
- effNs = effNs->next; |
- } |
- |
- } |
- /* |
- * NOTE that we don't need to apply ns-alising: this was |
- * already done at compile-time. |
- */ |
- if (cur->ns != NULL) { |
- /* |
- * If there's no such ns-decl in the result tree, |
- * then xsltGetSpecialNamespace() will |
- * create a ns-decl on the copied node. |
- */ |
- copy->ns = xsltGetSpecialNamespace(ctxt, cur, |
- cur->ns->href, cur->ns->prefix, copy); |
- } else { |
- /* |
- * Undeclare the default namespace if needed. |
- * This can be skipped, if the result element has |
- * no ns-decls, in which case the result element |
- * obviously does not declare a default namespace; |
- * AND there's either no parent, or the parent |
- * element is in no namespace; this means there's no |
- * default namespace is scope to care about. |
- * |
- * REVISIT: This might result in massive |
- * generation of ns-decls if nodes in a default |
- * namespaces are mixed with nodes in no namespace. |
- * |
- */ |
- if (copy->nsDef || |
- ((insert != NULL) && |
- (insert->type == XML_ELEMENT_NODE) && |
- (insert->ns != NULL))) |
- { |
- xsltGetSpecialNamespace(ctxt, cur, |
- NULL, NULL, copy); |
- } |
- } |
- } |
- /* |
- * SPEC XSLT 2.0 "Each attribute of the literal result |
- * element, other than an attribute in the XSLT namespace, |
- * is processed to produce an attribute for the element in |
- * the result tree." |
- * NOTE: See bug #341325. |
- */ |
- if (cur->properties != NULL) { |
- xsltAttrListTemplateProcess(ctxt, copy, cur->properties); |
- } |
- } else if (IS_XSLT_ELEM_FAST(cur)) { |
- /* |
- * XSLT instructions |
- * -------------------------------------------------------- |
- */ |
- if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) { |
- /* |
- * We hit an unknown XSLT element. |
- * Try to apply one of the fallback cases. |
- */ |
- ctxt->insert = insert; |
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { |
- xsltTransformError(ctxt, NULL, cur, |
- "The is no fallback behaviour defined for " |
- "the unknown XSLT element '%s'.\n", |
- cur->name); |
- } |
- ctxt->insert = oldInsert; |
- } else if (info->func != NULL) { |
- /* |
- * Execute the XSLT instruction. |
- */ |
- ctxt->insert = insert; |
- |
- info->func(ctxt, contextNode, cur, |
- (xsltElemPreCompPtr) info); |
- |
- /* |
- * Cleanup temporary tree fragments. |
- */ |
- if (oldLocalFragmentTop != ctxt->localRVT) |
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); |
- |
- ctxt->insert = oldInsert; |
- } else if (info->type == XSLT_FUNC_VARIABLE) { |
- xsltStackElemPtr tmpvar = ctxt->vars; |
- |
- xsltParseStylesheetVariable(ctxt, cur); |
- |
- if (tmpvar != ctxt->vars) { |
- /* |
- * TODO: Using a @tmpvar is an annoying workaround, but |
- * the current mechanisms do not provide any other way |
- * of knowing if the var was really pushed onto the |
- * stack. |
- */ |
- ctxt->vars->level = level; |
- } |
- } else if (info->type == XSLT_FUNC_MESSAGE) { |
- /* |
- * TODO: Won't be hit, since we don't compile xsl:message. |
- */ |
- xsltMessage(ctxt, contextNode, cur); |
- } else { |
- xsltTransformError(ctxt, NULL, cur, |
- "Unexpected XSLT element '%s'.\n", cur->name); |
- } |
- goto skip_children; |
- |
- } else { |
- xsltTransformFunction func; |
- /* |
- * Extension intructions (elements) |
- * -------------------------------------------------------- |
- */ |
- if (cur->psvi == xsltExtMarker) { |
- /* |
- * The xsltExtMarker was set during the compilation |
- * of extension instructions if there was no registered |
- * handler for this specific extension function at |
- * compile-time. |
- * Libxslt will now lookup if a handler is |
- * registered in the context of this transformation. |
- */ |
- func = (xsltTransformFunction) |
- xsltExtElementLookup(ctxt, cur->name, cur->ns->href); |
- } else |
- func = ((xsltElemPreCompPtr) cur->psvi)->func; |
- |
- if (func == NULL) { |
- /* |
- * No handler available. |
- * Try to execute fallback behaviour via xsl:fallback. |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, |
- xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: unknown extension %s\n", |
- cur->name)); |
-#endif |
- ctxt->insert = insert; |
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { |
- xsltTransformError(ctxt, NULL, cur, |
- "Unknown extension instruction '{%s}%s'.\n", |
- cur->ns->href, cur->name); |
- } |
- ctxt->insert = oldInsert; |
- } else { |
- /* |
- * Execute the handler-callback. |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: extension construct %s\n", |
- cur->name)); |
-#endif |
- /* |
- * Disable the xsltCopyTextString optimization for |
- * extension elements. Extensions could append text using |
- * xmlAddChild which will free the buffer pointed to by |
- * 'lasttext'. This buffer could later be reallocated with |
- * a different size than recorded in 'lasttsize'. See bug |
- * #777432. |
- */ |
- if (cur->psvi == xsltExtMarker) { |
- ctxt->lasttext = NULL; |
- } |
- |
- ctxt->insert = insert; |
- |
- func(ctxt, contextNode, cur, cur->psvi); |
- |
- /* |
- * Cleanup temporary tree fragments. |
- */ |
- if (oldLocalFragmentTop != ctxt->localRVT) |
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); |
- |
- ctxt->insert = oldInsert; |
- } |
- goto skip_children; |
- } |
- |
- } else if (XSLT_IS_TEXT_NODE(cur)) { |
- /* |
- * Text |
- * ------------------------------------------------------------ |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->name == xmlStringTextNoenc) { |
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, |
- xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy unescaped text '%s'\n", |
- cur->content)); |
- } else { |
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, |
- xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy text '%s'\n", |
- cur->content)); |
- } |
-#endif |
- if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) |
- goto error; |
- } |
- |
-#else /* XSLT_REFACTORED */ |
- |
- if (IS_XSLT_ELEM(cur)) { |
- /* |
- * This is an XSLT node |
- */ |
- xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi; |
- |
- if (info == NULL) { |
- if (IS_XSLT_NAME(cur, "message")) { |
- xsltMessage(ctxt, contextNode, cur); |
- } else { |
- /* |
- * That's an error try to apply one of the fallback cases |
- */ |
- ctxt->insert = insert; |
- if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { |
- xsltGenericError(xsltGenericErrorContext, |
- "xsltApplySequenceConstructor: %s was not compiled\n", |
- cur->name); |
- } |
- ctxt->insert = oldInsert; |
- } |
- goto skip_children; |
- } |
- |
- if (info->func != NULL) { |
- oldCurInst = ctxt->inst; |
- ctxt->inst = cur; |
- ctxt->insert = insert; |
- |
- info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); |
- |
- /* |
- * Cleanup temporary tree fragments. |
- */ |
- if (oldLocalFragmentTop != ctxt->localRVT) |
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); |
- |
- ctxt->insert = oldInsert; |
- ctxt->inst = oldCurInst; |
- goto skip_children; |
- } |
- |
- if (IS_XSLT_NAME(cur, "variable")) { |
- xsltStackElemPtr tmpvar = ctxt->vars; |
- |
- oldCurInst = ctxt->inst; |
- ctxt->inst = cur; |
- |
- xsltParseStylesheetVariable(ctxt, cur); |
- |
- ctxt->inst = oldCurInst; |
- |
- if (tmpvar != ctxt->vars) { |
- /* |
- * TODO: Using a @tmpvar is an annoying workaround, but |
- * the current mechanisms do not provide any other way |
- * of knowing if the var was really pushed onto the |
- * stack. |
- */ |
- ctxt->vars->level = level; |
- } |
- } else if (IS_XSLT_NAME(cur, "message")) { |
- xsltMessage(ctxt, contextNode, cur); |
- } else { |
- xsltTransformError(ctxt, NULL, cur, |
- "Unexpected XSLT element '%s'.\n", cur->name); |
- } |
- goto skip_children; |
- } else if ((cur->type == XML_TEXT_NODE) || |
- (cur->type == XML_CDATA_SECTION_NODE)) { |
- |
- /* |
- * This text comes from the stylesheet |
- * For stylesheets, the set of whitespace-preserving |
- * element names consists of just xsl:text. |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (cur->type == XML_CDATA_SECTION_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy CDATA text %s\n", |
- cur->content)); |
- } else if (cur->name == xmlStringTextNoenc) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy unescaped text %s\n", |
- cur->content)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy text %s\n", |
- cur->content)); |
- } |
-#endif |
- if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) |
- goto error; |
- } else if ((cur->type == XML_ELEMENT_NODE) && |
- (cur->ns != NULL) && (cur->psvi != NULL)) { |
- xsltTransformFunction function; |
- |
- oldCurInst = ctxt->inst; |
- ctxt->inst = cur; |
- /* |
- * Flagged as an extension element |
- */ |
- if (cur->psvi == xsltExtMarker) |
- function = (xsltTransformFunction) |
- xsltExtElementLookup(ctxt, cur->name, cur->ns->href); |
- else |
- function = ((xsltElemPreCompPtr) cur->psvi)->func; |
- |
- if (function == NULL) { |
- xmlNodePtr child; |
- int found = 0; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: unknown extension %s\n", |
- cur->name)); |
-#endif |
- /* |
- * Search if there are fallbacks |
- */ |
- child = cur->children; |
- while (child != NULL) { |
- if ((IS_XSLT_ELEM(child)) && |
- (IS_XSLT_NAME(child, "fallback"))) |
- { |
- found = 1; |
- xsltApplySequenceConstructor(ctxt, contextNode, |
- child->children, NULL); |
- } |
- child = child->next; |
- } |
- |
- if (!found) { |
- xsltTransformError(ctxt, NULL, cur, |
- "xsltApplySequenceConstructor: failed to find extension %s\n", |
- cur->name); |
- } |
- } else { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: extension construct %s\n", |
- cur->name)); |
-#endif |
- |
- /* |
- * Disable the xsltCopyTextString optimization for |
- * extension elements. Extensions could append text using |
- * xmlAddChild which will free the buffer pointed to by |
- * 'lasttext'. This buffer could later be reallocated with |
- * a different size than recorded in 'lasttsize'. See bug |
- * #777432. |
- */ |
- if (cur->psvi == xsltExtMarker) { |
- ctxt->lasttext = NULL; |
- } |
- |
- ctxt->insert = insert; |
- |
- function(ctxt, contextNode, cur, cur->psvi); |
- /* |
- * Cleanup temporary tree fragments. |
- */ |
- if (oldLocalFragmentTop != ctxt->localRVT) |
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); |
- |
- ctxt->insert = oldInsert; |
- |
- } |
- ctxt->inst = oldCurInst; |
- goto skip_children; |
- } else if (cur->type == XML_ELEMENT_NODE) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplySequenceConstructor: copy node %s\n", |
- cur->name)); |
-#endif |
- oldCurInst = ctxt->inst; |
- ctxt->inst = cur; |
- |
- if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL) |
- goto error; |
- /* |
- * Add extra namespaces inherited from the current template |
- * if we are in the first level children and this is a |
- * "real" template. |
- */ |
- if ((templ != NULL) && (oldInsert == insert) && |
- (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) { |
- int i; |
- xmlNsPtr ns, ret; |
- |
- for (i = 0; i < ctxt->templ->inheritedNsNr; i++) { |
- const xmlChar *URI = NULL; |
- xsltStylesheetPtr style; |
- ns = ctxt->templ->inheritedNs[i]; |
- |
- /* Note that the XSLT namespace was already excluded |
- * in xsltGetInheritedNsList(). |
- */ |
-#if 0 |
- if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) |
- continue; |
-#endif |
- style = ctxt->style; |
- while (style != NULL) { |
- if (style->nsAliases != NULL) |
- URI = (const xmlChar *) |
- xmlHashLookup(style->nsAliases, ns->href); |
- if (URI != NULL) |
- break; |
- |
- style = xsltNextImport(style); |
- } |
- if (URI == UNDEFINED_DEFAULT_NS) |
- continue; |
- if (URI == NULL) |
- URI = ns->href; |
- /* |
- * TODO: The following will still be buggy for the |
- * non-refactored code. |
- */ |
- ret = xmlSearchNs(copy->doc, copy, ns->prefix); |
- if ((ret == NULL) || (!xmlStrEqual(ret->href, URI))) |
- { |
- xmlNewNs(copy, URI, ns->prefix); |
- } |
- } |
- if (copy->ns != NULL) { |
- /* |
- * Fix the node namespace if needed |
- */ |
- copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy); |
- } |
- } |
- /* |
- * all the attributes are directly inherited |
- */ |
- if (cur->properties != NULL) { |
- xsltAttrListTemplateProcess(ctxt, copy, cur->properties); |
- } |
- ctxt->inst = oldCurInst; |
- } |
-#endif /* else of XSLT_REFACTORED */ |
- |
- /* |
- * Descend into content in document order. |
- */ |
- if (cur->children != NULL) { |
- if (cur->children->type != XML_ENTITY_DECL) { |
- cur = cur->children; |
- level++; |
- if (copy != NULL) |
- insert = copy; |
- continue; |
- } |
- } |
- |
-skip_children: |
- /* |
- * If xslt:message was just processed, we might have hit a |
- * terminate='yes'; if so, then break the loop and clean up. |
- * TODO: Do we need to check this also before trying to descend |
- * into the content? |
- */ |
- if (ctxt->state == XSLT_STATE_STOPPED) |
- break; |
- if (cur->next != NULL) { |
- cur = cur->next; |
- continue; |
- } |
- |
- do { |
- cur = cur->parent; |
- level--; |
- /* |
- * Pop variables/params (xsl:variable and xsl:param). |
- */ |
- if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) { |
- xsltLocalVariablePop(ctxt, oldVarsNr, level); |
- } |
- |
- insert = insert->parent; |
- if (cur == NULL) |
- break; |
- if (cur == list->parent) { |
- cur = NULL; |
- break; |
- } |
- if (cur->next != NULL) { |
- cur = cur->next; |
- break; |
- } |
- } while (cur != NULL); |
- } |
- |
-error: |
- /* |
- * In case of errors: pop remaining variables. |
- */ |
- if (ctxt->varsNr > oldVarsNr) |
- xsltLocalVariablePop(ctxt, oldVarsNr, -1); |
- |
- ctxt->node = oldContextNode; |
- ctxt->inst = oldInst; |
- ctxt->insert = oldInsert; |
- |
- ctxt->depth--; |
- |
-#ifdef WITH_DEBUGGER |
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { |
- xslDropCall(); |
- } |
-#endif |
-} |
- |
-/* |
-* xsltApplyXSLTTemplate: |
-* @ctxt: a XSLT transformation context |
-* @contextNode: the node in the source tree. |
-* @list: the nodes of a sequence constructor; |
-* (plus leading xsl:param elements) |
-* @templ: the compiled xsl:template declaration; |
-* NULL if a sequence constructor |
-* @withParams: a set of caller-parameters (xsl:with-param) or NULL |
-* |
-* Called by: |
-* - xsltApplyImports() |
-* - xsltCallTemplate() |
-* - xsltDefaultProcessOneNode() |
-* - xsltProcessOneNode() |
-*/ |
-static void |
-xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, |
- xmlNodePtr list, |
- xsltTemplatePtr templ, |
- xsltStackElemPtr withParams) |
-{ |
- int oldVarsBase = 0; |
- long start = 0; |
- xmlNodePtr cur; |
- xsltStackElemPtr tmpParam = NULL; |
- xmlDocPtr oldUserFragmentTop; |
- |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemParamPtr iparam; |
-#else |
- xsltStylePreCompPtr iparam; |
-#endif |
- |
-#ifdef WITH_DEBUGGER |
- int addCallResult = 0; |
-#endif |
- |
- if (ctxt == NULL) |
- return; |
- if (templ == NULL) { |
- xsltTransformError(ctxt, NULL, list, |
- "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n"); |
- return; |
- } |
- |
-#ifdef WITH_DEBUGGER |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) { |
- if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode, |
- list, templ, &addCallResult) == NULL) |
- return; |
- } |
-#endif |
- |
- if (list == NULL) |
- return; |
- CHECK_STOPPED; |
- |
- if (ctxt->varsNr >= ctxt->maxTemplateVars) |
- { |
- xsltTransformError(ctxt, NULL, list, |
- "xsltApplyXSLTTemplate: A potential infinite template recursion " |
- "was detected.\n" |
- "You can adjust maxTemplateVars (--maxvars) in order to " |
- "raise the maximum number of variables/params (currently set to %d).\n", |
- ctxt->maxTemplateVars); |
- xsltDebug(ctxt, contextNode, list, NULL); |
- ctxt->state = XSLT_STATE_STOPPED; |
- return; |
- } |
- |
- oldUserFragmentTop = ctxt->tmpRVT; |
- ctxt->tmpRVT = NULL; |
- |
- /* |
- * Initiate a distinct scope of local params/variables. |
- */ |
- oldVarsBase = ctxt->varsBase; |
- ctxt->varsBase = ctxt->varsNr; |
- |
- ctxt->node = contextNode; |
- if (ctxt->profile) { |
- templ->nbCalls++; |
- start = xsltTimestamp(); |
- profPush(ctxt, 0); |
- profCallgraphAdd(templ, ctxt->templ); |
- } |
- /* |
- * Push the xsl:template declaration onto the stack. |
- */ |
- templPush(ctxt, templ); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (templ->name != NULL) |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "applying xsl:template '%s'\n", templ->name)); |
-#endif |
- /* |
- * Process xsl:param instructions and skip those elements for |
- * further processing. |
- */ |
- cur = list; |
- do { |
- if (cur->type == XML_TEXT_NODE) { |
- cur = cur->next; |
- continue; |
- } |
- if ((cur->type != XML_ELEMENT_NODE) || |
- (cur->name[0] != 'p') || |
- (cur->psvi == NULL) || |
- (! xmlStrEqual(cur->name, BAD_CAST "param")) || |
- (! IS_XSLT_ELEM(cur))) |
- { |
- break; |
- } |
- |
- list = cur->next; |
- |
-#ifdef XSLT_REFACTORED |
- iparam = (xsltStyleItemParamPtr) cur->psvi; |
-#else |
- iparam = (xsltStylePreCompPtr) cur->psvi; |
-#endif |
- |
- /* |
- * Substitute xsl:param for a given xsl:with-param. |
- * Since the XPath expression will reference the params/vars |
- * by index, we need to slot the xsl:with-params in the |
- * order of encountered xsl:params to keep the sequence of |
- * params/variables in the stack exactly as it was at |
- * compile time, |
- */ |
- tmpParam = NULL; |
- if (withParams) { |
- tmpParam = withParams; |
- do { |
- if ((tmpParam->name == (iparam->name)) && |
- (tmpParam->nameURI == (iparam->ns))) |
- { |
- /* |
- * Push the caller-parameter. |
- */ |
- xsltLocalVariablePush(ctxt, tmpParam, -1); |
- break; |
- } |
- tmpParam = tmpParam->next; |
- } while (tmpParam != NULL); |
- } |
- /* |
- * Push the xsl:param. |
- */ |
- if (tmpParam == NULL) { |
- /* |
- * Note that we must assume that the added parameter |
- * has a @depth of 0. |
- */ |
- xsltParseStylesheetParam(ctxt, cur); |
- } |
- cur = cur->next; |
- } while (cur != NULL); |
- /* |
- * Process the sequence constructor. |
- */ |
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ); |
- |
- /* |
- * Remove remaining xsl:param and xsl:with-param items from |
- * the stack. Don't free xsl:with-param items. |
- */ |
- if (ctxt->varsNr > ctxt->varsBase) |
- xsltTemplateParamsCleanup(ctxt); |
- ctxt->varsBase = oldVarsBase; |
- |
- /* |
- * Release user-created fragments stored in the scope |
- * of xsl:template. Note that this mechanism is deprecated: |
- * user code should now use xsltRegisterLocalRVT() instead |
- * of the obsolete xsltRegisterTmpRVT(). |
- */ |
- if (ctxt->tmpRVT) { |
- xmlDocPtr curdoc = ctxt->tmpRVT, tmp; |
- |
- while (curdoc != NULL) { |
- tmp = curdoc; |
- curdoc = (xmlDocPtr) curdoc->next; |
- xsltReleaseRVT(ctxt, tmp); |
- } |
- } |
- ctxt->tmpRVT = oldUserFragmentTop; |
- |
- /* |
- * Pop the xsl:template declaration from the stack. |
- */ |
- templPop(ctxt); |
- if (ctxt->profile) { |
- long spent, child, total, end; |
- |
- end = xsltTimestamp(); |
- child = profPop(ctxt); |
- total = end - start; |
- spent = total - child; |
- if (spent <= 0) { |
- /* |
- * Not possible unless the original calibration failed |
- * we can try to correct it on the fly. |
- */ |
- xsltCalibrateAdjust(spent); |
- spent = 0; |
- } |
- |
- templ->time += spent; |
- if (ctxt->profNr > 0) |
- ctxt->profTab[ctxt->profNr - 1] += total; |
- } |
- |
-#ifdef WITH_DEBUGGER |
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { |
- xslDropCall(); |
- } |
-#endif |
-} |
- |
- |
-/** |
- * xsltApplyOneTemplate: |
- * @ctxt: a XSLT process context |
- * @contextNode: the node in the source tree. |
- * @list: the nodes of a sequence constructor |
- * @templ: not used |
- * @params: a set of parameters (xsl:param) or NULL |
- * |
- * Processes a sequence constructor on the current node in the source tree. |
- * |
- * @params are the already computed variable stack items; this function |
- * pushes them on the variable stack, and pops them before exiting; it's |
- * left to the caller to free or reuse @params afterwards. The initial |
- * states of the variable stack will always be restored before this |
- * function exits. |
- * NOTE that this does *not* initiate a new distinct variable scope; i.e. |
- * variables already on the stack are visible to the process. The caller's |
- * side needs to start a new variable scope if needed (e.g. in exsl:function). |
- * |
- * @templ is obsolete and not used anymore (e.g. <exslt:function> does not |
- * provide a @templ); a non-NULL @templ might raise an error in the future. |
- * |
- * BIG NOTE: This function is not intended to process the content of an |
- * xsl:template; it does not expect xsl:param instructions in @list and |
- * will report errors if found. |
- * |
- * Called by: |
- * - xsltEvalVariable() (variables.c) |
- * - exsltFuncFunctionFunction() (libexsl/functions.c) |
- */ |
-void |
-xsltApplyOneTemplate(xsltTransformContextPtr ctxt, |
- xmlNodePtr contextNode, |
- xmlNodePtr list, |
- xsltTemplatePtr templ ATTRIBUTE_UNUSED, |
- xsltStackElemPtr params) |
-{ |
- if ((ctxt == NULL) || (list == NULL)) |
- return; |
- CHECK_STOPPED; |
- |
- if (params) { |
- /* |
- * This code should be obsolete - was previously used |
- * by libexslt/functions.c, but due to bug 381319 the |
- * logic there was changed. |
- */ |
- int oldVarsNr = ctxt->varsNr; |
- |
- /* |
- * Push the given xsl:param(s) onto the variable stack. |
- */ |
- while (params != NULL) { |
- xsltLocalVariablePush(ctxt, params, -1); |
- params = params->next; |
- } |
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ); |
- /* |
- * Pop the given xsl:param(s) from the stack but don't free them. |
- */ |
- xsltLocalVariablePop(ctxt, oldVarsNr, -2); |
- } else |
- xsltApplySequenceConstructor(ctxt, contextNode, list, templ); |
-} |
- |
-/************************************************************************ |
- * * |
- * XSLT-1.1 extensions * |
- * * |
- ************************************************************************/ |
- |
-/** |
- * xsltDocumentElem: |
- * @ctxt: an XSLT processing context |
- * @node: The current node |
- * @inst: the instruction in the stylesheet |
- * @castedComp: precomputed information |
- * |
- * Process an EXSLT/XSLT-1.1 document element |
- */ |
-void |
-xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xsltStylesheetPtr style = NULL; |
- int ret; |
- xmlChar *filename = NULL, *prop, *elements; |
- xmlChar *element, *end; |
- xmlDocPtr res = NULL; |
- xmlDocPtr oldOutput; |
- xmlNodePtr oldInsert, root; |
- const char *oldOutputFile; |
- xsltOutputType oldType; |
- xmlChar *URL = NULL; |
- const xmlChar *method; |
- const xmlChar *doctypePublic; |
- const xmlChar *doctypeSystem; |
- const xmlChar *version; |
- const xmlChar *encoding; |
- int redirect_write_append = 0; |
- |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) |
- return; |
- |
- if (comp->filename == NULL) { |
- |
- if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { |
- /* |
- * The element "output" is in the namespace XSLT_SAXON_NAMESPACE |
- * (http://icl.com/saxon) |
- * The @file is in no namespace. |
- */ |
-#ifdef WITH_XSLT_DEBUG_EXTRA |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Found saxon:output extension\n"); |
-#endif |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "file", |
- XSLT_SAXON_NAMESPACE); |
- |
- if (URL == NULL) |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "href", |
- XSLT_SAXON_NAMESPACE); |
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { |
-#ifdef WITH_XSLT_DEBUG_EXTRA |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Found xalan:write extension\n"); |
-#endif |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "select", |
- XSLT_XALAN_NAMESPACE); |
- if (URL != NULL) { |
- xmlXPathCompExprPtr cmp; |
- xmlChar *val; |
- |
- /* |
- * Trying to handle bug #59212 |
- * The value of the "select" attribute is an |
- * XPath expression. |
- * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) |
- */ |
- cmp = xmlXPathCompile(URL); |
- val = xsltEvalXPathString(ctxt, cmp); |
- xmlXPathFreeCompExpr(cmp); |
- xmlFree(URL); |
- URL = val; |
- } |
- if (URL == NULL) |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "file", |
- XSLT_XALAN_NAMESPACE); |
- if (URL == NULL) |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "href", |
- XSLT_XALAN_NAMESPACE); |
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { |
- URL = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "href", |
- NULL); |
- } |
- |
- } else { |
- URL = xmlStrdup(comp->filename); |
- } |
- |
- if (URL == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: href/URI-Reference not found\n"); |
- return; |
- } |
- |
- /* |
- * If the computation failed, it's likely that the URL wasn't escaped |
- */ |
- filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile); |
- if (filename == NULL) { |
- xmlChar *escURL; |
- |
- escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,"); |
- if (escURL != NULL) { |
- filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile); |
- xmlFree(escURL); |
- } |
- } |
- |
- if (filename == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: URL computation failed for %s\n", |
- URL); |
- xmlFree(URL); |
- return; |
- } |
- |
- /* |
- * Security checking: can we write to this resource |
- */ |
- if (ctxt->sec != NULL) { |
- ret = xsltCheckWrite(ctxt->sec, ctxt, filename); |
- if (ret == 0) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: write rights for %s denied\n", |
- filename); |
- xmlFree(URL); |
- xmlFree(filename); |
- return; |
- } |
- } |
- |
- oldOutputFile = ctxt->outputFile; |
- oldOutput = ctxt->output; |
- oldInsert = ctxt->insert; |
- oldType = ctxt->type; |
- ctxt->outputFile = (const char *) filename; |
- |
- style = xsltNewStylesheet(); |
- if (style == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: out of memory\n"); |
- goto error; |
- } |
- |
- /* |
- * Version described in 1.1 draft allows full parameterization |
- * of the output. |
- */ |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "version", |
- NULL); |
- if (prop != NULL) { |
- if (style->version != NULL) |
- xmlFree(style->version); |
- style->version = prop; |
- } |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "encoding", |
- NULL); |
- if (prop != NULL) { |
- if (style->encoding != NULL) |
- xmlFree(style->encoding); |
- style->encoding = prop; |
- } |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "method", |
- NULL); |
- if (prop != NULL) { |
- const xmlChar *URI; |
- |
- if (style->method != NULL) |
- xmlFree(style->method); |
- style->method = NULL; |
- if (style->methodURI != NULL) |
- xmlFree(style->methodURI); |
- style->methodURI = NULL; |
- |
- URI = xsltGetQNameURI(inst, &prop); |
- if (prop == NULL) { |
- if (style != NULL) style->errors++; |
- } else if (URI == NULL) { |
- if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || |
- (xmlStrEqual(prop, (const xmlChar *) "html")) || |
- (xmlStrEqual(prop, (const xmlChar *) "text"))) { |
- style->method = prop; |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "invalid value for method: %s\n", prop); |
- if (style != NULL) style->warnings++; |
- } |
- } else { |
- style->method = prop; |
- style->methodURI = xmlStrdup(URI); |
- } |
- } |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "doctype-system", NULL); |
- if (prop != NULL) { |
- if (style->doctypeSystem != NULL) |
- xmlFree(style->doctypeSystem); |
- style->doctypeSystem = prop; |
- } |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "doctype-public", NULL); |
- if (prop != NULL) { |
- if (style->doctypePublic != NULL) |
- xmlFree(style->doctypePublic); |
- style->doctypePublic = prop; |
- } |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "standalone", |
- NULL); |
- if (prop != NULL) { |
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) { |
- style->standalone = 1; |
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { |
- style->standalone = 0; |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "invalid value for standalone: %s\n", |
- prop); |
- if (style != NULL) style->warnings++; |
- } |
- xmlFree(prop); |
- } |
- |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "indent", |
- NULL); |
- if (prop != NULL) { |
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) { |
- style->indent = 1; |
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { |
- style->indent = 0; |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "invalid value for indent: %s\n", prop); |
- if (style != NULL) style->warnings++; |
- } |
- xmlFree(prop); |
- } |
- |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "omit-xml-declaration", |
- NULL); |
- if (prop != NULL) { |
- if (xmlStrEqual(prop, (const xmlChar *) "yes")) { |
- style->omitXmlDeclaration = 1; |
- } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { |
- style->omitXmlDeclaration = 0; |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "invalid value for omit-xml-declaration: %s\n", |
- prop); |
- if (style != NULL) style->warnings++; |
- } |
- xmlFree(prop); |
- } |
- |
- elements = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) |
- "cdata-section-elements", |
- NULL); |
- if (elements != NULL) { |
- if (style->stripSpaces == NULL) |
- style->stripSpaces = xmlHashCreate(10); |
- if (style->stripSpaces == NULL) |
- return; |
- |
- element = elements; |
- while (*element != 0) { |
- while (IS_BLANK_CH(*element)) |
- element++; |
- if (*element == 0) |
- break; |
- end = element; |
- while ((*end != 0) && (!IS_BLANK_CH(*end))) |
- end++; |
- element = xmlStrndup(element, end - element); |
- if (element) { |
- const xmlChar *URI; |
- |
-#ifdef WITH_XSLT_DEBUG_PARSING |
- xsltGenericDebug(xsltGenericDebugContext, |
- "add cdata section output element %s\n", |
- element); |
-#endif |
- URI = xsltGetQNameURI(inst, &element); |
- |
- xmlHashAddEntry2(style->stripSpaces, element, URI, |
- (xmlChar *) "cdata"); |
- xmlFree(element); |
- } |
- element = end; |
- } |
- xmlFree(elements); |
- } |
- |
- /* |
- * Create a new document tree and process the element template |
- */ |
- XSLT_GET_IMPORT_PTR(method, style, method) |
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) |
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) |
- XSLT_GET_IMPORT_PTR(version, style, version) |
- XSLT_GET_IMPORT_PTR(encoding, style, encoding) |
- |
- if ((method != NULL) && |
- (!xmlStrEqual(method, (const xmlChar *) "xml"))) { |
- if (xmlStrEqual(method, (const xmlChar *) "html")) { |
- ctxt->type = XSLT_OUTPUT_HTML; |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) |
- res = htmlNewDoc(doctypeSystem, doctypePublic); |
- else { |
- if (version != NULL) { |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
- xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); |
-#endif |
- } |
- res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); |
- } |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
- } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: unsupported method xhtml\n"); |
- ctxt->type = XSLT_OUTPUT_HTML; |
- res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
- } else if (xmlStrEqual(method, (const xmlChar *) "text")) { |
- ctxt->type = XSLT_OUTPUT_TEXT; |
- res = xmlNewDoc(style->version); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: unsupported method (%s)\n", |
- method); |
- goto error; |
- } |
- } else { |
- ctxt->type = XSLT_OUTPUT_XML; |
- res = xmlNewDoc(style->version); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } |
- res->charset = XML_CHAR_ENCODING_UTF8; |
- if (encoding != NULL) |
- res->encoding = xmlStrdup(encoding); |
- ctxt->output = res; |
- ctxt->insert = (xmlNodePtr) res; |
- xsltApplySequenceConstructor(ctxt, node, inst->children, NULL); |
- |
- /* |
- * Do some post processing work depending on the generated output |
- */ |
- root = xmlDocGetRootElement(res); |
- if (root != NULL) { |
- const xmlChar *doctype = NULL; |
- |
- if ((root->ns != NULL) && (root->ns->prefix != NULL)) |
- doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); |
- if (doctype == NULL) |
- doctype = root->name; |
- |
- /* |
- * Apply the default selection of the method |
- */ |
- if ((method == NULL) && |
- (root->ns == NULL) && |
- (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { |
- xmlNodePtr tmp; |
- |
- tmp = res->children; |
- while ((tmp != NULL) && (tmp != root)) { |
- if (tmp->type == XML_ELEMENT_NODE) |
- break; |
- if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) |
- break; |
- tmp = tmp->next; |
- } |
- if (tmp == root) { |
- ctxt->type = XSLT_OUTPUT_HTML; |
- res->type = XML_HTML_DOCUMENT_NODE; |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { |
- res->intSubset = xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
- } else if (version != NULL) { |
- xsltGetHTMLIDs(version, &doctypePublic, |
- &doctypeSystem); |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) |
- res->intSubset = |
- xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
-#endif |
- } |
- } |
- |
- } |
- if (ctxt->type == XSLT_OUTPUT_XML) { |
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) |
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) |
- res->intSubset = xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
- } |
- } |
- |
- /* |
- * Calls to redirect:write also take an optional attribute append. |
- * Attribute append="true|yes" which will attempt to simply append |
- * to an existing file instead of always opening a new file. The |
- * default behavior of always overwriting the file still happens |
- * if we do not specify append. |
- * Note that append use will forbid use of remote URI target. |
- */ |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append", |
- NULL); |
- if (prop != NULL) { |
- if (xmlStrEqual(prop, (const xmlChar *) "true") || |
- xmlStrEqual(prop, (const xmlChar *) "yes")) { |
- style->omitXmlDeclaration = 1; |
- redirect_write_append = 1; |
- } else |
- style->omitXmlDeclaration = 0; |
- xmlFree(prop); |
- } |
- |
- if (redirect_write_append) { |
- FILE *f; |
- |
- f = fopen((const char *) filename, "ab"); |
- if (f == NULL) { |
- ret = -1; |
- } else { |
- ret = xsltSaveResultToFile(f, res, style); |
- fclose(f); |
- } |
- } else { |
- ret = xsltSaveResultToFilename((const char *) filename, res, style, 0); |
- } |
- if (ret < 0) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsltDocumentElem: unable to save to %s\n", |
- filename); |
-#ifdef WITH_XSLT_DEBUG_EXTRA |
- } else { |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Wrote %d bytes to %s\n", ret, filename); |
-#endif |
- } |
- |
- error: |
- ctxt->output = oldOutput; |
- ctxt->insert = oldInsert; |
- ctxt->type = oldType; |
- ctxt->outputFile = oldOutputFile; |
- if (URL != NULL) |
- xmlFree(URL); |
- if (filename != NULL) |
- xmlFree(filename); |
- if (style != NULL) |
- xsltFreeStylesheet(style); |
- if (res != NULL) |
- xmlFreeDoc(res); |
-} |
- |
-/************************************************************************ |
- * * |
- * Most of the XSLT-1.0 transformations * |
- * * |
- ************************************************************************/ |
- |
-/** |
- * xsltSort: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt sort node |
- * @comp: precomputed information |
- * |
- * function attached to xsl:sort nodes, but this should not be |
- * called directly |
- */ |
-void |
-xsltSort(xsltTransformContextPtr ctxt, |
- xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, |
- xsltStylePreCompPtr comp) { |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:sort : compilation failed\n"); |
- return; |
- } |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:sort : improper use this should not be reached\n"); |
-} |
- |
-/** |
- * xsltCopy: |
- * @ctxt: an XSLT process context |
- * @node: the node in the source tree |
- * @inst: the element node of the XSLT-copy instruction |
- * @castedComp: computed information of the XSLT-copy instruction |
- * |
- * Execute the XSLT-copy instruction on the source node. |
- */ |
-void |
-xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xmlNodePtr copy, oldInsert; |
- |
- oldInsert = ctxt->insert; |
- if (ctxt->insert != NULL) { |
- switch (node->type) { |
- case XML_TEXT_NODE: |
- case XML_CDATA_SECTION_NODE: |
- /* |
- * This text comes from the stylesheet |
- * For stylesheets, the set of whitespace-preserving |
- * element names consists of just xsl:text. |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (node->type == XML_CDATA_SECTION_NODE) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: CDATA text %s\n", node->content)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: text %s\n", node->content)); |
- } |
-#endif |
- xsltCopyText(ctxt, ctxt->insert, node, 0); |
- break; |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- break; |
- case XML_ELEMENT_NODE: |
- /* |
- * REVISIT NOTE: The "fake" is a doc-node, not an element node. |
- * REMOVED: |
- * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) |
- * return; |
- */ |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: node %s\n", node->name)); |
-#endif |
- copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0); |
- ctxt->insert = copy; |
- if (comp->use != NULL) { |
- xsltApplyAttributeSet(ctxt, node, inst, comp->use); |
- } |
- break; |
- case XML_ATTRIBUTE_NODE: { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: attribute %s\n", node->name)); |
-#endif |
- /* |
- * REVISIT: We could also raise an error if the parent is not |
- * an element node. |
- * OPTIMIZE TODO: Can we set the value/children of the |
- * attribute without an intermediate copy of the string value? |
- */ |
- xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); |
- break; |
- } |
- case XML_PI_NODE: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: PI %s\n", node->name)); |
-#endif |
- copy = xmlNewDocPI(ctxt->insert->doc, node->name, |
- node->content); |
- copy = xsltAddChild(ctxt->insert, copy); |
- break; |
- case XML_COMMENT_NODE: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: comment\n")); |
-#endif |
- copy = xmlNewComment(node->content); |
- copy = xsltAddChild(ctxt->insert, copy); |
- break; |
- case XML_NAMESPACE_DECL: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopy: namespace declaration\n")); |
-#endif |
- xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); |
- break; |
- default: |
- break; |
- |
- } |
- } |
- |
- switch (node->type) { |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- case XML_ELEMENT_NODE: |
- xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, |
- NULL); |
- break; |
- default: |
- break; |
- } |
- ctxt->insert = oldInsert; |
-} |
- |
-/** |
- * xsltText: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt text node |
- * @comp: precomputed information |
- * |
- * Process the xslt text node on the source node |
- */ |
-void |
-xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, |
- xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { |
- if ((inst->children != NULL) && (comp != NULL)) { |
- xmlNodePtr text = inst->children; |
- xmlNodePtr copy; |
- |
- while (text != NULL) { |
- if ((text->type != XML_TEXT_NODE) && |
- (text->type != XML_CDATA_SECTION_NODE)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:text content problem\n"); |
- break; |
- } |
- copy = xmlNewDocText(ctxt->output, text->content); |
- if (text->type != XML_CDATA_SECTION_NODE) { |
-#ifdef WITH_XSLT_DEBUG_PARSING |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Disable escaping: %s\n", text->content); |
-#endif |
- copy->name = xmlStringTextNoenc; |
- } |
- copy = xsltAddChild(ctxt->insert, copy); |
- text = text->next; |
- } |
- } |
-} |
- |
-/** |
- * xsltElement: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt element node |
- * @castedComp: precomputed information |
- * |
- * Process the xslt element node on the source node |
- */ |
-void |
-xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) { |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xmlChar *prop = NULL; |
- const xmlChar *name, *prefix = NULL, *nsName = NULL; |
- xmlNodePtr copy; |
- xmlNodePtr oldInsert; |
- |
- if (ctxt->insert == NULL) |
- return; |
- |
- /* |
- * A comp->has_name == 0 indicates that we need to skip this instruction, |
- * since it was evaluated to be invalid already during compilation. |
- */ |
- if (!comp->has_name) |
- return; |
- |
- /* |
- * stack and saves |
- */ |
- oldInsert = ctxt->insert; |
- |
- if (comp->name == NULL) { |
- /* TODO: fix attr acquisition wrt to the XSLT namespace */ |
- prop = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "name", XSLT_NAMESPACE); |
- if (prop == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element: The attribute 'name' is missing.\n"); |
- goto error; |
- } |
- if (xmlValidateQName(prop, 0)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element: The effective name '%s' is not a " |
- "valid QName.\n", prop); |
- /* we fall through to catch any further errors, if possible */ |
- } |
- name = xsltSplitQName(ctxt->dict, prop, &prefix); |
- xmlFree(prop); |
- } else { |
- /* |
- * The "name" value was static. |
- */ |
-#ifdef XSLT_REFACTORED |
- prefix = comp->nsPrefix; |
- name = comp->name; |
-#else |
- name = xsltSplitQName(ctxt->dict, comp->name, &prefix); |
-#endif |
- } |
- |
- /* |
- * Create the new element |
- */ |
- if (ctxt->output->dict == ctxt->dict) { |
- copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); |
- } else { |
- copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL); |
- } |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element : creation of %s failed\n", name); |
- return; |
- } |
- copy = xsltAddChild(ctxt->insert, copy); |
- if (copy == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element : xsltAddChild failed\n"); |
- return; |
- } |
- |
- /* |
- * Namespace |
- * --------- |
- */ |
- if (comp->has_ns) { |
- if (comp->ns != NULL) { |
- /* |
- * No AVT; just plain text for the namespace name. |
- */ |
- if (comp->ns[0] != 0) |
- nsName = comp->ns; |
- } else { |
- xmlChar *tmpNsName; |
- /* |
- * Eval the AVT. |
- */ |
- /* TODO: check attr acquisition wrt to the XSLT namespace */ |
- tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *) "namespace", XSLT_NAMESPACE); |
- /* |
- * SPEC XSLT 1.0: |
- * "If the string is empty, then the expanded-name of the |
- * attribute has a null namespace URI." |
- */ |
- if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) |
- nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); |
- xmlFree(tmpNsName); |
- } |
- |
- if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " |
- "forbidden.\n"); |
- goto error; |
- } |
- if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { |
- prefix = BAD_CAST "xml"; |
- } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { |
- prefix = NULL; |
- } |
- } else { |
- xmlNsPtr ns; |
- /* |
- * SPEC XSLT 1.0: |
- * "If the namespace attribute is not present, then the QName is |
- * expanded into an expanded-name using the namespace declarations |
- * in effect for the xsl:element element, including any default |
- * namespace declaration. |
- */ |
- ns = xmlSearchNs(inst->doc, inst, prefix); |
- if (ns == NULL) { |
- /* |
- * TODO: Check this in the compilation layer in case it's a |
- * static value. |
- */ |
- if (prefix != NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element: The QName '%s:%s' has no " |
- "namespace binding in scope in the stylesheet; " |
- "this is an error, since the namespace was not " |
- "specified by the instruction itself.\n", prefix, name); |
- } |
- } else |
- nsName = ns->href; |
- } |
- /* |
- * Find/create a matching ns-decl in the result tree. |
- */ |
- if (nsName != NULL) { |
- if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { |
- /* Don't use a prefix of "xmlns" */ |
- xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); |
- |
- copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy); |
- |
- xmlFree(pref); |
- } else { |
- copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, |
- copy); |
- } |
- } else if ((copy->parent != NULL) && |
- (copy->parent->type == XML_ELEMENT_NODE) && |
- (copy->parent->ns != NULL)) |
- { |
- /* |
- * "Undeclare" the default namespace. |
- */ |
- xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy); |
- } |
- |
- ctxt->insert = copy; |
- |
- if (comp->has_use) { |
- if (comp->use != NULL) { |
- xsltApplyAttributeSet(ctxt, node, inst, comp->use); |
- } else { |
- xmlChar *attrSets = NULL; |
- /* |
- * BUG TODO: use-attribute-sets is not a value template. |
- * use-attribute-sets = qnames |
- */ |
- attrSets = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *)"use-attribute-sets", NULL); |
- if (attrSets != NULL) { |
- xsltApplyAttributeSet(ctxt, node, inst, attrSets); |
- xmlFree(attrSets); |
- } |
- } |
- } |
- /* |
- * Instantiate the sequence constructor. |
- */ |
- if (inst->children != NULL) |
- xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, |
- NULL); |
- |
-error: |
- ctxt->insert = oldInsert; |
- return; |
-} |
- |
- |
-/** |
- * xsltComment: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt comment node |
- * @comp: precomputed information |
- * |
- * Process the xslt comment node on the source node |
- */ |
-void |
-xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { |
- xmlChar *value = NULL; |
- xmlNodePtr commentNode; |
- int len; |
- |
- value = xsltEvalTemplateString(ctxt, node, inst); |
- /* TODO: use or generate the compiled form */ |
- len = xmlStrlen(value); |
- if (len > 0) { |
- if ((value[len-1] == '-') || |
- (xmlStrstr(value, BAD_CAST "--"))) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:comment : '--' or ending '-' not allowed in comment\n"); |
- /* fall through to try to catch further errors */ |
- } |
- } |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (value == NULL) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltComment: empty\n")); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltComment: content %s\n", value)); |
- } |
-#endif |
- |
- commentNode = xmlNewComment(value); |
- commentNode = xsltAddChild(ctxt->insert, commentNode); |
- |
- if (value != NULL) |
- xmlFree(value); |
-} |
- |
-/** |
- * xsltProcessingInstruction: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt processing-instruction node |
- * @castedComp: precomputed information |
- * |
- * Process the xslt processing-instruction node on the source node |
- */ |
-void |
-xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) { |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- const xmlChar *name; |
- xmlChar *value = NULL; |
- xmlNodePtr pi; |
- |
- |
- if (ctxt->insert == NULL) |
- return; |
- if (comp->has_name == 0) |
- return; |
- if (comp->name == NULL) { |
- name = xsltEvalAttrValueTemplate(ctxt, inst, |
- (const xmlChar *)"name", NULL); |
- if (name == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:processing-instruction : name is missing\n"); |
- goto error; |
- } |
- } else { |
- name = comp->name; |
- } |
- /* TODO: check that it's both an an NCName and a PITarget. */ |
- |
- |
- value = xsltEvalTemplateString(ctxt, node, inst); |
- if (xmlStrstr(value, BAD_CAST "?>") != NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:processing-instruction: '?>' not allowed within PI content\n"); |
- goto error; |
- } |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (value == NULL) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessingInstruction: %s empty\n", name)); |
- } else { |
- XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltProcessingInstruction: %s content %s\n", name, value)); |
- } |
-#endif |
- |
- pi = xmlNewDocPI(ctxt->insert->doc, name, value); |
- pi = xsltAddChild(ctxt->insert, pi); |
- |
-error: |
- if ((name != NULL) && (name != comp->name)) |
- xmlFree((xmlChar *) name); |
- if (value != NULL) |
- xmlFree(value); |
-} |
- |
-/** |
- * xsltCopyOf: |
- * @ctxt: an XSLT transformation context |
- * @node: the current node in the source tree |
- * @inst: the element node of the XSLT copy-of instruction |
- * @castedComp: precomputed information of the XSLT copy-of instruction |
- * |
- * Process the XSLT copy-of instruction. |
- */ |
-void |
-xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) { |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xmlXPathObjectPtr res = NULL; |
- xmlNodeSetPtr list = NULL; |
- int i; |
- |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) |
- return; |
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:copy-of : compilation failed\n"); |
- return; |
- } |
- |
- /* |
- * SPEC XSLT 1.0: |
- * "The xsl:copy-of element can be used to insert a result tree |
- * fragment into the result tree, without first converting it to |
- * a string as xsl:value-of does (see [7.6.1 Generating Text with |
- * xsl:value-of]). The required select attribute contains an |
- * expression. When the result of evaluating the expression is a |
- * result tree fragment, the complete fragment is copied into the |
- * result tree. When the result is a node-set, all the nodes in the |
- * set are copied in document order into the result tree; copying |
- * an element node copies the attribute nodes, namespace nodes and |
- * children of the element node as well as the element node itself; |
- * a root node is copied by copying its children. When the result |
- * is neither a node-set nor a result tree fragment, the result is |
- * converted to a string and then inserted into the result tree, |
- * as with xsl:value-of. |
- */ |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyOf: select %s\n", comp->select)); |
-#endif |
- |
- /* |
- * Evaluate the "select" expression. |
- */ |
- res = xsltPreCompEval(ctxt, node, comp); |
- |
- if (res != NULL) { |
- if (res->type == XPATH_NODESET) { |
- /* |
- * Node-set |
- * -------- |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyOf: result is a node set\n")); |
-#endif |
- list = res->nodesetval; |
- if (list != NULL) { |
- xmlNodePtr cur; |
- /* |
- * The list is already sorted in document order by XPath. |
- * Append everything in this order under ctxt->insert. |
- */ |
- for (i = 0;i < list->nodeNr;i++) { |
- cur = list->nodeTab[i]; |
- if (cur == NULL) |
- continue; |
- if ((cur->type == XML_DOCUMENT_NODE) || |
- (cur->type == XML_HTML_DOCUMENT_NODE)) |
- { |
- xsltCopyTreeList(ctxt, inst, |
- cur->children, ctxt->insert, 0, 0); |
- } else if (cur->type == XML_ATTRIBUTE_NODE) { |
- xsltShallowCopyAttr(ctxt, inst, |
- ctxt->insert, (xmlAttrPtr) cur); |
- } else { |
- xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0); |
- } |
- } |
- } |
- } else if (res->type == XPATH_XSLT_TREE) { |
- /* |
- * Result tree fragment |
- * -------------------- |
- * E.g. via <xsl:variable ...><foo/></xsl:variable> |
- * Note that the root node of such trees is an xmlDocPtr in Libxslt. |
- */ |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyOf: result is a result tree fragment\n")); |
-#endif |
- list = res->nodesetval; |
- if ((list != NULL) && (list->nodeTab != NULL) && |
- (list->nodeTab[0] != NULL) && |
- (IS_XSLT_REAL_NODE(list->nodeTab[0]))) |
- { |
- xsltCopyTreeList(ctxt, inst, |
- list->nodeTab[0]->children, ctxt->insert, 0, 0); |
- } |
- } else { |
- xmlChar *value = NULL; |
- /* |
- * Convert to a string. |
- */ |
- value = xmlXPathCastToString(res); |
- if (value == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltCopyOf(): " |
- "failed to cast an XPath object to string.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- } else { |
- if (value[0] != 0) { |
- /* |
- * Append content as text node. |
- */ |
- xsltCopyTextString(ctxt, ctxt->insert, value, 0); |
- } |
- xmlFree(value); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltCopyOf: result %s\n", res->stringval)); |
-#endif |
- } |
- } |
- } else { |
- ctxt->state = XSLT_STATE_STOPPED; |
- } |
- |
- if (res != NULL) |
- xmlXPathFreeObject(res); |
-} |
- |
-/** |
- * xsltValueOf: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt value-of node |
- * @castedComp: precomputed information |
- * |
- * Process the xslt value-of node on the source node |
- */ |
-void |
-xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xmlXPathObjectPtr res = NULL; |
- xmlChar *value = NULL; |
- |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) |
- return; |
- |
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltValueOf(): " |
- "The XSLT 'value-of' instruction was not compiled.\n"); |
- return; |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltValueOf: select %s\n", comp->select)); |
-#endif |
- |
- res = xsltPreCompEval(ctxt, node, comp); |
- |
- /* |
- * Cast the XPath object to string. |
- */ |
- if (res != NULL) { |
- value = xmlXPathCastToString(res); |
- if (value == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltValueOf(): " |
- "failed to cast an XPath object to string.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- if (value[0] != 0) { |
- xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape); |
- } |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "XPath evaluation returned no result.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (value) { |
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltValueOf: result '%s'\n", value)); |
- } |
-#endif |
- |
-error: |
- if (value != NULL) |
- xmlFree(value); |
- if (res != NULL) |
- xmlXPathFreeObject(res); |
-} |
- |
-/** |
- * xsltNumber: |
- * @ctxt: a XSLT process context |
- * @node: the node in the source tree. |
- * @inst: the xslt number node |
- * @castedComp: precomputed information |
- * |
- * Process the xslt number node on the source node |
- */ |
-void |
-xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xmlXPathContextPtr xpctxt; |
- xmlNsPtr *oldXPNamespaces; |
- int oldXPNsNr; |
- |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:number : compilation failed\n"); |
- return; |
- } |
- |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) |
- return; |
- |
- comp->numdata.doc = inst->doc; |
- comp->numdata.node = inst; |
- |
- xpctxt = ctxt->xpathCtxt; |
- oldXPNsNr = xpctxt->nsNr; |
- oldXPNamespaces = xpctxt->namespaces; |
- |
-#ifdef XSLT_REFACTORED |
- if (comp->inScopeNs != NULL) { |
- xpctxt->namespaces = comp->inScopeNs->list; |
- xpctxt->nsNr = comp->inScopeNs->xpathNumber; |
- } else { |
- xpctxt->namespaces = NULL; |
- xpctxt->nsNr = 0; |
- } |
-#else |
- xpctxt->namespaces = comp->nsList; |
- xpctxt->nsNr = comp->nsNr; |
-#endif |
- |
- xsltNumberFormat(ctxt, &comp->numdata, node); |
- |
- xpctxt->nsNr = oldXPNsNr; |
- xpctxt->namespaces = oldXPNamespaces; |
-} |
- |
-/** |
- * xsltApplyImports: |
- * @ctxt: an XSLT transformation context |
- * @contextNode: the current node in the source tree. |
- * @inst: the element node of the XSLT 'apply-imports' instruction |
- * @comp: the compiled instruction |
- * |
- * Process the XSLT apply-imports element. |
- */ |
-void |
-xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, |
- xmlNodePtr inst, |
- xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) |
-{ |
- xsltTemplatePtr templ; |
- |
- if ((ctxt == NULL) || (inst == NULL)) |
- return; |
- |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltApplyImports(): " |
- "The XSLT 'apply-imports' instruction was not compiled.\n"); |
- return; |
- } |
- /* |
- * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the |
- * same; the former is the "Current Template Rule" as defined by the |
- * XSLT spec, the latter is simply the template struct being |
- * currently processed. |
- */ |
- if (ctxt->currentTemplateRule == NULL) { |
- /* |
- * SPEC XSLT 2.0: |
- * "[ERR XTDE0560] It is a non-recoverable dynamic error if |
- * xsl:apply-imports or xsl:next-match is evaluated when the |
- * current template rule is null." |
- */ |
- xsltTransformError(ctxt, NULL, inst, |
- "It is an error to call 'apply-imports' " |
- "when there's no current template rule.\n"); |
- return; |
- } |
- /* |
- * TODO: Check if this is correct. |
- */ |
- templ = xsltGetTemplate(ctxt, contextNode, |
- ctxt->currentTemplateRule->style); |
- |
- if (templ != NULL) { |
- xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule; |
- /* |
- * Set the current template rule. |
- */ |
- ctxt->currentTemplateRule = templ; |
- /* |
- * URGENT TODO: Need xsl:with-param be handled somehow here? |
- */ |
- xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, |
- templ, NULL); |
- |
- ctxt->currentTemplateRule = oldCurTemplRule; |
- } |
- else { |
- /* Use built-in templates. */ |
- xsltDefaultProcessOneNode(ctxt, contextNode, NULL); |
- } |
-} |
- |
-/** |
- * xsltCallTemplate: |
- * @ctxt: a XSLT transformation context |
- * @node: the "current node" in the source tree |
- * @inst: the XSLT 'call-template' instruction |
- * @castedComp: the compiled information of the instruction |
- * |
- * Processes the XSLT call-template instruction on the source node. |
- */ |
-void |
-xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemCallTemplatePtr comp = |
- (xsltStyleItemCallTemplatePtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- xsltStackElemPtr withParams = NULL; |
- |
- if (ctxt->insert == NULL) |
- return; |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "The XSLT 'call-template' instruction was not compiled.\n"); |
- return; |
- } |
- |
- /* |
- * The template must have been precomputed |
- */ |
- if (comp->templ == NULL) { |
- comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns); |
- if (comp->templ == NULL) { |
- if (comp->ns != NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "The called template '{%s}%s' was not found.\n", |
- comp->ns, comp->name); |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "The called template '%s' was not found.\n", |
- comp->name); |
- } |
- return; |
- } |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if ((comp != NULL) && (comp->name != NULL)) |
- XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "call-template: name %s\n", comp->name)); |
-#endif |
- |
- if (inst->children) { |
- xmlNodePtr cur; |
- xsltStackElemPtr param; |
- |
- cur = inst->children; |
- while (cur != NULL) { |
-#ifdef WITH_DEBUGGER |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(cur, node, comp->templ, ctxt); |
-#endif |
- if (ctxt->state == XSLT_STATE_STOPPED) break; |
- /* |
- * TODO: The "with-param"s could be part of the "call-template" |
- * structure. Avoid to "search" for params dynamically |
- * in the XML tree every time. |
- */ |
- if (IS_XSLT_ELEM(cur)) { |
- if (IS_XSLT_NAME(cur, "with-param")) { |
- param = xsltParseStylesheetCallerParam(ctxt, cur); |
- if (param != NULL) { |
- param->next = withParams; |
- withParams = param; |
- } |
- } else { |
- xsltGenericError(xsltGenericErrorContext, |
- "xsl:call-template: misplaced xsl:%s\n", cur->name); |
- } |
- } else { |
- xsltGenericError(xsltGenericErrorContext, |
- "xsl:call-template: misplaced %s element\n", cur->name); |
- } |
- cur = cur->next; |
- } |
- } |
- /* |
- * Create a new frame using the params first |
- */ |
- xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ, |
- withParams); |
- if (withParams != NULL) |
- xsltFreeStackElemList(withParams); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if ((comp != NULL) && (comp->name != NULL)) |
- XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, |
- "call-template returned: name %s\n", comp->name)); |
-#endif |
-} |
- |
-/** |
- * xsltApplyTemplates: |
- * @ctxt: a XSLT transformation context |
- * @node: the 'current node' in the source tree |
- * @inst: the element node of an XSLT 'apply-templates' instruction |
- * @castedComp: the compiled instruction |
- * |
- * Processes the XSLT 'apply-templates' instruction on the current node. |
- */ |
-void |
-xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemApplyTemplatesPtr comp = |
- (xsltStyleItemApplyTemplatesPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- int i; |
- xmlNodePtr cur, delNode = NULL, oldContextNode; |
- xmlNodeSetPtr list = NULL, oldList; |
- xsltStackElemPtr withParams = NULL; |
- int oldXPProximityPosition, oldXPContextSize; |
- const xmlChar *oldMode, *oldModeURI; |
- xmlDocPtr oldXPDoc; |
- xsltDocumentPtr oldDocInfo; |
- xmlXPathContextPtr xpctxt; |
- |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:apply-templates : compilation failed\n"); |
- return; |
- } |
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) |
- return; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if ((node != NULL) && (node->name != NULL)) |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: node: '%s'\n", node->name)); |
-#endif |
- |
- xpctxt = ctxt->xpathCtxt; |
- /* |
- * Save context states. |
- */ |
- oldContextNode = ctxt->node; |
- oldMode = ctxt->mode; |
- oldModeURI = ctxt->modeURI; |
- oldDocInfo = ctxt->document; |
- oldList = ctxt->nodeList; |
- |
- /* |
- * The xpath context size and proximity position, as |
- * well as the xpath and context documents, may be changed |
- * so we save their initial state and will restore on exit |
- */ |
- oldXPContextSize = xpctxt->contextSize; |
- oldXPProximityPosition = xpctxt->proximityPosition; |
- oldXPDoc = xpctxt->doc; |
- |
- /* |
- * Set up contexts. |
- */ |
- ctxt->mode = comp->mode; |
- ctxt->modeURI = comp->modeURI; |
- |
- if (comp->select != NULL) { |
- xmlXPathObjectPtr res = NULL; |
- |
- if (comp->comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:apply-templates : compilation failed\n"); |
- goto error; |
- } |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: select %s\n", comp->select)); |
-#endif |
- |
- res = xsltPreCompEval(ctxt, node, comp); |
- |
- if (res != NULL) { |
- if (res->type == XPATH_NODESET) { |
- list = res->nodesetval; /* consume the node set */ |
- res->nodesetval = NULL; |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "The 'select' expression did not evaluate to a " |
- "node set.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- xmlXPathFreeObject(res); |
- goto error; |
- } |
- xmlXPathFreeObject(res); |
- /* |
- * Note: An xsl:apply-templates with a 'select' attribute, |
- * can change the current source doc. |
- */ |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "Failed to evaluate the 'select' expression.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- if (list == NULL) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: select didn't evaluate to a node list\n")); |
-#endif |
- goto exit; |
- } |
- /* |
- * |
- * NOTE: Previously a document info (xsltDocument) was |
- * created and attached to the Result Tree Fragment. |
- * But such a document info is created on demand in |
- * xsltKeyFunction() (functions.c), so we need to create |
- * it here beforehand. |
- * In order to take care of potential keys we need to |
- * do some extra work for the case when a Result Tree Fragment |
- * is converted into a nodeset (e.g. exslt:node-set()) : |
- * We attach a "pseudo-doc" (xsltDocument) to _private. |
- * This xsltDocument, together with the keyset, will be freed |
- * when the Result Tree Fragment is freed. |
- * |
- */ |
-#if 0 |
- if ((ctxt->nbKeys > 0) && |
- (list->nodeNr != 0) && |
- (list->nodeTab[0]->doc != NULL) && |
- XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc)) |
- { |
- /* |
- * NOTE that it's also OK if @effectiveDocInfo will be |
- * set to NULL. |
- */ |
- isRTF = 1; |
- effectiveDocInfo = list->nodeTab[0]->doc->_private; |
- } |
-#endif |
- } else { |
- /* |
- * Build an XPath node set with the children |
- */ |
- list = xmlXPathNodeSetCreate(NULL); |
- if (list == NULL) |
- goto error; |
- if (node->type != XML_NAMESPACE_DECL) |
- cur = node->children; |
- else |
- cur = NULL; |
- while (cur != NULL) { |
- switch (cur->type) { |
- case XML_TEXT_NODE: |
- if ((IS_BLANK_NODE(cur)) && |
- (cur->parent != NULL) && |
- (cur->parent->type == XML_ELEMENT_NODE) && |
- (ctxt->style->stripSpaces != NULL)) { |
- const xmlChar *val; |
- |
- if (cur->parent->ns != NULL) { |
- val = (const xmlChar *) |
- xmlHashLookup2(ctxt->style->stripSpaces, |
- cur->parent->name, |
- cur->parent->ns->href); |
- if (val == NULL) { |
- val = (const xmlChar *) |
- xmlHashLookup2(ctxt->style->stripSpaces, |
- BAD_CAST "*", |
- cur->parent->ns->href); |
- } |
- } else { |
- val = (const xmlChar *) |
- xmlHashLookup2(ctxt->style->stripSpaces, |
- cur->parent->name, NULL); |
- } |
- if ((val != NULL) && |
- (xmlStrEqual(val, (xmlChar *) "strip"))) { |
- delNode = cur; |
- break; |
- } |
- } |
- /* no break on purpose */ |
- case XML_ELEMENT_NODE: |
- case XML_DOCUMENT_NODE: |
- case XML_HTML_DOCUMENT_NODE: |
- case XML_CDATA_SECTION_NODE: |
- case XML_PI_NODE: |
- case XML_COMMENT_NODE: |
- xmlXPathNodeSetAddUnique(list, cur); |
- break; |
- case XML_DTD_NODE: |
- /* Unlink the DTD, it's still reachable |
- * using doc->intSubset */ |
- if (cur->next != NULL) |
- cur->next->prev = cur->prev; |
- if (cur->prev != NULL) |
- cur->prev->next = cur->next; |
- break; |
- case XML_NAMESPACE_DECL: |
- break; |
- default: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: skipping cur type %d\n", |
- cur->type)); |
-#endif |
- delNode = cur; |
- } |
- cur = cur->next; |
- if (delNode != NULL) { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: removing ignorable blank cur\n")); |
-#endif |
- xmlUnlinkNode(delNode); |
- xmlFreeNode(delNode); |
- delNode = NULL; |
- } |
- } |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- if (list != NULL) |
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyTemplates: list of %d nodes\n", list->nodeNr)); |
-#endif |
- |
- if ((list == NULL) || (list->nodeNr == 0)) |
- goto exit; |
- |
- /* |
- * Set the context's node set and size; this is also needed for |
- * for xsltDoSortFunction(). |
- */ |
- ctxt->nodeList = list; |
- /* |
- * Process xsl:with-param and xsl:sort instructions. |
- * (The code became so verbose just to avoid the |
- * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort) |
- * BUG TODO: We are not using namespaced potentially defined on the |
- * xsl:sort or xsl:with-param elements; XPath expression might fail. |
- */ |
- if (inst->children) { |
- xsltStackElemPtr param; |
- |
- cur = inst->children; |
- while (cur) { |
- |
-#ifdef WITH_DEBUGGER |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(cur, node, NULL, ctxt); |
-#endif |
- if (ctxt->state == XSLT_STATE_STOPPED) |
- break; |
- if (cur->type == XML_TEXT_NODE) { |
- cur = cur->next; |
- continue; |
- } |
- if (! IS_XSLT_ELEM(cur)) |
- break; |
- if (IS_XSLT_NAME(cur, "with-param")) { |
- param = xsltParseStylesheetCallerParam(ctxt, cur); |
- if (param != NULL) { |
- param->next = withParams; |
- withParams = param; |
- } |
- } |
- if (IS_XSLT_NAME(cur, "sort")) { |
- xsltTemplatePtr oldCurTempRule = |
- ctxt->currentTemplateRule; |
- int nbsorts = 0; |
- xmlNodePtr sorts[XSLT_MAX_SORT]; |
- |
- sorts[nbsorts++] = cur; |
- |
- while (cur) { |
- |
-#ifdef WITH_DEBUGGER |
- if (ctxt->debugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(cur, node, NULL, ctxt); |
-#endif |
- if (ctxt->state == XSLT_STATE_STOPPED) |
- break; |
- |
- if (cur->type == XML_TEXT_NODE) { |
- cur = cur->next; |
- continue; |
- } |
- |
- if (! IS_XSLT_ELEM(cur)) |
- break; |
- if (IS_XSLT_NAME(cur, "with-param")) { |
- param = xsltParseStylesheetCallerParam(ctxt, cur); |
- if (param != NULL) { |
- param->next = withParams; |
- withParams = param; |
- } |
- } |
- if (IS_XSLT_NAME(cur, "sort")) { |
- if (nbsorts >= XSLT_MAX_SORT) { |
- xsltTransformError(ctxt, NULL, cur, |
- "The number (%d) of xsl:sort instructions exceeds the " |
- "maximum allowed by this processor's settings.\n", |
- nbsorts); |
- ctxt->state = XSLT_STATE_STOPPED; |
- break; |
- } else { |
- sorts[nbsorts++] = cur; |
- } |
- } |
- cur = cur->next; |
- } |
- /* |
- * The "current template rule" is cleared for xsl:sort. |
- */ |
- ctxt->currentTemplateRule = NULL; |
- /* |
- * Sort. |
- */ |
- xsltDoSortFunction(ctxt, sorts, nbsorts); |
- ctxt->currentTemplateRule = oldCurTempRule; |
- break; |
- } |
- cur = cur->next; |
- } |
- } |
- xpctxt->contextSize = list->nodeNr; |
- /* |
- * Apply templates for all selected source nodes. |
- */ |
- for (i = 0; i < list->nodeNr; i++) { |
- cur = list->nodeTab[i]; |
- /* |
- * The node becomes the "current node". |
- */ |
- ctxt->node = cur; |
- /* |
- * An xsl:apply-templates can change the current context doc. |
- * OPTIMIZE TODO: Get rid of the need to set the context doc. |
- */ |
- if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) |
- xpctxt->doc = cur->doc; |
- |
- xpctxt->proximityPosition = i + 1; |
- /* |
- * Find and apply a template for this node. |
- */ |
- xsltProcessOneNode(ctxt, cur, withParams); |
- } |
- |
-exit: |
-error: |
- /* |
- * Free the parameter list. |
- */ |
- if (withParams != NULL) |
- xsltFreeStackElemList(withParams); |
- if (list != NULL) |
- xmlXPathFreeNodeSet(list); |
- /* |
- * Restore context states. |
- */ |
- xpctxt->doc = oldXPDoc; |
- xpctxt->contextSize = oldXPContextSize; |
- xpctxt->proximityPosition = oldXPProximityPosition; |
- |
- ctxt->document = oldDocInfo; |
- ctxt->nodeList = oldList; |
- ctxt->node = oldContextNode; |
- ctxt->mode = oldMode; |
- ctxt->modeURI = oldModeURI; |
-} |
- |
- |
-/** |
- * xsltChoose: |
- * @ctxt: a XSLT process context |
- * @contextNode: the current node in the source tree |
- * @inst: the xsl:choose instruction |
- * @comp: compiled information of the instruction |
- * |
- * Processes the xsl:choose instruction on the source node. |
- */ |
-void |
-xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, |
- xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) |
-{ |
- xmlNodePtr cur; |
- |
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) |
- return; |
- |
- /* |
- * TODO: Content model checks should be done only at compilation |
- * time. |
- */ |
- cur = inst->children; |
- if (cur == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:choose: The instruction has no content.\n"); |
- return; |
- } |
- |
-#ifdef XSLT_REFACTORED |
- /* |
- * We don't check the content model during transformation. |
- */ |
-#else |
- if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:choose: xsl:when expected first\n"); |
- return; |
- } |
-#endif |
- |
- { |
- int testRes = 0, res = 0; |
- |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemWhenPtr wcomp = NULL; |
-#else |
- xsltStylePreCompPtr wcomp = NULL; |
-#endif |
- |
- /* |
- * Process xsl:when --------------------------------------------------- |
- */ |
- while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { |
- wcomp = cur->psvi; |
- |
- if ((wcomp == NULL) || (wcomp->test == NULL) || |
- (wcomp->comp == NULL)) |
- { |
- xsltTransformError(ctxt, NULL, cur, |
- "Internal error in xsltChoose(): " |
- "The XSLT 'when' instruction was not compiled.\n"); |
- goto error; |
- } |
- |
- |
-#ifdef WITH_DEBUGGER |
- if (xslDebugStatus != XSLT_DEBUG_NONE) { |
- /* |
- * TODO: Isn't comp->templ always NULL for xsl:choose? |
- */ |
- xslHandleDebugger(cur, contextNode, NULL, ctxt); |
- } |
-#endif |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltChoose: test %s\n", wcomp->test)); |
-#endif |
- |
-#ifdef XSLT_FAST_IF |
- res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp); |
- |
- if (res == -1) { |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- testRes = (res == 1) ? 1 : 0; |
- |
-#else /* XSLT_FAST_IF */ |
- |
- res = xsltPreCompEval(ctxt, cotextNode, wcomp); |
- |
- if (res != NULL) { |
- if (res->type != XPATH_BOOLEAN) |
- res = xmlXPathConvertBoolean(res); |
- if (res->type == XPATH_BOOLEAN) |
- testRes = res->boolval; |
- else { |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltChoose: test didn't evaluate to a boolean\n")); |
-#endif |
- goto error; |
- } |
- xmlXPathFreeObject(res); |
- res = NULL; |
- } else { |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- |
-#endif /* else of XSLT_FAST_IF */ |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltChoose: test evaluate to %d\n", testRes)); |
-#endif |
- if (testRes) |
- goto test_is_true; |
- |
- cur = cur->next; |
- } |
- |
- /* |
- * Process xsl:otherwise ---------------------------------------------- |
- */ |
- if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) { |
- |
-#ifdef WITH_DEBUGGER |
- if (xslDebugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(cur, contextNode, NULL, ctxt); |
-#endif |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, |
- "evaluating xsl:otherwise\n")); |
-#endif |
- goto test_is_true; |
- } |
- goto exit; |
- |
-test_is_true: |
- |
- goto process_sequence; |
- } |
- |
-process_sequence: |
- |
- /* |
- * Instantiate the sequence constructor. |
- */ |
- xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children, |
- NULL); |
- |
-exit: |
-error: |
- return; |
-} |
- |
-/** |
- * xsltIf: |
- * @ctxt: a XSLT process context |
- * @contextNode: the current node in the source tree |
- * @inst: the xsl:if instruction |
- * @castedComp: compiled information of the instruction |
- * |
- * Processes the xsl:if instruction on the source node. |
- */ |
-void |
-xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
- int res = 0; |
- |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- |
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) |
- return; |
- if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltIf(): " |
- "The XSLT 'if' instruction was not compiled.\n"); |
- return; |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltIf: test %s\n", comp->test)); |
-#endif |
- |
-#ifdef XSLT_FAST_IF |
- { |
- xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; |
- |
- res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp); |
- |
- /* |
- * Cleanup fragments created during evaluation of the |
- * "select" expression. |
- */ |
- if (oldLocalFragmentTop != ctxt->localRVT) |
- xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); |
- } |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltIf: test evaluate to %d\n", res)); |
-#endif |
- |
- if (res == -1) { |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- if (res == 1) { |
- /* |
- * Instantiate the sequence constructor of xsl:if. |
- */ |
- xsltApplySequenceConstructor(ctxt, |
- contextNode, inst->children, NULL); |
- } |
- |
-#else /* XSLT_FAST_IF */ |
- { |
- /* |
- * OLD CODE: |
- */ |
- xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp); |
- if (xpobj != NULL) { |
- if (xpobj->type != XPATH_BOOLEAN) |
- xpobj = xmlXPathConvertBoolean(xpobj); |
- if (xpobj->type == XPATH_BOOLEAN) { |
- res = xpobj->boolval; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltIf: test evaluate to %d\n", res)); |
-#endif |
- if (res) { |
- xsltApplySequenceConstructor(ctxt, |
- contextNode, inst->children, NULL); |
- } |
- } else { |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt, XSLT_TRACE_IF, |
- xsltGenericDebug(xsltGenericDebugContext, |
- "xsltIf: test didn't evaluate to a boolean\n")); |
-#endif |
- ctxt->state = XSLT_STATE_STOPPED; |
- } |
- xmlXPathFreeObject(xpobj); |
- } else { |
- ctxt->state = XSLT_STATE_STOPPED; |
- } |
- } |
-#endif /* else of XSLT_FAST_IF */ |
- |
-error: |
- return; |
-} |
- |
-/** |
- * xsltForEach: |
- * @ctxt: an XSLT transformation context |
- * @contextNode: the "current node" in the source tree |
- * @inst: the element node of the xsl:for-each instruction |
- * @castedComp: the compiled information of the instruction |
- * |
- * Process the xslt for-each node on the source node |
- */ |
-void |
-xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, |
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) |
-{ |
-#ifdef XSLT_REFACTORED |
- xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp; |
-#else |
- xsltStylePreCompPtr comp = castedComp; |
-#endif |
- int i; |
- xmlXPathObjectPtr res = NULL; |
- xmlNodePtr cur, curInst; |
- xmlNodeSetPtr list = NULL; |
- xmlNodeSetPtr oldList; |
- int oldXPProximityPosition, oldXPContextSize; |
- xmlNodePtr oldContextNode; |
- xsltTemplatePtr oldCurTemplRule; |
- xmlDocPtr oldXPDoc; |
- xsltDocumentPtr oldDocInfo; |
- xmlXPathContextPtr xpctxt; |
- |
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) { |
- xsltGenericError(xsltGenericErrorContext, |
- "xsltForEach(): Bad arguments.\n"); |
- return; |
- } |
- |
- if (comp == NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltForEach(): " |
- "The XSLT 'for-each' instruction was not compiled.\n"); |
- return; |
- } |
- if ((comp->select == NULL) || (comp->comp == NULL)) { |
- xsltTransformError(ctxt, NULL, inst, |
- "Internal error in xsltForEach(): " |
- "The selecting expression of the XSLT 'for-each' " |
- "instruction was not compiled correctly.\n"); |
- return; |
- } |
- xpctxt = ctxt->xpathCtxt; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltForEach: select %s\n", comp->select)); |
-#endif |
- |
- /* |
- * Save context states. |
- */ |
- oldDocInfo = ctxt->document; |
- oldList = ctxt->nodeList; |
- oldContextNode = ctxt->node; |
- /* |
- * The "current template rule" is cleared for the instantiation of |
- * xsl:for-each. |
- */ |
- oldCurTemplRule = ctxt->currentTemplateRule; |
- ctxt->currentTemplateRule = NULL; |
- |
- oldXPDoc = xpctxt->doc; |
- oldXPProximityPosition = xpctxt->proximityPosition; |
- oldXPContextSize = xpctxt->contextSize; |
- |
- /* |
- * Evaluate the 'select' expression. |
- */ |
- res = xsltPreCompEval(ctxt, contextNode, comp); |
- |
- if (res != NULL) { |
- if (res->type == XPATH_NODESET) |
- list = res->nodesetval; |
- else { |
- xsltTransformError(ctxt, NULL, inst, |
- "The 'select' expression does not evaluate to a node set.\n"); |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltForEach: select didn't evaluate to a node list\n")); |
-#endif |
- goto error; |
- } |
- } else { |
- xsltTransformError(ctxt, NULL, inst, |
- "Failed to evaluate the 'select' expression.\n"); |
- ctxt->state = XSLT_STATE_STOPPED; |
- goto error; |
- } |
- |
- if ((list == NULL) || (list->nodeNr <= 0)) |
- goto exit; |
- |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltForEach: select evaluates to %d nodes\n", list->nodeNr)); |
-#endif |
- |
- /* |
- * Set the list; this has to be done already here for xsltDoSortFunction(). |
- */ |
- ctxt->nodeList = list; |
- /* |
- * Handle xsl:sort instructions and skip them for further processing. |
- * BUG TODO: We are not using namespaced potentially defined on the |
- * xsl:sort element; XPath expression might fail. |
- */ |
- curInst = inst->children; |
- if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { |
- int nbsorts = 0; |
- xmlNodePtr sorts[XSLT_MAX_SORT]; |
- |
- sorts[nbsorts++] = curInst; |
- |
-#ifdef WITH_DEBUGGER |
- if (xslDebugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(curInst, contextNode, NULL, ctxt); |
-#endif |
- |
- curInst = curInst->next; |
- while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { |
- if (nbsorts >= XSLT_MAX_SORT) { |
- xsltTransformError(ctxt, NULL, curInst, |
- "The number of xsl:sort instructions exceeds the " |
- "maximum (%d) allowed by this processor.\n", |
- XSLT_MAX_SORT); |
- goto error; |
- } else { |
- sorts[nbsorts++] = curInst; |
- } |
- |
-#ifdef WITH_DEBUGGER |
- if (xslDebugStatus != XSLT_DEBUG_NONE) |
- xslHandleDebugger(curInst, contextNode, NULL, ctxt); |
-#endif |
- curInst = curInst->next; |
- } |
- xsltDoSortFunction(ctxt, sorts, nbsorts); |
- } |
- xpctxt->contextSize = list->nodeNr; |
- /* |
- * Instantiate the sequence constructor for each selected node. |
- */ |
- for (i = 0; i < list->nodeNr; i++) { |
- cur = list->nodeTab[i]; |
- /* |
- * The selected node becomes the "current node". |
- */ |
- ctxt->node = cur; |
- /* |
- * An xsl:for-each can change the current context doc. |
- * OPTIMIZE TODO: Get rid of the need to set the context doc. |
- */ |
- if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) |
- xpctxt->doc = cur->doc; |
- |
- xpctxt->proximityPosition = i + 1; |
- |
- xsltApplySequenceConstructor(ctxt, cur, curInst, NULL); |
- } |
- |
-exit: |
-error: |
- if (res != NULL) |
- xmlXPathFreeObject(res); |
- /* |
- * Restore old states. |
- */ |
- ctxt->document = oldDocInfo; |
- ctxt->nodeList = oldList; |
- ctxt->node = oldContextNode; |
- ctxt->currentTemplateRule = oldCurTemplRule; |
- |
- xpctxt->doc = oldXPDoc; |
- xpctxt->contextSize = oldXPContextSize; |
- xpctxt->proximityPosition = oldXPProximityPosition; |
-} |
- |
-/************************************************************************ |
- * * |
- * Generic interface * |
- * * |
- ************************************************************************/ |
- |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
-typedef struct xsltHTMLVersion { |
- const char *version; |
- const char *public; |
- const char *system; |
-} xsltHTMLVersion; |
- |
-static xsltHTMLVersion xsltHTMLVersions[] = { |
- { "5", NULL, "about:legacy-compat" }, |
- { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", |
- "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, |
- { "4.01strict", "-//W3C//DTD HTML 4.01//EN", |
- "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"}, |
- { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN", |
- "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, |
- { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN", |
- "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, |
- { "4.0strict", "-//W3C//DTD HTML 4.01//EN", |
- "http://www.w3.org/TR/html4/strict.dtd"}, |
- { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN", |
- "http://www.w3.org/TR/html4/loose.dtd"}, |
- { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN", |
- "http://www.w3.org/TR/html4/frameset.dtd"}, |
- { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN", |
- "http://www.w3.org/TR/html4/loose.dtd"}, |
- { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL } |
-}; |
- |
-/** |
- * xsltGetHTMLIDs: |
- * @version: the version string |
- * @publicID: used to return the public ID |
- * @systemID: used to return the system ID |
- * |
- * Returns -1 if not found, 0 otherwise and the system and public |
- * Identifier for this given verion of HTML |
- */ |
-static int |
-xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, |
- const xmlChar **systemID) { |
- unsigned int i; |
- if (version == NULL) |
- return(-1); |
- for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1])); |
- i++) { |
- if (!xmlStrcasecmp(version, |
- (const xmlChar *) xsltHTMLVersions[i].version)) { |
- if (publicID != NULL) |
- *publicID = (const xmlChar *) xsltHTMLVersions[i].public; |
- if (systemID != NULL) |
- *systemID = (const xmlChar *) xsltHTMLVersions[i].system; |
- return(0); |
- } |
- } |
- return(-1); |
-} |
-#endif |
- |
-/** |
- * xsltApplyStripSpaces: |
- * @ctxt: a XSLT process context |
- * @node: the root of the XML tree |
- * |
- * Strip the unwanted ignorable spaces from the input tree |
- */ |
-void |
-xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) { |
- xmlNodePtr current; |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- int nb = 0; |
-#endif |
- |
- |
- current = node; |
- while (current != NULL) { |
- /* |
- * Cleanup children empty nodes if asked for |
- */ |
- if ((IS_XSLT_REAL_NODE(current)) && |
- (current->children != NULL) && |
- (xsltFindElemSpaceHandling(ctxt, current))) { |
- xmlNodePtr delete = NULL, cur = current->children; |
- |
- while (cur != NULL) { |
- if (IS_BLANK_NODE(cur)) |
- delete = cur; |
- |
- cur = cur->next; |
- if (delete != NULL) { |
- xmlUnlinkNode(delete); |
- xmlFreeNode(delete); |
- delete = NULL; |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- nb++; |
-#endif |
- } |
- } |
- } |
- |
- /* |
- * Skip to next node in document order. |
- */ |
- if (node->type == XML_ENTITY_REF_NODE) { |
- /* process deep in entities */ |
- xsltApplyStripSpaces(ctxt, node->children); |
- } |
- if ((current->children != NULL) && |
- (current->type != XML_ENTITY_REF_NODE)) { |
- current = current->children; |
- } else if (current->next != NULL) { |
- current = current->next; |
- } else { |
- do { |
- current = current->parent; |
- if (current == NULL) |
- break; |
- if (current == node) |
- goto done; |
- if (current->next != NULL) { |
- current = current->next; |
- break; |
- } |
- } while (current != NULL); |
- } |
- } |
- |
-done: |
-#ifdef WITH_XSLT_DEBUG_PROCESS |
- XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext, |
- "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb)); |
-#endif |
- return; |
-} |
- |
-static int |
-xsltCountKeys(xsltTransformContextPtr ctxt) |
-{ |
- xsltStylesheetPtr style; |
- xsltKeyDefPtr keyd; |
- |
- if (ctxt == NULL) |
- return(-1); |
- |
- /* |
- * Do we have those nastly templates with a key() in the match pattern? |
- */ |
- ctxt->hasTemplKeyPatterns = 0; |
- style = ctxt->style; |
- while (style != NULL) { |
- if (style->keyMatch != NULL) { |
- ctxt->hasTemplKeyPatterns = 1; |
- break; |
- } |
- style = xsltNextImport(style); |
- } |
- /* |
- * Count number of key declarations. |
- */ |
- ctxt->nbKeys = 0; |
- style = ctxt->style; |
- while (style != NULL) { |
- keyd = style->keys; |
- while (keyd) { |
- ctxt->nbKeys++; |
- keyd = keyd->next; |
- } |
- style = xsltNextImport(style); |
- } |
- return(ctxt->nbKeys); |
-} |
- |
-/** |
- * xsltApplyStylesheetInternal: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated array of parameters names/values tuples |
- * @output: the targetted output |
- * @profile: profile FILE * output or NULL |
- * @user: user provided parameter |
- * |
- * Apply the stylesheet to the document |
- * NOTE: This may lead to a non-wellformed output XML wise ! |
- * |
- * Returns the result document or NULL in case of error |
- */ |
-static xmlDocPtr |
-xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params, const char *output, |
- FILE * profile, xsltTransformContextPtr userCtxt) |
-{ |
- xmlDocPtr res = NULL; |
- xsltTransformContextPtr ctxt = NULL; |
- xmlNodePtr root, node; |
- const xmlChar *method; |
- const xmlChar *doctypePublic; |
- const xmlChar *doctypeSystem; |
- const xmlChar *version; |
- const xmlChar *encoding; |
- xsltStackElemPtr variables; |
- xsltStackElemPtr vptr; |
- |
- xsltInitGlobals(); |
- |
- if ((style == NULL) || (doc == NULL)) |
- return (NULL); |
- |
- if (style->internalized == 0) { |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "Stylesheet was not fully internalized !\n"); |
-#endif |
- } |
- if (doc->intSubset != NULL) { |
- /* |
- * Avoid hitting the DTD when scanning nodes |
- * but keep it linked as doc->intSubset |
- */ |
- xmlNodePtr cur = (xmlNodePtr) doc->intSubset; |
- if (cur->next != NULL) |
- cur->next->prev = cur->prev; |
- if (cur->prev != NULL) |
- cur->prev->next = cur->next; |
- if (doc->children == cur) |
- doc->children = cur->next; |
- if (doc->last == cur) |
- doc->last = cur->prev; |
- cur->prev = cur->next = NULL; |
- } |
- |
- /* |
- * Check for XPath document order availability |
- */ |
- root = xmlDocGetRootElement(doc); |
- if (root != NULL) { |
- if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE)) |
- xmlXPathOrderDocElems(doc); |
- } |
- |
- if (userCtxt != NULL) |
- ctxt = userCtxt; |
- else |
- ctxt = xsltNewTransformContext(style, doc); |
- |
- if (ctxt == NULL) |
- return (NULL); |
- |
- ctxt->initialContextDoc = doc; |
- ctxt->initialContextNode = (xmlNodePtr) doc; |
- |
- if (profile != NULL) |
- ctxt->profile = 1; |
- |
- if (output != NULL) |
- ctxt->outputFile = output; |
- else |
- ctxt->outputFile = NULL; |
- |
- /* |
- * internalize the modes if needed |
- */ |
- if (ctxt->dict != NULL) { |
- if (ctxt->mode != NULL) |
- ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1); |
- if (ctxt->modeURI != NULL) |
- ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1); |
- } |
- |
- XSLT_GET_IMPORT_PTR(method, style, method) |
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) |
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) |
- XSLT_GET_IMPORT_PTR(version, style, version) |
- XSLT_GET_IMPORT_PTR(encoding, style, encoding) |
- |
- if ((method != NULL) && |
- (!xmlStrEqual(method, (const xmlChar *) "xml"))) |
- { |
- if (xmlStrEqual(method, (const xmlChar *) "html")) { |
- ctxt->type = XSLT_OUTPUT_HTML; |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { |
- res = htmlNewDoc(doctypeSystem, doctypePublic); |
- } else { |
- if (version == NULL) { |
- xmlDtdPtr dtd; |
- |
- res = htmlNewDoc(NULL, NULL); |
- /* |
- * Make sure no DTD node is generated in this case |
- */ |
- if (res != NULL) { |
- dtd = xmlGetIntSubset(res); |
- if (dtd != NULL) { |
- xmlUnlinkNode((xmlNodePtr) dtd); |
- xmlFreeDtd(dtd); |
- } |
- res->intSubset = NULL; |
- res->extSubset = NULL; |
- } |
- } else { |
- |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
- xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); |
-#endif |
- res = htmlNewDoc(doctypeSystem, doctypePublic); |
- } |
- } |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
- |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { |
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, |
- "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n"); |
- ctxt->type = XSLT_OUTPUT_HTML; |
- res = htmlNewDoc(doctypeSystem, doctypePublic); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
- |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } else if (xmlStrEqual(method, (const xmlChar *) "text")) { |
- ctxt->type = XSLT_OUTPUT_TEXT; |
- res = xmlNewDoc(style->version); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(res->dict); |
- |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } else { |
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, |
- "xsltApplyStylesheetInternal: unsupported method (%s)\n", |
- method); |
- goto error; |
- } |
- } else { |
- ctxt->type = XSLT_OUTPUT_XML; |
- res = xmlNewDoc(style->version); |
- if (res == NULL) |
- goto error; |
- res->dict = ctxt->dict; |
- xmlDictReference(ctxt->dict); |
-#ifdef WITH_XSLT_DEBUG |
- xsltGenericDebug(xsltGenericDebugContext, |
- "reusing transformation dict for output\n"); |
-#endif |
- } |
- res->charset = XML_CHAR_ENCODING_UTF8; |
- if (encoding != NULL) |
- res->encoding = xmlStrdup(encoding); |
- variables = style->variables; |
- |
- /* |
- * Start the evaluation, evaluate the params, the stylesheets globals |
- * and start by processing the top node. |
- */ |
- if (xsltNeedElemSpaceHandling(ctxt)) |
- xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); |
- /* |
- * Evaluate global params and user-provided params. |
- */ |
- ctxt->node = (xmlNodePtr) doc; |
- if (ctxt->globalVars == NULL) |
- ctxt->globalVars = xmlHashCreate(20); |
- if (params != NULL) { |
- xsltEvalUserParams(ctxt, params); |
- } |
- |
- /* need to be called before evaluating global variables */ |
- xsltCountKeys(ctxt); |
- |
- xsltEvalGlobalVariables(ctxt); |
- |
- /* Clean up any unused RVTs. */ |
- xsltReleaseLocalRVTs(ctxt, NULL); |
- |
- ctxt->node = (xmlNodePtr) doc; |
- ctxt->output = res; |
- ctxt->insert = (xmlNodePtr) res; |
- ctxt->varsBase = ctxt->varsNr - 1; |
- |
- ctxt->xpathCtxt->contextSize = 1; |
- ctxt->xpathCtxt->proximityPosition = 1; |
- ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */ |
- /* |
- * Start processing the source tree ----------------------------------- |
- */ |
- xsltProcessOneNode(ctxt, ctxt->node, NULL); |
- /* |
- * Remove all remaining vars from the stack. |
- */ |
- xsltLocalVariablePop(ctxt, 0, -2); |
- xsltShutdownCtxtExts(ctxt); |
- |
- xsltCleanupTemplates(style); /* TODO: <- style should be read only */ |
- |
- /* |
- * Now cleanup our variables so stylesheet can be re-used |
- * |
- * TODO: this is not needed anymore global variables are copied |
- * and not evaluated directly anymore, keep this as a check |
- */ |
- if (style->variables != variables) { |
- vptr = style->variables; |
- while (vptr->next != variables) |
- vptr = vptr->next; |
- vptr->next = NULL; |
- xsltFreeStackElemList(style->variables); |
- style->variables = variables; |
- } |
- vptr = style->variables; |
- while (vptr != NULL) { |
- if (vptr->computed) { |
- if (vptr->value != NULL) { |
- xmlXPathFreeObject(vptr->value); |
- vptr->value = NULL; |
- vptr->computed = 0; |
- } |
- } |
- vptr = vptr->next; |
- } |
-#if 0 |
- /* |
- * code disabled by wmb; awaiting kb's review |
- * problem is that global variable(s) may contain xpath objects |
- * from doc associated with RVT, so can't be freed at this point. |
- * xsltFreeTransformContext includes a call to xsltFreeRVTs, so |
- * I assume this shouldn't be required at this point. |
- */ |
- /* |
- * Free all remaining tree fragments. |
- */ |
- xsltFreeRVTs(ctxt); |
-#endif |
- /* |
- * Do some post processing work depending on the generated output |
- */ |
- root = xmlDocGetRootElement(res); |
- if (root != NULL) { |
- const xmlChar *doctype = NULL; |
- |
- if ((root->ns != NULL) && (root->ns->prefix != NULL)) |
- doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); |
- if (doctype == NULL) |
- doctype = root->name; |
- |
- /* |
- * Apply the default selection of the method |
- */ |
- if ((method == NULL) && |
- (root->ns == NULL) && |
- (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { |
- xmlNodePtr tmp; |
- |
- tmp = res->children; |
- while ((tmp != NULL) && (tmp != root)) { |
- if (tmp->type == XML_ELEMENT_NODE) |
- break; |
- if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) |
- break; |
- tmp = tmp->next; |
- } |
- if (tmp == root) { |
- ctxt->type = XSLT_OUTPUT_HTML; |
- /* |
- * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the |
- * transformation on the doc, but functions like |
- */ |
- res->type = XML_HTML_DOCUMENT_NODE; |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { |
- res->intSubset = xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
-#ifdef XSLT_GENERATE_HTML_DOCTYPE |
- } else if (version != NULL) { |
- xsltGetHTMLIDs(version, &doctypePublic, |
- &doctypeSystem); |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) |
- res->intSubset = |
- xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
-#endif |
- } |
- } |
- |
- } |
- if (ctxt->type == XSLT_OUTPUT_XML) { |
- XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) |
- XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) |
- if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { |
- xmlNodePtr last; |
- /* Need a small "hack" here to assure DTD comes before |
- possible comment nodes */ |
- node = res->children; |
- last = res->last; |
- res->children = NULL; |
- res->last = NULL; |
- res->intSubset = xmlCreateIntSubset(res, doctype, |
- doctypePublic, |
- doctypeSystem); |
- if (res->children != NULL) { |
- res->children->next = node; |
- node->prev = res->children; |
- res->last = last; |
- } else { |
- res->children = node; |
- res->last = last; |
- } |
- } |
- } |
- } |
- xmlXPathFreeNodeSet(ctxt->nodeList); |
- if (profile != NULL) { |
- xsltSaveProfiling(ctxt, profile); |
- } |
- |
- /* |
- * Be pedantic. |
- */ |
- if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) { |
- xmlFreeDoc(res); |
- res = NULL; |
- } |
- if ((res != NULL) && (ctxt != NULL) && (output != NULL)) { |
- int ret; |
- |
- ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output); |
- if (ret == 0) { |
- xsltTransformError(ctxt, NULL, NULL, |
- "xsltApplyStylesheet: forbidden to save to %s\n", |
- output); |
- } else if (ret < 0) { |
- xsltTransformError(ctxt, NULL, NULL, |
- "xsltApplyStylesheet: saving to %s may not be possible\n", |
- output); |
- } |
- } |
- |
-#ifdef XSLT_DEBUG_PROFILE_CACHE |
- printf("# Cache:\n"); |
- printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); |
- printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); |
-#endif |
- |
- if ((ctxt != NULL) && (userCtxt == NULL)) |
- xsltFreeTransformContext(ctxt); |
- |
- return (res); |
- |
-error: |
- if (res != NULL) |
- xmlFreeDoc(res); |
- |
-#ifdef XSLT_DEBUG_PROFILE_CACHE |
- printf("# Cache:\n"); |
- printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); |
- printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); |
-#endif |
- |
- if ((ctxt != NULL) && (userCtxt == NULL)) |
- xsltFreeTransformContext(ctxt); |
- return (NULL); |
-} |
- |
-/** |
- * xsltApplyStylesheet: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated arry of parameters names/values tuples |
- * |
- * Apply the stylesheet to the document |
- * NOTE: This may lead to a non-wellformed output XML wise ! |
- * |
- * Returns the result document or NULL in case of error |
- */ |
-xmlDocPtr |
-xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params) |
-{ |
- return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL)); |
-} |
- |
-/** |
- * xsltProfileStylesheet: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated arry of parameters names/values tuples |
- * @output: a FILE * for the profiling output |
- * |
- * Apply the stylesheet to the document and dump the profiling to |
- * the given output. |
- * |
- * Returns the result document or NULL in case of error |
- */ |
-xmlDocPtr |
-xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params, FILE * output) |
-{ |
- xmlDocPtr res; |
- |
- res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL); |
- return (res); |
-} |
- |
-/** |
- * xsltApplyStylesheetUser: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated array of parameters names/values tuples |
- * @output: the targetted output |
- * @profile: profile FILE * output or NULL |
- * @userCtxt: user provided transform context |
- * |
- * Apply the stylesheet to the document and allow the user to provide |
- * its own transformation context. |
- * |
- * Returns the result document or NULL in case of error |
- */ |
-xmlDocPtr |
-xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params, const char *output, |
- FILE * profile, xsltTransformContextPtr userCtxt) |
-{ |
- xmlDocPtr res; |
- |
- res = xsltApplyStylesheetInternal(style, doc, params, output, |
- profile, userCtxt); |
- return (res); |
-} |
- |
-/** |
- * xsltRunStylesheetUser: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated array of parameters names/values tuples |
- * @output: the URL/filename ot the generated resource if available |
- * @SAX: a SAX handler for progressive callback output (not implemented yet) |
- * @IObuf: an output buffer for progressive output (not implemented yet) |
- * @profile: profile FILE * output or NULL |
- * @userCtxt: user provided transform context |
- * |
- * Apply the stylesheet to the document and generate the output according |
- * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. |
- * |
- * NOTE: This may lead to a non-wellformed output XML wise ! |
- * NOTE: This may also result in multiple files being generated |
- * NOTE: using IObuf, the result encoding used will be the one used for |
- * creating the output buffer, use the following macro to read it |
- * from the stylesheet |
- * XSLT_GET_IMPORT_PTR(encoding, style, encoding) |
- * NOTE: using SAX, any encoding specified in the stylesheet will be lost |
- * since the interface uses only UTF8 |
- * |
- * Returns the number of by written to the main resource or -1 in case of |
- * error. |
- */ |
-int |
-xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params, const char *output, |
- xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf, |
- FILE * profile, xsltTransformContextPtr userCtxt) |
-{ |
- xmlDocPtr tmp; |
- int ret; |
- |
- if ((output == NULL) && (SAX == NULL) && (IObuf == NULL)) |
- return (-1); |
- if ((SAX != NULL) && (IObuf != NULL)) |
- return (-1); |
- |
- /* unsupported yet */ |
- if (SAX != NULL) { |
- XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */ |
- return (-1); |
- } |
- |
- tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile, |
- userCtxt); |
- if (tmp == NULL) { |
- xsltTransformError(NULL, NULL, (xmlNodePtr) doc, |
- "xsltRunStylesheet : run failed\n"); |
- return (-1); |
- } |
- if (IObuf != NULL) { |
- /* TODO: incomplete, IObuf output not progressive */ |
- ret = xsltSaveResultTo(IObuf, tmp, style); |
- } else { |
- ret = xsltSaveResultToFilename(output, tmp, style, 0); |
- } |
- xmlFreeDoc(tmp); |
- return (ret); |
-} |
- |
-/** |
- * xsltRunStylesheet: |
- * @style: a parsed XSLT stylesheet |
- * @doc: a parsed XML document |
- * @params: a NULL terminated array of parameters names/values tuples |
- * @output: the URL/filename ot the generated resource if available |
- * @SAX: a SAX handler for progressive callback output (not implemented yet) |
- * @IObuf: an output buffer for progressive output (not implemented yet) |
- * |
- * Apply the stylesheet to the document and generate the output according |
- * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. |
- * |
- * NOTE: This may lead to a non-wellformed output XML wise ! |
- * NOTE: This may also result in multiple files being generated |
- * NOTE: using IObuf, the result encoding used will be the one used for |
- * creating the output buffer, use the following macro to read it |
- * from the stylesheet |
- * XSLT_GET_IMPORT_PTR(encoding, style, encoding) |
- * NOTE: using SAX, any encoding specified in the stylesheet will be lost |
- * since the interface uses only UTF8 |
- * |
- * Returns the number of bytes written to the main resource or -1 in case of |
- * error. |
- */ |
-int |
-xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, |
- const char **params, const char *output, |
- xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf) |
-{ |
- return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf, |
- NULL, NULL)); |
-} |
- |
-/** |
- * xsltRegisterAllElement: |
- * @ctxt: the XPath context |
- * |
- * Registers all default XSLT elements in this context |
- */ |
-void |
-xsltRegisterAllElement(xsltTransformContextPtr ctxt) |
-{ |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltApplyTemplates); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltApplyImports); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltCallTemplate); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "element", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltElement); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltAttribute); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "text", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltText); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltProcessingInstruction); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "comment", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltComment); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "copy", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltCopy); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltValueOf); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "number", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltNumber); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltForEach); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "if", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltIf); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "choose", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltChoose); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "sort", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltSort); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltCopyOf); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "message", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltMessage); |
- |
- /* |
- * Those don't have callable entry points but are registered anyway |
- */ |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "variable", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "param", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "when", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback", |
- XSLT_NAMESPACE, |
- (xsltTransformFunction) xsltDebug); |
- |
-} |