+Fri Jul 14 17:55:42 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+ * libxslt/attributes.c libxslt/documents.c
+ libxslt/functions.c libxslt/keys.c libxslt/namespaces.c
+ libxslt/pattern.c libxslt/preproc.c libxslt/templates.c
+ libxslt/templates.h libxslt/transform.c libxslt/variables.c
+ libxslt/xslt.c libxslt/xsltInternals.h libxslt/xsltutils.c
+ libxslt/xsltutils.h libexslt/common.c libexslt/dynamic.c
+ libexslt/functions.c libexslt/strings.c:
+ Refactored xsltValueOf(). Changed to use xmlXPathCastToString()
+ directly, rather than creating an intermediate object with
+ xmlXPathConvertString(). This now does not add a text-node to
+ the result if the string is empty (this has impact on
+ serialization, since an empty text-node is serialized as
+ <foo></foo>, and now it will be serialized as <foo/>).
+ Refactored other functions in transform.c:
+ Mostly code cleanup/restructuring. Minimized number of
+ function variables for instruction which eat up function stack
+ memory when recursing templates (xsltIf(), xsltChoose(),
+ xsltApplyTemplates(), xsltCallTemplate()).
+ Changed XSLT tests to use xmlXPathCompiledEvalToBoolean().
+ Implemented redefinition checks at compilation-time and
+ eliminating them at transformation time in the refactored code
+ paths.
+ Introduced the field @currentTemplateRule on xsltTransformContext to
+ reflect the "Current Template Rule" as defined by the spec.
+ 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 by Libxslt.
+ Added XML_COMMENT_NODE and XML_CDATA_SECTION_NODE to the macro
+ IS_XSLT_REAL_NODE.
+ Misc code cleanup/restructuring and everything else I already forgot.
+ Refactored lifetime of temporary result tree fragments.
+ Substituted all calls to the now deprecated xsltRegisterTmpRVT()
+ for the new xsltRegisterLocalRVT().
+ Fragments of xsl:variable and xsl:param are freed when the
+ variable/pram is freed.
+ Fragments created when evaluating a "select" of xsl:varible and
+ xsl:param are also bound to the lifetime of the var/param.
+ EXSLT's func:function now uses the following functions to let take
+ care the transformation's garbage collector of returned tree
+ fragments:
+ xsltExtensionInstructionResultRegister(),
+ xsltExtensionInstructionResultFinalize()
+ Fixes:
+ #339222 - xsl:param at invalid position inside an xsl:template is
+ not catched
+ #346015 - Non-declared caller-parameters are accepted
+ #160400 - Compiles invalid XSLT; unbound variable accepted
+ #308441 - namespaced parameters become unregistered
+ #307103 - problem with proximity position in predicates of match
+ patterns
+ #328218 - problem with exsl:node-set() when converting strings
+ to node sets
+ #318088 - infinite recursion detection
+ #321505 - Multiple contiguous CDATA in output
+ #334493 - "--param" option does not have root context
+ #114377 - weird func:result/xsl:variable/exsl:node-set interaction
+ #150309 - Regression caused by fix for 142768
+
Wed Jun 21 15:13:27 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* tests/docs/bug-54.xml tests/general/bug-54.out
-#define IN_LIBEXSLT
-#include "libexslt/libexslt.h"
-
-#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
-#include <win32config.h>
-#else
-#include "config.h"
-#endif
-
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-
-#include <libxslt/xsltconfig.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/extensions.h>
-#include <libxslt/transform.h>
-#include <libxslt/extra.h>
-#include <libxslt/preproc.h>
-
-#include "exslt.h"
-
-static void
-exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlChar *strval;
- xmlNodePtr retNode;
- xmlXPathObjectPtr ret;
-
- if (nargs != 1) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (xmlXPathStackIsNodeSet (ctxt)) {
- xsltFunctionNodeSet (ctxt, nargs);
- return;
- }
-
- strval = xmlXPathPopString (ctxt);
- retNode = xmlNewDocText (NULL, strval);
- ret = xmlXPathNewValueTree (retNode);
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltNodeSetFunction: ret == NULL\n");
- } else {
- ret->type = XPATH_NODESET;
- }
-
- if (strval != NULL)
- xmlFree (strval);
-
- valuePush (ctxt, ret);
-}
-
-static void
-exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlXPathObjectPtr obj, ret;
-
- if (nargs != 1) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- obj = valuePop(ctxt);
-
- switch (obj->type) {
- case XPATH_STRING:
- ret = xmlXPathNewCString("string");
- break;
- case XPATH_NUMBER:
- ret = xmlXPathNewCString("number");
- break;
- case XPATH_BOOLEAN:
- ret = xmlXPathNewCString("boolean");
- break;
- case XPATH_NODESET:
- ret = xmlXPathNewCString("node-set");
- break;
- case XPATH_XSLT_TREE:
- ret = xmlXPathNewCString("RTF");
- break;
- case XPATH_USERS:
- ret = xmlXPathNewCString("external");
- break;
- default:
- xsltGenericError(xsltGenericErrorContext,
- "object-type() invalid arg\n");
- ctxt->error = XPATH_INVALID_TYPE;
- xmlXPathFreeObject(obj);
- return;
- }
- xmlXPathFreeObject(obj);
- valuePush(ctxt, ret);
-}
-
-
-/**
- * exsltCommonRegister:
- *
- * Registers the EXSLT - Common module
- */
-
-void
-exsltCommonRegister (void) {
- xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
- EXSLT_COMMON_NAMESPACE,
- exsltNodeSetFunction);
- xsltRegisterExtModuleFunction((const xmlChar *) "object-type",
- EXSLT_COMMON_NAMESPACE,
- exsltObjectTypeFunction);
- xsltRegisterExtModuleElement((const xmlChar *) "document",
- EXSLT_COMMON_NAMESPACE,
- (xsltPreComputeFunction) xsltDocumentComp,
- (xsltTransformFunction) xsltDocumentElem);
-}
+#define IN_LIBEXSLT\r
+#include "libexslt/libexslt.h"\r
+\r
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)\r
+#include <win32config.h>\r
+#else\r
+#include "config.h"\r
+#endif\r
+\r
+#include <libxml/tree.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+\r
+#include <libxslt/xsltconfig.h>\r
+#include <libxslt/xsltutils.h>\r
+#include <libxslt/xsltInternals.h>\r
+#include <libxslt/extensions.h>\r
+#include <libxslt/transform.h>\r
+#include <libxslt/extra.h>\r
+#include <libxslt/preproc.h>\r
+\r
+#include "exslt.h"\r
+\r
+static void\r
+exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ if (nargs != 1) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+ if (xmlXPathStackIsNodeSet (ctxt)) {\r
+ xsltFunctionNodeSet (ctxt, nargs);\r
+ return;\r
+ } else {\r
+ xmlDocPtr fragment;\r
+ xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);\r
+ xmlNodePtr txt;\r
+ xmlChar *strval;\r
+ xmlXPathObjectPtr obj;\r
+ /*\r
+ * SPEC EXSLT:\r
+ * "You can also use this function to turn a string into a text\r
+ * node, which is helpful if you want to pass a string to a\r
+ * function that only accepts a node-set."\r
+ */\r
+ fragment = xsltCreateRVT(tctxt);\r
+ if (fragment == NULL) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "exsltNodeSetFunction: Failed to create a tree fragment.\n");\r
+ tctxt->state = XSLT_STATE_STOPPED; \r
+ return;\r
+ }\r
+ xsltRegisterLocalRVT(tctxt, fragment);\r
+\r
+ strval = xmlXPathPopString (ctxt);\r
+ \r
+ txt = xmlNewDocText (fragment, strval);\r
+ xmlAddChild((xmlNodePtr) fragment, txt);\r
+ obj = xmlXPathNewNodeSet(txt); \r
+ if (obj == NULL) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "exsltNodeSetFunction: Failed to create a node set object.\n");\r
+ tctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+ if (strval != NULL)\r
+ xmlFree (strval);\r
+ \r
+ valuePush (ctxt, obj);\r
+ }\r
+}\r
+\r
+static void\r
+exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xmlXPathObjectPtr obj, ret;\r
+\r
+ if (nargs != 1) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ obj = valuePop(ctxt);\r
+\r
+ switch (obj->type) {\r
+ case XPATH_STRING:\r
+ ret = xmlXPathNewCString("string");\r
+ break;\r
+ case XPATH_NUMBER:\r
+ ret = xmlXPathNewCString("number");\r
+ break;\r
+ case XPATH_BOOLEAN:\r
+ ret = xmlXPathNewCString("boolean");\r
+ break;\r
+ case XPATH_NODESET:\r
+ ret = xmlXPathNewCString("node-set");\r
+ break;\r
+ case XPATH_XSLT_TREE:\r
+ ret = xmlXPathNewCString("RTF");\r
+ break;\r
+ case XPATH_USERS:\r
+ ret = xmlXPathNewCString("external");\r
+ break;\r
+ default:\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "object-type() invalid arg\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ xmlXPathFreeObject(obj);\r
+ return;\r
+ }\r
+ xmlXPathFreeObject(obj);\r
+ valuePush(ctxt, ret);\r
+}\r
+\r
+\r
+/**\r
+ * exsltCommonRegister:\r
+ *\r
+ * Registers the EXSLT - Common module\r
+ */\r
+\r
+void\r
+exsltCommonRegister (void) {\r
+ xsltRegisterExtModuleFunction((const xmlChar *) "node-set",\r
+ EXSLT_COMMON_NAMESPACE,\r
+ exsltNodeSetFunction);\r
+ xsltRegisterExtModuleFunction((const xmlChar *) "object-type",\r
+ EXSLT_COMMON_NAMESPACE,\r
+ exsltObjectTypeFunction);\r
+ xsltRegisterExtModuleElement((const xmlChar *) "document",\r
+ EXSLT_COMMON_NAMESPACE,\r
+ (xsltPreComputeFunction) xsltDocumentComp,\r
+ (xsltTransformFunction) xsltDocumentElem);\r
+}\r
-/*
- * dynamic.c: Implementation of the EXSLT -- Dynamic module
- *
- * References:
- * http://www.exslt.org/dyn/dyn.html
- *
- * See Copyright for the status of this software.
- *
- * Authors:
- * Mark Vakoc <mark_vakoc@jdedwards.com>
- * Thomas Broyer <tbroyer@ltgt.net>
- *
- * TODO:
- * elements:
- * functions:
- * min
- * max
- * sum
- * map
- * closure
- */
-
-#define IN_LIBEXSLT
-#include "libexslt/libexslt.h"
-
-#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
-#include <win32config.h>
-#else
-#include "config.h"
-#endif
-
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-
-#include <libxslt/xsltconfig.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/extensions.h>
-
-#include "exslt.h"
-
-/**
- * exsltDynEvaluateFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Evaluates the string as an XPath expression and returns the result
- * value, which may be a boolean, number, string, node set, result tree
- * fragment or external object.
- */
-
-static void
-exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
- xmlChar *str = NULL;
- xmlXPathObjectPtr ret = NULL;
-
- if (ctxt == NULL)
- return;
- if (nargs != 1) {
- xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
- xsltGenericError(xsltGenericErrorContext,
- "dyn:evalute() : invalid number of args %d\n", nargs);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- str = xmlXPathPopString(ctxt);
- /* return an empty node-set if an empty string is passed in */
- if (!str||!xmlStrlen(str)) {
- if (str) xmlFree(str);
- valuePush(ctxt,xmlXPathNewNodeSet(NULL));
- return;
- }
- ret = xmlXPathEval(str,ctxt->context);
- if (ret)
- valuePush(ctxt,ret);
- else {
- xsltGenericError(xsltGenericErrorContext,
- "dyn:evaluate() : unable to evaluate expression '%s'\n",str);
- valuePush(ctxt,xmlXPathNewNodeSet(NULL));
- }
- xmlFree(str);
- return;
-}
-
-/**
- * exsltDynMapFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Evaluates the string as an XPath expression and returns the result
- * value, which may be a boolean, number, string, node set, result tree
- * fragment or external object.
- */
-
-static void
-exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)
-{
- xmlChar *str = NULL;
- xmlNodeSetPtr nodeset = NULL;
- xmlXPathCompExprPtr comp = NULL;
- xmlXPathObjectPtr ret = NULL;
- xmlDocPtr oldDoc, container;
- xmlNodePtr oldNode;
- int oldContextSize;
- int oldProximityPosition;
- int i, j;
-
-
- if (nargs != 2) {
- xmlXPathSetArityError(ctxt);
- return;
- }
- str = xmlXPathPopString(ctxt);
- if (xmlXPathCheckError(ctxt)) {
- xmlXPathSetTypeError(ctxt);
- return;
- }
-
- nodeset = xmlXPathPopNodeSet(ctxt);
- if (xmlXPathCheckError(ctxt)) {
- xmlXPathSetTypeError(ctxt);
- return;
- }
- if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) {
- if (nodeset != NULL)
- xmlXPathFreeNodeSet(nodeset);
- if (str != NULL)
- xmlFree(str);
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- return;
- }
-
- ret = xmlXPathNewNodeSet(NULL);
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltDynMapFunctoin: ret == NULL\n");
- goto cleanup;
- }
-
- oldDoc = ctxt->context->doc;
- oldNode = ctxt->context->node;
- oldContextSize = ctxt->context->contextSize;
- oldProximityPosition = ctxt->context->proximityPosition;
-
- /**
- * since we really don't know we're going to be adding node(s)
- * down the road we create the RVT regardless
- */
- container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt));
- if (container != NULL)
- xsltRegisterTmpRVT(xsltXPathGetTransformContext(ctxt), container);
-
- if (nodeset && nodeset->nodeNr > 0) {
- xmlXPathNodeSetSort(nodeset);
- ctxt->context->contextSize = nodeset->nodeNr;
- ctxt->context->proximityPosition = 0;
- for (i = 0; i < nodeset->nodeNr; i++) {
- xmlXPathObjectPtr subResult = NULL;
-
- ctxt->context->proximityPosition++;
- ctxt->context->node = nodeset->nodeTab[i];
- ctxt->context->doc = nodeset->nodeTab[i]->doc;
-
- subResult = xmlXPathCompiledEval(comp, ctxt->context);
- if (subResult != NULL) {
- switch (subResult->type) {
- case XPATH_NODESET:
- if (subResult->nodesetval != NULL)
- for (j = 0; j < subResult->nodesetval->nodeNr;
- j++)
- xmlXPathNodeSetAdd(ret->nodesetval,
- subResult->nodesetval->
- nodeTab[j]);
- break;
- case XPATH_BOOLEAN:
- if (container != NULL) {
- xmlNodePtr cur =
- xmlNewChild((xmlNodePtr) container, NULL,
- BAD_CAST "boolean",
- BAD_CAST (subResult->
- boolval ? "true" : ""));
- if (cur != NULL) {
- cur->ns =
- xmlNewNs(cur,
- BAD_CAST
- "http://exslt.org/common",
- BAD_CAST "exsl");
- xmlXPathNodeSetAddUnique(ret->nodesetval,
- cur);
- }
- }
- break;
- case XPATH_NUMBER:
- if (container != NULL) {
- xmlChar *val =
- xmlXPathCastNumberToString(subResult->
- floatval);
- xmlNodePtr cur =
- xmlNewChild((xmlNodePtr) container, NULL,
- BAD_CAST "number", val);
- if (val != NULL)
- xmlFree(val);
-
- if (cur != NULL) {
- cur->ns =
- xmlNewNs(cur,
- BAD_CAST
- "http://exslt.org/common",
- BAD_CAST "exsl");
- xmlXPathNodeSetAddUnique(ret->nodesetval,
- cur);
- }
- }
- break;
- case XPATH_STRING:
- if (container != NULL) {
- xmlNodePtr cur =
- xmlNewChild((xmlNodePtr) container, NULL,
- BAD_CAST "string",
- subResult->stringval);
- if (cur != NULL) {
- cur->ns =
- xmlNewNs(cur,
- BAD_CAST
- "http://exslt.org/common",
- BAD_CAST "exsl");
- xmlXPathNodeSetAddUnique(ret->nodesetval,
- cur);
- }
- }
- break;
- default:
- break;
- }
- xmlXPathFreeObject(subResult);
- }
- }
- }
- ctxt->context->doc = oldDoc;
- ctxt->context->node = oldNode;
- ctxt->context->contextSize = oldContextSize;
- ctxt->context->proximityPosition = oldProximityPosition;
-
-
- cleanup:
- /* restore the xpath context */
- if (comp != NULL)
- xmlXPathFreeCompExpr(comp);
- if (nodeset != NULL)
- xmlXPathFreeNodeSet(nodeset);
- if (str != NULL)
- xmlFree(str);
- valuePush(ctxt, ret);
- return;
-}
-
-
-/**
- * exsltDynRegister:
- *
- * Registers the EXSLT - Dynamic module
- */
-
-void
-exsltDynRegister (void) {
- xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
- EXSLT_DYNAMIC_NAMESPACE,
- exsltDynEvaluateFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "map",
- EXSLT_DYNAMIC_NAMESPACE,
- exsltDynMapFunction);
-
-}
+/*\r
+ * dynamic.c: Implementation of the EXSLT -- Dynamic module\r
+ *\r
+ * References:\r
+ * http://www.exslt.org/dyn/dyn.html\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * Authors:\r
+ * Mark Vakoc <mark_vakoc@jdedwards.com>\r
+ * Thomas Broyer <tbroyer@ltgt.net>\r
+ *\r
+ * TODO:\r
+ * elements:\r
+ * functions:\r
+ * min\r
+ * max\r
+ * sum\r
+ * map\r
+ * closure\r
+ */\r
+\r
+#define IN_LIBEXSLT\r
+#include "libexslt/libexslt.h"\r
+\r
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)\r
+#include <win32config.h>\r
+#else\r
+#include "config.h"\r
+#endif\r
+\r
+#include <libxml/tree.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+\r
+#include <libxslt/xsltconfig.h>\r
+#include <libxslt/xsltutils.h>\r
+#include <libxslt/xsltInternals.h>\r
+#include <libxslt/extensions.h>\r
+\r
+#include "exslt.h"\r
+\r
+/**\r
+ * exsltDynEvaluateFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Evaluates the string as an XPath expression and returns the result\r
+ * value, which may be a boolean, number, string, node set, result tree\r
+ * fragment or external object.\r
+ */\r
+\r
+static void\r
+exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xmlChar *str = NULL;\r
+ xmlXPathObjectPtr ret = NULL;\r
+\r
+ if (ctxt == NULL)\r
+ return;\r
+ if (nargs != 1) {\r
+ xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "dyn:evalute() : invalid number of args %d\n", nargs);\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ str = xmlXPathPopString(ctxt);\r
+ /* return an empty node-set if an empty string is passed in */\r
+ if (!str||!xmlStrlen(str)) {\r
+ if (str) xmlFree(str);\r
+ valuePush(ctxt,xmlXPathNewNodeSet(NULL));\r
+ return;\r
+ }\r
+ ret = xmlXPathEval(str,ctxt->context);\r
+ if (ret)\r
+ valuePush(ctxt,ret);\r
+ else {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "dyn:evaluate() : unable to evaluate expression '%s'\n",str);\r
+ valuePush(ctxt,xmlXPathNewNodeSet(NULL));\r
+ } \r
+ xmlFree(str);\r
+ return;\r
+}\r
+\r
+/**\r
+ * exsltDynMapFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Evaluates the string as an XPath expression and returns the result\r
+ * value, which may be a boolean, number, string, node set, result tree\r
+ * fragment or external object.\r
+ */\r
+\r
+static void\r
+exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)\r
+{\r
+ xmlChar *str = NULL;\r
+ xmlNodeSetPtr nodeset = NULL;\r
+ xmlXPathCompExprPtr comp = NULL;\r
+ xmlXPathObjectPtr ret = NULL;\r
+ xmlDocPtr oldDoc, container;\r
+ xmlNodePtr oldNode;\r
+ int oldContextSize;\r
+ int oldProximityPosition;\r
+ int i, j;\r
+\r
+\r
+ if (nargs != 2) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+ str = xmlXPathPopString(ctxt);\r
+ if (xmlXPathCheckError(ctxt)) {\r
+ xmlXPathSetTypeError(ctxt);\r
+ return;\r
+ }\r
+\r
+ nodeset = xmlXPathPopNodeSet(ctxt);\r
+ if (xmlXPathCheckError(ctxt)) {\r
+ xmlXPathSetTypeError(ctxt);\r
+ return;\r
+ }\r
+ if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) {\r
+ if (nodeset != NULL)\r
+ xmlXPathFreeNodeSet(nodeset);\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ return;\r
+ }\r
+\r
+ ret = xmlXPathNewNodeSet(NULL);\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltDynMapFunctoin: ret == NULL\n");\r
+ goto cleanup;\r
+ }\r
+\r
+ oldDoc = ctxt->context->doc;\r
+ oldNode = ctxt->context->node;\r
+ oldContextSize = ctxt->context->contextSize;\r
+ oldProximityPosition = ctxt->context->proximityPosition;\r
+\r
+ /** \r
+ * since we really don't know we're going to be adding node(s) \r
+ * down the road we create the RVT regardless \r
+ */\r
+ container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt));\r
+ if (container != NULL)\r
+ xsltRegisterLocalRVT(xsltXPathGetTransformContext(ctxt), container);\r
+\r
+ if (nodeset && nodeset->nodeNr > 0) {\r
+ xmlXPathNodeSetSort(nodeset);\r
+ ctxt->context->contextSize = nodeset->nodeNr;\r
+ ctxt->context->proximityPosition = 0;\r
+ for (i = 0; i < nodeset->nodeNr; i++) {\r
+ xmlXPathObjectPtr subResult = NULL;\r
+\r
+ ctxt->context->proximityPosition++;\r
+ ctxt->context->node = nodeset->nodeTab[i];\r
+ ctxt->context->doc = nodeset->nodeTab[i]->doc;\r
+\r
+ subResult = xmlXPathCompiledEval(comp, ctxt->context);\r
+ if (subResult != NULL) {\r
+ switch (subResult->type) {\r
+ case XPATH_NODESET:\r
+ if (subResult->nodesetval != NULL)\r
+ for (j = 0; j < subResult->nodesetval->nodeNr;\r
+ j++)\r
+ xmlXPathNodeSetAdd(ret->nodesetval,\r
+ subResult->nodesetval->\r
+ nodeTab[j]);\r
+ break;\r
+ case XPATH_BOOLEAN:\r
+ if (container != NULL) {\r
+ xmlNodePtr cur =\r
+ xmlNewChild((xmlNodePtr) container, NULL,\r
+ BAD_CAST "boolean",\r
+ BAD_CAST (subResult->\r
+ boolval ? "true" : ""));\r
+ if (cur != NULL) {\r
+ cur->ns =\r
+ xmlNewNs(cur,\r
+ BAD_CAST\r
+ "http://exslt.org/common",\r
+ BAD_CAST "exsl");\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval,\r
+ cur);\r
+ }\r
+ }\r
+ break;\r
+ case XPATH_NUMBER:\r
+ if (container != NULL) {\r
+ xmlChar *val =\r
+ xmlXPathCastNumberToString(subResult->\r
+ floatval);\r
+ xmlNodePtr cur =\r
+ xmlNewChild((xmlNodePtr) container, NULL,\r
+ BAD_CAST "number", val);\r
+ if (val != NULL)\r
+ xmlFree(val);\r
+\r
+ if (cur != NULL) {\r
+ cur->ns =\r
+ xmlNewNs(cur,\r
+ BAD_CAST\r
+ "http://exslt.org/common",\r
+ BAD_CAST "exsl");\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval,\r
+ cur);\r
+ }\r
+ }\r
+ break;\r
+ case XPATH_STRING:\r
+ if (container != NULL) {\r
+ xmlNodePtr cur =\r
+ xmlNewChild((xmlNodePtr) container, NULL,\r
+ BAD_CAST "string",\r
+ subResult->stringval);\r
+ if (cur != NULL) {\r
+ cur->ns =\r
+ xmlNewNs(cur,\r
+ BAD_CAST\r
+ "http://exslt.org/common",\r
+ BAD_CAST "exsl");\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval,\r
+ cur);\r
+ }\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ xmlXPathFreeObject(subResult);\r
+ }\r
+ }\r
+ }\r
+ ctxt->context->doc = oldDoc;\r
+ ctxt->context->node = oldNode;\r
+ ctxt->context->contextSize = oldContextSize;\r
+ ctxt->context->proximityPosition = oldProximityPosition;\r
+\r
+\r
+ cleanup:\r
+ /* restore the xpath context */\r
+ if (comp != NULL)\r
+ xmlXPathFreeCompExpr(comp);\r
+ if (nodeset != NULL)\r
+ xmlXPathFreeNodeSet(nodeset);\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+ valuePush(ctxt, ret);\r
+ return;\r
+}\r
+\r
+\r
+/**\r
+ * exsltDynRegister:\r
+ *\r
+ * Registers the EXSLT - Dynamic module\r
+ */\r
+\r
+void\r
+exsltDynRegister (void) {\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",\r
+ EXSLT_DYNAMIC_NAMESPACE,\r
+ exsltDynEvaluateFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "map",\r
+ EXSLT_DYNAMIC_NAMESPACE,\r
+ exsltDynMapFunction);\r
+\r
+}\r
-#define IN_LIBEXSLT
-#include "libexslt/libexslt.h"
-
-#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
-#include <win32config.h>
-#else
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/hash.h>
-#include <libxml/debugXML.h>
-
-#include <libxslt/xsltutils.h>
-#include <libxslt/variables.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/extensions.h>
-#include <libxslt/transform.h>
-#include <libxslt/imports.h>
-
-#include "exslt.h"
-
-typedef struct _exsltFuncFunctionData exsltFuncFunctionData;
-struct _exsltFuncFunctionData {
- int nargs; /* number of arguments to the function */
- xmlNodePtr content; /* the func:fuction template content */
-};
-
-typedef struct _exsltFuncData exsltFuncData;
-struct _exsltFuncData {
- xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
- xmlXPathObjectPtr result; /* returned by func:result */
- int error; /* did an error occur? */
-};
-
-typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
-struct _exsltFuncResultPreComp {
- xsltElemPreComp comp;
- xmlXPathCompExprPtr select;
- xmlNsPtr *nsList;
- int nsNr;
-};
-
-/* Used for callback function in exsltInitFunc */
-typedef struct _exsltFuncImportRegData exsltFuncImportRegData;
-struct _exsltFuncImportRegData {
- xsltTransformContextPtr ctxt;
- xmlHashTablePtr hash;
-};
-
-static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
- int nargs);
-static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
-
-/**
- * exsltFuncRegisterFunc:
- * @func: the #exsltFuncFunctionData for the function
- * @ctxt: an XSLT transformation context
- * @URI: the function namespace URI
- * @name: the function name
- *
- * Registers a function declared by a func:function element
- */
-static void
-exsltFuncRegisterFunc (exsltFuncFunctionData *data,
- xsltTransformContextPtr ctxt,
- const xmlChar *URI, const xmlChar *name,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
- return;
-
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncRegisterFunc: register {%s}%s\n",
- URI, name);
- xsltRegisterExtFunction(ctxt, name, URI,
- exsltFuncFunctionFunction);
-}
-
-/*
- * exsltFuncRegisterImportFunc
- * @data: the exsltFuncFunctionData for the function
- * @ch: structure containing context and hash table
- * @URI: the function namespace URI
- * @name: the function name
- *
- * Checks if imported function is already registered in top-level
- * stylesheet. If not, copies function data and registers function
- */
-static void
-exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,
- exsltFuncImportRegData *ch,
- const xmlChar *URI, const xmlChar *name,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- exsltFuncFunctionData *func=NULL;
-
- if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))
- return;
-
- if (ch->ctxt == NULL || ch->hash == NULL)
- return;
-
- /* Check if already present */
- func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);
- if (func == NULL) { /* Not yet present - copy it in */
- func = exsltFuncNewFunctionData();
- memcpy(func, data, sizeof(exsltFuncFunctionData));
- if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {
- xsltGenericError(xsltGenericErrorContext,
- "Failed to register function {%s}%s\n",
- URI, name);
- } else { /* Do the registration */
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncRegisterImportFunc: register {%s}%s\n",
- URI, name);
- xsltRegisterExtFunction(ch->ctxt, name, URI,
- exsltFuncFunctionFunction);
- }
- }
-}
-
-/**
- * exsltFuncInit:
- * @ctxt: an XSLT transformation context
- * @URI: the namespace URI for the extension
- *
- * Initializes the EXSLT - Functions module.
- * Called at transformation-time; merges all
- * functions declared in the import tree taking
- * import precedence into account, i.e. overriding
- * functions with lower import precedence.
- *
- * Returns the data for this transformation
- */
-static exsltFuncData *
-exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
- exsltFuncData *ret;
- xsltStylesheetPtr tmp;
- exsltFuncImportRegData ch;
- xmlHashTablePtr hash;
-
- ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncInit: not enough memory\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(exsltFuncData));
-
- ret->result = NULL;
- ret->error = 0;
-
- ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
- ret->funcs = ch.hash;
- xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
- tmp = ctxt->style;
- ch.ctxt = ctxt;
- while ((tmp=xsltNextImport(tmp))!=NULL) {
- hash = xsltGetExtInfo(tmp, URI);
- if (hash != NULL) {
- xmlHashScanFull(hash,
- (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);
- }
- }
-
- return(ret);
-}
-
-/**
- * exsltFuncShutdown:
- * @ctxt: an XSLT transformation context
- * @URI: the namespace URI for the extension
- * @data: the module data to free up
- *
- * Shutdown the EXSLT - Functions module
- * Called at transformation-time.
- */
-static void
-exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED,
- exsltFuncData *data) {
- if (data->result != NULL)
- xmlXPathFreeObject(data->result);
- xmlFree(data);
-}
-
-/**
- * exsltFuncStyleInit:
- * @style: an XSLT stylesheet
- * @URI: the namespace URI for the extension
- *
- * Allocates the stylesheet data for EXSLT - Function
- * Called at compile-time.
- *
- * Returns the allocated data
- */
-static xmlHashTablePtr
-exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED) {
- return xmlHashCreate(1);
-}
-
-/**
- * exsltFuncStyleShutdown:
- * @style: an XSLT stylesheet
- * @URI: the namespace URI for the extension
- * @data: the stylesheet data to free up
- *
- * Shutdown the EXSLT - Function module
- * Called at compile-time.
- */
-static void
-exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
- const xmlChar *URI ATTRIBUTE_UNUSED,
- xmlHashTablePtr data) {
- xmlHashFree(data, (xmlHashDeallocator) xmlFree);
-}
-
-/**
- * exsltFuncNewFunctionData:
- *
- * Allocates an #exslFuncFunctionData object
- *
- * Returns the new structure
- */
-static exsltFuncFunctionData *
-exsltFuncNewFunctionData (void) {
- exsltFuncFunctionData *ret;
-
- ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncNewFunctionData: not enough memory\n");
- return (NULL);
- }
- memset(ret, 0, sizeof(exsltFuncFunctionData));
-
- ret->nargs = 0;
- ret->content = NULL;
-
- return(ret);
-}
-
-/**
- * exsltFreeFuncResultPreComp:
- * @comp: the #exsltFuncResultPreComp to free up
- *
- * Deallocates an #exsltFuncResultPreComp
- */
-static void
-exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {
- if (comp == NULL)
- return;
-
- if (comp->select != NULL)
- xmlXPathFreeCompExpr (comp->select);
- if (comp->nsList != NULL)
- xmlFree(comp->nsList);
- xmlFree(comp);
-}
-
-/**
- * exsltFuncFunctionFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Evaluates the func:function element that defines the called function.
- */
-static void
-exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlXPathObjectPtr obj, oldResult, ret;
- exsltFuncData *data;
- exsltFuncFunctionData *func;
- xmlNodePtr paramNode, oldInsert, fake, content = NULL;
- int oldBase;
- xsltStackElemPtr params = NULL, param;
- xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
- int i;
-
- /*
- * retrieve func:function template
- */
- data = (exsltFuncData *) xsltGetExtData (tctxt,
- EXSLT_FUNCTIONS_NAMESPACE);
- oldResult = data->result;
- data->result = NULL;
-
- func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,
- ctxt->context->functionURI,
- ctxt->context->function);
-
- /*
- * params handling
- */
- if (nargs > func->nargs) {
- xsltGenericError(xsltGenericErrorContext,
- "{%s}%s: called with too many arguments\n",
- ctxt->context->functionURI, ctxt->context->function);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if (func->content != NULL) {
- paramNode = func->content->prev;
- content = func->content;
- }
- else
- paramNode = NULL;
- if ((paramNode == NULL) && (func->nargs != 0)) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncFunctionFunction: nargs != 0 and "
- "param == NULL\n");
- return;
- }
-
- /* set params */
- for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
- paramNode = paramNode->prev;
- if (content != NULL)
- content = content->prev;
- }
- while ((i-- > 0) && (paramNode != NULL)) {
- obj = valuePop(ctxt);
- /* FIXME: this is a bit hackish */
- param = xsltParseStylesheetCallerParam (tctxt, paramNode);
- param->computed = 1;
- if (param->value != NULL)
- xmlXPathFreeObject(param->value);
- param->value = obj;
- param->next = params;
- params = param;
- paramNode = paramNode->prev;
- }
-
- /*
- * actual processing
- */
- fake = xmlNewDocNode(tctxt->output, NULL,
- (const xmlChar *)"fake", NULL);
- oldInsert = tctxt->insert;
- tctxt->insert = fake;
- /*
- * In order to give the function variables a new 'scope' we
- * change varsBase in the context.
- */
- oldBase = tctxt->varsBase;
- tctxt->varsBase = tctxt->varsNr;
- xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
- content, NULL, params);
- tctxt->insert = oldInsert;
- tctxt->varsBase = oldBase; /* restore original scope */
- if (params != NULL)
- xsltFreeStackElemList(params);
-
- if (data->error != 0)
- return;
-
- if (data->result != NULL)
- ret = data->result;
- else
- ret = xmlXPathNewCString("");
-
- data->result = oldResult;
-
- /*
- * It is an error if the instantiation of the template results in
- * the generation of result nodes.
- */
- if (fake->children != NULL) {
-#ifdef LIBXML_DEBUG_ENABLED
- xmlDebugDumpNode (stderr, fake, 1);
-#endif
- xsltGenericError(xsltGenericErrorContext,
- "{%s}%s: cannot write to result tree while "
- "executing a function\n",
- ctxt->context->functionURI, ctxt->context->function);
- xmlFreeNode(fake);
- return;
- }
- xmlFreeNode(fake);
- valuePush(ctxt, ret);
-}
-
-
-static void
-exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
- xmlChar *name, *prefix;
- xmlNsPtr ns;
- xmlHashTablePtr data;
- exsltFuncFunctionData *func;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-
- {
- xmlChar *qname;
-
- qname = xmlGetProp(inst, (const xmlChar *) "name");
- name = xmlSplitQName2 (qname, &prefix);
- xmlFree(qname);
- }
- if ((name == NULL) || (prefix == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "func:function: not a QName\n");
- if (name != NULL)
- xmlFree(name);
- return;
- }
- /* namespace lookup */
- ns = xmlSearchNs (inst->doc, inst, prefix);
- if (ns == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:function: undeclared prefix %s\n",
- prefix);
- xmlFree(name);
- xmlFree(prefix);
- return;
- }
- xmlFree(prefix);
-
- /*
- * Create function data
- */
- func = exsltFuncNewFunctionData();
- func->content = inst->children;
- while (IS_XSLT_ELEM(func->content) &&
- IS_XSLT_NAME(func->content, "param")) {
- func->content = func->content->next;
- func->nargs++;
- }
-
- xsltParseTemplateContent(style, inst);
-
- /*
- * Register the function data such that it can be retrieved
- * by exslFuncFunctionFunction
- */
-#ifdef XSLT_REFACTORED
- /*
- * Ensure that the hash table will be stored in the *current*
- * stylesheet level in order to correctly evaluate the
- * import precedence.
- */
- data = (xmlHashTablePtr)
- xsltStyleStylesheetLevelGetExtData(style,
- EXSLT_FUNCTIONS_NAMESPACE);
-#else
- data = (xmlHashTablePtr)
- xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);
-#endif
- if (data == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncFunctionComp: no stylesheet data\n");
- xmlFree(name);
- return;
- }
-
- if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
- xsltTransformError(NULL, style, inst,
- "Failed to register function {%s}%s\n",
- ns->href, name);
- style->errors++;
- } else {
- xsltGenericDebug(xsltGenericDebugContext,
- "exsltFuncFunctionComp: register {%s}%s\n",
- ns->href, name);
- }
- xmlFree(name);
-}
-
-static xsltElemPreCompPtr
-exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,
- xsltTransformFunction function) {
- xmlNodePtr test;
- xmlChar *sel;
- exsltFuncResultPreComp *ret;
-
- /*
- * "Validity" checking
- */
- /* it is an error to have any following sibling elements aside
- * from the xsl:fallback element.
- */
- for (test = inst->next; test != NULL; test = test->next) {
- if (test->type != XML_ELEMENT_NODE)
- continue;
- if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))
- continue;
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: only xsl:fallback is "
- "allowed to follow func:result\n");
- return (NULL);
- }
- /* it is an error for a func:result element to not be a descendant
- * of func:function.
- * it is an error if a func:result occurs within a func:result
- * element.
- * it is an error if instanciating the content of a variable
- * binding element (i.e. xsl:variable, xsl:param) results in the
- * instanciation of a func:result element.
- */
- for (test = inst->parent; test != NULL; test = test->parent) {
- if ((test->ns != NULL) &&
- (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {
- if (xmlStrEqual(test->name, (const xmlChar *) "function")) {
- break;
- }
- if (xmlStrEqual(test->name, (const xmlChar *) "result")) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result element not allowed within"
- " another func:result element\n");
- return (NULL);
- }
- }
- if (IS_XSLT_ELEM(test) &&
- (IS_XSLT_NAME(test, "variable") ||
- IS_XSLT_NAME(test, "param"))) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result element not allowed within"
- " a variable binding element\n");
- return (NULL);
- }
- }
-
- /*
- * Precomputation
- */
- ret = (exsltFuncResultPreComp *)
- xmlMalloc (sizeof(exsltFuncResultPreComp));
- if (ret == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL);
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultComp : malloc failed\n");
- return (NULL);
- }
- memset(ret, 0, sizeof(exsltFuncResultPreComp));
-
- xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,
- (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);
- ret->select = NULL;
-
- /*
- * Precompute the select attribute
- */
- sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);
- if (sel != NULL) {
- ret->select = xmlXPathCompile (sel);
- xmlFree(sel);
- }
- /*
- * Precompute the namespace list
- */
- ret->nsList = xmlGetNsList(inst->doc, inst);
- if (ret->nsList != NULL) {
- int i = 0;
- while (ret->nsList[i] != NULL)
- i++;
- ret->nsNr = i;
- }
- return ((xsltElemPreCompPtr) ret);
-}
-
-static void
-exsltFuncResultElem (xsltTransformContextPtr ctxt,
- xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
- exsltFuncResultPreComp *comp) {
- exsltFuncData *data;
- xmlXPathObjectPtr ret;
- xmlNsPtr *oldNsList;
- int oldNsNr;
-
- /* It is an error if instantiating the content of the
- * func:function element results in the instantiation of more than
- * one func:result elements.
- */
- data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
- if (data == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncReturnElem: data == NULL\n");
- return;
- }
- if (data->result != NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result already instanciated\n");
- data->error = 1;
- return;
- }
- /*
- * Processing
- */
- if (comp->select != NULL) {
- /* If the func:result element has a select attribute, then the
- * value of the attribute must be an expression and the
- * returned value is the object that results from evaluating
- * the expression. In this case, the content must be empty.
- */
- if (inst->children != NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "func:result content must be empty if it"
- " has a select attribute\n");
- data->error = 1;
- return;
- }
- oldNsList = ctxt->xpathCtxt->namespaces;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
- ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNsList;
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: ret == NULL\n");
- return;
- }
- } else if (inst->children != NULL) {
- /* If the func:result element does not have a select attribute
- * and has non-empty content (i.e. the func:result element has
- * one or more child nodes), then the content of the
- * func:result element specifies the value.
- */
- xmlNodePtr oldInsert;
- xmlDocPtr container;
-
- container = xsltCreateRVT(ctxt);
- if (container == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: out of memory\n");
- data->error = 1;
- return;
- }
- xsltRegisterTmpRVT(ctxt, container);
- oldInsert = ctxt->insert;
- ctxt->insert = (xmlNodePtr) container;
- xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
- inst->children, NULL, NULL);
- ctxt->insert = oldInsert;
-
- ret = xmlXPathNewValueTree((xmlNodePtr) container);
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "exsltFuncResultElem: ret == NULL\n");
- data->error = 1;
- } else {
- ret->boolval = 0; /* Freeing is not handled there anymore */
- }
- } else {
- /* If the func:result element has empty content and does not
- * have a select attribute, then the returned value is an
- * empty string.
- */
- ret = xmlXPathNewCString("");
- }
- data->result = ret;
-}
-
-/**
- * exsltFuncRegister:
- *
- * Registers the EXSLT - Functions module
- */
-void
-exsltFuncRegister (void) {
- xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
- (xsltExtInitFunction) exsltFuncInit,
- (xsltExtShutdownFunction) exsltFuncShutdown,
- (xsltStyleExtInitFunction) exsltFuncStyleInit,
- (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
-
- xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
- EXSLT_FUNCTIONS_NAMESPACE,
- exsltFuncFunctionComp);
- xsltRegisterExtModuleElement ((const xmlChar *) "result",
- EXSLT_FUNCTIONS_NAMESPACE,
- (xsltPreComputeFunction)exsltFuncResultComp,
- (xsltTransformFunction) exsltFuncResultElem);
-}
+#define IN_LIBEXSLT\r
+#include "libexslt/libexslt.h"\r
+\r
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)\r
+#include <win32config.h>\r
+#else\r
+#include "config.h"\r
+#endif\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/tree.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/debugXML.h>\r
+\r
+#include <libxslt/xsltutils.h>\r
+#include <libxslt/variables.h>\r
+#include <libxslt/xsltInternals.h>\r
+#include <libxslt/extensions.h>\r
+#include <libxslt/transform.h>\r
+#include <libxslt/imports.h>\r
+\r
+#include "exslt.h"\r
+\r
+typedef struct _exsltFuncFunctionData exsltFuncFunctionData;\r
+struct _exsltFuncFunctionData {\r
+ int nargs; /* number of arguments to the function */\r
+ xmlNodePtr content; /* the func:fuction template content */\r
+};\r
+\r
+typedef struct _exsltFuncData exsltFuncData;\r
+struct _exsltFuncData {\r
+ xmlHashTablePtr funcs; /* pointer to the stylesheet module data */\r
+ xmlXPathObjectPtr result; /* returned by func:result */\r
+ int error; /* did an error occur? */\r
+ xmlDocPtr RVT; /* result tree fragment */\r
+};\r
+\r
+typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;\r
+struct _exsltFuncResultPreComp {\r
+ xsltElemPreComp comp;\r
+ xmlXPathCompExprPtr select;\r
+ xmlNsPtr *nsList;\r
+ int nsNr;\r
+};\r
+\r
+/* Used for callback function in exsltInitFunc */\r
+typedef struct _exsltFuncImportRegData exsltFuncImportRegData;\r
+struct _exsltFuncImportRegData {\r
+ xsltTransformContextPtr ctxt;\r
+ xmlHashTablePtr hash;\r
+};\r
+\r
+static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,\r
+ int nargs);\r
+static exsltFuncFunctionData *exsltFuncNewFunctionData(void);\r
+\r
+static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";\r
+\r
+/**\r
+ * exsltFuncRegisterFunc:\r
+ * @func: the #exsltFuncFunctionData for the function\r
+ * @ctxt: an XSLT transformation context\r
+ * @URI: the function namespace URI\r
+ * @name: the function name\r
+ *\r
+ * Registers a function declared by a func:function element\r
+ */\r
+static void\r
+exsltFuncRegisterFunc (exsltFuncFunctionData *data,\r
+ xsltTransformContextPtr ctxt,\r
+ const xmlChar *URI, const xmlChar *name,\r
+ ATTRIBUTE_UNUSED const xmlChar *ignored) {\r
+ if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))\r
+ return;\r
+\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "exsltFuncRegisterFunc: register {%s}%s\n",\r
+ URI, name);\r
+ xsltRegisterExtFunction(ctxt, name, URI,\r
+ exsltFuncFunctionFunction);\r
+}\r
+\r
+/*\r
+ * exsltFuncRegisterImportFunc\r
+ * @data: the exsltFuncFunctionData for the function\r
+ * @ch: structure containing context and hash table\r
+ * @URI: the function namespace URI\r
+ * @name: the function name\r
+ *\r
+ * Checks if imported function is already registered in top-level\r
+ * stylesheet. If not, copies function data and registers function\r
+ */\r
+static void\r
+exsltFuncRegisterImportFunc (exsltFuncFunctionData *data,\r
+ exsltFuncImportRegData *ch,\r
+ const xmlChar *URI, const xmlChar *name,\r
+ ATTRIBUTE_UNUSED const xmlChar *ignored) {\r
+ exsltFuncFunctionData *func=NULL;\r
+\r
+ if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL))\r
+ return;\r
+\r
+ if (ch->ctxt == NULL || ch->hash == NULL)\r
+ return;\r
+\r
+ /* Check if already present */\r
+ func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name);\r
+ if (func == NULL) { /* Not yet present - copy it in */\r
+ func = exsltFuncNewFunctionData();\r
+ memcpy(func, data, sizeof(exsltFuncFunctionData));\r
+ if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "Failed to register function {%s}%s\n",\r
+ URI, name);\r
+ } else { /* Do the registration */\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "exsltFuncRegisterImportFunc: register {%s}%s\n",\r
+ URI, name);\r
+ xsltRegisterExtFunction(ch->ctxt, name, URI,\r
+ exsltFuncFunctionFunction);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * exsltFuncInit:\r
+ * @ctxt: an XSLT transformation context\r
+ * @URI: the namespace URI for the extension\r
+ *\r
+ * Initializes the EXSLT - Functions module.\r
+ * Called at transformation-time; merges all\r
+ * functions declared in the import tree taking\r
+ * import precedence into account, i.e. overriding\r
+ * functions with lower import precedence.\r
+ *\r
+ * Returns the data for this transformation\r
+ */\r
+static exsltFuncData *\r
+exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {\r
+ exsltFuncData *ret;\r
+ xsltStylesheetPtr tmp;\r
+ exsltFuncImportRegData ch;\r
+ xmlHashTablePtr hash;\r
+ \r
+ ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncInit: not enough memory\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(exsltFuncData));\r
+\r
+ ret->result = NULL;\r
+ ret->error = 0;\r
+\r
+ ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);\r
+ ret->funcs = ch.hash;\r
+ xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);\r
+ tmp = ctxt->style;\r
+ ch.ctxt = ctxt;\r
+ while ((tmp=xsltNextImport(tmp))!=NULL) {\r
+ hash = xsltGetExtInfo(tmp, URI);\r
+ if (hash != NULL) {\r
+ xmlHashScanFull(hash, \r
+ (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch);\r
+ }\r
+ }\r
+\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * exsltFuncShutdown:\r
+ * @ctxt: an XSLT transformation context\r
+ * @URI: the namespace URI for the extension\r
+ * @data: the module data to free up\r
+ * \r
+ * Shutdown the EXSLT - Functions module\r
+ * Called at transformation-time.\r
+ */\r
+static void\r
+exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,\r
+ const xmlChar *URI ATTRIBUTE_UNUSED,\r
+ exsltFuncData *data) {\r
+ if (data->result != NULL)\r
+ xmlXPathFreeObject(data->result);\r
+ xmlFree(data);\r
+}\r
+\r
+/**\r
+ * exsltFuncStyleInit:\r
+ * @style: an XSLT stylesheet\r
+ * @URI: the namespace URI for the extension\r
+ *\r
+ * Allocates the stylesheet data for EXSLT - Function\r
+ * Called at compile-time.\r
+ *\r
+ * Returns the allocated data\r
+ */\r
+static xmlHashTablePtr\r
+exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,\r
+ const xmlChar *URI ATTRIBUTE_UNUSED) {\r
+ return xmlHashCreate(1);\r
+}\r
+\r
+/**\r
+ * exsltFuncStyleShutdown:\r
+ * @style: an XSLT stylesheet\r
+ * @URI: the namespace URI for the extension\r
+ * @data: the stylesheet data to free up \r
+ *\r
+ * Shutdown the EXSLT - Function module\r
+ * Called at compile-time.\r
+ */\r
+static void\r
+exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,\r
+ const xmlChar *URI ATTRIBUTE_UNUSED,\r
+ xmlHashTablePtr data) {\r
+ xmlHashFree(data, (xmlHashDeallocator) xmlFree);\r
+}\r
+\r
+/**\r
+ * exsltFuncNewFunctionData:\r
+ *\r
+ * Allocates an #exslFuncFunctionData object\r
+ *\r
+ * Returns the new structure\r
+ */\r
+static exsltFuncFunctionData *\r
+exsltFuncNewFunctionData (void) {\r
+ exsltFuncFunctionData *ret;\r
+\r
+ ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData));\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncNewFunctionData: not enough memory\n");\r
+ return (NULL);\r
+ }\r
+ memset(ret, 0, sizeof(exsltFuncFunctionData));\r
+\r
+ ret->nargs = 0;\r
+ ret->content = NULL;\r
+\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * exsltFreeFuncResultPreComp:\r
+ * @comp: the #exsltFuncResultPreComp to free up\r
+ *\r
+ * Deallocates an #exsltFuncResultPreComp\r
+ */\r
+static void\r
+exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) {\r
+ if (comp == NULL)\r
+ return;\r
+\r
+ if (comp->select != NULL)\r
+ xmlXPathFreeCompExpr (comp->select);\r
+ if (comp->nsList != NULL)\r
+ xmlFree(comp->nsList);\r
+ xmlFree(comp);\r
+}\r
+\r
+/**\r
+ * exsltFuncFunctionFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Evaluates the func:function element that defines the called function.\r
+ */\r
+static void\r
+exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xmlXPathObjectPtr obj, oldResult, ret;\r
+ exsltFuncData *data;\r
+ exsltFuncFunctionData *func;\r
+ xmlNodePtr paramNode, oldInsert, fake;\r
+ int oldBase;\r
+ xsltStackElemPtr params = NULL, param;\r
+ xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);\r
+ int i;\r
+\r
+ /*\r
+ * retrieve func:function template\r
+ */\r
+ data = (exsltFuncData *) xsltGetExtData (tctxt,\r
+ EXSLT_FUNCTIONS_NAMESPACE);\r
+ oldResult = data->result;\r
+ data->result = NULL;\r
+\r
+ func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs,\r
+ ctxt->context->functionURI,\r
+ ctxt->context->function);\r
+\r
+ /*\r
+ * params handling\r
+ */\r
+ if (nargs > func->nargs) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "{%s}%s: called with too many arguments\n",\r
+ ctxt->context->functionURI, ctxt->context->function);\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ if (func->content != NULL) {\r
+ paramNode = func->content->prev;\r
+ }\r
+ else\r
+ paramNode = NULL;\r
+ if ((paramNode == NULL) && (func->nargs != 0)) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncFunctionFunction: nargs != 0 and "\r
+ "param == NULL\n");\r
+ return;\r
+ }\r
+ /*\r
+ * Process xsl:param instructions which were not set by the\r
+ * invoking function call.\r
+ */\r
+ for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {\r
+ /*\r
+ * Those are the xsl:param instructions, which were not\r
+ * set by the calling function. \r
+ */\r
+ param = xsltParseStylesheetCallerParam (tctxt, paramNode);\r
+ param->next = params;\r
+ params = param;\r
+ paramNode = paramNode->prev;\r
+ }\r
+ /*\r
+ * Process xsl:param instructions which are set by the\r
+ * invoking function call.\r
+ */\r
+ while ((i-- > 0) && (paramNode != NULL)) {\r
+ obj = valuePop(ctxt);\r
+ /*\r
+ * TODO: Using xsltParseStylesheetCallerParam() is actually\r
+ * not correct, since we are processing an xsl:param; but\r
+ * using xsltParseStylesheetParam() won't work, as it puts\r
+ * the param on the varible stack and does not give access to\r
+ * the created xsltStackElemPtr.\r
+ * It's also not correct, as xsltParseStylesheetCallerParam()\r
+ * will report error messages indicating an "xsl:with-param" and\r
+ * not the actual "xsl:param".\r
+ */\r
+ param = xsltParseStylesheetCallerParam (tctxt, paramNode);\r
+ param->computed = 1;\r
+ if (param->value != NULL)\r
+ xmlXPathFreeObject(param->value);\r
+ param->value = obj;\r
+ param->next = params;\r
+ params = param;\r
+ paramNode = paramNode->prev;\r
+ }\r
+ \r
+ /*\r
+ * actual processing\r
+ */\r
+ fake = xmlNewDocNode(tctxt->output, NULL,\r
+ (const xmlChar *)"fake", NULL);\r
+ oldInsert = tctxt->insert;\r
+ tctxt->insert = fake;\r
+ /* \r
+ * In order to give the function variables a new 'scope' we\r
+ * change varsBase in the context.\r
+ */\r
+ oldBase = tctxt->varsBase;\r
+ tctxt->varsBase = tctxt->varsNr;\r
+ xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),\r
+ func->content, NULL, params);\r
+ tctxt->insert = oldInsert;\r
+ tctxt->varsBase = oldBase; /* restore original scope */\r
+ if (params != NULL)\r
+ xsltFreeStackElemList(params); \r
+\r
+ if (data->error != 0)\r
+ goto error;\r
+\r
+ if (data->result != NULL) {\r
+ ret = data->result;\r
+ } else\r
+ ret = xmlXPathNewCString("");\r
+\r
+ data->result = oldResult;\r
+\r
+ /*\r
+ * It is an error if the instantiation of the template results in\r
+ * the generation of result nodes.\r
+ */\r
+ if (fake->children != NULL) {\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+ xmlDebugDumpNode (stderr, fake, 1);\r
+#endif\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "{%s}%s: cannot write to result tree while "\r
+ "executing a function\n",\r
+ ctxt->context->functionURI, ctxt->context->function);\r
+ xmlFreeNode(fake);\r
+ goto error;\r
+ }\r
+ xmlFreeNode(fake);\r
+ valuePush(ctxt, ret);\r
+\r
+error:\r
+ /*\r
+ * IMPORTANT: This enables previously tree fragments marked as\r
+ * being results of a function, to be garbage-collected after\r
+ * the calling process exits.\r
+ */\r
+ xsltExtensionInstructionResultFinalize(tctxt);\r
+}\r
+\r
+\r
+static void\r
+exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {\r
+ xmlChar *name, *prefix;\r
+ xmlNsPtr ns;\r
+ xmlHashTablePtr data;\r
+ exsltFuncFunctionData *func;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+\r
+ {\r
+ xmlChar *qname;\r
+\r
+ qname = xmlGetProp(inst, (const xmlChar *) "name");\r
+ name = xmlSplitQName2 (qname, &prefix);\r
+ xmlFree(qname);\r
+ }\r
+ if ((name == NULL) || (prefix == NULL)) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:function: not a QName\n");\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+ return;\r
+ }\r
+ /* namespace lookup */\r
+ ns = xmlSearchNs (inst->doc, inst, prefix);\r
+ if (ns == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:function: undeclared prefix %s\n",\r
+ prefix);\r
+ xmlFree(name);\r
+ xmlFree(prefix);\r
+ return;\r
+ }\r
+ xmlFree(prefix);\r
+\r
+ /*\r
+ * Create function data\r
+ */\r
+ func = exsltFuncNewFunctionData();\r
+ func->content = inst->children;\r
+ while (IS_XSLT_ELEM(func->content) &&\r
+ IS_XSLT_NAME(func->content, "param")) {\r
+ func->content = func->content->next;\r
+ func->nargs++;\r
+ }\r
+\r
+ xsltParseTemplateContent(style, inst);\r
+\r
+ /*\r
+ * Register the function data such that it can be retrieved\r
+ * by exslFuncFunctionFunction\r
+ */\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Ensure that the hash table will be stored in the *current*\r
+ * stylesheet level in order to correctly evaluate the\r
+ * import precedence.\r
+ */\r
+ data = (xmlHashTablePtr)\r
+ xsltStyleStylesheetLevelGetExtData(style,\r
+ EXSLT_FUNCTIONS_NAMESPACE);\r
+#else\r
+ data = (xmlHashTablePtr)\r
+ xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE);\r
+#endif\r
+ if (data == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncFunctionComp: no stylesheet data\n");\r
+ xmlFree(name);\r
+ return;\r
+ }\r
+\r
+ if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "Failed to register function {%s}%s\n",\r
+ ns->href, name);\r
+ style->errors++;\r
+ } else {\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "exsltFuncFunctionComp: register {%s}%s\n",\r
+ ns->href, name);\r
+ }\r
+ xmlFree(name);\r
+}\r
+\r
+static xsltElemPreCompPtr\r
+exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst,\r
+ xsltTransformFunction function) {\r
+ xmlNodePtr test;\r
+ xmlChar *sel;\r
+ exsltFuncResultPreComp *ret;\r
+\r
+ /*\r
+ * "Validity" checking\r
+ */\r
+ /* it is an error to have any following sibling elements aside\r
+ * from the xsl:fallback element.\r
+ */\r
+ for (test = inst->next; test != NULL; test = test->next) {\r
+ if (test->type != XML_ELEMENT_NODE)\r
+ continue;\r
+ if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback"))\r
+ continue;\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncResultElem: only xsl:fallback is "\r
+ "allowed to follow func:result\n");\r
+ return (NULL);\r
+ }\r
+ /* it is an error for a func:result element to not be a descendant\r
+ * of func:function.\r
+ * it is an error if a func:result occurs within a func:result\r
+ * element.\r
+ * it is an error if instanciating the content of a variable\r
+ * binding element (i.e. xsl:variable, xsl:param) results in the \r
+ * instanciation of a func:result element.\r
+ */\r
+ for (test = inst->parent; test != NULL; test = test->parent) {\r
+ if ((test->ns != NULL) &&\r
+ (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) {\r
+ if (xmlStrEqual(test->name, (const xmlChar *) "function")) {\r
+ break;\r
+ }\r
+ if (xmlStrEqual(test->name, (const xmlChar *) "result")) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:result element not allowed within"\r
+ " another func:result element\n");\r
+ return (NULL);\r
+ }\r
+ }\r
+ if (IS_XSLT_ELEM(test) &&\r
+ (IS_XSLT_NAME(test, "variable") ||\r
+ IS_XSLT_NAME(test, "param"))) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:result element not allowed within"\r
+ " a variable binding element\n");\r
+ return (NULL);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Precomputation\r
+ */\r
+ ret = (exsltFuncResultPreComp *)\r
+ xmlMalloc (sizeof(exsltFuncResultPreComp));\r
+ if (ret == NULL) {\r
+ xsltPrintErrorContext(NULL, NULL, NULL);\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncResultComp : malloc failed\n");\r
+ return (NULL);\r
+ }\r
+ memset(ret, 0, sizeof(exsltFuncResultPreComp));\r
+\r
+ xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function,\r
+ (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp);\r
+ ret->select = NULL;\r
+\r
+ /*\r
+ * Precompute the select attribute\r
+ */\r
+ sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL);\r
+ if (sel != NULL) {\r
+ ret->select = xmlXPathCompile (sel);\r
+ xmlFree(sel);\r
+ }\r
+ /*\r
+ * Precompute the namespace list\r
+ */\r
+ ret->nsList = xmlGetNsList(inst->doc, inst);\r
+ if (ret->nsList != NULL) {\r
+ int i = 0;\r
+ while (ret->nsList[i] != NULL)\r
+ i++;\r
+ ret->nsNr = i;\r
+ }\r
+ return ((xsltElemPreCompPtr) ret);\r
+}\r
+\r
+static void\r
+exsltFuncResultElem (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,\r
+ exsltFuncResultPreComp *comp) {\r
+ exsltFuncData *data;\r
+ xmlXPathObjectPtr ret;\r
+ \r
+\r
+ /* It is an error if instantiating the content of the\r
+ * func:function element results in the instantiation of more than\r
+ * one func:result elements.\r
+ */\r
+ data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);\r
+ if (data == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncReturnElem: data == NULL\n");\r
+ return;\r
+ }\r
+ if (data->result != NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:result already instanciated\n");\r
+ data->error = 1;\r
+ return;\r
+ }\r
+ /*\r
+ * Processing\r
+ */\r
+ if (comp->select != NULL) {\r
+ xmlNsPtr *oldXPNsList;\r
+ int oldXPNsNr;\r
+ xmlNodePtr oldXPContextNode;\r
+ /* If the func:result element has a select attribute, then the\r
+ * value of the attribute must be an expression and the\r
+ * returned value is the object that results from evaluating\r
+ * the expression. In this case, the content must be empty.\r
+ */\r
+ if (inst->children != NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "func:result content must be empty if it"\r
+ " has a select attribute\n");\r
+ data->error = 1;\r
+ return;\r
+ }\r
+ oldXPNsList = ctxt->xpathCtxt->namespaces;\r
+ oldXPNsNr = ctxt->xpathCtxt->nsNr;\r
+ oldXPContextNode = ctxt->xpathCtxt->node;\r
+\r
+ ctxt->xpathCtxt->namespaces = comp->nsList;\r
+ ctxt->xpathCtxt->nsNr = comp->nsNr;\r
+\r
+ ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);\r
+\r
+ ctxt->xpathCtxt->node = oldXPContextNode;\r
+ ctxt->xpathCtxt->nsNr = oldXPNsNr;\r
+ ctxt->xpathCtxt->namespaces = oldXPNsList;\r
+\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncResultElem: ret == NULL\n");\r
+ return;\r
+ }\r
+ /*\r
+ * Mark it as a function result in order to avoid garbage\r
+ * collecting of tree fragments before the function exits.\r
+ */\r
+ xsltExtensionInstructionResultRegister(ctxt, ret);\r
+ } else if (inst->children != NULL) {\r
+ /* If the func:result element does not have a select attribute\r
+ * and has non-empty content (i.e. the func:result element has\r
+ * one or more child nodes), then the content of the\r
+ * func:result element specifies the value.\r
+ */\r
+ xmlNodePtr oldInsert;\r
+ xmlDocPtr container;\r
+\r
+ container = xsltCreateRVT(ctxt);\r
+ if (container == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncResultElem: out of memory\n");\r
+ data->error = 1;\r
+ return;\r
+ }\r
+ xsltRegisterLocalRVT(ctxt, container); \r
+\r
+ oldInsert = ctxt->insert;\r
+ ctxt->insert = (xmlNodePtr) container;\r
+ xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,\r
+ inst->children, NULL, NULL);\r
+ ctxt->insert = oldInsert;\r
+\r
+ ret = xmlXPathNewValueTree((xmlNodePtr) container);\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "exsltFuncResultElem: ret == NULL\n");\r
+ data->error = 1;\r
+ } else {\r
+ ret->boolval = 0; /* Freeing is not handled there anymore */\r
+ /*\r
+ * Mark it as a function result in order to avoid garbage\r
+ * collecting of tree fragments before the function exits.\r
+ */\r
+ xsltExtensionInstructionResultRegister(ctxt, ret);\r
+ }\r
+ } else {\r
+ /* If the func:result element has empty content and does not\r
+ * have a select attribute, then the returned value is an\r
+ * empty string.\r
+ */\r
+ ret = xmlXPathNewCString("");\r
+ }\r
+ data->result = ret;\r
+}\r
+\r
+/**\r
+ * exsltFuncRegister:\r
+ *\r
+ * Registers the EXSLT - Functions module\r
+ */\r
+void\r
+exsltFuncRegister (void) {\r
+ xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,\r
+ (xsltExtInitFunction) exsltFuncInit,\r
+ (xsltExtShutdownFunction) exsltFuncShutdown,\r
+ (xsltStyleExtInitFunction) exsltFuncStyleInit,\r
+ (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);\r
+\r
+ xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",\r
+ EXSLT_FUNCTIONS_NAMESPACE,\r
+ exsltFuncFunctionComp);\r
+ xsltRegisterExtModuleElement ((const xmlChar *) "result",\r
+ EXSLT_FUNCTIONS_NAMESPACE,\r
+ (xsltPreComputeFunction)exsltFuncResultComp,\r
+ (xsltTransformFunction) exsltFuncResultElem);\r
+}\r
-#define IN_LIBEXSLT
-#include "libexslt/libexslt.h"
-
-#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
-#include <win32config.h>
-#else
-#include "config.h"
-#endif
-
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/parser.h>
-#include <libxml/encoding.h>
-#include <libxml/uri.h>
-
-#include <libxslt/xsltconfig.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/extensions.h>
-
-#include "exslt.h"
-
-/**
- * exsltStrTokenizeFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Splits up a string on the characters of the delimiter string and returns a
- * node set of token elements, each containing one token from the string.
- */
-static void
-exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
-{
- xsltTransformContextPtr tctxt;
- xmlChar *str, *delimiters, *cur;
- const xmlChar *token, *delimiter;
- xmlNodePtr node;
- xmlDocPtr container;
- xmlXPathObjectPtr ret = NULL;
- int clen;
-
- if ((nargs < 1) || (nargs > 2)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs == 2) {
- delimiters = xmlXPathPopString(ctxt);
- if (xmlXPathCheckError(ctxt))
- return;
- } else {
- delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
- }
- if (delimiters == NULL)
- return;
-
- str = xmlXPathPopString(ctxt);
- if (xmlXPathCheckError(ctxt) || (str == NULL)) {
- xmlFree(delimiters);
- return;
- }
-
- /* Return a result tree fragment */
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "exslt:tokenize : internal error tctxt == NULL\n");
- goto fail;
- }
-
- container = xsltCreateRVT(tctxt);
- if (container != NULL) {
- xsltRegisterTmpRVT(tctxt, container);
- ret = xmlXPathNewNodeSet(NULL);
- if (ret != NULL) {
- ret->boolval = 0; /* Freeing is not handled there anymore */
- for (cur = str, token = str; *cur != 0; cur += clen) {
- clen = xmlUTF8Size(cur);
- if (*delimiters == 0) { /* empty string case */
- xmlChar ctmp;
- ctmp = *(cur+clen);
- *(cur+clen) = 0;
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", cur);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- *(cur+clen) = ctmp; /* restore the changed byte */
- token = cur + clen;
- } else for (delimiter = delimiters; *delimiter != 0;
- delimiter += xmlUTF8Size(delimiter)) {
- if (!xmlUTF8Charcmp(cur, delimiter)) {
- if (cur == token) {
- /* discard empty tokens */
- token = cur + clen;
- break;
- }
- *cur = 0; /* terminate the token */
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", token);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- *cur = *delimiter; /* restore the changed byte */
- token = cur + clen;
- break;
- }
- }
- }
- if (token != cur) {
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", token);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- }
- }
- }
-
-fail:
- if (str != NULL)
- xmlFree(str);
- if (delimiters != NULL)
- xmlFree(delimiters);
- if (ret != NULL)
- valuePush(ctxt, ret);
- else
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-}
-
-/**
- * exsltStrSplitFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Splits up a string on a delimiting string and returns a node set of token
- * elements, each containing one token from the string.
- */
-static void
-exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
- xsltTransformContextPtr tctxt;
- xmlChar *str, *delimiter, *cur;
- const xmlChar *token;
- xmlNodePtr node;
- xmlDocPtr container;
- xmlXPathObjectPtr ret = NULL;
- int delimiterLength;
-
- if ((nargs < 1) || (nargs > 2)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs == 2) {
- delimiter = xmlXPathPopString(ctxt);
- if (xmlXPathCheckError(ctxt))
- return;
- } else {
- delimiter = xmlStrdup((const xmlChar *) " ");
- }
- if (delimiter == NULL)
- return;
- delimiterLength = xmlStrlen (delimiter);
-
- str = xmlXPathPopString(ctxt);
- if (xmlXPathCheckError(ctxt) || (str == NULL)) {
- xmlFree(delimiter);
- return;
- }
-
- /* Return a result tree fragment */
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "exslt:tokenize : internal error tctxt == NULL\n");
- goto fail;
- }
-
- container = xsltCreateRVT(tctxt);
- if (container != NULL) {
- xsltRegisterTmpRVT(tctxt, container);
- ret = xmlXPathNewNodeSet(NULL);
- if (ret != NULL) {
- ret->boolval = 0; /* Freeing is not handled there anymore */
- for (cur = str, token = str; *cur != 0; cur++) {
- if (delimiterLength == 0) {
- if (cur != token) {
- xmlChar tmp = *cur;
- *cur = 0;
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", token);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- *cur = tmp;
- token++;
- }
- }
- else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {
- if (cur == token) {
- /* discard empty tokens */
- cur = cur + delimiterLength - 1;
- token = cur + 1;
- continue;
- }
- *cur = 0;
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", token);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- *cur = *delimiter;
- cur = cur + delimiterLength - 1;
- token = cur + 1;
- }
- }
- if (token != cur) {
- node = xmlNewDocRawNode(container, NULL,
- (const xmlChar *) "token", token);
- xmlAddChild((xmlNodePtr) container, node);
- xmlXPathNodeSetAddUnique(ret->nodesetval, node);
- }
- }
- }
-
-fail:
- if (str != NULL)
- xmlFree(str);
- if (delimiter != NULL)
- xmlFree(delimiter);
- if (ret != NULL)
- valuePush(ctxt, ret);
- else
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-}
-
-/**
- * exsltStrEncodeUriFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * URI-Escapes a string
- */
-static void
-exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- int escape_all = 1, str_len = 0;
- xmlChar *str = NULL, *ret = NULL, *tmp;
-
- if ((nargs < 2) || (nargs > 3)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs >= 3) {
- /* check for UTF-8 if encoding was explicitly given;
- we don't support anything else yet */
- tmp = xmlXPathPopString(ctxt);
- if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(tmp);
- return;
- }
- xmlFree(tmp);
- }
-
- escape_all = xmlXPathPopBoolean(ctxt);
-
- str = xmlXPathPopString(ctxt);
- str_len = xmlUTF8Strlen(str);
-
- if (str_len == 0) {
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(str);
- return;
- }
-
- ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));
- xmlXPathReturnString(ctxt, ret);
-
- if (str != NULL)
- xmlFree(str);
-}
-
-/**
- * exsltStrDecodeUriFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * reverses URI-Escaping of a string
- */
-static void
-exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- int str_len = 0;
- xmlChar *str = NULL, *ret = NULL, *tmp;
-
- if ((nargs < 1) || (nargs > 2)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs >= 2) {
- /* check for UTF-8 if encoding was explicitly given;
- we don't support anything else yet */
- tmp = xmlXPathPopString(ctxt);
- if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(tmp);
- return;
- }
- xmlFree(tmp);
- }
-
- str = xmlXPathPopString(ctxt);
- str_len = xmlUTF8Strlen(str);
-
- if (str_len == 0) {
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(str);
- return;
- }
-
- ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);
- if (!xmlCheckUTF8(ret)) {
- /* FIXME: instead of throwing away the whole URI, we should
- only discard the invalid sequence(s). How to do that? */
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(str);
- xmlFree(ret);
- return;
- }
-
- xmlXPathReturnString(ctxt, ret);
-
- if (str != NULL)
- xmlFree(str);
-}
-
-/**
- * exsltStrPaddingFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Creates a padding string of a certain length.
- */
-static void
-exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- int number, str_len = 0;
- xmlChar *str = NULL, *ret = NULL, *tmp;
-
- if ((nargs < 1) || (nargs > 2)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs == 2) {
- str = xmlXPathPopString(ctxt);
- str_len = xmlUTF8Strlen(str);
- }
- if (str_len == 0) {
- if (str != NULL) xmlFree(str);
- str = xmlStrdup((const xmlChar *) " ");
- str_len = 1;
- }
-
- number = (int) xmlXPathPopNumber(ctxt);
-
- if (number <= 0) {
- xmlXPathReturnEmptyString(ctxt);
- xmlFree(str);
- return;
- }
-
- while (number >= str_len) {
- ret = xmlStrncat(ret, str, str_len);
- number -= str_len;
- }
- tmp = xmlUTF8Strndup (str, number);
- ret = xmlStrcat(ret, tmp);
- if (tmp != NULL)
- xmlFree (tmp);
-
- xmlXPathReturnString(ctxt, ret);
-
- if (str != NULL)
- xmlFree(str);
-}
-
-/**
- * exsltStrAlignFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Aligns a string within another string.
- */
-static void
-exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlChar *str, *padding, *alignment, *ret;
- int str_l, padding_l;
-
- if ((nargs < 2) || (nargs > 3)) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (nargs == 3)
- alignment = xmlXPathPopString(ctxt);
- else
- alignment = NULL;
-
- padding = xmlXPathPopString(ctxt);
- str = xmlXPathPopString(ctxt);
-
- str_l = xmlUTF8Strlen (str);
- padding_l = xmlUTF8Strlen (padding);
-
- if (str_l == padding_l) {
- xmlXPathReturnString (ctxt, str);
- xmlFree(padding);
- xmlFree(alignment);
- return;
- }
-
- if (str_l > padding_l) {
- ret = xmlUTF8Strndup (str, padding_l);
- } else {
- if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
- ret = xmlUTF8Strndup (padding, padding_l - str_l);
- ret = xmlStrcat (ret, str);
- } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
- int left = (padding_l - str_l) / 2;
- int right_start;
-
- ret = xmlUTF8Strndup (padding, left);
- ret = xmlStrcat (ret, str);
-
- right_start = xmlUTF8Strsize (padding, left + str_l);
- ret = xmlStrcat (ret, padding + right_start);
- } else {
- int str_s;
-
- str_s = xmlStrlen (str);
- ret = xmlStrdup (str);
- ret = xmlStrcat (ret, padding + str_s);
- }
- }
-
- xmlXPathReturnString (ctxt, ret);
-
- xmlFree(str);
- xmlFree(padding);
- xmlFree(alignment);
-}
-
-/**
- * exsltStrConcatFunction:
- * @ctxt: an XPath parser context
- * @nargs: the number of arguments
- *
- * Takes a node set and returns the concatenation of the string values
- * of the nodes in that node set. If the node set is empty, it
- * returns an empty string.
- */
-static void
-exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
- xmlXPathObjectPtr obj;
- xmlChar *ret = NULL;
- int i;
-
- if (nargs != 1) {
- xmlXPathSetArityError(ctxt);
- return;
- }
-
- if (!xmlXPathStackIsNodeSet(ctxt)) {
- xmlXPathSetTypeError(ctxt);
- return;
- }
-
- obj = valuePop (ctxt);
-
- if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
- xmlXPathReturnEmptyString(ctxt);
- return;
- }
-
- for (i = 0; i < obj->nodesetval->nodeNr; i++) {
- xmlChar *tmp;
- tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
-
- ret = xmlStrcat (ret, tmp);
-
- xmlFree(tmp);
- }
-
- xmlXPathFreeObject (obj);
-
- xmlXPathReturnString(ctxt, ret);
-}
-
-/**
- * exsltStrRegister:
- *
- * Registers the EXSLT - Strings module
- */
-
-void
-exsltStrRegister (void) {
- xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrTokenizeFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "split",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrSplitFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrEncodeUriFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrDecodeUriFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrPaddingFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "align",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrAlignFunction);
- xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
- EXSLT_STRINGS_NAMESPACE,
- exsltStrConcatFunction);
-}
+#define IN_LIBEXSLT\r
+#include "libexslt/libexslt.h"\r
+\r
+#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)\r
+#include <win32config.h>\r
+#else\r
+#include "config.h"\r
+#endif\r
+\r
+#include <libxml/tree.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/encoding.h>\r
+#include <libxml/uri.h>\r
+\r
+#include <libxslt/xsltconfig.h>\r
+#include <libxslt/xsltutils.h>\r
+#include <libxslt/xsltInternals.h>\r
+#include <libxslt/extensions.h>\r
+\r
+#include "exslt.h"\r
+\r
+/**\r
+ * exsltStrTokenizeFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Splits up a string on the characters of the delimiter string and returns a\r
+ * node set of token elements, each containing one token from the string. \r
+ */\r
+static void\r
+exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)\r
+{\r
+ xsltTransformContextPtr tctxt;\r
+ xmlChar *str, *delimiters, *cur;\r
+ const xmlChar *token, *delimiter;\r
+ xmlNodePtr node;\r
+ xmlDocPtr container;\r
+ xmlXPathObjectPtr ret = NULL;\r
+ int clen;\r
+\r
+ if ((nargs < 1) || (nargs > 2)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs == 2) {\r
+ delimiters = xmlXPathPopString(ctxt);\r
+ if (xmlXPathCheckError(ctxt))\r
+ return;\r
+ } else {\r
+ delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");\r
+ }\r
+ if (delimiters == NULL)\r
+ return;\r
+\r
+ str = xmlXPathPopString(ctxt);\r
+ if (xmlXPathCheckError(ctxt) || (str == NULL)) {\r
+ xmlFree(delimiters);\r
+ return;\r
+ }\r
+\r
+ /* Return a result tree fragment */\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "exslt:tokenize : internal error tctxt == NULL\n");\r
+ goto fail;\r
+ }\r
+\r
+ container = xsltCreateRVT(tctxt);\r
+ if (container != NULL) {\r
+ xsltRegisterLocalRVT(tctxt, container);\r
+ ret = xmlXPathNewNodeSet(NULL);\r
+ if (ret != NULL) {\r
+ for (cur = str, token = str; *cur != 0; cur += clen) {\r
+ clen = xmlUTF8Size(cur);\r
+ if (*delimiters == 0) { /* empty string case */\r
+ xmlChar ctmp;\r
+ ctmp = *(cur+clen);\r
+ *(cur+clen) = 0;\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", cur);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ *(cur+clen) = ctmp; /* restore the changed byte */\r
+ token = cur + clen;\r
+ } else for (delimiter = delimiters; *delimiter != 0;\r
+ delimiter += xmlUTF8Size(delimiter)) {\r
+ if (!xmlUTF8Charcmp(cur, delimiter)) {\r
+ if (cur == token) {\r
+ /* discard empty tokens */\r
+ token = cur + clen;\r
+ break;\r
+ }\r
+ *cur = 0; /* terminate the token */\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", token);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ *cur = *delimiter; /* restore the changed byte */\r
+ token = cur + clen;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if (token != cur) {\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", token);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ }\r
+ }\r
+ }\r
+\r
+fail:\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+ if (delimiters != NULL)\r
+ xmlFree(delimiters);\r
+ if (ret != NULL)\r
+ valuePush(ctxt, ret);\r
+ else\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+}\r
+\r
+/**\r
+ * exsltStrSplitFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Splits up a string on a delimiting string and returns a node set of token\r
+ * elements, each containing one token from the string. \r
+ */\r
+static void\r
+exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xsltTransformContextPtr tctxt;\r
+ xmlChar *str, *delimiter, *cur;\r
+ const xmlChar *token;\r
+ xmlNodePtr node;\r
+ xmlDocPtr container;\r
+ xmlXPathObjectPtr ret = NULL;\r
+ int delimiterLength;\r
+\r
+ if ((nargs < 1) || (nargs > 2)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs == 2) {\r
+ delimiter = xmlXPathPopString(ctxt);\r
+ if (xmlXPathCheckError(ctxt))\r
+ return;\r
+ } else {\r
+ delimiter = xmlStrdup((const xmlChar *) " ");\r
+ }\r
+ if (delimiter == NULL)\r
+ return;\r
+ delimiterLength = xmlStrlen (delimiter);\r
+\r
+ str = xmlXPathPopString(ctxt);\r
+ if (xmlXPathCheckError(ctxt) || (str == NULL)) {\r
+ xmlFree(delimiter);\r
+ return;\r
+ }\r
+\r
+ /* Return a result tree fragment */\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "exslt:tokenize : internal error tctxt == NULL\n");\r
+ goto fail;\r
+ }\r
+\r
+ /*\r
+ * OPTIMIZE TODO: We are creating an xmlDoc for every split!\r
+ */\r
+ container = xsltCreateRVT(tctxt);\r
+ if (container != NULL) {\r
+ xsltRegisterLocalRVT(tctxt, container);\r
+ ret = xmlXPathNewNodeSet(NULL);\r
+ if (ret != NULL) {\r
+ for (cur = str, token = str; *cur != 0; cur++) {\r
+ if (delimiterLength == 0) {\r
+ if (cur != token) {\r
+ xmlChar tmp = *cur;\r
+ *cur = 0;\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", token);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ *cur = tmp;\r
+ token++;\r
+ }\r
+ }\r
+ else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {\r
+ if (cur == token) {\r
+ /* discard empty tokens */\r
+ cur = cur + delimiterLength - 1;\r
+ token = cur + 1;\r
+ continue;\r
+ }\r
+ *cur = 0;\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", token);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ *cur = *delimiter;\r
+ cur = cur + delimiterLength - 1;\r
+ token = cur + 1;\r
+ }\r
+ }\r
+ if (token != cur) {\r
+ node = xmlNewDocRawNode(container, NULL,\r
+ (const xmlChar *) "token", token);\r
+ xmlAddChild((xmlNodePtr) container, node);\r
+ xmlXPathNodeSetAddUnique(ret->nodesetval, node);\r
+ }\r
+ }\r
+ }\r
+\r
+fail:\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+ if (delimiter != NULL)\r
+ xmlFree(delimiter);\r
+ if (ret != NULL)\r
+ valuePush(ctxt, ret);\r
+ else\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+}\r
+\r
+/**\r
+ * exsltStrEncodeUriFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * URI-Escapes a string\r
+ */\r
+static void\r
+exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ int escape_all = 1, str_len = 0;\r
+ xmlChar *str = NULL, *ret = NULL, *tmp;\r
+\r
+ if ((nargs < 2) || (nargs > 3)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs >= 3) {\r
+ /* check for UTF-8 if encoding was explicitly given;\r
+ we don't support anything else yet */\r
+ tmp = xmlXPathPopString(ctxt);\r
+ if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(tmp);\r
+ return;\r
+ }\r
+ xmlFree(tmp);\r
+ }\r
+\r
+ escape_all = xmlXPathPopBoolean(ctxt);\r
+\r
+ str = xmlXPathPopString(ctxt);\r
+ str_len = xmlUTF8Strlen(str);\r
+\r
+ if (str_len == 0) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(str);\r
+ return;\r
+ }\r
+\r
+ ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));\r
+ xmlXPathReturnString(ctxt, ret);\r
+\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+}\r
+\r
+/**\r
+ * exsltStrDecodeUriFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * reverses URI-Escaping of a string\r
+ */\r
+static void\r
+exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ int str_len = 0;\r
+ xmlChar *str = NULL, *ret = NULL, *tmp;\r
+\r
+ if ((nargs < 1) || (nargs > 2)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs >= 2) {\r
+ /* check for UTF-8 if encoding was explicitly given;\r
+ we don't support anything else yet */\r
+ tmp = xmlXPathPopString(ctxt);\r
+ if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(tmp);\r
+ return;\r
+ }\r
+ xmlFree(tmp);\r
+ }\r
+\r
+ str = xmlXPathPopString(ctxt);\r
+ str_len = xmlUTF8Strlen(str);\r
+\r
+ if (str_len == 0) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(str);\r
+ return;\r
+ }\r
+\r
+ ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);\r
+ if (!xmlCheckUTF8(ret)) {\r
+ /* FIXME: instead of throwing away the whole URI, we should\r
+ only discard the invalid sequence(s). How to do that? */\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(str);\r
+ xmlFree(ret);\r
+ return;\r
+ }\r
+ \r
+ xmlXPathReturnString(ctxt, ret);\r
+\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+}\r
+\r
+/**\r
+ * exsltStrPaddingFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Creates a padding string of a certain length.\r
+ */\r
+static void\r
+exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ int number, str_len = 0;\r
+ xmlChar *str = NULL, *ret = NULL, *tmp;\r
+\r
+ if ((nargs < 1) || (nargs > 2)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs == 2) {\r
+ str = xmlXPathPopString(ctxt);\r
+ str_len = xmlUTF8Strlen(str);\r
+ }\r
+ if (str_len == 0) {\r
+ if (str != NULL) xmlFree(str);\r
+ str = xmlStrdup((const xmlChar *) " ");\r
+ str_len = 1;\r
+ }\r
+\r
+ number = (int) xmlXPathPopNumber(ctxt);\r
+\r
+ if (number <= 0) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ xmlFree(str);\r
+ return;\r
+ }\r
+\r
+ while (number >= str_len) {\r
+ ret = xmlStrncat(ret, str, str_len);\r
+ number -= str_len;\r
+ }\r
+ tmp = xmlUTF8Strndup (str, number);\r
+ ret = xmlStrcat(ret, tmp);\r
+ if (tmp != NULL)\r
+ xmlFree (tmp);\r
+\r
+ xmlXPathReturnString(ctxt, ret);\r
+\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+}\r
+\r
+/**\r
+ * exsltStrAlignFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Aligns a string within another string.\r
+ */\r
+static void\r
+exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xmlChar *str, *padding, *alignment, *ret;\r
+ int str_l, padding_l;\r
+\r
+ if ((nargs < 2) || (nargs > 3)) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (nargs == 3)\r
+ alignment = xmlXPathPopString(ctxt);\r
+ else\r
+ alignment = NULL;\r
+\r
+ padding = xmlXPathPopString(ctxt);\r
+ str = xmlXPathPopString(ctxt);\r
+\r
+ str_l = xmlUTF8Strlen (str);\r
+ padding_l = xmlUTF8Strlen (padding);\r
+\r
+ if (str_l == padding_l) {\r
+ xmlXPathReturnString (ctxt, str);\r
+ xmlFree(padding);\r
+ xmlFree(alignment);\r
+ return;\r
+ }\r
+\r
+ if (str_l > padding_l) {\r
+ ret = xmlUTF8Strndup (str, padding_l);\r
+ } else {\r
+ if (xmlStrEqual(alignment, (const xmlChar *) "right")) {\r
+ ret = xmlUTF8Strndup (padding, padding_l - str_l);\r
+ ret = xmlStrcat (ret, str);\r
+ } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {\r
+ int left = (padding_l - str_l) / 2;\r
+ int right_start;\r
+\r
+ ret = xmlUTF8Strndup (padding, left);\r
+ ret = xmlStrcat (ret, str);\r
+\r
+ right_start = xmlUTF8Strsize (padding, left + str_l);\r
+ ret = xmlStrcat (ret, padding + right_start);\r
+ } else {\r
+ int str_s;\r
+\r
+ str_s = xmlStrlen (str);\r
+ ret = xmlStrdup (str);\r
+ ret = xmlStrcat (ret, padding + str_s);\r
+ }\r
+ }\r
+\r
+ xmlXPathReturnString (ctxt, ret);\r
+\r
+ xmlFree(str);\r
+ xmlFree(padding);\r
+ xmlFree(alignment);\r
+}\r
+\r
+/**\r
+ * exsltStrConcatFunction:\r
+ * @ctxt: an XPath parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Takes a node set and returns the concatenation of the string values\r
+ * of the nodes in that node set. If the node set is empty, it\r
+ * returns an empty string.\r
+ */\r
+static void\r
+exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {\r
+ xmlXPathObjectPtr obj;\r
+ xmlChar *ret = NULL;\r
+ int i;\r
+\r
+ if (nargs != 1) {\r
+ xmlXPathSetArityError(ctxt);\r
+ return;\r
+ }\r
+\r
+ if (!xmlXPathStackIsNodeSet(ctxt)) {\r
+ xmlXPathSetTypeError(ctxt);\r
+ return;\r
+ }\r
+\r
+ obj = valuePop (ctxt);\r
+\r
+ if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {\r
+ xmlXPathReturnEmptyString(ctxt);\r
+ return;\r
+ }\r
+\r
+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {\r
+ xmlChar *tmp;\r
+ tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);\r
+\r
+ ret = xmlStrcat (ret, tmp);\r
+\r
+ xmlFree(tmp);\r
+ }\r
+\r
+ xmlXPathFreeObject (obj);\r
+\r
+ xmlXPathReturnString(ctxt, ret);\r
+}\r
+\r
+/**\r
+ * exsltStrRegister:\r
+ *\r
+ * Registers the EXSLT - Strings module\r
+ */\r
+\r
+void\r
+exsltStrRegister (void) {\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrTokenizeFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "split",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrSplitFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrEncodeUriFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrDecodeUriFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "padding",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrPaddingFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "align",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrAlignFunction);\r
+ xsltRegisterExtModuleFunction ((const xmlChar *) "concat",\r
+ EXSLT_STRINGS_NAMESPACE,\r
+ exsltStrConcatFunction);\r
+}\r
-/*
- * attributes.c: Implementation of the XSLT attributes handling
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_MATH_H
-#include <math.h>
-#endif
-#ifdef HAVE_FLOAT_H
-#include <float.h>
-#endif
-#ifdef HAVE_IEEEFP_H
-#include <ieeefp.h>
-#endif
-#ifdef HAVE_NAN_H
-#include <nan.h>
-#endif
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/uri.h>
-#include <libxml/parserInternals.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "attributes.h"
-#include "namespaces.h"
-#include "templates.h"
-#include "imports.h"
-#include "transform.h"
-#include "preproc.h"
-
-#define WITH_XSLT_DEBUG_ATTRIBUTES
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_ATTRIBUTES
-#endif
-
-/*
- * TODO: merge attribute sets from different import precedence.
- * all this should be precomputed just before the transformation
- * starts or at first hit with a cache in the context.
- * The simple way for now would be to not allow redefinition of
- * attributes once generated in the output tree, possibly costlier.
- */
-
-/*
- * Useful macros
- */
-#ifdef IS_BLANK
-#undef IS_BLANK
-#endif
-
-#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
- ((c) == 0x0D))
-
-#define IS_BLANK_NODE(n) \
- (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
-
-
-/*
- * The in-memory structure corresponding to an XSLT Attribute in
- * an attribute set
- */
-
-
-typedef struct _xsltAttrElem xsltAttrElem;
-typedef xsltAttrElem *xsltAttrElemPtr;
-struct _xsltAttrElem {
- struct _xsltAttrElem *next;/* chained list */
- xmlNodePtr attr; /* the xsl:attribute definition */
- const xmlChar *set; /* or the attribute set */
- const xmlChar *ns; /* and its namespace */
-};
-
-/************************************************************************
- * *
- * XSLT Attribute handling *
- * *
- ************************************************************************/
-
-/**
- * xsltNewAttrElem:
- * @attr: the new xsl:attribute node
- *
- * Create a new XSLT AttrElem
- *
- * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
- */
-static xsltAttrElemPtr
-xsltNewAttrElem(xmlNodePtr attr) {
- xsltAttrElemPtr cur;
-
- cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));
- if (cur == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltNewAttrElem : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltAttrElem));
- cur->attr = attr;
- return(cur);
-}
-
-/**
- * xsltFreeAttrElem:
- * @attr: an XSLT AttrElem
- *
- * Free up the memory allocated by @attr
- */
-static void
-xsltFreeAttrElem(xsltAttrElemPtr attr) {
- xmlFree(attr);
-}
-
-/**
- * xsltFreeAttrElemList:
- * @list: an XSLT AttrElem list
- *
- * Free up the memory allocated by @list
- */
-static void
-xsltFreeAttrElemList(xsltAttrElemPtr list) {
- xsltAttrElemPtr next;
-
- while (list != NULL) {
- next = list->next;
- xsltFreeAttrElem(list);
- list = next;
- }
-}
-
-#ifdef XSLT_REFACTORED
- /*
- * This was moved to xsltParseStylesheetAttributeSet().
- */
-#else
-/**
- * xsltAddAttrElemList:
- * @list: an XSLT AttrElem list
- * @attr: the new xsl:attribute node
- *
- * Add the new attribute to the list.
- *
- * Returns the new list pointer
- */
-static xsltAttrElemPtr
-xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
- xsltAttrElemPtr next, cur;
-
- if (attr == NULL)
- return(list);
- if (list == NULL)
- return(xsltNewAttrElem(attr));
- cur = list;
- while (cur != NULL) {
- next = cur->next;
- if (cur->attr == attr)
- return(cur);
- if (cur->next == NULL) {
- cur->next = xsltNewAttrElem(attr);
- return(list);
- }
- cur = next;
- }
- return(list);
-}
-#endif /* XSLT_REFACTORED */
-
-/**
- * xsltMergeAttrElemList:
- * @list: an XSLT AttrElem list
- * @old: another XSLT AttrElem list
- *
- * Add all the attributes from list @old to list @list,
- * but drop redefinition of existing values.
- *
- * Returns the new list pointer
- */
-static xsltAttrElemPtr
-xsltMergeAttrElemList(xsltStylesheetPtr style,
- xsltAttrElemPtr list, xsltAttrElemPtr old) {
- xsltAttrElemPtr cur;
- int add;
-
- while (old != NULL) {
- if ((old->attr == NULL) && (old->set == NULL)) {
- old = old->next;
- continue;
- }
- /*
- * Check that the attribute is not yet in the list
- */
- cur = list;
- add = 1;
- while (cur != NULL) {
- if ((cur->attr == NULL) && (cur->set == NULL)) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if ((cur->set != NULL) && (cur->set == old->set)) {
- add = 0;
- break;
- }
- if (cur->set != NULL) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if (old->set != NULL) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if (cur->attr == old->attr) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets recursion detected\n");
- return(list);
- }
- if (cur->next == NULL)
- break;
- cur = cur->next;
- }
-
- if (add == 1) {
- /*
- * Changed to use the string-dict, rather than duplicating
- * @set and @ns; this fixes bug #340400.
- */
- if (cur == NULL) {
- list = xsltNewAttrElem(old->attr);
- if (old->set != NULL) {
- list->set = xmlDictLookup(style->dict, old->set, -1);
- if (old->ns != NULL)
- list->ns = xmlDictLookup(style->dict, old->ns, -1);
- }
- } else if (add) {
- cur->next = xsltNewAttrElem(old->attr);
- if (old->set != NULL) {
- cur->next->set = xmlDictLookup(style->dict, old->set, -1);
- if (old->ns != NULL)
- cur->next->ns = xmlDictLookup(style->dict, old->ns, -1);
- }
- }
- }
-
- old = old->next;
- }
- return(list);
-}
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltParseStylesheetAttributeSet:
- * @style: the XSLT stylesheet
- * @cur: the "attribute-set" element
- *
- * parse an XSLT stylesheet attribute-set element
- */
-
-void
-xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
- const xmlChar *ncname;
- const xmlChar *prefix;
- xmlChar *value;
- xmlNodePtr child;
- xsltAttrElemPtr attrItems;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL);
- if (value == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : name is missing\n");
- return;
- }
-
- ncname = xsltSplitQName(style->dict, value, &prefix);
- xmlFree(value);
- value = NULL;
-
- if (style->attributeSets == NULL) {
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "creating attribute set table\n");
-#endif
- style->attributeSets = xmlHashCreate(10);
- }
- if (style->attributeSets == NULL)
- return;
-
- attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix);
-
- /*
- * Parse the content. Only xsl:attribute elements are allowed.
- */
- child = cur->children;
- while (child != NULL) {
- /*
- * Report invalid nodes.
- */
- if ((child->type != XML_ELEMENT_NODE) ||
- (child->ns == NULL) ||
- (! IS_XSLT_ELEM(child)))
- {
- if (child->type == XML_ELEMENT_NODE)
- xsltTransformError(NULL, style, child,
- "xsl:attribute-set : unexpected child %s\n",
- child->name);
- else
- xsltTransformError(NULL, style, child,
- "xsl:attribute-set : child of unexpected type\n");
- } else if (!IS_XSLT_NAME(child, "attribute")) {
- xsltTransformError(NULL, style, child,
- "xsl:attribute-set : unexpected child xsl:%s\n",
- child->name);
- } else {
-#ifdef XSLT_REFACTORED
- xsltAttrElemPtr nextAttr, curAttr;
-
- /*
- * Process xsl:attribute
- * ---------------------
- */
-
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "add attribute to list %s\n", ncname);
-#endif
- /*
- * The following was taken over from
- * xsltAddAttrElemList().
- */
- if (attrItems == NULL) {
- attrItems = xsltNewAttrElem(child);
- } else {
- curAttr = attrItems;
- while (curAttr != NULL) {
- nextAttr = curAttr->next;
- if (curAttr->attr == child) {
- /*
- * URGENT TODO: Can somebody explain
- * why attrItems is set to curAttr
- * here? Is this somehow related to
- * avoidance of recursions?
- */
- attrItems = curAttr;
- goto next_child;
- }
- if (curAttr->next == NULL)
- curAttr->next = xsltNewAttrElem(child);
- curAttr = nextAttr;
- }
- }
- /*
- * Parse the xsl:attribute and its content.
- */
- xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
-#else
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "add attribute to list %s\n", ncname);
-#endif
- /*
- * OLD behaviour:
- */
- attrItems = xsltAddAttrElemList(attrItems, child);
-#endif
- }
-
-#ifdef XSLT_REFACTORED
-next_child:
-#endif
- child = child->next;
- }
-
- /*
- * Process attribue "use-attribute-sets".
- */
- /* TODO check recursion */
- value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
- NULL);
- if (value != NULL) {
- const xmlChar *curval, *endval;
- curval = value;
- while (*curval != 0) {
- while (IS_BLANK(*curval)) curval++;
- if (*curval == 0)
- break;
- endval = curval;
- while ((*endval != 0) && (!IS_BLANK(*endval))) endval++;
- curval = xmlDictLookup(style->dict, curval, endval - curval);
- if (curval) {
- const xmlChar *ncname2 = NULL;
- const xmlChar *prefix2 = NULL;
- xsltAttrElemPtr refAttrItems;
-
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "xsl:attribute-set : %s adds use %s\n", ncname, curval);
-#endif
- ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
- refAttrItems = xsltNewAttrElem(NULL);
- if (refAttrItems != NULL) {
- refAttrItems->set = ncname2;
- refAttrItems->ns = prefix2;
- attrItems = xsltMergeAttrElemList(style,
- attrItems, refAttrItems);
- xsltFreeAttrElem(refAttrItems);
- }
- }
- curval = endval;
- }
- xmlFree(value);
- value = NULL;
- }
-
- /*
- * Update the value
- */
- /*
- * TODO: Why is this dummy entry needed.?
- */
- if (attrItems == NULL)
- attrItems = xsltNewAttrElem(NULL);
- xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL);
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "updated attribute list %s\n", ncname);
-#endif
-}
-
-/**
- * xsltGetSAS:
- * @style: the XSLT stylesheet
- * @name: the attribute list name
- * @ns: the attribute list namespace
- *
- * lookup an attribute set based on the style cascade
- *
- * Returns the attribute set or NULL
- */
-static xsltAttrElemPtr
-xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) {
- xsltAttrElemPtr values;
-
- while (style != NULL) {
- values = xmlHashLookup2(style->attributeSets, name, ns);
- if (values != NULL)
- return(values);
- style = xsltNextImport(style);
- }
- return(NULL);
-}
-
-/**
- * xsltResolveSASCallback,:
- * @style: the XSLT stylesheet
- *
- * resolve the references in an attribute set.
- */
-static void
-xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
- const xmlChar *name, const xmlChar *ns,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- xsltAttrElemPtr tmp;
- xsltAttrElemPtr refs;
-
- tmp = values;
- while (tmp != NULL) {
- if (tmp->set != NULL) {
- /*
- * Check against cycles !
- */
- if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
- name);
- } else {
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "Importing attribute list %s\n", tmp->set);
-#endif
-
- refs = xsltGetSAS(style, tmp->set, tmp->ns);
- if (refs == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
- name, tmp->set);
- } else {
- /*
- * recurse first for cleanup
- */
- xsltResolveSASCallback(refs, style, name, ns, NULL);
- /*
- * Then merge
- */
- xsltMergeAttrElemList(style, values, refs);
- /*
- * Then suppress the reference
- */
- tmp->set = NULL;
- tmp->ns = NULL;
- }
- }
- }
- tmp = tmp->next;
- }
-}
-
-/**
- * xsltMergeSASCallback,:
- * @style: the XSLT stylesheet
- *
- * Merge an attribute set from an imported stylesheet.
- */
-static void
-xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
- const xmlChar *name, const xmlChar *ns,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- int ret;
- xsltAttrElemPtr topSet;
-
- ret = xmlHashAddEntry2(style->attributeSets, name, ns, values);
- if (ret < 0) {
- /*
- * Add failed, this attribute set can be removed.
- */
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "attribute set %s present already in top stylesheet"
- " - merging\n", name);
-#endif
- topSet = xmlHashLookup2(style->attributeSets, name, ns);
- if (topSet==NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : logic error merging from imports for"
- " attribute-set %s\n", name);
- } else {
- topSet = xsltMergeAttrElemList(style, topSet, values);
- xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL);
- }
- xsltFreeAttrElemList(values);
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- } else {
- xsltGenericDebug(xsltGenericDebugContext,
- "attribute set %s moved to top stylesheet\n",
- name);
-#endif
- }
-}
-
-/**
- * xsltResolveStylesheetAttributeSet:
- * @style: the XSLT stylesheet
- *
- * resolve the references between attribute sets.
- */
-void
-xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
- xsltStylesheetPtr cur;
-
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "Resolving attribute sets references\n");
-#endif
- /*
- * First aggregate all the attribute sets definitions from the imports
- */
- cur = xsltNextImport(style);
- while (cur != NULL) {
- if (cur->attributeSets != NULL) {
- if (style->attributeSets == NULL) {
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "creating attribute set table\n");
-#endif
- style->attributeSets = xmlHashCreate(10);
- }
- xmlHashScanFull(cur->attributeSets,
- (xmlHashScannerFull) xsltMergeSASCallback, style);
- /*
- * the attribute lists have either been migrated to style
- * or freed directly in xsltMergeSASCallback()
- */
- xmlHashFree(cur->attributeSets, NULL);
- cur->attributeSets = NULL;
- }
- cur = xsltNextImport(cur);
- }
-
- /*
- * Then resolve all the references and computes the resulting sets
- */
- if (style->attributeSets != NULL) {
- xmlHashScanFull(style->attributeSets,
- (xmlHashScannerFull) xsltResolveSASCallback, style);
- }
-}
-
-/**
- * xsltAttributeInternal:
- * @ctxt: a XSLT process context
- * @node: the current node in the source tree
- * @inst: the xsl:attribute element
- * @comp: precomputed information
- * @fromAttributeSet: the attribute comes from an attribute-set
- *
- * Process the xslt attribute node on the source node
- */
-static void
-xsltAttributeInternal(xsltTransformContextPtr ctxt,
- xmlNodePtr currentNode,
- xmlNodePtr inst,
- xsltStylePreCompPtr castedComp,
- int fromAttributeSet)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemAttributePtr comp =
- (xsltStyleItemAttributePtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xmlNodePtr targetElem;
- xmlChar *prop = NULL;
- const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;
- xmlChar *value = NULL;
- xmlNsPtr ns = NULL;
- xmlAttrPtr attr;
-
- if ((ctxt == NULL) || (currentNode == NULL) || (inst == 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;
- /*
- * BIG NOTE: This previously used xsltGetSpecialNamespace() and
- * xsltGetNamespace(), but since both are not appropriate, we
- * will process namespace lookup here to avoid adding yet another
- * ns-lookup function to namespaces.c.
- */
- /*
- * SPEC XSLT 1.0: Error cases:
- * - Creating nodes other than text nodes during the instantiation of
- * the content of the xsl:attribute element; implementations may
- * either signal the error or ignore the offending nodes."
- */
-
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltAttributeInternal(): "
- "The instruction was no compiled.\n");
- return;
- }
- /*
- * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
- * So report an internal error?
- */
- if (ctxt->insert == NULL)
- return;
- /*
- * SPEC XSLT 1.0:
- * "Adding an attribute to a node that is not an element;
- * implementations may either signal the error or ignore the attribute."
- *
- * TODO: I think we should signal such errors in the future, and maybe
- * provide an option to ignore such errors.
- */
- targetElem = ctxt->insert;
- if (targetElem->type != XML_ELEMENT_NODE)
- return;
-
- /*
- * SPEC XSLT 1.0:
- * "Adding an attribute to an element after children have been added
- * to it; implementations may either signal the error or ignore the
- * attribute."
- *
- * TODO: We should decide whether not to report such errors or
- * to ignore them; note that we *ignore* if the parent is not an
- * element, but here we report an error.
- */
- if (targetElem->children != NULL) {
- /*
- * NOTE: Ah! This seems to be intended to support streamed
- * result generation!.
- */
- xsltTransformError(ctxt, NULL, inst,
- "xsl:attribute: Cannot add attributes to an "
- "element if children have been already added "
- "to the element.\n");
- return;
- }
-
- /*
- * Process the name
- * ----------------
- */
-
-#ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(inst, currentNode, NULL, ctxt);
-#endif
-
- 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:attribute: The attribute 'name' is missing.\n");
- goto error;
- }
- if (xmlValidateQName(prop, 0)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:attribute: 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);
-
- /*
- * Reject a prefix of "xmlns".
- */
- if ((prefix != NULL) &&
- (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)))
- {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAttribute: xmlns prefix forbidden\n");
-#endif
- /*
- * SPEC XSLT 1.0:
- * "It is an error if the string that results from instantiating
- * the attribute value template is not a QName or is the string
- * xmlns. An XSLT processor may signal the error; if it does not
- * signal the error, it must recover by not adding the attribute
- * to the result tree."
- * TODO: Decide which way to go here.
- */
- goto error;
- }
-
- } else {
- /*
- * The "name" value was static.
- */
-#ifdef XSLT_REFACTORED
- prefix = comp->nsPrefix;
- name = comp->name;
-#else
- name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
-#endif
- }
-
- /*
- * Process namespace semantics
- * ---------------------------
- *
- * Evaluate the namespace name.
- */
- if (comp->has_ns) {
- /*
- * The "namespace" attribute was existent.
- */
- 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);
- /*
- * This fixes bug #302020: The AVT might also evaluate to the
- * empty string; this means that the empty string also indicates
- * "no 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);
- };
- } else if (prefix != NULL) {
- /*
- * 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:attribute element, *not* including any
- * default namespace declaration."
- */
- ns = xmlSearchNs(inst->doc, inst, prefix);
- if (ns == NULL) {
- /*
- * Note that this is treated as an error now (checked with
- * Saxon, Xalan-J and MSXML).
- */
- xsltTransformError(ctxt, NULL, inst,
- "xsl:attribute: 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;
- }
-
- if (fromAttributeSet) {
- /*
- * This tries to ensure that xsl:attribute(s) coming
- * from an xsl:attribute-set won't override attribute of
- * literal result elements or of explicit xsl:attribute(s).
- * URGENT TODO: This might be buggy, since it will miss to
- * overwrite two equal attributes both from attribute sets.
- */
- attr = xmlHasNsProp(targetElem, name, nsName);
- if (attr != NULL)
- return;
- }
-
- /*
- * Find/create a matching ns-decl in the result tree.
- */
- ns = NULL;
-
-#if 0
- if (0) {
- /*
- * OPTIMIZE TODO: How do we know if we are adding to a
- * fragment or to the result tree?
- *
- * If we are adding to a result tree fragment (i.e., not to the
- * actual result tree), we'll don't bother searching for the
- * ns-decl, but just store it in the dummy-doc of the result
- * tree fragment.
- */
- if (nsName != NULL) {
- ns = xsltTreeAcquireStoredNs(ctxt->document->doc, nsName,
- prefix);
- }
- }
-#endif
-
- if (nsName != NULL) {
- /*
- * Something about ns-prefixes:
- * SPEC XSLT 1.0:
- * "XSLT processors may make use of the prefix of the QName specified
- * in the name attribute when selecting the prefix used for outputting
- * the created attribute as XML; however, they are not required to do
- * so and, if the prefix is xmlns, they must not do so"
- */
- /*
- * xsl:attribute can produce a scenario where the prefix is NULL,
- * so generate a prefix.
- */
- if (prefix == NULL) {
- xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
-
- ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST pref,
- targetElem);
-
- xmlFree(pref);
- } else {
- ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
- targetElem);
- }
- if (ns == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Namespace fixup error: Failed to acquire an in-scope "
- "namespace binding for the generated attribute '{%s}%s'.\n",
- nsName, name);
- goto error;
- }
- }
- /*
- * Construction of the value
- * -------------------------
- */
- if (inst->children == NULL) {
- /*
- * No content.
- * TODO: Do we need to put the empty string in ?
- */
- attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
- } else if ((inst->children->next == NULL) &&
- ((inst->children->type == XML_TEXT_NODE) ||
- (inst->children->type == XML_CDATA_SECTION_NODE)))
- {
- xmlNodePtr copyTxt;
-
- /*
- * xmlSetNsProp() will take care of duplicates.
- */
- attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
- if (attr == NULL) /* TODO: report error ? */
- goto error;
- /*
- * This was taken over from xsltCopyText() (transform.c).
- */
- if (ctxt->internalized &&
- (ctxt->insert->doc != NULL) &&
- (ctxt->insert->doc->dict == ctxt->dict))
- {
- copyTxt = xmlNewText(NULL);
- if (copyTxt == NULL) /* TODO: report error */
- goto error;
- /*
- * This is a safe scenario where we don't need to lookup
- * the dict.
- */
- copyTxt->content = inst->children->content;
- /*
- * Copy "disable-output-escaping" information.
- * TODO: Does this have any effect for attribute values
- * anyway?
- */
- if (inst->children->name == xmlStringTextNoenc)
- copyTxt->name = xmlStringTextNoenc;
- } else {
- /*
- * Copy the value.
- */
- copyTxt = xmlNewText(inst->children->content);
- if (copyTxt == NULL) /* TODO: report error */
- goto error;
- }
- attr->children = attr->last = copyTxt;
- copyTxt->parent = (xmlNodePtr) attr;
- copyTxt->doc = attr->doc;
- /*
- * Copy "disable-output-escaping" information.
- * TODO: Does this have any effect for attribute values
- * anyway?
- */
- if (inst->children->name == xmlStringTextNoenc)
- copyTxt->name = xmlStringTextNoenc;
-
- } else {
- /*
- * The sequence constructor might be complex, so instantiate it.
- */
- value = xsltEvalTemplateString(ctxt, currentNode, inst);
- if (value != NULL) {
- attr = xmlSetNsProp(ctxt->insert, ns, name, value);
- xmlFree(value);
- } else {
- /*
- * TODO: Do we have to add the empty string to the attr?
- * TODO: Does a value of NULL indicate an
- * error in xsltEvalTemplateString() ?
- */
- attr = xmlSetNsProp(ctxt->insert, ns, name,
- (const xmlChar *) "");
- }
- }
-
-error:
- return;
-}
-
-/**
- * xsltAttribute:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt attribute node
- * @comp: precomputed information
- *
- * Process the xslt attribute node on the source node
- */
-void
-xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr comp) {
- xsltAttributeInternal(ctxt, node, inst, comp, 0);
-}
-
-/**
- * xsltApplyAttributeSet:
- * @ctxt: the XSLT stylesheet
- * @node: the node in the source tree.
- * @inst: the attribute node "xsl:use-attribute-sets"
- * @attrSets: the list of QNames of the attribute-sets to be applied
- *
- * Apply the xsl:use-attribute-sets.
- * If @attrSets is NULL, then @inst will be used to exctract this
- * value.
- * If both, @attrSets and @inst, are NULL, then this will do nothing.
- */
-void
-xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst,
- const xmlChar *attrSets)
-{
- const xmlChar *ncname = NULL;
- const xmlChar *prefix = NULL;
- const xmlChar *curstr, *endstr;
- xsltAttrElemPtr attrs;
- xsltStylesheetPtr style;
-
- if (attrSets == NULL) {
- if (inst == NULL)
- return;
- else {
- /*
- * Extract the value from @inst.
- */
- if (inst->type == XML_ATTRIBUTE_NODE) {
- if ( ((xmlAttrPtr) inst)->children != NULL)
- attrSets = ((xmlAttrPtr) inst)->children->content;
-
- }
- if (attrSets == NULL) {
- /*
- * TODO: Return an error?
- */
- return;
- }
- }
- }
- /*
- * Parse/apply the list of QNames.
- */
- curstr = attrSets;
- while (*curstr != 0) {
- while (IS_BLANK(*curstr))
- curstr++;
- if (*curstr == 0)
- break;
- endstr = curstr;
- while ((*endstr != 0) && (!IS_BLANK(*endstr)))
- endstr++;
- curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
- if (curstr) {
- /*
- * TODO: Validate the QName.
- */
-
-#ifdef WITH_XSLT_DEBUG_curstrUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "apply curstrute set %s\n", curstr);
-#endif
- ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
-
- style = ctxt->style;
-
-#ifdef WITH_DEBUGGER
- if ((style != NULL) &&
- (style->attributeSets != NULL) &&
- (ctxt->debugStatus != XSLT_DEBUG_NONE))
- {
- attrs =
- xmlHashLookup2(style->attributeSets, ncname, prefix);
- if ((attrs != NULL) && (attrs->attr != NULL))
- xslHandleDebugger(attrs->attr->parent, node, NULL,
- ctxt);
- }
-#endif
- /*
- * Lookup the referenced curstrute-set.
- */
- while (style != NULL) {
- attrs =
- xmlHashLookup2(style->attributeSets, ncname, prefix);
- while (attrs != NULL) {
- if (attrs->attr != NULL) {
- xsltAttributeInternal(ctxt, node, attrs->attr,
- attrs->attr->psvi, 1);
- }
- attrs = attrs->next;
- }
- style = xsltNextImport(style);
- }
- }
- curstr = endstr;
- }
-}
-
-/**
- * xsltFreeAttributeSetsHashes:
- * @style: an XSLT stylesheet
- *
- * Free up the memory used by attribute sets
- */
-void
-xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
- if (style->attributeSets != NULL)
- xmlHashFree((xmlHashTablePtr) style->attributeSets,
- (xmlHashDeallocator) xsltFreeAttrElemList);
- style->attributeSets = NULL;
-}
+/*\r
+ * attributes.c: Implementation of the XSLT attributes handling\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#ifdef HAVE_SYS_TYPES_H\r
+#include <sys/types.h>\r
+#endif\r
+#ifdef HAVE_MATH_H\r
+#include <math.h>\r
+#endif\r
+#ifdef HAVE_FLOAT_H\r
+#include <float.h>\r
+#endif\r
+#ifdef HAVE_IEEEFP_H\r
+#include <ieeefp.h>\r
+#endif\r
+#ifdef HAVE_NAN_H\r
+#include <nan.h>\r
+#endif\r
+#ifdef HAVE_CTYPE_H\r
+#include <ctype.h>\r
+#endif\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/uri.h>\r
+#include <libxml/parserInternals.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "attributes.h"\r
+#include "namespaces.h"\r
+#include "templates.h"\r
+#include "imports.h"\r
+#include "transform.h"\r
+#include "preproc.h"\r
+\r
+#define WITH_XSLT_DEBUG_ATTRIBUTES\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_ATTRIBUTES\r
+#endif\r
+\r
+/*\r
+ * TODO: merge attribute sets from different import precedence.\r
+ * all this should be precomputed just before the transformation\r
+ * starts or at first hit with a cache in the context.\r
+ * The simple way for now would be to not allow redefinition of\r
+ * attributes once generated in the output tree, possibly costlier.\r
+ */\r
+\r
+/*\r
+ * Useful macros\r
+ */\r
+#ifdef IS_BLANK\r
+#undef IS_BLANK\r
+#endif\r
+\r
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \\r
+ ((c) == 0x0D))\r
+\r
+#define IS_BLANK_NODE(n) \\r
+ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))\r
+\r
+\r
+/*\r
+ * The in-memory structure corresponding to an XSLT Attribute in\r
+ * an attribute set\r
+ */\r
+\r
+\r
+typedef struct _xsltAttrElem xsltAttrElem;\r
+typedef xsltAttrElem *xsltAttrElemPtr;\r
+struct _xsltAttrElem {\r
+ struct _xsltAttrElem *next;/* chained list */\r
+ xmlNodePtr attr; /* the xsl:attribute definition */\r
+ const xmlChar *set; /* or the attribute set */\r
+ const xmlChar *ns; /* and its namespace */\r
+};\r
+\r
+/************************************************************************\r
+ * *\r
+ * XSLT Attribute handling *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewAttrElem:\r
+ * @attr: the new xsl:attribute node\r
+ *\r
+ * Create a new XSLT AttrElem\r
+ *\r
+ * Returns the newly allocated xsltAttrElemPtr or NULL in case of error\r
+ */\r
+static xsltAttrElemPtr\r
+xsltNewAttrElem(xmlNodePtr attr) {\r
+ xsltAttrElemPtr cur;\r
+\r
+ cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));\r
+ if (cur == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltNewAttrElem : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltAttrElem));\r
+ cur->attr = attr;\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeAttrElem:\r
+ * @attr: an XSLT AttrElem\r
+ *\r
+ * Free up the memory allocated by @attr\r
+ */\r
+static void\r
+xsltFreeAttrElem(xsltAttrElemPtr attr) {\r
+ xmlFree(attr);\r
+}\r
+\r
+/**\r
+ * xsltFreeAttrElemList:\r
+ * @list: an XSLT AttrElem list\r
+ *\r
+ * Free up the memory allocated by @list\r
+ */\r
+static void\r
+xsltFreeAttrElemList(xsltAttrElemPtr list) {\r
+ xsltAttrElemPtr next;\r
+ \r
+ while (list != NULL) {\r
+ next = list->next;\r
+ xsltFreeAttrElem(list);\r
+ list = next;\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * This was moved to xsltParseStylesheetAttributeSet().\r
+ */\r
+#else\r
+/**\r
+ * xsltAddAttrElemList:\r
+ * @list: an XSLT AttrElem list\r
+ * @attr: the new xsl:attribute node\r
+ *\r
+ * Add the new attribute to the list.\r
+ *\r
+ * Returns the new list pointer\r
+ */\r
+static xsltAttrElemPtr\r
+xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {\r
+ xsltAttrElemPtr next, cur;\r
+\r
+ if (attr == NULL)\r
+ return(list);\r
+ if (list == NULL)\r
+ return(xsltNewAttrElem(attr));\r
+ cur = list;\r
+ while (cur != NULL) { \r
+ next = cur->next;\r
+ if (cur->attr == attr)\r
+ return(cur);\r
+ if (cur->next == NULL) {\r
+ cur->next = xsltNewAttrElem(attr);\r
+ return(list);\r
+ }\r
+ cur = next;\r
+ }\r
+ return(list);\r
+}\r
+#endif /* XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltMergeAttrElemList:\r
+ * @list: an XSLT AttrElem list\r
+ * @old: another XSLT AttrElem list\r
+ *\r
+ * Add all the attributes from list @old to list @list,\r
+ * but drop redefinition of existing values.\r
+ *\r
+ * Returns the new list pointer\r
+ */\r
+static xsltAttrElemPtr\r
+xsltMergeAttrElemList(xsltStylesheetPtr style,\r
+ xsltAttrElemPtr list, xsltAttrElemPtr old) {\r
+ xsltAttrElemPtr cur;\r
+ int add;\r
+\r
+ while (old != NULL) {\r
+ if ((old->attr == NULL) && (old->set == NULL)) {\r
+ old = old->next;\r
+ continue;\r
+ }\r
+ /*\r
+ * Check that the attribute is not yet in the list\r
+ */\r
+ cur = list;\r
+ add = 1;\r
+ while (cur != NULL) {\r
+ if ((cur->attr == NULL) && (cur->set == NULL)) {\r
+ if (cur->next == NULL)\r
+ break;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if ((cur->set != NULL) && (cur->set == old->set)) {\r
+ add = 0;\r
+ break;\r
+ }\r
+ if (cur->set != NULL) {\r
+ if (cur->next == NULL)\r
+ break;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if (old->set != NULL) {\r
+ if (cur->next == NULL)\r
+ break;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if (cur->attr == old->attr) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:attribute-set : use-attribute-sets recursion detected\n");\r
+ return(list);\r
+ }\r
+ if (cur->next == NULL)\r
+ break;\r
+ cur = cur->next;\r
+ }\r
+\r
+ if (add == 1) {\r
+ /*\r
+ * Changed to use the string-dict, rather than duplicating\r
+ * @set and @ns; this fixes bug #340400.\r
+ */\r
+ if (cur == NULL) {\r
+ list = xsltNewAttrElem(old->attr);\r
+ if (old->set != NULL) {\r
+ list->set = xmlDictLookup(style->dict, old->set, -1);\r
+ if (old->ns != NULL)\r
+ list->ns = xmlDictLookup(style->dict, old->ns, -1);\r
+ }\r
+ } else if (add) {\r
+ cur->next = xsltNewAttrElem(old->attr);\r
+ if (old->set != NULL) {\r
+ cur->next->set = xmlDictLookup(style->dict, old->set, -1);\r
+ if (old->ns != NULL)\r
+ cur->next->ns = xmlDictLookup(style->dict, old->ns, -1);\r
+ }\r
+ }\r
+ }\r
+\r
+ old = old->next;\r
+ }\r
+ return(list);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltParseStylesheetAttributeSet:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "attribute-set" element\r
+ *\r
+ * parse an XSLT stylesheet attribute-set element\r
+ */\r
+\r
+void\r
+xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {\r
+ const xmlChar *ncname;\r
+ const xmlChar *prefix;\r
+ xmlChar *value;\r
+ xmlNodePtr child;\r
+ xsltAttrElemPtr attrItems;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+\r
+ value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL);\r
+ if (value == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:attribute-set : name is missing\n");\r
+ return;\r
+ }\r
+\r
+ ncname = xsltSplitQName(style->dict, value, &prefix);\r
+ xmlFree(value);\r
+ value = NULL;\r
+\r
+ if (style->attributeSets == NULL) {\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "creating attribute set table\n");\r
+#endif\r
+ style->attributeSets = xmlHashCreate(10);\r
+ }\r
+ if (style->attributeSets == NULL)\r
+ return;\r
+\r
+ attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix);\r
+\r
+ /*\r
+ * Parse the content. Only xsl:attribute elements are allowed.\r
+ */\r
+ child = cur->children;\r
+ while (child != NULL) {\r
+ /*\r
+ * Report invalid nodes.\r
+ */\r
+ if ((child->type != XML_ELEMENT_NODE) ||\r
+ (child->ns == NULL) ||\r
+ (! IS_XSLT_ELEM(child)))\r
+ {\r
+ if (child->type == XML_ELEMENT_NODE)\r
+ xsltTransformError(NULL, style, child,\r
+ "xsl:attribute-set : unexpected child %s\n",\r
+ child->name);\r
+ else\r
+ xsltTransformError(NULL, style, child,\r
+ "xsl:attribute-set : child of unexpected type\n");\r
+ } else if (!IS_XSLT_NAME(child, "attribute")) {\r
+ xsltTransformError(NULL, style, child,\r
+ "xsl:attribute-set : unexpected child xsl:%s\n",\r
+ child->name);\r
+ } else {\r
+#ifdef XSLT_REFACTORED\r
+ xsltAttrElemPtr nextAttr, curAttr;\r
+\r
+ /*\r
+ * Process xsl:attribute\r
+ * ---------------------\r
+ */\r
+\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add attribute to list %s\n", ncname);\r
+#endif\r
+ /*\r
+ * The following was taken over from\r
+ * xsltAddAttrElemList().\r
+ */\r
+ if (attrItems == NULL) {\r
+ attrItems = xsltNewAttrElem(child);\r
+ } else {\r
+ curAttr = attrItems;\r
+ while (curAttr != NULL) {\r
+ nextAttr = curAttr->next;\r
+ if (curAttr->attr == child) {\r
+ /*\r
+ * URGENT TODO: Can somebody explain\r
+ * why attrItems is set to curAttr\r
+ * here? Is this somehow related to\r
+ * avoidance of recursions?\r
+ */\r
+ attrItems = curAttr;\r
+ goto next_child;\r
+ }\r
+ if (curAttr->next == NULL) \r
+ curAttr->next = xsltNewAttrElem(child);\r
+ curAttr = nextAttr;\r
+ }\r
+ }\r
+ /*\r
+ * Parse the xsl:attribute and its content.\r
+ */\r
+ xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);\r
+#else\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add attribute to list %s\n", ncname);\r
+#endif\r
+ /*\r
+ * OLD behaviour:\r
+ */\r
+ attrItems = xsltAddAttrElemList(attrItems, child);\r
+#endif\r
+ }\r
+\r
+#ifdef XSLT_REFACTORED\r
+next_child:\r
+#endif\r
+ child = child->next;\r
+ }\r
+\r
+ /*\r
+ * Process attribue "use-attribute-sets".\r
+ */\r
+ /* TODO check recursion */ \r
+ value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",\r
+ NULL);\r
+ if (value != NULL) {\r
+ const xmlChar *curval, *endval;\r
+ curval = value;\r
+ while (*curval != 0) {\r
+ while (IS_BLANK(*curval)) curval++;\r
+ if (*curval == 0)\r
+ break;\r
+ endval = curval;\r
+ while ((*endval != 0) && (!IS_BLANK(*endval))) endval++;\r
+ curval = xmlDictLookup(style->dict, curval, endval - curval);\r
+ if (curval) {\r
+ const xmlChar *ncname2 = NULL;\r
+ const xmlChar *prefix2 = NULL;\r
+ xsltAttrElemPtr refAttrItems;\r
+ \r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsl:attribute-set : %s adds use %s\n", ncname, curval);\r
+#endif\r
+ ncname2 = xsltSplitQName(style->dict, curval, &prefix2);\r
+ refAttrItems = xsltNewAttrElem(NULL);\r
+ if (refAttrItems != NULL) {\r
+ refAttrItems->set = ncname2;\r
+ refAttrItems->ns = prefix2;\r
+ attrItems = xsltMergeAttrElemList(style,\r
+ attrItems, refAttrItems);\r
+ xsltFreeAttrElem(refAttrItems);\r
+ }\r
+ }\r
+ curval = endval;\r
+ }\r
+ xmlFree(value);\r
+ value = NULL;\r
+ }\r
+\r
+ /*\r
+ * Update the value\r
+ */\r
+ /*\r
+ * TODO: Why is this dummy entry needed.?\r
+ */\r
+ if (attrItems == NULL)\r
+ attrItems = xsltNewAttrElem(NULL);\r
+ xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL);\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "updated attribute list %s\n", ncname);\r
+#endif\r
+}\r
+\r
+/**\r
+ * xsltGetSAS:\r
+ * @style: the XSLT stylesheet\r
+ * @name: the attribute list name\r
+ * @ns: the attribute list namespace\r
+ *\r
+ * lookup an attribute set based on the style cascade\r
+ *\r
+ * Returns the attribute set or NULL\r
+ */\r
+static xsltAttrElemPtr\r
+xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) {\r
+ xsltAttrElemPtr values;\r
+\r
+ while (style != NULL) {\r
+ values = xmlHashLookup2(style->attributeSets, name, ns);\r
+ if (values != NULL)\r
+ return(values);\r
+ style = xsltNextImport(style);\r
+ }\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltResolveSASCallback,:\r
+ * @style: the XSLT stylesheet\r
+ *\r
+ * resolve the references in an attribute set.\r
+ */\r
+static void\r
+xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,\r
+ const xmlChar *name, const xmlChar *ns,\r
+ ATTRIBUTE_UNUSED const xmlChar *ignored) {\r
+ xsltAttrElemPtr tmp;\r
+ xsltAttrElemPtr refs;\r
+\r
+ tmp = values;\r
+ while (tmp != NULL) {\r
+ if (tmp->set != NULL) {\r
+ /*\r
+ * Check against cycles !\r
+ */\r
+ if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",\r
+ name);\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Importing attribute list %s\n", tmp->set);\r
+#endif\r
+\r
+ refs = xsltGetSAS(style, tmp->set, tmp->ns);\r
+ if (refs == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",\r
+ name, tmp->set);\r
+ } else {\r
+ /*\r
+ * recurse first for cleanup\r
+ */\r
+ xsltResolveSASCallback(refs, style, name, ns, NULL);\r
+ /*\r
+ * Then merge\r
+ */\r
+ xsltMergeAttrElemList(style, values, refs);\r
+ /*\r
+ * Then suppress the reference\r
+ */\r
+ tmp->set = NULL;\r
+ tmp->ns = NULL;\r
+ }\r
+ }\r
+ }\r
+ tmp = tmp->next;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltMergeSASCallback,:\r
+ * @style: the XSLT stylesheet\r
+ *\r
+ * Merge an attribute set from an imported stylesheet.\r
+ */\r
+static void\r
+xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,\r
+ const xmlChar *name, const xmlChar *ns,\r
+ ATTRIBUTE_UNUSED const xmlChar *ignored) {\r
+ int ret;\r
+ xsltAttrElemPtr topSet;\r
+\r
+ ret = xmlHashAddEntry2(style->attributeSets, name, ns, values);\r
+ if (ret < 0) {\r
+ /*\r
+ * Add failed, this attribute set can be removed.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "attribute set %s present already in top stylesheet"\r
+ " - merging\n", name);\r
+#endif\r
+ topSet = xmlHashLookup2(style->attributeSets, name, ns);\r
+ if (topSet==NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:attribute-set : logic error merging from imports for"\r
+ " attribute-set %s\n", name);\r
+ } else {\r
+ topSet = xsltMergeAttrElemList(style, topSet, values);\r
+ xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL);\r
+ }\r
+ xsltFreeAttrElemList(values);\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ } else {\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "attribute set %s moved to top stylesheet\n",\r
+ name);\r
+#endif\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltResolveStylesheetAttributeSet:\r
+ * @style: the XSLT stylesheet\r
+ *\r
+ * resolve the references between attribute sets.\r
+ */\r
+void\r
+xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {\r
+ xsltStylesheetPtr cur;\r
+\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Resolving attribute sets references\n");\r
+#endif\r
+ /*\r
+ * First aggregate all the attribute sets definitions from the imports\r
+ */\r
+ cur = xsltNextImport(style);\r
+ while (cur != NULL) {\r
+ if (cur->attributeSets != NULL) {\r
+ if (style->attributeSets == NULL) {\r
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "creating attribute set table\n");\r
+#endif\r
+ style->attributeSets = xmlHashCreate(10);\r
+ }\r
+ xmlHashScanFull(cur->attributeSets, \r
+ (xmlHashScannerFull) xsltMergeSASCallback, style);\r
+ /*\r
+ * the attribute lists have either been migrated to style\r
+ * or freed directly in xsltMergeSASCallback()\r
+ */\r
+ xmlHashFree(cur->attributeSets, NULL);\r
+ cur->attributeSets = NULL;\r
+ }\r
+ cur = xsltNextImport(cur);\r
+ }\r
+\r
+ /*\r
+ * Then resolve all the references and computes the resulting sets\r
+ */\r
+ if (style->attributeSets != NULL) {\r
+ xmlHashScanFull(style->attributeSets, \r
+ (xmlHashScannerFull) xsltResolveSASCallback, style);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltAttributeInternal:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the current node in the source tree\r
+ * @inst: the xsl:attribute element\r
+ * @comp: precomputed information\r
+ * @fromAttributeSet: the attribute comes from an attribute-set\r
+ *\r
+ * Process the xslt attribute node on the source node\r
+ */\r
+static void\r
+xsltAttributeInternal(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr inst,\r
+ xsltStylePreCompPtr castedComp,\r
+ int fromAttributeSet)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemAttributePtr comp =\r
+ (xsltStyleItemAttributePtr) castedComp; \r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xmlNodePtr targetElem;\r
+ xmlChar *prop = NULL; \r
+ const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;\r
+ xmlChar *value = NULL;\r
+ xmlNsPtr ns = NULL;\r
+ xmlAttrPtr attr; \r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))\r
+ return;\r
+\r
+ /* \r
+ * A comp->has_name == 0 indicates that we need to skip this instruction,\r
+ * since it was evaluated to be invalid already during compilation.\r
+ */\r
+ if (!comp->has_name)\r
+ return;\r
+ /*\r
+ * BIG NOTE: This previously used xsltGetSpecialNamespace() and\r
+ * xsltGetNamespace(), but since both are not appropriate, we\r
+ * will process namespace lookup here to avoid adding yet another\r
+ * ns-lookup function to namespaces.c.\r
+ */\r
+ /*\r
+ * SPEC XSLT 1.0: Error cases:\r
+ * - Creating nodes other than text nodes during the instantiation of\r
+ * the content of the xsl:attribute element; implementations may\r
+ * either signal the error or ignore the offending nodes."\r
+ */\r
+\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltAttributeInternal(): "\r
+ "The XSLT 'attribute' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+ /*\r
+ * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?\r
+ * So report an internal error?\r
+ */\r
+ if (ctxt->insert == NULL)\r
+ return; \r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "Adding an attribute to a node that is not an element;\r
+ * implementations may either signal the error or ignore the attribute."\r
+ *\r
+ * TODO: I think we should signal such errors in the future, and maybe\r
+ * provide an option to ignore such errors.\r
+ */\r
+ targetElem = ctxt->insert;\r
+ if (targetElem->type != XML_ELEMENT_NODE)\r
+ return;\r
+ \r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "Adding an attribute to an element after children have been added\r
+ * to it; implementations may either signal the error or ignore the\r
+ * attribute."\r
+ *\r
+ * TODO: We should decide whether not to report such errors or\r
+ * to ignore them; note that we *ignore* if the parent is not an\r
+ * element, but here we report an error.\r
+ */\r
+ if (targetElem->children != NULL) {\r
+ /*\r
+ * NOTE: Ah! This seems to be intended to support streamed\r
+ * result generation!.\r
+ */\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:attribute: Cannot add attributes to an "\r
+ "element if children have been already added "\r
+ "to the element.\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Process the name\r
+ * ----------------\r
+ */ \r
+\r
+#ifdef WITH_DEBUGGER\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(inst, contextNode, NULL, ctxt);\r
+#endif\r
+\r
+ if (comp->name == NULL) {\r
+ /* TODO: fix attr acquisition wrt to the XSLT namespace */\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:attribute: The attribute 'name' is missing.\n");\r
+ goto error;\r
+ }\r
+ if (xmlValidateQName(prop, 0)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:attribute: The effective name '%s' is not a "\r
+ "valid QName.\n", prop);\r
+ /* we fall through to catch any further errors, if possible */\r
+ }\r
+ name = xsltSplitQName(ctxt->dict, prop, &prefix);\r
+ xmlFree(prop);\r
+\r
+ /*\r
+ * Reject a prefix of "xmlns".\r
+ */\r
+ if ((prefix != NULL) &&\r
+ (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)))\r
+ {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltAttribute: xmlns prefix forbidden\n");\r
+#endif\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "It is an error if the string that results from instantiating\r
+ * the attribute value template is not a QName or is the string\r
+ * xmlns. An XSLT processor may signal the error; if it does not\r
+ * signal the error, it must recover by not adding the attribute\r
+ * to the result tree."\r
+ * TODO: Decide which way to go here.\r
+ */\r
+ goto error;\r
+ }\r
+\r
+ } else {\r
+ /*\r
+ * The "name" value was static.\r
+ */\r
+#ifdef XSLT_REFACTORED\r
+ prefix = comp->nsPrefix;\r
+ name = comp->name;\r
+#else\r
+ name = xsltSplitQName(ctxt->dict, comp->name, &prefix);\r
+#endif\r
+ }\r
+ \r
+ /*\r
+ * Process namespace semantics\r
+ * ---------------------------\r
+ *\r
+ * Evaluate the namespace name.\r
+ */\r
+ if (comp->has_ns) {\r
+ /*\r
+ * The "namespace" attribute was existent.\r
+ */\r
+ if (comp->ns != NULL) {\r
+ /*\r
+ * No AVT; just plain text for the namespace name.\r
+ */\r
+ if (comp->ns[0] != 0)\r
+ nsName = comp->ns;\r
+ } else {\r
+ xmlChar *tmpNsName;\r
+ /*\r
+ * Eval the AVT.\r
+ */\r
+ /* TODO: check attr acquisition wrt to the XSLT namespace */\r
+ tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "namespace", XSLT_NAMESPACE); \r
+ /*\r
+ * This fixes bug #302020: The AVT might also evaluate to the \r
+ * empty string; this means that the empty string also indicates\r
+ * "no namespace".\r
+ * SPEC XSLT 1.0:\r
+ * "If the string is empty, then the expanded-name of the\r
+ * attribute has a null namespace URI."\r
+ */\r
+ if ((tmpNsName != NULL) && (tmpNsName[0] != 0))\r
+ nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);\r
+ xmlFree(tmpNsName); \r
+ }; \r
+ } else if (prefix != NULL) {\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If the namespace attribute is not present, then the QName is\r
+ * expanded into an expanded-name using the namespace declarations\r
+ * in effect for the xsl:attribute element, *not* including any\r
+ * default namespace declaration."\r
+ */ \r
+ ns = xmlSearchNs(inst->doc, inst, prefix);\r
+ if (ns == NULL) {\r
+ /*\r
+ * Note that this is treated as an error now (checked with\r
+ * Saxon, Xalan-J and MSXML).\r
+ */\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:attribute: The QName '%s:%s' has no "\r
+ "namespace binding in scope in the stylesheet; "\r
+ "this is an error, since the namespace was not "\r
+ "specified by the instruction itself.\n", prefix, name);\r
+ } else\r
+ nsName = ns->href; \r
+ }\r
+\r
+ if (fromAttributeSet) {\r
+ /*\r
+ * This tries to ensure that xsl:attribute(s) coming\r
+ * from an xsl:attribute-set won't override attribute of\r
+ * literal result elements or of explicit xsl:attribute(s).\r
+ * URGENT TODO: This might be buggy, since it will miss to\r
+ * overwrite two equal attributes both from attribute sets.\r
+ */\r
+ attr = xmlHasNsProp(targetElem, name, nsName);\r
+ if (attr != NULL)\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Find/create a matching ns-decl in the result tree.\r
+ */\r
+ ns = NULL;\r
+ \r
+#if 0\r
+ if (0) { \r
+ /*\r
+ * OPTIMIZE TODO: How do we know if we are adding to a\r
+ * fragment or to the result tree?\r
+ *\r
+ * If we are adding to a result tree fragment (i.e., not to the\r
+ * actual result tree), we'll don't bother searching for the\r
+ * ns-decl, but just store it in the dummy-doc of the result\r
+ * tree fragment.\r
+ */\r
+ if (nsName != NULL) {\r
+ /*\r
+ * TODO: Get the doc of @targetElem.\r
+ */\r
+ ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix);\r
+ }\r
+ }\r
+#endif\r
+\r
+ if (nsName != NULL) { \r
+ /*\r
+ * Something about ns-prefixes:\r
+ * SPEC XSLT 1.0:\r
+ * "XSLT processors may make use of the prefix of the QName specified\r
+ * in the name attribute when selecting the prefix used for outputting\r
+ * the created attribute as XML; however, they are not required to do\r
+ * so and, if the prefix is xmlns, they must not do so"\r
+ */\r
+ /*\r
+ * xsl:attribute can produce a scenario where the prefix is NULL,\r
+ * so generate a prefix.\r
+ */\r
+ if (prefix == NULL) {\r
+ xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");\r
+\r
+ ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST pref,\r
+ targetElem);\r
+\r
+ xmlFree(pref);\r
+ } else {\r
+ ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,\r
+ targetElem);\r
+ }\r
+ if (ns == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Namespace fixup error: Failed to acquire an in-scope "\r
+ "namespace binding for the generated attribute '{%s}%s'.\n",\r
+ nsName, name);\r
+ goto error;\r
+ }\r
+ }\r
+ /*\r
+ * Construction of the value\r
+ * -------------------------\r
+ */\r
+ if (inst->children == NULL) {\r
+ /*\r
+ * No content.\r
+ * TODO: Do we need to put the empty string in ?\r
+ */\r
+ attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");\r
+ } else if ((inst->children->next == NULL) && \r
+ ((inst->children->type == XML_TEXT_NODE) ||\r
+ (inst->children->type == XML_CDATA_SECTION_NODE)))\r
+ {\r
+ xmlNodePtr copyTxt;\r
+ \r
+ /*\r
+ * xmlSetNsProp() will take care of duplicates.\r
+ */\r
+ attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);\r
+ if (attr == NULL) /* TODO: report error ? */\r
+ goto error;\r
+ /*\r
+ * This was taken over from xsltCopyText() (transform.c).\r
+ */\r
+ if (ctxt->internalized &&\r
+ (ctxt->insert->doc != NULL) &&\r
+ (ctxt->insert->doc->dict == ctxt->dict))\r
+ {\r
+ copyTxt = xmlNewText(NULL);\r
+ if (copyTxt == NULL) /* TODO: report error */\r
+ goto error;\r
+ /*\r
+ * This is a safe scenario where we don't need to lookup\r
+ * the dict.\r
+ */\r
+ copyTxt->content = inst->children->content;\r
+ /*\r
+ * Copy "disable-output-escaping" information.\r
+ * TODO: Does this have any effect for attribute values\r
+ * anyway?\r
+ */\r
+ if (inst->children->name == xmlStringTextNoenc)\r
+ copyTxt->name = xmlStringTextNoenc;\r
+ } else {\r
+ /*\r
+ * Copy the value.\r
+ */\r
+ copyTxt = xmlNewText(inst->children->content);\r
+ if (copyTxt == NULL) /* TODO: report error */\r
+ goto error; \r
+ }\r
+ attr->children = attr->last = copyTxt;\r
+ copyTxt->parent = (xmlNodePtr) attr;\r
+ copyTxt->doc = attr->doc;\r
+ /*\r
+ * Copy "disable-output-escaping" information.\r
+ * TODO: Does this have any effect for attribute values\r
+ * anyway?\r
+ */\r
+ if (inst->children->name == xmlStringTextNoenc)\r
+ copyTxt->name = xmlStringTextNoenc; \r
+\r
+ } else {\r
+ /*\r
+ * The sequence constructor might be complex, so instantiate it.\r
+ */\r
+ value = xsltEvalTemplateString(ctxt, contextNode, inst);\r
+ if (value != NULL) {\r
+ attr = xmlSetNsProp(ctxt->insert, ns, name, value);\r
+ xmlFree(value);\r
+ } else {\r
+ /*\r
+ * TODO: Do we have to add the empty string to the attr?\r
+ * TODO: Does a value of NULL indicate an\r
+ * error in xsltEvalTemplateString() ?\r
+ */\r
+ attr = xmlSetNsProp(ctxt->insert, ns, name,\r
+ (const xmlChar *) "");\r
+ }\r
+ }\r
+\r
+error:\r
+ return; \r
+}\r
+\r
+/**\r
+ * xsltAttribute:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt attribute node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt attribute node on the source node\r
+ */\r
+void\r
+xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr comp) {\r
+ xsltAttributeInternal(ctxt, node, inst, comp, 0);\r
+}\r
+\r
+/**\r
+ * xsltApplyAttributeSet:\r
+ * @ctxt: the XSLT stylesheet\r
+ * @node: the node in the source tree.\r
+ * @inst: the attribute node "xsl:use-attribute-sets"\r
+ * @attrSets: the list of QNames of the attribute-sets to be applied\r
+ *\r
+ * Apply the xsl:use-attribute-sets.\r
+ * If @attrSets is NULL, then @inst will be used to exctract this\r
+ * value.\r
+ * If both, @attrSets and @inst, are NULL, then this will do nothing.\r
+ */\r
+void\r
+xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst,\r
+ const xmlChar *attrSets)\r
+{\r
+ const xmlChar *ncname = NULL;\r
+ const xmlChar *prefix = NULL; \r
+ const xmlChar *curstr, *endstr;\r
+ xsltAttrElemPtr attrs;\r
+ xsltStylesheetPtr style; \r
+\r
+ if (attrSets == NULL) {\r
+ if (inst == NULL)\r
+ return;\r
+ else {\r
+ /*\r
+ * Extract the value from @inst.\r
+ */\r
+ if (inst->type == XML_ATTRIBUTE_NODE) {\r
+ if ( ((xmlAttrPtr) inst)->children != NULL)\r
+ attrSets = ((xmlAttrPtr) inst)->children->content;\r
+ \r
+ }\r
+ if (attrSets == NULL) {\r
+ /*\r
+ * TODO: Return an error?\r
+ */\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * Parse/apply the list of QNames.\r
+ */\r
+ curstr = attrSets;\r
+ while (*curstr != 0) {\r
+ while (IS_BLANK(*curstr))\r
+ curstr++;\r
+ if (*curstr == 0)\r
+ break;\r
+ endstr = curstr;\r
+ while ((*endstr != 0) && (!IS_BLANK(*endstr)))\r
+ endstr++;\r
+ curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);\r
+ if (curstr) {\r
+ /*\r
+ * TODO: Validate the QName.\r
+ */\r
+\r
+#ifdef WITH_XSLT_DEBUG_curstrUTES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "apply curstrute set %s\n", curstr);\r
+#endif\r
+ ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);\r
+\r
+ style = ctxt->style;\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if ((style != NULL) &&\r
+ (style->attributeSets != NULL) &&\r
+ (ctxt->debugStatus != XSLT_DEBUG_NONE))\r
+ {\r
+ attrs =\r
+ xmlHashLookup2(style->attributeSets, ncname, prefix);\r
+ if ((attrs != NULL) && (attrs->attr != NULL))\r
+ xslHandleDebugger(attrs->attr->parent, node, NULL,\r
+ ctxt);\r
+ }\r
+#endif\r
+ /*\r
+ * Lookup the referenced curstrute-set.\r
+ */\r
+ while (style != NULL) {\r
+ attrs =\r
+ xmlHashLookup2(style->attributeSets, ncname, prefix);\r
+ while (attrs != NULL) {\r
+ if (attrs->attr != NULL) {\r
+ xsltAttributeInternal(ctxt, node, attrs->attr,\r
+ attrs->attr->psvi, 1);\r
+ }\r
+ attrs = attrs->next;\r
+ }\r
+ style = xsltNextImport(style);\r
+ }\r
+ }\r
+ curstr = endstr;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltFreeAttributeSetsHashes:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Free up the memory used by attribute sets\r
+ */\r
+void\r
+xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {\r
+ if (style->attributeSets != NULL)\r
+ xmlHashFree((xmlHashTablePtr) style->attributeSets,\r
+ (xmlHashDeallocator) xsltFreeAttrElemList);\r
+ style->attributeSets = NULL;\r
+}\r
-/*
- * documents.c: Implementation of the documents handling
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/hash.h>
-#include <libxml/parser.h>
-#include <libxml/parserInternals.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "documents.h"
-#include "transform.h"
-#include "imports.h"
-#include "keys.h"
-#include "security.h"
-
-#ifdef LIBXML_XINCLUDE_ENABLED
-#include <libxml/xinclude.h>
-#endif
-
-#define WITH_XSLT_DEBUG_DOCUMENTS
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_DOCUMENTS
-#endif
-
-/************************************************************************
- * *
- * Hooks for the document loader *
- * *
- ************************************************************************/
-
-/**
- * xsltDocDefaultLoaderFunc:
- * @URI: the URI of the document to load
- * @dict: the dictionnary to use when parsing that document
- * @options: parsing options, a set of xmlParserOption
- * @ctxt: the context, either a stylesheet or a transformation context
- * @type: the xsltLoadType indicating the kind of loading required
- *
- * Default function to load document not provided by the compilation or
- * transformation API themselve, for example when an xsl:import,
- * xsl:include is found at compilation time or when a document()
- * call is made at runtime.
- *
- * Returns the pointer to the document (which will be modified and
- * freed by the engine later), or NULL in case of error.
- */
-static xmlDocPtr
-xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,
- void *ctxt ATTRIBUTE_UNUSED,
- xsltLoadType type ATTRIBUTE_UNUSED)
-{
- xmlParserCtxtPtr pctxt;
- xmlParserInputPtr inputStream;
- xmlDocPtr doc;
-
- pctxt = xmlNewParserCtxt();
- if (pctxt == NULL)
- return(NULL);
- if ((dict != NULL) && (pctxt->dict != NULL)) {
- xmlDictFree(pctxt->dict);
- pctxt->dict = NULL;
- }
- if (dict != NULL) {
- pctxt->dict = dict;
- xmlDictReference(pctxt->dict);
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "Reusing dictionary for document\n");
-#endif
- }
- xmlCtxtUseOptions(pctxt, options);
- inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
- if (inputStream == NULL) {
- xmlFreeParserCtxt(pctxt);
- return(NULL);
- }
- inputPush(pctxt, inputStream);
- if (pctxt->directory == NULL)
- pctxt->directory = xmlParserGetDirectory((const char *) URI);
-
- xmlParseDocument(pctxt);
-
- if (pctxt->wellFormed) {
- doc = pctxt->myDoc;
- }
- else {
- doc = NULL;
- xmlFreeDoc(pctxt->myDoc);
- pctxt->myDoc = NULL;
- }
- xmlFreeParserCtxt(pctxt);
-
- return(doc);
-}
-
-
-xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
-
-/**
- * xsltSetLoaderFunc:
- * @f: the new function to handle document loading.
- *
- * Set the new function to load document, if NULL it resets it to the
- * default function.
- */
-
-void
-xsltSetLoaderFunc(xsltDocLoaderFunc f) {
- if (f == NULL)
- xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
- else
- xsltDocDefaultLoader = f;
-}
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltNewDocument:
- * @ctxt: an XSLT transformation context (or NULL)
- * @doc: a parsed XML document
- *
- * Register a new document, apply key computations
- *
- * Returns a handler to the document
- */
-xsltDocumentPtr
-xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
- xsltDocumentPtr cur;
-
- cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
- if (cur == NULL) {
- xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
- "xsltNewDocument : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltDocument));
- cur->doc = doc;
- if (ctxt != NULL) {
- if (! XSLT_IS_RES_TREE_FRAG(doc)) {
- cur->next = ctxt->docList;
- ctxt->docList = cur;
- }
-#ifdef XSLT_REFACTORED_KEYCOMP
- /*
- * A key with a specific name for a specific document
- * will only be computed if there's a call to the key()
- * function using that specific name for that specific
- * document. I.e. computation of keys will be done in
- * xsltGetKey() (keys.c) on an on-demand basis.
- */
-#else
- /*
- * Old behaviour.
- */
- xsltInitCtxtKeys(ctxt, cur);
-#endif
- }
- return(cur);
-}
-
-/**
- * xsltNewStyleDocument:
- * @style: an XSLT style sheet
- * @doc: a parsed XML document
- *
- * Register a new document, apply key computations
- *
- * Returns a handler to the document
- */
-xsltDocumentPtr
-xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
- xsltDocumentPtr cur;
-
- cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
- if (cur == NULL) {
- xsltTransformError(NULL, style, (xmlNodePtr) doc,
- "xsltNewStyleDocument : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltDocument));
- cur->doc = doc;
- if (style != NULL) {
- cur->next = style->docList;
- style->docList = cur;
- }
- return(cur);
-}
-
-/**
- * xsltFreeStyleDocuments:
- * @style: an XSLT stylesheet (representing a stylesheet-level)
- *
- * Frees the node-trees (and xsltDocument structures) of all
- * stylesheet-modules of the stylesheet-level represented by
- * the given @style.
- */
-void
-xsltFreeStyleDocuments(xsltStylesheetPtr style) {
- xsltDocumentPtr doc, cur;
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- xsltNsMapPtr nsMap;
-#endif
-
- if (style == NULL)
- return;
-
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if (XSLT_HAS_INTERNAL_NSMAP(style))
- nsMap = XSLT_GET_INTERNAL_NSMAP(style);
- else
- nsMap = NULL;
-#endif
-
- cur = style->docList;
- while (cur != NULL) {
- doc = cur;
- cur = cur->next;
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Restore all changed namespace URIs of ns-decls.
- */
- if (nsMap)
- xsltRestoreDocumentNamespaces(nsMap, doc->doc);
-#endif
- xsltFreeDocumentKeys(doc);
- if (!doc->main)
- xmlFreeDoc(doc->doc);
- xmlFree(doc);
- }
-}
-
-/**
- * xsltFreeDocuments:
- * @ctxt: an XSLT transformation context
- *
- * Free up all the space used by the loaded documents
- */
-void
-xsltFreeDocuments(xsltTransformContextPtr ctxt) {
- xsltDocumentPtr doc, cur;
-
- cur = ctxt->docList;
- while (cur != NULL) {
- doc = cur;
- cur = cur->next;
- xsltFreeDocumentKeys(doc);
- if (!doc->main)
- xmlFreeDoc(doc->doc);
- xmlFree(doc);
- }
- cur = ctxt->styleList;
- while (cur != NULL) {
- doc = cur;
- cur = cur->next;
- xsltFreeDocumentKeys(doc);
- if (!doc->main)
- xmlFreeDoc(doc->doc);
- xmlFree(doc);
- }
-}
-
-/**
- * xsltLoadDocument:
- * @ctxt: an XSLT transformation context
- * @URI: the computed URI of the document
- *
- * Try to load a document (not a stylesheet)
- * within the XSLT transformation context
- *
- * Returns the new xsltDocumentPtr or NULL in case of error
- */
-xsltDocumentPtr
-xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
- xsltDocumentPtr ret;
- xmlDocPtr doc;
-
- if ((ctxt == NULL) || (URI == NULL))
- return(NULL);
-
- /*
- * Security framework check
- */
- if (ctxt->sec != NULL) {
- int res;
-
- res = xsltCheckRead(ctxt->sec, ctxt, URI);
- if (res == 0) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltLoadDocument: read rights for %s denied\n",
- URI);
- return(NULL);
- }
- }
-
- /*
- * Walk the context list to find the document if preparsed
- */
- ret = ctxt->docList;
- while (ret != NULL) {
- if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
- (xmlStrEqual(ret->doc->URL, URI)))
- return(ret);
- ret = ret->next;
- }
-
- doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
- (void *) ctxt, XSLT_LOAD_DOCUMENT);
-
- if (doc == NULL)
- return(NULL);
-
- if (ctxt->xinclude != 0) {
-#ifdef LIBXML_XINCLUDE_ENABLED
-#if LIBXML_VERSION >= 20603
- xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
-#else
- xmlXIncludeProcess(doc);
-#endif
-#else
- xsltTransformError(ctxt, NULL, NULL,
- "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
- URI);
-#endif
- }
- /*
- * Apply white-space stripping if asked for
- */
- if (xsltNeedElemSpaceHandling(ctxt))
- xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
- if (ctxt->debugStatus == XSLT_DEBUG_NONE)
- xmlXPathOrderDocElems(doc);
-
- ret = xsltNewDocument(ctxt, doc);
- return(ret);
-}
-
-/**
- * xsltLoadStyleDocument:
- * @style: an XSLT style sheet
- * @URI: the computed URI of the document
- *
- * Try to load a stylesheet document within the XSLT transformation context
- *
- * Returns the new xsltDocumentPtr or NULL in case of error
- */
-xsltDocumentPtr
-xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
- xsltDocumentPtr ret;
- xmlDocPtr doc;
- xsltSecurityPrefsPtr sec;
-
- if ((style == NULL) || (URI == NULL))
- return(NULL);
-
- /*
- * Security framework check
- */
- sec = xsltGetDefaultSecurityPrefs();
- if (sec != NULL) {
- int res;
-
- res = xsltCheckRead(sec, NULL, URI);
- if (res == 0) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltLoadStyleDocument: read rights for %s denied\n",
- URI);
- return(NULL);
- }
- }
-
- /*
- * Walk the context list to find the document if preparsed
- */
- ret = style->docList;
- while (ret != NULL) {
- if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
- (xmlStrEqual(ret->doc->URL, URI)))
- return(ret);
- ret = ret->next;
- }
-
- doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
- (void *) style, XSLT_LOAD_STYLESHEET);
- if (doc == NULL)
- return(NULL);
-
- ret = xsltNewStyleDocument(style, doc);
- return(ret);
-}
-
-/**
- * xsltFindDocument:
- * @ctxt: an XSLT transformation context
- * @doc: a parsed XML document
- *
- * Try to find a document within the XSLT transformation context
- *
- * Returns the desired xsltDocumentPtr or NULL in case of error
- */
-xsltDocumentPtr
-xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
- xsltDocumentPtr ret;
-
- if ((ctxt == NULL) || (doc == NULL))
- return(NULL);
-
- /*
- * Walk the context list to find the document
- */
- ret = ctxt->docList;
- while (ret != NULL) {
- if (ret->doc == doc)
- return(ret);
- ret = ret->next;
- }
- if (doc == ctxt->style->doc)
- return(ctxt->document);
- return(NULL);
-}
-
+/*\r
+ * documents.c: Implementation of the documents handling\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/parserInternals.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "documents.h"\r
+#include "transform.h"\r
+#include "imports.h"\r
+#include "keys.h"\r
+#include "security.h"\r
+\r
+#ifdef LIBXML_XINCLUDE_ENABLED\r
+#include <libxml/xinclude.h>\r
+#endif\r
+\r
+#define WITH_XSLT_DEBUG_DOCUMENTS\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_DOCUMENTS\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * Hooks for the document loader *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltDocDefaultLoaderFunc:\r
+ * @URI: the URI of the document to load\r
+ * @dict: the dictionnary to use when parsing that document\r
+ * @options: parsing options, a set of xmlParserOption\r
+ * @ctxt: the context, either a stylesheet or a transformation context\r
+ * @type: the xsltLoadType indicating the kind of loading required\r
+ *\r
+ * Default function to load document not provided by the compilation or\r
+ * transformation API themselve, for example when an xsl:import,\r
+ * xsl:include is found at compilation time or when a document()\r
+ * call is made at runtime.\r
+ *\r
+ * Returns the pointer to the document (which will be modified and\r
+ * freed by the engine later), or NULL in case of error.\r
+ */\r
+static xmlDocPtr\r
+xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,\r
+ void *ctxt ATTRIBUTE_UNUSED,\r
+ xsltLoadType type ATTRIBUTE_UNUSED)\r
+{\r
+ xmlParserCtxtPtr pctxt;\r
+ xmlParserInputPtr inputStream;\r
+ xmlDocPtr doc;\r
+\r
+ pctxt = xmlNewParserCtxt();\r
+ if (pctxt == NULL)\r
+ return(NULL);\r
+ if ((dict != NULL) && (pctxt->dict != NULL)) {\r
+ xmlDictFree(pctxt->dict);\r
+ pctxt->dict = NULL;\r
+ }\r
+ if (dict != NULL) {\r
+ pctxt->dict = dict;\r
+ xmlDictReference(pctxt->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Reusing dictionary for document\n");\r
+#endif\r
+ }\r
+ xmlCtxtUseOptions(pctxt, options);\r
+ inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);\r
+ if (inputStream == NULL) {\r
+ xmlFreeParserCtxt(pctxt);\r
+ return(NULL);\r
+ }\r
+ inputPush(pctxt, inputStream);\r
+ if (pctxt->directory == NULL)\r
+ pctxt->directory = xmlParserGetDirectory((const char *) URI);\r
+\r
+ xmlParseDocument(pctxt);\r
+\r
+ if (pctxt->wellFormed) {\r
+ doc = pctxt->myDoc;\r
+ }\r
+ else {\r
+ doc = NULL;\r
+ xmlFreeDoc(pctxt->myDoc);\r
+ pctxt->myDoc = NULL;\r
+ }\r
+ xmlFreeParserCtxt(pctxt);\r
+\r
+ return(doc);\r
+}\r
+\r
+\r
+xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;\r
+\r
+/**\r
+ * xsltSetLoaderFunc:\r
+ * @f: the new function to handle document loading.\r
+ *\r
+ * Set the new function to load document, if NULL it resets it to the\r
+ * default function.\r
+ */\r
+ \r
+void\r
+xsltSetLoaderFunc(xsltDocLoaderFunc f) {\r
+ if (f == NULL)\r
+ xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;\r
+ else\r
+ xsltDocDefaultLoader = f;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewDocument:\r
+ * @ctxt: an XSLT transformation context (or NULL)\r
+ * @doc: a parsed XML document\r
+ *\r
+ * Register a new document, apply key computations\r
+ *\r
+ * Returns a handler to the document\r
+ */\r
+xsltDocumentPtr \r
+xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {\r
+ xsltDocumentPtr cur;\r
+\r
+ cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));\r
+ if (cur == NULL) {\r
+ xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,\r
+ "xsltNewDocument : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltDocument));\r
+ cur->doc = doc;\r
+ if (ctxt != NULL) {\r
+ if (! XSLT_IS_RES_TREE_FRAG(doc)) {\r
+ cur->next = ctxt->docList;\r
+ ctxt->docList = cur;\r
+ }\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+ /*\r
+ * A key with a specific name for a specific document\r
+ * will only be computed if there's a call to the key()\r
+ * function using that specific name for that specific\r
+ * document. I.e. computation of keys will be done in\r
+ * xsltGetKey() (keys.c) on an on-demand basis.\r
+ */\r
+#else\r
+ /*\r
+ * Old behaviour.\r
+ */\r
+ xsltInitCtxtKeys(ctxt, cur);\r
+#endif\r
+ }\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltNewStyleDocument:\r
+ * @style: an XSLT style sheet\r
+ * @doc: a parsed XML document\r
+ *\r
+ * Register a new document, apply key computations\r
+ *\r
+ * Returns a handler to the document\r
+ */\r
+xsltDocumentPtr \r
+xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {\r
+ xsltDocumentPtr cur;\r
+\r
+ cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, style, (xmlNodePtr) doc,\r
+ "xsltNewStyleDocument : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltDocument));\r
+ cur->doc = doc;\r
+ if (style != NULL) {\r
+ cur->next = style->docList;\r
+ style->docList = cur;\r
+ }\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeStyleDocuments:\r
+ * @style: an XSLT stylesheet (representing a stylesheet-level)\r
+ *\r
+ * Frees the node-trees (and xsltDocument structures) of all\r
+ * stylesheet-modules of the stylesheet-level represented by\r
+ * the given @style. \r
+ */\r
+void \r
+xsltFreeStyleDocuments(xsltStylesheetPtr style) {\r
+ xsltDocumentPtr doc, cur;\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ xsltNsMapPtr nsMap;\r
+#endif\r
+ \r
+ if (style == NULL)\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ if (XSLT_HAS_INTERNAL_NSMAP(style))\r
+ nsMap = XSLT_GET_INTERNAL_NSMAP(style);\r
+ else\r
+ nsMap = NULL; \r
+#endif \r
+\r
+ cur = style->docList;\r
+ while (cur != NULL) {\r
+ doc = cur;\r
+ cur = cur->next;\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ /*\r
+ * Restore all changed namespace URIs of ns-decls.\r
+ */\r
+ if (nsMap)\r
+ xsltRestoreDocumentNamespaces(nsMap, doc->doc);\r
+#endif\r
+ xsltFreeDocumentKeys(doc);\r
+ if (!doc->main)\r
+ xmlFreeDoc(doc->doc);\r
+ xmlFree(doc);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltFreeDocuments:\r
+ * @ctxt: an XSLT transformation context\r
+ *\r
+ * Free up all the space used by the loaded documents\r
+ */\r
+void \r
+xsltFreeDocuments(xsltTransformContextPtr ctxt) {\r
+ xsltDocumentPtr doc, cur;\r
+\r
+ cur = ctxt->docList;\r
+ while (cur != NULL) {\r
+ doc = cur;\r
+ cur = cur->next;\r
+ xsltFreeDocumentKeys(doc);\r
+ if (!doc->main)\r
+ xmlFreeDoc(doc->doc);\r
+ xmlFree(doc);\r
+ }\r
+ cur = ctxt->styleList;\r
+ while (cur != NULL) {\r
+ doc = cur;\r
+ cur = cur->next;\r
+ xsltFreeDocumentKeys(doc);\r
+ if (!doc->main)\r
+ xmlFreeDoc(doc->doc);\r
+ xmlFree(doc);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltLoadDocument:\r
+ * @ctxt: an XSLT transformation context\r
+ * @URI: the computed URI of the document\r
+ *\r
+ * Try to load a document (not a stylesheet)\r
+ * within the XSLT transformation context\r
+ *\r
+ * Returns the new xsltDocumentPtr or NULL in case of error\r
+ */\r
+xsltDocumentPtr \r
+xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {\r
+ xsltDocumentPtr ret;\r
+ xmlDocPtr doc;\r
+\r
+ if ((ctxt == NULL) || (URI == NULL))\r
+ return(NULL);\r
+\r
+ /*\r
+ * Security framework check\r
+ */\r
+ if (ctxt->sec != NULL) {\r
+ int res;\r
+ \r
+ res = xsltCheckRead(ctxt->sec, ctxt, URI);\r
+ if (res == 0) {\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xsltLoadDocument: read rights for %s denied\n",\r
+ URI);\r
+ return(NULL);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Walk the context list to find the document if preparsed\r
+ */\r
+ ret = ctxt->docList;\r
+ while (ret != NULL) {\r
+ if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&\r
+ (xmlStrEqual(ret->doc->URL, URI)))\r
+ return(ret);\r
+ ret = ret->next;\r
+ }\r
+\r
+ doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,\r
+ (void *) ctxt, XSLT_LOAD_DOCUMENT);\r
+\r
+ if (doc == NULL)\r
+ return(NULL);\r
+\r
+ if (ctxt->xinclude != 0) {\r
+#ifdef LIBXML_XINCLUDE_ENABLED\r
+#if LIBXML_VERSION >= 20603\r
+ xmlXIncludeProcessFlags(doc, ctxt->parserOptions);\r
+#else\r
+ xmlXIncludeProcess(doc);\r
+#endif\r
+#else\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xsltLoadDocument(%s) : XInclude processing not compiled in\n",\r
+ URI);\r
+#endif\r
+ }\r
+ /*\r
+ * Apply white-space stripping if asked for\r
+ */\r
+ if (xsltNeedElemSpaceHandling(ctxt))\r
+ xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));\r
+ if (ctxt->debugStatus == XSLT_DEBUG_NONE)\r
+ xmlXPathOrderDocElems(doc);\r
+\r
+ ret = xsltNewDocument(ctxt, doc);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltLoadStyleDocument:\r
+ * @style: an XSLT style sheet\r
+ * @URI: the computed URI of the document\r
+ *\r
+ * Try to load a stylesheet document within the XSLT transformation context\r
+ *\r
+ * Returns the new xsltDocumentPtr or NULL in case of error\r
+ */\r
+xsltDocumentPtr \r
+xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {\r
+ xsltDocumentPtr ret;\r
+ xmlDocPtr doc;\r
+ xsltSecurityPrefsPtr sec;\r
+\r
+ if ((style == NULL) || (URI == NULL))\r
+ return(NULL);\r
+\r
+ /*\r
+ * Security framework check\r
+ */\r
+ sec = xsltGetDefaultSecurityPrefs();\r
+ if (sec != NULL) {\r
+ int res;\r
+\r
+ res = xsltCheckRead(sec, NULL, URI);\r
+ if (res == 0) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltLoadStyleDocument: read rights for %s denied\n",\r
+ URI);\r
+ return(NULL);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Walk the context list to find the document if preparsed\r
+ */\r
+ ret = style->docList;\r
+ while (ret != NULL) {\r
+ if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&\r
+ (xmlStrEqual(ret->doc->URL, URI)))\r
+ return(ret);\r
+ ret = ret->next;\r
+ }\r
+\r
+ doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,\r
+ (void *) style, XSLT_LOAD_STYLESHEET);\r
+ if (doc == NULL)\r
+ return(NULL);\r
+\r
+ ret = xsltNewStyleDocument(style, doc);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltFindDocument:\r
+ * @ctxt: an XSLT transformation context\r
+ * @doc: a parsed XML document\r
+ *\r
+ * Try to find a document within the XSLT transformation context.\r
+ * This will not find document infos for temporary\r
+ * Result Tree Fragments.\r
+ *\r
+ * Returns the desired xsltDocumentPtr or NULL in case of error\r
+ */\r
+xsltDocumentPtr\r
+xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {\r
+ xsltDocumentPtr ret;\r
+\r
+ if ((ctxt == NULL) || (doc == NULL))\r
+ return(NULL);\r
+\r
+ /*\r
+ * Walk the context list to find the document\r
+ */\r
+ ret = ctxt->docList;\r
+ while (ret != NULL) {\r
+ if (ret->doc == doc)\r
+ return(ret);\r
+ ret = ret->next;\r
+ }\r
+ if (doc == ctxt->style->doc)\r
+ return(ctxt->document);\r
+ return(NULL);\r
+}\r
+\r
-/*
- * functions.c: Implementation of the XSLT extra functions
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- * Bjorn Reese <breese@users.sourceforge.net> for number formatting
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/parserInternals.h>
-#include <libxml/uri.h>
-#include <libxml/xpointer.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "functions.h"
-#include "extensions.h"
-#include "numbersInternals.h"
-#include "keys.h"
-#include "documents.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_FUNCTION
-#endif
-
-/*
- * Some versions of DocBook XSL use the vendor string to detect
- * supporting chunking, this is a workaround to be considered
- * in the list of decent XSLT processors <grin/>
- */
-#define DOCBOOK_XSL_HACK
-
-/**
- * xsltXPathFunctionLookup:
- * @ctxt: a void * but the XSLT transformation context actually
- * @name: the function name
- * @ns_uri: the function namespace URI
- *
- * This is the entry point when a function is needed by the XPath
- * interpretor.
- *
- * Returns the callback function or NULL if not found
- */
-xmlXPathFunction
-xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
- const xmlChar *name, const xmlChar *ns_uri) {
- xmlXPathFunction ret;
-
- if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
- return (NULL);
-
-#ifdef WITH_XSLT_DEBUG_FUNCTION
- xsltGenericDebug(xsltGenericDebugContext,
- "Lookup function {%s}%s\n", ns_uri, name);
-#endif
-
- /* give priority to context-level functions */
- /*
- ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
- */
- XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
-
- if (ret == NULL)
- ret = xsltExtModuleFunctionLookup(name, ns_uri);
-
-#ifdef WITH_XSLT_DEBUG_FUNCTION
- if (ret != NULL)
- xsltGenericDebug(xsltGenericDebugContext,
- "found function %s\n", name);
-#endif
- return(ret);
-}
-
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-static void
-xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
-{
- xsltTransformContextPtr tctxt;
- xmlURIPtr uri;
- xmlChar *fragment;
- xsltDocumentPtr xsltdoc;
- xmlDocPtr doc;
- xmlXPathContextPtr xptrctxt = NULL;
- xmlXPathObjectPtr object = NULL;
-
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : internal error tctxt == NULL\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- return;
- }
-
- uri = xmlParseURI((const char *) URI);
- if (uri == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : failed to parse URI\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- return;
- }
-
- /*
- * check for and remove fragment identifier
- */
- fragment = (xmlChar *)uri->fragment;
- if (fragment != NULL) {
- uri->fragment = NULL;
- URI = xmlSaveUri(uri);
- xsltdoc = xsltLoadDocument(tctxt, URI);
- xmlFree(URI);
- } else
- xsltdoc = xsltLoadDocument(tctxt, URI);
- xmlFreeURI(uri);
-
- if (xsltdoc == NULL) {
- if ((URI == NULL) ||
- (URI[0] == '#') ||
- (xmlStrEqual(tctxt->style->doc->URL, URI))) {
- doc = tctxt->style->doc;
- } else {
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-
- if (fragment != NULL)
- xmlFree(fragment);
-
- return;
- }
- } else
- doc = xsltdoc->doc;
-
- if ( fragment == NULL ) {
- valuePush(ctxt,
- xmlXPathNewNodeSet((xmlNodePtr) doc));
- return;
- }
-
- /* use XPointer of HTML location for fragment ID */
-#ifdef LIBXML_XPTR_ENABLED
- xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
- if (xptrctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : internal error xptrctxt == NULL\n");
- goto out_fragment;
- }
-
- object = xmlXPtrEval(fragment, xptrctxt);
-#endif
- xmlFree(fragment);
- if (xptrctxt != NULL)
- xmlXPathFreeContext(xptrctxt);
-
- if (object == NULL)
- goto out_fragment;
-
- switch (object->type) {
- case XPATH_NODESET:
- break;
- case XPATH_UNDEFINED:
- case XPATH_BOOLEAN:
- case XPATH_NUMBER:
- case XPATH_STRING:
- case XPATH_POINT:
- case XPATH_USERS:
- case XPATH_XSLT_TREE:
- case XPATH_RANGE:
- case XPATH_LOCATIONSET:
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : XPointer does not select a node set: #%s\n",
- fragment);
- goto out_object;
- }
-
- valuePush(ctxt, object);
- return;
-
-out_object:
- xmlXPathFreeObject(object);
-
-out_fragment:
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-}
-
-/**
- * xsltDocumentFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the document() XSLT function
- * node-set document(object, node-set?)
- */
-void
-xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
-{
- xmlXPathObjectPtr obj, obj2 = NULL;
- xmlChar *base = NULL, *URI;
-
-
- if ((nargs < 1) || (nargs > 2)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid number of args %d\n",
- nargs);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if (ctxt->value == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid arg value\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
-
- if (nargs == 2) {
- if (ctxt->value->type != XPATH_NODESET) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid arg expecting a nodeset\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
-
- obj2 = valuePop(ctxt);
- }
-
- if (ctxt->value->type == XPATH_NODESET) {
- int i;
- xmlXPathObjectPtr newobj, ret;
-
- obj = valuePop(ctxt);
- ret = xmlXPathNewNodeSet(NULL);
-
- if (obj->nodesetval) {
- for (i = 0; i < obj->nodesetval->nodeNr; i++) {
- valuePush(ctxt,
- xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
- xmlXPathStringFunction(ctxt, 1);
- if (nargs == 2) {
- valuePush(ctxt, xmlXPathObjectCopy(obj2));
- } else {
- valuePush(ctxt,
- xmlXPathNewNodeSet(obj->nodesetval->
- nodeTab[i]));
- }
- xsltDocumentFunction(ctxt, 2);
- newobj = valuePop(ctxt);
- ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
- newobj->nodesetval);
- xmlXPathFreeObject(newobj);
- }
- }
-
- xmlXPathFreeObject(obj);
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
- valuePush(ctxt, ret);
- return;
- }
- /*
- * Make sure it's converted to a string
- */
- xmlXPathStringFunction(ctxt, 1);
- if (ctxt->value->type != XPATH_STRING) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "document() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
- return;
- }
- obj = valuePop(ctxt);
- if (obj->stringval == NULL) {
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- } else {
- if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
- (obj2->nodesetval->nodeNr > 0) &&
- IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
- xmlNodePtr target;
-
- target = obj2->nodesetval->nodeTab[0];
- if ((target->type == XML_ATTRIBUTE_NODE) ||
- (target->type == XML_PI_NODE)) {
- target = ((xmlAttrPtr) target)->parent;
- }
- base = xmlNodeGetBase(target->doc, target);
- } else {
- xsltTransformContextPtr tctxt;
-
- tctxt = xsltXPathGetTransformContext(ctxt);
- if ((tctxt != NULL) && (tctxt->inst != NULL)) {
- base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
- } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
- (tctxt->style->doc != NULL)) {
- base = xmlNodeGetBase(tctxt->style->doc,
- (xmlNodePtr) tctxt->style->doc);
- }
- }
- URI = xmlBuildURI(obj->stringval, base);
- if (base != NULL)
- xmlFree(base);
- if (URI == NULL) {
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- } else {
- xsltDocumentFunctionLoadDocument( ctxt, URI );
- xmlFree(URI);
- }
- }
- xmlXPathFreeObject(obj);
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
-}
-
-/**
- * xsltKeyFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the key() XSLT function
- * node-set key(string, object)
- */
-void
-xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlNodeSetPtr nodelist;
- xmlXPathObjectPtr obj1, obj2;
- xmlChar *key = NULL, *value;
- const xmlChar *keyURI;
- xsltTransformContextPtr tctxt;
- xsltDocumentPtr oldDocumentPtr;
- xmlDocPtr oldXPathDocPtr;
-
- if (nargs != 2) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : expects two arguments\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
-
- obj2 = valuePop(ctxt);
- xmlXPathStringFunction(ctxt, 1);
- if ((obj2 == NULL) ||
- (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- xmlXPathFreeObject(obj2);
-
- return;
- }
- obj1 = valuePop(ctxt);
-
- if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
- int i;
- xmlXPathObjectPtr newobj, ret;
-
- ret = xmlXPathNewNodeSet(NULL);
-
- if (obj2->nodesetval != NULL) {
- for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
- valuePush(ctxt, xmlXPathObjectCopy(obj1));
- valuePush(ctxt,
- xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
- xmlXPathStringFunction(ctxt, 1);
- xsltKeyFunction(ctxt, 2);
- newobj = valuePop(ctxt);
- ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
- newobj->nodesetval);
- xmlXPathFreeObject(newobj);
- }
- }
- valuePush(ctxt, ret);
- } else {
- xmlChar *qname, *prefix;
-
- /*
- * Get the associated namespace URI if qualified name
- */
- qname = obj1->stringval;
- key = xmlSplitQName2(qname, &prefix);
- if (key == NULL) {
- key = xmlStrdup(obj1->stringval);
- keyURI = NULL;
- if (prefix != NULL)
- xmlFree(prefix);
- } else {
- if (prefix != NULL) {
- keyURI = xmlXPathNsLookup(ctxt->context, prefix);
- if (keyURI == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : prefix %s is not bound\n", prefix);
- }
- xmlFree(prefix);
- } else {
- keyURI = NULL;
- }
- }
-
- /*
- * Force conversion of first arg to string
- */
- valuePush(ctxt, obj2);
- xmlXPathStringFunction(ctxt, 1);
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "key() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- xmlXPathFreeObject(obj1);
-
- return;
- }
- obj2 = valuePop(ctxt);
- value = obj2->stringval;
-
- tctxt = xsltXPathGetTransformContext(ctxt);
- oldDocumentPtr = tctxt->document;
- oldXPathDocPtr = tctxt->xpathCtxt->doc;
- if ((ctxt->context->doc != NULL) &&
- (tctxt->document->doc != ctxt->context->doc)) {
- /*
- * The xpath context document needs to be changed. If the
- * current context document is a node-set, we must use an
- * xsltDocument associated with the node-set, which may or
- * may not currently exist.
- */
- if (xmlStrEqual((const xmlChar *)ctxt->context->doc->name,
- BAD_CAST " fake node libxslt")) { /* node-set */
- /*
- * Check whether we already have an xsltDocument set up
- */
- if (ctxt->context->doc->_private == NULL) /* nope */
- ctxt->context->doc->_private =
- xsltNewDocument(tctxt, ctxt->context->doc);
- tctxt->document = ctxt->context->doc->_private;
- }
- else {
- tctxt->document = xsltFindDocument(tctxt, ctxt->context->doc);
- if (tctxt->document == NULL)
- tctxt->document = oldDocumentPtr;
- else
- tctxt->xpathCtxt->doc = ctxt->context->doc;
- }
- }
- nodelist = xsltGetKey(tctxt, key, keyURI, value);
- tctxt->document = oldDocumentPtr;
- tctxt->xpathCtxt->doc = oldXPathDocPtr;
- valuePush(ctxt, xmlXPathWrapNodeSet(
- xmlXPathNodeSetMerge(NULL, nodelist)));
- }
-
-
- if (obj1 != NULL)
- xmlXPathFreeObject(obj1);
- if (obj2 != NULL)
- xmlXPathFreeObject(obj2);
- if (key != NULL)
- xmlFree(key);
-}
-
-/**
- * xsltUnparsedEntityURIFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the unparsed-entity-uri() XSLT function
- * string unparsed-entity-uri(string)
- */
-void
-xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *str;
-
- if ((nargs != 1) || (ctxt->value == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "unparsed-entity-uri() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- obj = valuePop(ctxt);
- if (obj->type != XPATH_STRING) {
- obj = xmlXPathConvertString(obj);
- }
-
- str = obj->stringval;
- if (str == NULL) {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- } else {
- xmlEntityPtr entity;
-
- entity = xmlGetDocEntity(ctxt->context->doc, str);
- if (entity == NULL) {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- } else {
- if (entity->URI != NULL)
- valuePush(ctxt, xmlXPathNewString(entity->URI));
- else
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- }
- }
- xmlXPathFreeObject(obj);
-}
-
-/**
- * xsltFormatNumberFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the format-number() XSLT function
- * string format-number(number, string, string?)
- */
-void
-xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
-{
- xmlXPathObjectPtr numberObj = NULL;
- xmlXPathObjectPtr formatObj = NULL;
- xmlXPathObjectPtr decimalObj = NULL;
- xsltStylesheetPtr sheet;
- xsltDecimalFormatPtr formatValues;
- xmlChar *result;
- xsltTransformContextPtr tctxt;
-
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL)
- return;
- sheet = tctxt->style;
- if (sheet == NULL)
- return;
- formatValues = sheet->decimalFormat;
-
- switch (nargs) {
- case 3:
- CAST_TO_STRING;
- decimalObj = valuePop(ctxt);
- formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
- if (formatValues == NULL) {
- xsltTransformError(tctxt, NULL, NULL,
- "format-number() : undeclared decimal format '%s'\n",
- decimalObj->stringval);
- }
- /* Intentional fall-through */
- case 2:
- CAST_TO_STRING;
- formatObj = valuePop(ctxt);
- CAST_TO_NUMBER;
- numberObj = valuePop(ctxt);
- break;
- default:
- XP_ERROR(XPATH_INVALID_ARITY);
- }
-
- if (formatValues != NULL) {
- if (xsltFormatNumberConversion(formatValues,
- formatObj->stringval,
- numberObj->floatval,
- &result) == XPATH_EXPRESSION_OK) {
- valuePush(ctxt, xmlXPathNewString(result));
- xmlFree(result);
- }
- }
-
- xmlXPathFreeObject(numberObj);
- xmlXPathFreeObject(formatObj);
- xmlXPathFreeObject(decimalObj);
-}
-
-/**
- * xsltGenerateIdFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the generate-id() XSLT function
- * string generate-id(node-set?)
- */
-void
-xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlNodePtr cur = NULL;
- unsigned long val;
- xmlChar str[20];
-
- if (nargs == 0) {
- cur = ctxt->context->node;
- } else if (nargs == 1) {
- xmlXPathObjectPtr obj;
- xmlNodeSetPtr nodelist;
- int i, ret;
-
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
- ctxt->error = XPATH_INVALID_TYPE;
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "generate-id() : invalid arg expecting a node-set\n");
- return;
- }
- obj = valuePop(ctxt);
- nodelist = obj->nodesetval;
- if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
- xmlXPathFreeObject(obj);
- valuePush(ctxt, xmlXPathNewCString(""));
- return;
- }
- cur = nodelist->nodeTab[0];
- for (i = 1;i < nodelist->nodeNr;i++) {
- ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
- if (ret == -1)
- cur = nodelist->nodeTab[i];
- }
- xmlXPathFreeObject(obj);
- } else {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "generate-id() : invalid number of args %d\n", nargs);
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- /*
- * Okay this is ugly but should work, use the NodePtr address
- * to forge the ID
- */
- val = (unsigned long)((char *)cur - (char *)0);
- val /= sizeof(xmlNode);
- sprintf((char *)str, "id%ld", val);
- valuePush(ctxt, xmlXPathNewString(str));
-}
-
-/**
- * xsltSystemPropertyFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the system-property() XSLT function
- * object system-property(string)
- */
-void
-xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *prefix, *name;
- const xmlChar *nsURI = NULL;
-
- if (nargs != 1) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "system-property() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "system-property() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
- obj = valuePop(ctxt);
- if (obj->stringval == NULL) {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- } else {
- name = xmlSplitQName2(obj->stringval, &prefix);
- if (name == NULL) {
- name = xmlStrdup(obj->stringval);
- } else {
- nsURI = xmlXPathNsLookup(ctxt->context, prefix);
- if (nsURI == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "system-property() : prefix %s is not bound\n", prefix);
- }
- }
-
- if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
-#ifdef DOCBOOK_XSL_HACK
- if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
- xsltStylesheetPtr sheet;
- xsltTransformContextPtr tctxt;
-
- tctxt = xsltXPathGetTransformContext(ctxt);
- if ((tctxt != NULL) && (tctxt->inst != NULL) &&
- (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
- (tctxt->inst->parent != NULL) &&
- (xmlStrEqual(tctxt->inst->parent->name,
- BAD_CAST "template")))
- sheet = tctxt->style;
- else
- sheet = NULL;
- if ((sheet != NULL) && (sheet->doc != NULL) &&
- (sheet->doc->URL != NULL) &&
- (xmlStrstr(sheet->doc->URL,
- (const xmlChar *)"chunk") != NULL)) {
- valuePush(ctxt, xmlXPathNewString(
- (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
-
- } else {
- valuePush(ctxt, xmlXPathNewString(
- (const xmlChar *)XSLT_DEFAULT_VENDOR));
- }
- } else
-#else
- if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
- valuePush(ctxt, xmlXPathNewString(
- (const xmlChar *)XSLT_DEFAULT_VENDOR));
- } else
-#endif
- if (xmlStrEqual(name, (const xmlChar *)"version")) {
- valuePush(ctxt, xmlXPathNewString(
- (const xmlChar *)XSLT_DEFAULT_VERSION));
- } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
- valuePush(ctxt, xmlXPathNewString(
- (const xmlChar *)XSLT_DEFAULT_URL));
- } else {
- valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
- }
- }
- if (name != NULL)
- xmlFree(name);
- if (prefix != NULL)
- xmlFree(prefix);
- }
- xmlXPathFreeObject(obj);
-}
-
-/**
- * xsltElementAvailableFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the element-available() XSLT function
- * boolean element-available(string)
- */
-void
-xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *prefix, *name;
- const xmlChar *nsURI = NULL;
- xsltTransformContextPtr tctxt;
-
- if (nargs != 1) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
- obj = valuePop(ctxt);
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : internal error tctxt == NULL\n");
- xmlXPathFreeObject(obj);
- valuePush(ctxt, xmlXPathNewBoolean(0));
- return;
- }
-
-
- name = xmlSplitQName2(obj->stringval, &prefix);
- if (name == NULL) {
- xmlNsPtr ns;
-
- name = xmlStrdup(obj->stringval);
- ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
- if (ns != NULL) nsURI = xmlStrdup(ns->href);
- } else {
- nsURI = xmlXPathNsLookup(ctxt->context, prefix);
- if (nsURI == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "element-available() : prefix %s is not bound\n", prefix);
- }
- }
-
- if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
- valuePush(ctxt, xmlXPathNewBoolean(1));
- } else {
- valuePush(ctxt, xmlXPathNewBoolean(0));
- }
-
- xmlXPathFreeObject(obj);
- if (name != NULL)
- xmlFree(name);
- if (prefix != NULL)
- xmlFree(prefix);
-}
-
-/**
- * xsltFunctionAvailableFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the function-available() XSLT function
- * boolean function-available(string)
- */
-void
-xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xmlXPathObjectPtr obj;
- xmlChar *prefix, *name;
- const xmlChar *nsURI = NULL;
-
- if (nargs != 1) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "function-available() : expects one string arg\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "function-available() : invalid arg expecting a string\n");
- ctxt->error = XPATH_INVALID_TYPE;
- return;
- }
- obj = valuePop(ctxt);
-
- name = xmlSplitQName2(obj->stringval, &prefix);
- if (name == NULL) {
- name = xmlStrdup(obj->stringval);
- } else {
- nsURI = xmlXPathNsLookup(ctxt->context, prefix);
- if (nsURI == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "function-available() : prefix %s is not bound\n", prefix);
- }
- }
-
- if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
- valuePush(ctxt, xmlXPathNewBoolean(1));
- } else {
- valuePush(ctxt, xmlXPathNewBoolean(0));
- }
-
- xmlXPathFreeObject(obj);
- if (name != NULL)
- xmlFree(name);
- if (prefix != NULL)
- xmlFree(prefix);
-}
-
-/**
- * xsltCurrentFunction:
- * @ctxt: the XPath Parser context
- * @nargs: the number of arguments
- *
- * Implement the current() XSLT function
- * node-set current()
- */
-static void
-xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
- xsltTransformContextPtr tctxt;
-
- if (nargs != 0) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "current() : function uses no argument\n");
- ctxt->error = XPATH_INVALID_ARITY;
- return;
- }
- tctxt = xsltXPathGetTransformContext(ctxt);
- if (tctxt == NULL) {
- xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
- "current() : internal error tctxt == NULL\n");
- valuePush(ctxt, xmlXPathNewNodeSet(NULL));
- } else {
- valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
- }
-}
-
-/************************************************************************
- * *
- * Registration of XSLT and libxslt functions *
- * *
- ************************************************************************/
-
-/**
- * xsltRegisterAllFunctions:
- * @ctxt: the XPath context
- *
- * Registers all default XSLT functions in this context
- */
-void
-xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
-{
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
- xsltCurrentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
- xsltDocumentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
- xsltUnparsedEntityURIFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
- xsltFormatNumberFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
- xsltGenerateIdFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
- xsltSystemPropertyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
- xsltElementAvailableFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
- xsltFunctionAvailableFunction);
-}
+/*\r
+ * functions.c: Implementation of the XSLT extra functions\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ * Bjorn Reese <breese@users.sourceforge.net> for number formatting\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#ifdef HAVE_SYS_TYPES_H\r
+#include <sys/types.h>\r
+#endif\r
+#ifdef HAVE_CTYPE_H\r
+#include <ctype.h>\r
+#endif\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/parserInternals.h>\r
+#include <libxml/uri.h>\r
+#include <libxml/xpointer.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "functions.h"\r
+#include "extensions.h"\r
+#include "numbersInternals.h"\r
+#include "keys.h"\r
+#include "documents.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_FUNCTION\r
+#endif\r
+\r
+/*\r
+ * Some versions of DocBook XSL use the vendor string to detect\r
+ * supporting chunking, this is a workaround to be considered\r
+ * in the list of decent XSLT processors <grin/>\r
+ */\r
+#define DOCBOOK_XSL_HACK\r
+\r
+/**\r
+ * xsltXPathFunctionLookup:\r
+ * @ctxt: a void * but the XSLT transformation context actually\r
+ * @name: the function name\r
+ * @ns_uri: the function namespace URI\r
+ *\r
+ * This is the entry point when a function is needed by the XPath\r
+ * interpretor.\r
+ *\r
+ * Returns the callback function or NULL if not found\r
+ */\r
+xmlXPathFunction\r
+xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,\r
+ const xmlChar *name, const xmlChar *ns_uri) {\r
+ xmlXPathFunction ret;\r
+\r
+ if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))\r
+ return (NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_FUNCTION\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Lookup function {%s}%s\n", ns_uri, name);\r
+#endif\r
+\r
+ /* give priority to context-level functions */\r
+ /*\r
+ ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);\r
+ */\r
+ XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);\r
+\r
+ if (ret == NULL)\r
+ ret = xsltExtModuleFunctionLookup(name, ns_uri);\r
+\r
+#ifdef WITH_XSLT_DEBUG_FUNCTION\r
+ if (ret != NULL)\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "found function %s\n", name);\r
+#endif\r
+ return(ret);\r
+}\r
+\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+static void\r
+xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)\r
+{\r
+ xsltTransformContextPtr tctxt;\r
+ xmlURIPtr uri;\r
+ xmlChar *fragment;\r
+ xsltDocumentPtr idoc; /* document info */\r
+ xmlDocPtr doc;\r
+ xmlXPathContextPtr xptrctxt = NULL;\r
+ xmlXPathObjectPtr resObj = NULL;\r
+\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "document() : internal error tctxt == NULL\n");\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ return;\r
+ } \r
+ \r
+ uri = xmlParseURI((const char *) URI);\r
+ if (uri == NULL) {\r
+ xsltTransformError(tctxt, NULL, NULL,\r
+ "document() : failed to parse URI\n");\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ return;\r
+ } \r
+ \r
+ /*\r
+ * check for and remove fragment identifier\r
+ */\r
+ fragment = (xmlChar *)uri->fragment;\r
+ if (fragment != NULL) {\r
+ uri->fragment = NULL;\r
+ URI = xmlSaveUri(uri);\r
+ idoc = xsltLoadDocument(tctxt, URI);\r
+ xmlFree(URI);\r
+ } else\r
+ idoc = xsltLoadDocument(tctxt, URI);\r
+ xmlFreeURI(uri);\r
+ \r
+ if (idoc == NULL) {\r
+ if ((URI == NULL) ||\r
+ (URI[0] == '#') ||\r
+ (xmlStrEqual(tctxt->style->doc->URL, URI))) \r
+ {\r
+ /*\r
+ * This selects the stylesheet's doc itself.\r
+ */\r
+ doc = tctxt->style->doc;\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+\r
+ if (fragment != NULL)\r
+ xmlFree(fragment);\r
+\r
+ return;\r
+ }\r
+ } else\r
+ doc = idoc->doc;\r
+\r
+ if (fragment == NULL) {\r
+ valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));\r
+ return;\r
+ }\r
+ \r
+ /* use XPointer of HTML location for fragment ID */\r
+#ifdef LIBXML_XPTR_ENABLED\r
+ xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);\r
+ if (xptrctxt == NULL) {\r
+ xsltTransformError(tctxt, NULL, NULL,\r
+ "document() : internal error xptrctxt == NULL\n");\r
+ goto out_fragment;\r
+ }\r
+\r
+ resObj = xmlXPtrEval(fragment, xptrctxt);\r
+ xmlXPathFreeContext(xptrctxt);\r
+#endif\r
+ xmlFree(fragment); \r
+\r
+ if (resObj == NULL)\r
+ goto out_fragment;\r
+ \r
+ switch (resObj->type) {\r
+ case XPATH_NODESET:\r
+ break;\r
+ case XPATH_UNDEFINED:\r
+ case XPATH_BOOLEAN:\r
+ case XPATH_NUMBER:\r
+ case XPATH_STRING:\r
+ case XPATH_POINT:\r
+ case XPATH_USERS:\r
+ case XPATH_XSLT_TREE:\r
+ case XPATH_RANGE:\r
+ case XPATH_LOCATIONSET:\r
+ xsltTransformError(tctxt, NULL, NULL,\r
+ "document() : XPointer does not select a node set: #%s\n", \r
+ fragment);\r
+ goto out_object;\r
+ }\r
+ \r
+ valuePush(ctxt, resObj);\r
+ return;\r
+\r
+out_object:\r
+ xmlXPathFreeObject(resObj);\r
+\r
+out_fragment:\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+}\r
+\r
+/**\r
+ * xsltDocumentFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the document() XSLT function\r
+ * node-set document(object, node-set?)\r
+ */\r
+void\r
+xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)\r
+{\r
+ xmlXPathObjectPtr obj, obj2 = NULL;\r
+ xmlChar *base = NULL, *URI;\r
+\r
+\r
+ if ((nargs < 1) || (nargs > 2)) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "document() : invalid number of args %d\n",\r
+ nargs);\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ if (ctxt->value == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "document() : invalid arg value\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ return;\r
+ }\r
+\r
+ if (nargs == 2) {\r
+ if (ctxt->value->type != XPATH_NODESET) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "document() : invalid arg expecting a nodeset\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ return;\r
+ }\r
+\r
+ obj2 = valuePop(ctxt);\r
+ }\r
+\r
+ if (ctxt->value->type == XPATH_NODESET) {\r
+ int i;\r
+ xmlXPathObjectPtr newobj, ret;\r
+\r
+ obj = valuePop(ctxt);\r
+ ret = xmlXPathNewNodeSet(NULL);\r
+\r
+ if (obj->nodesetval) {\r
+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {\r
+ valuePush(ctxt,\r
+ xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));\r
+ xmlXPathStringFunction(ctxt, 1);\r
+ if (nargs == 2) {\r
+ valuePush(ctxt, xmlXPathObjectCopy(obj2));\r
+ } else {\r
+ valuePush(ctxt,\r
+ xmlXPathNewNodeSet(obj->nodesetval->\r
+ nodeTab[i]));\r
+ }\r
+ xsltDocumentFunction(ctxt, 2);\r
+ newobj = valuePop(ctxt);\r
+ ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,\r
+ newobj->nodesetval);\r
+ xmlXPathFreeObject(newobj);\r
+ }\r
+ }\r
+\r
+ xmlXPathFreeObject(obj);\r
+ if (obj2 != NULL)\r
+ xmlXPathFreeObject(obj2);\r
+ valuePush(ctxt, ret);\r
+ return;\r
+ }\r
+ /*\r
+ * Make sure it's converted to a string\r
+ */\r
+ xmlXPathStringFunction(ctxt, 1);\r
+ if (ctxt->value->type != XPATH_STRING) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "document() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ if (obj2 != NULL)\r
+ xmlXPathFreeObject(obj2);\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+ if (obj->stringval == NULL) {\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ } else {\r
+ if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&\r
+ (obj2->nodesetval->nodeNr > 0) &&\r
+ IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {\r
+ xmlNodePtr target;\r
+\r
+ target = obj2->nodesetval->nodeTab[0];\r
+ if ((target->type == XML_ATTRIBUTE_NODE) ||\r
+ (target->type == XML_PI_NODE)) {\r
+ target = ((xmlAttrPtr) target)->parent;\r
+ }\r
+ base = xmlNodeGetBase(target->doc, target);\r
+ } else {\r
+ xsltTransformContextPtr tctxt;\r
+\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if ((tctxt != NULL) && (tctxt->inst != NULL)) {\r
+ base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);\r
+ } else if ((tctxt != NULL) && (tctxt->style != NULL) &&\r
+ (tctxt->style->doc != NULL)) {\r
+ base = xmlNodeGetBase(tctxt->style->doc,\r
+ (xmlNodePtr) tctxt->style->doc);\r
+ }\r
+ }\r
+ URI = xmlBuildURI(obj->stringval, base);\r
+ if (base != NULL)\r
+ xmlFree(base);\r
+ if (URI == NULL) {\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ } else {\r
+ xsltDocumentFunctionLoadDocument( ctxt, URI );\r
+ xmlFree(URI);\r
+ }\r
+ }\r
+ xmlXPathFreeObject(obj);\r
+ if (obj2 != NULL)\r
+ xmlXPathFreeObject(obj2);\r
+}\r
+\r
+/**\r
+ * xsltKeyFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the key() XSLT function\r
+ * node-set key(string, object)\r
+ */\r
+void\r
+xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ \r
+ xmlXPathObjectPtr obj1, obj2; \r
+ \r
+ if (nargs != 2) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "key() : expects two arguments\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ } \r
+\r
+ /*\r
+ * Get the key's value.\r
+ */\r
+ obj2 = valuePop(ctxt);\r
+ xmlXPathStringFunction(ctxt, 1);\r
+ if ((obj2 == NULL) ||\r
+ (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "key() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ xmlXPathFreeObject(obj2);\r
+\r
+ return;\r
+ }\r
+ /*\r
+ * Get the key's name.\r
+ */\r
+ obj1 = valuePop(ctxt); \r
+\r
+ if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {\r
+ int i;\r
+ xmlXPathObjectPtr newobj, ret;\r
+\r
+ ret = xmlXPathNewNodeSet(NULL);\r
+\r
+ if (obj2->nodesetval != NULL) {\r
+ for (i = 0; i < obj2->nodesetval->nodeNr; i++) {\r
+ valuePush(ctxt, xmlXPathObjectCopy(obj1));\r
+ valuePush(ctxt,\r
+ xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));\r
+ xmlXPathStringFunction(ctxt, 1);\r
+ xsltKeyFunction(ctxt, 2);\r
+ newobj = valuePop(ctxt);\r
+ ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,\r
+ newobj->nodesetval);\r
+ xmlXPathFreeObject(newobj);\r
+ }\r
+ }\r
+ valuePush(ctxt, ret);\r
+ } else {\r
+ xmlNodeSetPtr nodelist = NULL;\r
+ xmlChar *key = NULL, *value;\r
+ const xmlChar *keyURI;\r
+ xsltTransformContextPtr tctxt; \r
+ xmlChar *qname, *prefix;\r
+ xmlXPathContextPtr xpctxt = ctxt->context;\r
+ xmlNodePtr tmpNode = NULL;\r
+ xsltDocumentPtr oldDocInfo;\r
+\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+\r
+ oldDocInfo = tctxt->document;\r
+\r
+ if (xpctxt->node == NULL) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "Internal error in xsltKeyFunction(): "\r
+ "The context node is not set on the XPath context.\n");\r
+ tctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ } \r
+ /*\r
+ * Get the associated namespace URI if qualified name\r
+ */\r
+ qname = obj1->stringval;\r
+ key = xmlSplitQName2(qname, &prefix);\r
+ if (key == NULL) {\r
+ key = xmlStrdup(obj1->stringval);\r
+ keyURI = NULL;\r
+ if (prefix != NULL)\r
+ xmlFree(prefix);\r
+ } else {\r
+ if (prefix != NULL) {\r
+ keyURI = xmlXPathNsLookup(xpctxt, prefix);\r
+ if (keyURI == NULL) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "key() : prefix %s is not bound\n", prefix);\r
+ /*\r
+ * TODO: Shouldn't we stop here?\r
+ */\r
+ }\r
+ xmlFree(prefix);\r
+ } else {\r
+ keyURI = NULL;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Force conversion of first arg to string\r
+ */\r
+ valuePush(ctxt, obj2);\r
+ xmlXPathStringFunction(ctxt, 1);\r
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "key() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ goto error;\r
+ }\r
+ obj2 = valuePop(ctxt);\r
+ value = obj2->stringval;\r
+ \r
+ /*\r
+ * We need to ensure that ctxt->document is available for\r
+ * xsltGetKey().\r
+ * First find the relevant doc, which is the context node's\r
+ * owner doc; using context->doc is not safe, since\r
+ * the doc could have been acquired via the document() function,\r
+ * or the doc might be a Result Tree Fragment.\r
+ * FUTURE INFO: In XSLT 2.0 the key() function takes an additional\r
+ * argument indicating the doc to use.\r
+ */ \r
+ if (xpctxt->node->type == XML_NAMESPACE_DECL) {\r
+ /*\r
+ * REVISIT: This is a libxml hack! Check xpath.c for details.\r
+ * The XPath module sets the owner element of a ns-node on\r
+ * the ns->next field.\r
+ */\r
+ if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&\r
+ (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))\r
+ {\r
+ tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;\r
+ }\r
+ } else\r
+ tmpNode = xpctxt->node;\r
+\r
+ if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "Internal error in xsltKeyFunction(): "\r
+ "Couldn't get the doc of the XPath context node.\n");\r
+ goto error;\r
+ }\r
+\r
+ if ((tctxt->document == NULL) ||\r
+ (tctxt->document->doc != tmpNode->doc))\r
+ { \r
+ if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {\r
+ /*\r
+ * This is a Result Tree Fragment.\r
+ */\r
+ if (tmpNode->doc->_private == NULL) {\r
+ tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);\r
+ if (tmpNode->doc->_private == NULL)\r
+ goto error;\r
+ }\r
+ tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private; \r
+ } else {\r
+ /*\r
+ * May be the initial source doc or a doc acquired via the\r
+ * document() function.\r
+ */\r
+ tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);\r
+ }\r
+ if (tctxt->document == NULL) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "Internal error in xsltKeyFunction(): "\r
+ "Could not get the document info of a context doc.\n");\r
+ tctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ }\r
+ /*\r
+ * Get/compute the key value.\r
+ */\r
+ nodelist = xsltGetKey(tctxt, key, keyURI, value);\r
+\r
+error: \r
+ tctxt->document = oldDocInfo;\r
+ valuePush(ctxt, xmlXPathWrapNodeSet(\r
+ xmlXPathNodeSetMerge(NULL, nodelist)));\r
+ if (key != NULL)\r
+ xmlFree(key);\r
+ } \r
+\r
+ if (obj1 != NULL)\r
+ xmlXPathFreeObject(obj1);\r
+ if (obj2 != NULL)\r
+ xmlXPathFreeObject(obj2); \r
+}\r
+\r
+/**\r
+ * xsltUnparsedEntityURIFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the unparsed-entity-uri() XSLT function\r
+ * string unparsed-entity-uri(string)\r
+ */\r
+void\r
+xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xmlXPathObjectPtr obj;\r
+ xmlChar *str;\r
+\r
+ if ((nargs != 1) || (ctxt->value == NULL)) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "unparsed-entity-uri() : expects one string arg\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+ if (obj->type != XPATH_STRING) {\r
+ obj = xmlXPathConvertString(obj);\r
+ }\r
+\r
+ str = obj->stringval;\r
+ if (str == NULL) {\r
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));\r
+ } else {\r
+ xmlEntityPtr entity;\r
+\r
+ entity = xmlGetDocEntity(ctxt->context->doc, str);\r
+ if (entity == NULL) {\r
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));\r
+ } else {\r
+ if (entity->URI != NULL)\r
+ valuePush(ctxt, xmlXPathNewString(entity->URI));\r
+ else\r
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));\r
+ }\r
+ }\r
+ xmlXPathFreeObject(obj);\r
+}\r
+\r
+/**\r
+ * xsltFormatNumberFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the format-number() XSLT function\r
+ * string format-number(number, string, string?)\r
+ */\r
+void\r
+xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)\r
+{\r
+ xmlXPathObjectPtr numberObj = NULL;\r
+ xmlXPathObjectPtr formatObj = NULL;\r
+ xmlXPathObjectPtr decimalObj = NULL;\r
+ xsltStylesheetPtr sheet;\r
+ xsltDecimalFormatPtr formatValues;\r
+ xmlChar *result;\r
+ xsltTransformContextPtr tctxt;\r
+\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL)\r
+ return;\r
+ sheet = tctxt->style;\r
+ if (sheet == NULL)\r
+ return;\r
+ formatValues = sheet->decimalFormat;\r
+ \r
+ switch (nargs) {\r
+ case 3:\r
+ CAST_TO_STRING;\r
+ decimalObj = valuePop(ctxt);\r
+ formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);\r
+ if (formatValues == NULL) {\r
+ xsltTransformError(tctxt, NULL, NULL,\r
+ "format-number() : undeclared decimal format '%s'\n", \r
+ decimalObj->stringval);\r
+ }\r
+ /* Intentional fall-through */\r
+ case 2:\r
+ CAST_TO_STRING;\r
+ formatObj = valuePop(ctxt);\r
+ CAST_TO_NUMBER;\r
+ numberObj = valuePop(ctxt);\r
+ break;\r
+ default:\r
+ XP_ERROR(XPATH_INVALID_ARITY);\r
+ }\r
+\r
+ if (formatValues != NULL) {\r
+ if (xsltFormatNumberConversion(formatValues,\r
+ formatObj->stringval,\r
+ numberObj->floatval,\r
+ &result) == XPATH_EXPRESSION_OK) {\r
+ valuePush(ctxt, xmlXPathNewString(result));\r
+ xmlFree(result);\r
+ }\r
+ }\r
+\r
+ xmlXPathFreeObject(numberObj);\r
+ xmlXPathFreeObject(formatObj);\r
+ xmlXPathFreeObject(decimalObj);\r
+}\r
+\r
+/**\r
+ * xsltGenerateIdFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the generate-id() XSLT function\r
+ * string generate-id(node-set?)\r
+ */\r
+void\r
+xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xmlNodePtr cur = NULL;\r
+ unsigned long val;\r
+ xmlChar str[20];\r
+\r
+ if (nargs == 0) {\r
+ cur = ctxt->context->node;\r
+ } else if (nargs == 1) {\r
+ xmlXPathObjectPtr obj;\r
+ xmlNodeSetPtr nodelist;\r
+ int i, ret;\r
+\r
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "generate-id() : invalid arg expecting a node-set\n");\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+ nodelist = obj->nodesetval;\r
+ if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {\r
+ xmlXPathFreeObject(obj);\r
+ valuePush(ctxt, xmlXPathNewCString(""));\r
+ return;\r
+ }\r
+ cur = nodelist->nodeTab[0];\r
+ for (i = 1;i < nodelist->nodeNr;i++) {\r
+ ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);\r
+ if (ret == -1)\r
+ cur = nodelist->nodeTab[i];\r
+ }\r
+ xmlXPathFreeObject(obj);\r
+ } else {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "generate-id() : invalid number of args %d\n", nargs);\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ /*\r
+ * Okay this is ugly but should work, use the NodePtr address\r
+ * to forge the ID\r
+ */\r
+ val = (unsigned long)((char *)cur - (char *)0);\r
+ val /= sizeof(xmlNode);\r
+ sprintf((char *)str, "id%ld", val);\r
+ valuePush(ctxt, xmlXPathNewString(str));\r
+}\r
+\r
+/**\r
+ * xsltSystemPropertyFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the system-property() XSLT function\r
+ * object system-property(string)\r
+ */\r
+void\r
+xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xmlXPathObjectPtr obj;\r
+ xmlChar *prefix, *name;\r
+ const xmlChar *nsURI = NULL;\r
+\r
+ if (nargs != 1) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "system-property() : expects one string arg\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "system-property() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+ if (obj->stringval == NULL) {\r
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));\r
+ } else {\r
+ name = xmlSplitQName2(obj->stringval, &prefix);\r
+ if (name == NULL) {\r
+ name = xmlStrdup(obj->stringval);\r
+ } else {\r
+ nsURI = xmlXPathNsLookup(ctxt->context, prefix);\r
+ if (nsURI == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "system-property() : prefix %s is not bound\n", prefix);\r
+ }\r
+ }\r
+\r
+ if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {\r
+#ifdef DOCBOOK_XSL_HACK\r
+ if (xmlStrEqual(name, (const xmlChar *)"vendor")) {\r
+ xsltStylesheetPtr sheet;\r
+ xsltTransformContextPtr tctxt;\r
+\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if ((tctxt != NULL) && (tctxt->inst != NULL) &&\r
+ (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&\r
+ (tctxt->inst->parent != NULL) &&\r
+ (xmlStrEqual(tctxt->inst->parent->name,\r
+ BAD_CAST "template")))\r
+ sheet = tctxt->style;\r
+ else\r
+ sheet = NULL;\r
+ if ((sheet != NULL) && (sheet->doc != NULL) &&\r
+ (sheet->doc->URL != NULL) &&\r
+ (xmlStrstr(sheet->doc->URL,\r
+ (const xmlChar *)"chunk") != NULL)) {\r
+ valuePush(ctxt, xmlXPathNewString(\r
+ (const xmlChar *)"libxslt (SAXON 6.2 compatible)"));\r
+\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewString(\r
+ (const xmlChar *)XSLT_DEFAULT_VENDOR));\r
+ }\r
+ } else\r
+#else\r
+ if (xmlStrEqual(name, (const xmlChar *)"vendor")) {\r
+ valuePush(ctxt, xmlXPathNewString(\r
+ (const xmlChar *)XSLT_DEFAULT_VENDOR));\r
+ } else\r
+#endif\r
+ if (xmlStrEqual(name, (const xmlChar *)"version")) {\r
+ valuePush(ctxt, xmlXPathNewString(\r
+ (const xmlChar *)XSLT_DEFAULT_VERSION));\r
+ } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {\r
+ valuePush(ctxt, xmlXPathNewString(\r
+ (const xmlChar *)XSLT_DEFAULT_URL));\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));\r
+ }\r
+ }\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+ if (prefix != NULL)\r
+ xmlFree(prefix);\r
+ }\r
+ xmlXPathFreeObject(obj);\r
+}\r
+\r
+/**\r
+ * xsltElementAvailableFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the element-available() XSLT function\r
+ * boolean element-available(string)\r
+ */\r
+void\r
+xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xmlXPathObjectPtr obj;\r
+ xmlChar *prefix, *name;\r
+ const xmlChar *nsURI = NULL;\r
+ xsltTransformContextPtr tctxt;\r
+\r
+ if (nargs != 1) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "element-available() : expects one string arg\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "element-available() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "element-available() : internal error tctxt == NULL\n");\r
+ xmlXPathFreeObject(obj);\r
+ valuePush(ctxt, xmlXPathNewBoolean(0));\r
+ return;\r
+ }\r
+\r
+\r
+ name = xmlSplitQName2(obj->stringval, &prefix);\r
+ if (name == NULL) {\r
+ xmlNsPtr ns;\r
+\r
+ name = xmlStrdup(obj->stringval);\r
+ ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);\r
+ if (ns != NULL) nsURI = xmlStrdup(ns->href);\r
+ } else {\r
+ nsURI = xmlXPathNsLookup(ctxt->context, prefix);\r
+ if (nsURI == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "element-available() : prefix %s is not bound\n", prefix);\r
+ }\r
+ }\r
+\r
+ if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {\r
+ valuePush(ctxt, xmlXPathNewBoolean(1));\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewBoolean(0));\r
+ }\r
+\r
+ xmlXPathFreeObject(obj);\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+ if (prefix != NULL)\r
+ xmlFree(prefix);\r
+}\r
+\r
+/**\r
+ * xsltFunctionAvailableFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the function-available() XSLT function\r
+ * boolean function-available(string)\r
+ */\r
+void\r
+xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xmlXPathObjectPtr obj;\r
+ xmlChar *prefix, *name;\r
+ const xmlChar *nsURI = NULL;\r
+\r
+ if (nargs != 1) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "function-available() : expects one string arg\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "function-available() : invalid arg expecting a string\n");\r
+ ctxt->error = XPATH_INVALID_TYPE;\r
+ return;\r
+ }\r
+ obj = valuePop(ctxt);\r
+\r
+ name = xmlSplitQName2(obj->stringval, &prefix);\r
+ if (name == NULL) {\r
+ name = xmlStrdup(obj->stringval);\r
+ } else {\r
+ nsURI = xmlXPathNsLookup(ctxt->context, prefix);\r
+ if (nsURI == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "function-available() : prefix %s is not bound\n", prefix);\r
+ }\r
+ }\r
+\r
+ if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {\r
+ valuePush(ctxt, xmlXPathNewBoolean(1));\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewBoolean(0));\r
+ }\r
+\r
+ xmlXPathFreeObject(obj);\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+ if (prefix != NULL)\r
+ xmlFree(prefix);\r
+}\r
+\r
+/**\r
+ * xsltCurrentFunction:\r
+ * @ctxt: the XPath Parser context\r
+ * @nargs: the number of arguments\r
+ *\r
+ * Implement the current() XSLT function\r
+ * node-set current()\r
+ */\r
+static void\r
+xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){\r
+ xsltTransformContextPtr tctxt;\r
+\r
+ if (nargs != 0) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "current() : function uses no argument\n");\r
+ ctxt->error = XPATH_INVALID_ARITY;\r
+ return;\r
+ }\r
+ tctxt = xsltXPathGetTransformContext(ctxt);\r
+ if (tctxt == NULL) {\r
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,\r
+ "current() : internal error tctxt == NULL\n");\r
+ valuePush(ctxt, xmlXPathNewNodeSet(NULL));\r
+ } else {\r
+ valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */\r
+ }\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Registration of XSLT and libxslt functions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltRegisterAllFunctions:\r
+ * @ctxt: the XPath context\r
+ *\r
+ * Registers all default XSLT functions in this context\r
+ */\r
+void\r
+xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)\r
+{\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",\r
+ xsltCurrentFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",\r
+ xsltDocumentFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",\r
+ xsltUnparsedEntityURIFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",\r
+ xsltFormatNumberFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",\r
+ xsltGenerateIdFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",\r
+ xsltSystemPropertyFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",\r
+ xsltElementAvailableFunction);\r
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",\r
+ xsltFunctionAvailableFunction);\r
+}\r
-/*
- * keys.c: Implemetation of the keys support
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parserInternals.h>
-#include <libxml/xpathInternals.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "imports.h"
-#include "templates.h"
-#include "keys.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_KEYS
-#endif
-
-
-/************************************************************************
- * *
- * Type functions *
- * *
- ************************************************************************/
-
-/**
- * xsltNewKeyDef:
- * @name: the key name or NULL
- * @nameURI: the name URI or NULL
- *
- * Create a new XSLT KeyDef
- *
- * Returns the newly allocated xsltKeyDefPtr or NULL in case of error
- */
-static xsltKeyDefPtr
-xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
- xsltKeyDefPtr cur;
-
- cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewKeyDef : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltKeyDef));
- if (name != NULL)
- cur->name = xmlStrdup(name);
- if (nameURI != NULL)
- cur->nameURI = xmlStrdup(nameURI);
- cur->nsList = NULL;
- return(cur);
-}
-
-/**
- * xsltFreeKeyDef:
- * @keyd: an XSLT key definition
- *
- * Free up the memory allocated by @keyd
- */
-static void
-xsltFreeKeyDef(xsltKeyDefPtr keyd) {
- if (keyd == NULL)
- return;
- if (keyd->comp != NULL)
- xmlXPathFreeCompExpr(keyd->comp);
- if (keyd->usecomp != NULL)
- xmlXPathFreeCompExpr(keyd->usecomp);
- if (keyd->name != NULL)
- xmlFree(keyd->name);
- if (keyd->nameURI != NULL)
- xmlFree(keyd->nameURI);
- if (keyd->match != NULL)
- xmlFree(keyd->match);
- if (keyd->use != NULL)
- xmlFree(keyd->use);
- if (keyd->nsList != NULL)
- xmlFree(keyd->nsList);
- memset(keyd, -1, sizeof(xsltKeyDef));
- xmlFree(keyd);
-}
-
-/**
- * xsltFreeKeyDefList:
- * @keyd: an XSLT key definition list
- *
- * Free up the memory allocated by all the elements of @keyd
- */
-static void
-xsltFreeKeyDefList(xsltKeyDefPtr keyd) {
- xsltKeyDefPtr cur;
-
- while (keyd != NULL) {
- cur = keyd;
- keyd = keyd->next;
- xsltFreeKeyDef(cur);
- }
-}
-
-/**
- * xsltNewKeyTable:
- * @name: the key name or NULL
- * @nameURI: the name URI or NULL
- *
- * Create a new XSLT KeyTable
- *
- * Returns the newly allocated xsltKeyTablePtr or NULL in case of error
- */
-static xsltKeyTablePtr
-xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
- xsltKeyTablePtr cur;
-
- cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewKeyTable : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltKeyTable));
- if (name != NULL)
- cur->name = xmlStrdup(name);
- if (nameURI != NULL)
- cur->nameURI = xmlStrdup(nameURI);
- cur->keys = xmlHashCreate(0);
- return(cur);
-}
-
-/**
- * xsltFreeKeyTable:
- * @keyt: an XSLT key table
- *
- * Free up the memory allocated by @keyt
- */
-static void
-xsltFreeKeyTable(xsltKeyTablePtr keyt) {
- if (keyt == NULL)
- return;
- if (keyt->name != NULL)
- xmlFree(keyt->name);
- if (keyt->nameURI != NULL)
- xmlFree(keyt->nameURI);
- if (keyt->keys != NULL)
- xmlHashFree(keyt->keys,
- (xmlHashDeallocator) xmlXPathFreeNodeSet);
- memset(keyt, -1, sizeof(xsltKeyTable));
- xmlFree(keyt);
-}
-
-/**
- * xsltFreeKeyTableList:
- * @keyt: an XSLT key table list
- *
- * Free up the memory allocated by all the elements of @keyt
- */
-static void
-xsltFreeKeyTableList(xsltKeyTablePtr keyt) {
- xsltKeyTablePtr cur;
-
- while (keyt != NULL) {
- cur = keyt;
- keyt = keyt->next;
- xsltFreeKeyTable(cur);
- }
-}
-
-/************************************************************************
- * *
- * The interpreter for the precompiled patterns *
- * *
- ************************************************************************/
-
-
-/**
- * xsltFreeKeys:
- * @style: an XSLT stylesheet
- *
- * Free up the memory used by XSLT keys in a stylesheet
- */
-void
-xsltFreeKeys(xsltStylesheetPtr style) {
- if (style->keys)
- xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);
-}
-
-/**
- * skipString:
- * @cur: the current pointer
- * @end: the current offset
- *
- * skip a string delimited by " or '
- *
- * Returns the byte after the string or -1 in case of error
- */
-static int
-skipString(const xmlChar *cur, int end) {
- xmlChar limit;
-
- if ((cur == NULL) || (end < 0)) return(-1);
- if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];
- else return(end);
- end++;
- while (cur[end] != 0) {
- if (cur[end] == limit)
- return(end + 1);
- end++;
- }
- return(-1);
-}
-
-/**
- * skipPredicate:
- * @cur: the current pointer
- * @end: the current offset
- *
- * skip a predicate
- *
- * Returns the byte after the predicate or -1 in case of error
- */
-static int
-skipPredicate(const xmlChar *cur, int end) {
- if ((cur == NULL) || (end < 0)) return(-1);
- if (cur[end] != '[') return(end);
- end++;
- while (cur[end] != 0) {
- if ((cur[end] == '\'') || (cur[end] == '"')) {
- end = skipString(cur, end);
- if (end <= 0)
- return(-1);
- continue;
- } else if (cur[end] == '[') {
- end = skipPredicate(cur, end);
- if (end <= 0)
- return(-1);
- continue;
- } else if (cur[end] == ']')
- return(end + 1);
- end++;
- }
- return(-1);
-}
-
-/**
- * xsltAddKey:
- * @style: an XSLT stylesheet
- * @name: the key name or NULL
- * @nameURI: the name URI or NULL
- * @match: the match value
- * @use: the use value
- * @inst: the key instruction
- *
- * add a key definition to a stylesheet
- *
- * Returns 0 in case of success, and -1 in case of failure.
- */
-int
-xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
- const xmlChar *nameURI, const xmlChar *match,
- const xmlChar *use, xmlNodePtr inst) {
- xsltKeyDefPtr key;
- xmlChar *pattern = NULL;
- int current, end, start, i = 0;
-
- if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
- return(-1);
-
-#ifdef WITH_XSLT_DEBUG_KEYS
- xsltGenericDebug(xsltGenericDebugContext,
- "Add key %s, match %s, use %s\n", name, match, use);
-#endif
-
- key = xsltNewKeyDef(name, nameURI);
- key->match = xmlStrdup(match);
- key->use = xmlStrdup(use);
- key->inst = inst;
- key->nsList = xmlGetNsList(inst->doc, inst);
- if (key->nsList != NULL) {
- while (key->nsList[i] != NULL)
- i++;
- }
- key->nsNr = i;
-
- /*
- * Split the | and register it as as many keys
- */
- current = end = 0;
- while (match[current] != 0) {
- start = current;
- while (IS_BLANK_CH(match[current]))
- current++;
- end = current;
- while ((match[end] != 0) && (match[end] != '|')) {
- if (match[end] == '[') {
- end = skipPredicate(match, end);
- if (end <= 0) {
- xsltTransformError(NULL, style, inst,
- "key pattern is malformed: %s",
- key->match);
- if (style != NULL) style->errors++;
- goto error;
- }
- } else
- end++;
- }
- if (current == end) {
- xsltTransformError(NULL, style, inst,
- "key pattern is empty\n");
- if (style != NULL) style->errors++;
- goto error;
- }
- if (match[start] != '/') {
- pattern = xmlStrcat(pattern, (xmlChar *)"//");
- if (pattern == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- }
- }
- pattern = xmlStrncat(pattern, &match[start], end - start);
- if (pattern == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- }
-
- if (match[end] == '|') {
- pattern = xmlStrcat(pattern, (xmlChar *)"|");
- end++;
- }
- current = end;
- }
-#ifdef WITH_XSLT_DEBUG_KEYS
- xsltGenericDebug(xsltGenericDebugContext,
- " resulting pattern %s\n", pattern);
-#endif
- /*
- * XSLT-1: "It is an error for the value of either the use
- * attribute or the match attribute to contain a
- * VariableReference."
- * TODO: We should report a variable-reference at compile-time.
- * Maybe a search for "$", if it occurs outside of quotation
- * marks, could be sufficient.
- */
- key->comp = xsltXPathCompile(style, pattern);
- if (key->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:key : XPath pattern compilation failed '%s'\n",
- pattern);
- if (style != NULL) style->errors++;
- }
- key->usecomp = xsltXPathCompile(style, use);
- if (key->usecomp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:key : XPath pattern compilation failed '%s'\n",
- use);
- if (style != NULL) style->errors++;
- }
- key->next = style->keys;
- style->keys = key;
-error:
- if (pattern != NULL)
- xmlFree(pattern);
- return(0);
-}
-
-/**
- * xsltGetKey:
- * @ctxt: an XSLT transformation context
- * @name: the key name or NULL
- * @nameURI: the name URI or NULL
- * @value: the key value to look for
- *
- * Lookup a key
- *
- * Returns the nodeset resulting from the query or NULL
- */
-xmlNodeSetPtr
-xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *nameURI, const xmlChar *value) {
- xmlNodeSetPtr ret;
- xsltKeyTablePtr table;
-#ifdef XSLT_REFACTORED_KEYCOMP
- int found = 0;
-#endif
-
- if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
- (ctxt->document == NULL))
- return(NULL);
-
-#ifdef WITH_XSLT_DEBUG_KEYS
- xsltGenericDebug(xsltGenericDebugContext,
- "Get key %s, value %s\n", name, value);
-#endif
- table = (xsltKeyTablePtr) ctxt->document->keys;
- while (table != NULL) {
- if (((nameURI != NULL) == (table->nameURI != NULL)) &&
- xmlStrEqual(table->name, name) &&
- xmlStrEqual(table->nameURI, nameURI))
- {
-#ifdef XSLT_REFACTORED_KEYCOMP
- found = 1;
-#endif
- ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
- return(ret);
- }
- table = table->next;
- }
-#ifdef XSLT_REFACTORED_KEYCOMP
- if (! found) {
- xsltStylesheetPtr style = ctxt->style;
- xsltKeyDefPtr keyd;
- /*
- * This might be the first call to the key with the specified
- * name and the specified document.
- * Find all keys with a matching name and compute them for the
- * current tree.
- */
- found = 0;
- while (style != NULL) {
- keyd = (xsltKeyDefPtr) style->keys;
- while (keyd != NULL) {
- if (((nameURI != NULL) == (keyd->nameURI != NULL)) &&
- xmlStrEqual(keyd->name, name) &&
- xmlStrEqual(keyd->nameURI, nameURI))
- {
- found = 1;
- xsltInitCtxtKey(ctxt, ctxt->document, keyd);
- }
- keyd = keyd->next;
- }
- style = xsltNextImport(style);
- }
- if (found) {
- /*
- * The key was computed, so look it up.
- */
- table = (xsltKeyTablePtr) ctxt->document->keys;
- while (table != NULL) {
- if (((nameURI != NULL) == (table->nameURI != NULL)) &&
- xmlStrEqual(table->name, name) &&
- xmlStrEqual(table->nameURI, nameURI))
- {
- ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
- return(ret);
- }
- table = table->next;
- }
-
- }
- }
-#endif
- return(NULL);
-}
-
-/**
- * xsltEvalXPathKeys:
- * @ctxt: the XSLT transformation context
- * @comp: the compiled XPath expression
- *
- * Process the expression using XPath to get the list of keys
- *
- * Returns the array of computed string value or NULL, must be deallocated
- * by the caller.
- */
-static xmlChar **
-xsltEvalXPathKeys(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
- xsltKeyDefPtr keyd) {
- xmlChar **ret = NULL;
- xmlXPathObjectPtr res;
- xmlNodePtr oldInst;
- xmlNodePtr oldNode;
- int oldPos, oldSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- oldInst = ctxt->inst;
- oldNode = ctxt->node;
- oldPos = ctxt->xpathCtxt->proximityPosition;
- oldSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
-
- ctxt->xpathCtxt->node = ctxt->node;
- ctxt->xpathCtxt->namespaces = keyd->nsList;
- ctxt->xpathCtxt->nsNr = keyd->nsNr;
- res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
- if (res != NULL) {
- if (res->type == XPATH_NODESET) {
- int len, i, j;
-
- if (res->nodesetval != NULL)
- len = res->nodesetval->nodeNr;
- else
- len = 0;
- if (len != 0) {
- ret = (xmlChar **) xmlMalloc((len + 1) * sizeof(xmlChar *));
- if (ret != NULL) {
- for (i = 0,j = 0;i < len;i++) {
- ret[j] = xmlXPathCastNodeToString(
- res->nodesetval->nodeTab[i]);
- if (ret[j] != NULL)
- j++;
- }
- ret[j] = NULL;
- }
- }
- } else {
- if (res->type != XPATH_STRING)
- res = xmlXPathConvertString(res);
- if (res->type == XPATH_STRING) {
- ret = (xmlChar **) xmlMalloc(2 * sizeof(xmlChar *));
- if (ret != NULL) {
- ret[0] = res->stringval;
- ret[1] = NULL;
- res->stringval = NULL;
- }
- } else {
- xsltTransformError(ctxt, NULL, NULL,
- "xpath : string() function didn't return a String\n");
- }
- }
- xmlXPathFreeObject(res);
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
-#ifdef WITH_XSLT_DEBUG_TEMPLATES
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltEvalXPathString: returns %s\n", ret);
-#endif
- ctxt->inst = oldInst;
- ctxt->node = oldNode;
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- return(ret);
-}
-
-/**
- * xsltInitCtxtKey:
- * @ctxt: an XSLT transformation context
- * @doc: an XSLT document
- * @keyd: the key definition
- *
- * Computes the key tables this key and for the current input document.
- */
-int
-xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr doc,
- xsltKeyDefPtr keyd) {
- int i;
- xmlNodeSetPtr nodelist = NULL, keylist;
- xmlXPathObjectPtr res = NULL;
- xmlChar *str, **list;
- xsltKeyTablePtr table;
- int oldPos, oldSize;
- xmlNodePtr oldInst;
- xmlNodePtr oldNode;
- xsltDocumentPtr oldDoc;
- xmlDocPtr oldXDoc;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- doc->nbKeysComputed++;
- /*
- * Evaluate the nodelist
- */
-
- oldXDoc= ctxt->xpathCtxt->doc;
- oldPos = ctxt->xpathCtxt->proximityPosition;
- oldSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- oldInst = ctxt->inst;
- oldDoc = ctxt->document;
- oldNode = ctxt->node;
-
- if (keyd->comp == NULL)
- goto error;
- if (keyd->usecomp == NULL)
- goto error;
-
- ctxt->document = doc;
- ctxt->xpathCtxt->doc = doc->doc;
- ctxt->xpathCtxt->node = (xmlNodePtr) doc->doc;
- ctxt->node = (xmlNodePtr) doc->doc;
- /* TODO : clarify the use of namespaces in keys evaluation */
- ctxt->xpathCtxt->namespaces = keyd->nsList;
- ctxt->xpathCtxt->nsNr = keyd->nsNr;
- ctxt->inst = keyd->inst;
- res = xmlXPathCompiledEval(keyd->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
- ctxt->inst = oldInst;
-
- if (res != NULL) {
- if (res->type == XPATH_NODESET) {
- nodelist = res->nodesetval;
-#ifdef WITH_XSLT_DEBUG_KEYS
- if (nodelist != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
- "xsltInitCtxtKey: %s evaluates to %d nodes\n",
- keyd->match, nodelist->nodeNr));
-#endif
- } else {
-#ifdef WITH_XSLT_DEBUG_KEYS
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
- "xsltInitCtxtKey: %s is not a node set\n", keyd->match));
-#endif
- goto error;
- }
- } else {
-#ifdef WITH_XSLT_DEBUG_KEYS
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
- "xsltInitCtxtKey: %s evaluation failed\n", keyd->match));
-#endif
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
-
- /*
- * for each node in the list evaluate the key and insert the node
- */
- if ((nodelist == NULL) || (nodelist->nodeNr <= 0))
- goto error;
-
- /**
- * Multiple key definitions for the same name are allowed, so
- * we must check if the key is already present for this doc
- */
- table = (xsltKeyTablePtr) doc->keys;
- while (table != NULL) {
- if (xmlStrEqual(table->name, keyd->name) &&
- (((keyd->nameURI == NULL) && (table->nameURI == NULL)) ||
- ((keyd->nameURI != NULL) && (table->nameURI != NULL) &&
- (xmlStrEqual(table->nameURI, keyd->nameURI)))))
- break;
- table = table->next;
- }
- /**
- * If the key was not previously defined, create it now and
- * chain it to the list of keys for the doc
- */
- if (table == NULL) {
- table = xsltNewKeyTable(keyd->name, keyd->nameURI);
- if (table == NULL)
- goto error;
- table->next = doc->keys;
- doc->keys = table;
- }
-
- for (i = 0;i < nodelist->nodeNr;i++) {
- if (IS_XSLT_REAL_NODE(nodelist->nodeTab[i])) {
- ctxt->node = nodelist->nodeTab[i];
-
- list = xsltEvalXPathKeys(ctxt, keyd->usecomp, keyd);
- if (list != NULL) {
- int ix = 0;
-
- str = list[ix++];
- while (str != NULL) {
-#ifdef WITH_XSLT_DEBUG_KEYS
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
- "xsl:key : node associated to(%s,%s)\n",
- keyd->name, str));
-#endif
- keylist = xmlHashLookup(table->keys, str);
- if (keylist == NULL) {
- keylist = xmlXPathNodeSetCreate(nodelist->nodeTab[i]);
- xmlHashAddEntry(table->keys, str, keylist);
- } else {
- xmlXPathNodeSetAdd(keylist, nodelist->nodeTab[i]);
- }
- switch (nodelist->nodeTab[i]->type) {
- case XML_ELEMENT_NODE:
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- nodelist->nodeTab[i]->psvi = keyd;
- break;
- case XML_ATTRIBUTE_NODE: {
- xmlAttrPtr attr = (xmlAttrPtr)
- nodelist->nodeTab[i];
- attr->psvi = keyd;
- break;
- }
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE: {
- xmlDocPtr kdoc = (xmlDocPtr)
- nodelist->nodeTab[i];
- kdoc->psvi = keyd;
- break;
- }
- default:
- break;
- }
- xmlFree(str);
- str = list[ix++];
- }
- xmlFree(list);
-#ifdef WITH_XSLT_DEBUG_KEYS
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
- "xsl:key : use %s failed to return strings\n",
- keyd->use));
-#endif
- }
- }
- }
-
-error:
- ctxt->document = oldDoc;
- ctxt->xpathCtxt->doc = oldXDoc;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- ctxt->node = oldNode;
- if (res != NULL)
- xmlXPathFreeObject(res);
- return(0);
-}
-
-/**
- * xsltInitCtxtKeys:
- * @ctxt: an XSLT transformation context
- * @doc: an XSLT document
- *
- * Computes all the keys tables for the current input document.
- * Should be done before global varibales are initialized.
- * NOTE: Not used anymore in the refactored code.
- */
-void
-xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr doc) {
- xsltStylesheetPtr style;
- xsltKeyDefPtr keyd;
-
- if ((ctxt == NULL) || (doc == NULL))
- return;
-#ifdef WITH_XSLT_DEBUG_KEYS
- if ((doc->doc != NULL) && (doc->doc->URL != NULL))
- XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
- doc->doc->URL));
-#endif
- style = ctxt->style;
- while (style != NULL) {
- keyd = (xsltKeyDefPtr) style->keys;
- while (keyd != NULL) {
- xsltInitCtxtKey(ctxt, doc, keyd);
-
- keyd = keyd->next;
- }
-
- style = xsltNextImport(style);
- }
-}
-
-/**
- * xsltFreeDocumentKeys:
- * @doc: a XSLT document
- *
- * Free the keys associated to a document
- */
-void
-xsltFreeDocumentKeys(xsltDocumentPtr doc) {
- if (doc != NULL)
- xsltFreeKeyTableList(doc->keys);
-}
-
+/*\r
+ * keys.c: Implemetation of the keys support\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/parserInternals.h>\r
+#include <libxml/xpathInternals.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "imports.h"\r
+#include "templates.h"\r
+#include "keys.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_KEYS\r
+#endif\r
+\r
+\r
+/************************************************************************\r
+ * *\r
+ * Type functions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewKeyDef:\r
+ * @name: the key name or NULL\r
+ * @nameURI: the name URI or NULL\r
+ *\r
+ * Create a new XSLT KeyDef\r
+ *\r
+ * Returns the newly allocated xsltKeyDefPtr or NULL in case of error\r
+ */\r
+static xsltKeyDefPtr\r
+xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {\r
+ xsltKeyDefPtr cur;\r
+\r
+ cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewKeyDef : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltKeyDef));\r
+ if (name != NULL)\r
+ cur->name = xmlStrdup(name);\r
+ if (nameURI != NULL)\r
+ cur->nameURI = xmlStrdup(nameURI);\r
+ cur->nsList = NULL;\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeKeyDef:\r
+ * @keyd: an XSLT key definition\r
+ *\r
+ * Free up the memory allocated by @keyd\r
+ */\r
+static void\r
+xsltFreeKeyDef(xsltKeyDefPtr keyd) {\r
+ if (keyd == NULL)\r
+ return;\r
+ if (keyd->comp != NULL)\r
+ xmlXPathFreeCompExpr(keyd->comp);\r
+ if (keyd->usecomp != NULL)\r
+ xmlXPathFreeCompExpr(keyd->usecomp);\r
+ if (keyd->name != NULL)\r
+ xmlFree(keyd->name);\r
+ if (keyd->nameURI != NULL)\r
+ xmlFree(keyd->nameURI);\r
+ if (keyd->match != NULL)\r
+ xmlFree(keyd->match);\r
+ if (keyd->use != NULL)\r
+ xmlFree(keyd->use);\r
+ if (keyd->nsList != NULL)\r
+ xmlFree(keyd->nsList);\r
+ memset(keyd, -1, sizeof(xsltKeyDef));\r
+ xmlFree(keyd);\r
+}\r
+\r
+/**\r
+ * xsltFreeKeyDefList:\r
+ * @keyd: an XSLT key definition list\r
+ *\r
+ * Free up the memory allocated by all the elements of @keyd\r
+ */\r
+static void\r
+xsltFreeKeyDefList(xsltKeyDefPtr keyd) {\r
+ xsltKeyDefPtr cur;\r
+\r
+ while (keyd != NULL) {\r
+ cur = keyd;\r
+ keyd = keyd->next;\r
+ xsltFreeKeyDef(cur);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltNewKeyTable:\r
+ * @name: the key name or NULL\r
+ * @nameURI: the name URI or NULL\r
+ *\r
+ * Create a new XSLT KeyTable\r
+ *\r
+ * Returns the newly allocated xsltKeyTablePtr or NULL in case of error\r
+ */\r
+static xsltKeyTablePtr\r
+xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {\r
+ xsltKeyTablePtr cur;\r
+\r
+ cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewKeyTable : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltKeyTable));\r
+ if (name != NULL)\r
+ cur->name = xmlStrdup(name);\r
+ if (nameURI != NULL)\r
+ cur->nameURI = xmlStrdup(nameURI);\r
+ cur->keys = xmlHashCreate(0);\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeKeyTable:\r
+ * @keyt: an XSLT key table\r
+ *\r
+ * Free up the memory allocated by @keyt\r
+ */\r
+static void\r
+xsltFreeKeyTable(xsltKeyTablePtr keyt) {\r
+ if (keyt == NULL)\r
+ return;\r
+ if (keyt->name != NULL)\r
+ xmlFree(keyt->name);\r
+ if (keyt->nameURI != NULL)\r
+ xmlFree(keyt->nameURI);\r
+ if (keyt->keys != NULL)\r
+ xmlHashFree(keyt->keys, \r
+ (xmlHashDeallocator) xmlXPathFreeNodeSet);\r
+ memset(keyt, -1, sizeof(xsltKeyTable));\r
+ xmlFree(keyt);\r
+}\r
+\r
+/**\r
+ * xsltFreeKeyTableList:\r
+ * @keyt: an XSLT key table list\r
+ *\r
+ * Free up the memory allocated by all the elements of @keyt\r
+ */\r
+static void\r
+xsltFreeKeyTableList(xsltKeyTablePtr keyt) {\r
+ xsltKeyTablePtr cur;\r
+\r
+ while (keyt != NULL) {\r
+ cur = keyt;\r
+ keyt = keyt->next;\r
+ xsltFreeKeyTable(cur);\r
+ }\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * The interpreter for the precompiled patterns *\r
+ * *\r
+ ************************************************************************/\r
+\r
+\r
+/**\r
+ * xsltFreeKeys:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Free up the memory used by XSLT keys in a stylesheet\r
+ */\r
+void\r
+xsltFreeKeys(xsltStylesheetPtr style) {\r
+ if (style->keys)\r
+ xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);\r
+}\r
+\r
+/**\r
+ * skipString:\r
+ * @cur: the current pointer\r
+ * @end: the current offset\r
+ *\r
+ * skip a string delimited by " or '\r
+ *\r
+ * Returns the byte after the string or -1 in case of error\r
+ */\r
+static int\r
+skipString(const xmlChar *cur, int end) {\r
+ xmlChar limit;\r
+\r
+ if ((cur == NULL) || (end < 0)) return(-1);\r
+ if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];\r
+ else return(end);\r
+ end++;\r
+ while (cur[end] != 0) {\r
+ if (cur[end] == limit)\r
+ return(end + 1);\r
+ end++;\r
+ }\r
+ return(-1);\r
+}\r
+\r
+/**\r
+ * skipPredicate:\r
+ * @cur: the current pointer\r
+ * @end: the current offset\r
+ *\r
+ * skip a predicate\r
+ *\r
+ * Returns the byte after the predicate or -1 in case of error\r
+ */\r
+static int\r
+skipPredicate(const xmlChar *cur, int end) {\r
+ if ((cur == NULL) || (end < 0)) return(-1);\r
+ if (cur[end] != '[') return(end);\r
+ end++;\r
+ while (cur[end] != 0) {\r
+ if ((cur[end] == '\'') || (cur[end] == '"')) {\r
+ end = skipString(cur, end);\r
+ if (end <= 0)\r
+ return(-1);\r
+ continue;\r
+ } else if (cur[end] == '[') {\r
+ end = skipPredicate(cur, end);\r
+ if (end <= 0)\r
+ return(-1);\r
+ continue;\r
+ } else if (cur[end] == ']')\r
+ return(end + 1);\r
+ end++;\r
+ }\r
+ return(-1);\r
+}\r
+\r
+/**\r
+ * xsltAddKey:\r
+ * @style: an XSLT stylesheet\r
+ * @name: the key name or NULL\r
+ * @nameURI: the name URI or NULL\r
+ * @match: the match value\r
+ * @use: the use value\r
+ * @inst: the key instruction\r
+ *\r
+ * add a key definition to a stylesheet\r
+ *\r
+ * Returns 0 in case of success, and -1 in case of failure.\r
+ */\r
+int \r
+xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,\r
+ const xmlChar *nameURI, const xmlChar *match,\r
+ const xmlChar *use, xmlNodePtr inst) {\r
+ xsltKeyDefPtr key;\r
+ xmlChar *pattern = NULL;\r
+ int current, end, start, i = 0;\r
+\r
+ if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))\r
+ return(-1);\r
+\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Add key %s, match %s, use %s\n", name, match, use);\r
+#endif\r
+\r
+ key = xsltNewKeyDef(name, nameURI);\r
+ key->match = xmlStrdup(match);\r
+ key->use = xmlStrdup(use);\r
+ key->inst = inst;\r
+ key->nsList = xmlGetNsList(inst->doc, inst);\r
+ if (key->nsList != NULL) {\r
+ while (key->nsList[i] != NULL)\r
+ i++;\r
+ }\r
+ key->nsNr = i;\r
+\r
+ /*\r
+ * Split the | and register it as as many keys\r
+ */\r
+ current = end = 0;\r
+ while (match[current] != 0) {\r
+ start = current;\r
+ while (IS_BLANK_CH(match[current]))\r
+ current++;\r
+ end = current;\r
+ while ((match[end] != 0) && (match[end] != '|')) {\r
+ if (match[end] == '[') {\r
+ end = skipPredicate(match, end);\r
+ if (end <= 0) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "key pattern is malformed: %s",\r
+ key->match);\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+ } else\r
+ end++;\r
+ }\r
+ if (current == end) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "key pattern is empty\n");\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+ if (match[start] != '/') {\r
+ pattern = xmlStrcat(pattern, (xmlChar *)"//");\r
+ if (pattern == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+ }\r
+ pattern = xmlStrncat(pattern, &match[start], end - start);\r
+ if (pattern == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ if (match[end] == '|') {\r
+ pattern = xmlStrcat(pattern, (xmlChar *)"|");\r
+ end++;\r
+ }\r
+ current = end;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ " resulting pattern %s\n", pattern);\r
+#endif\r
+ /* \r
+ * XSLT-1: "It is an error for the value of either the use\r
+ * attribute or the match attribute to contain a\r
+ * VariableReference."\r
+ * TODO: We should report a variable-reference at compile-time.\r
+ * Maybe a search for "$", if it occurs outside of quotation\r
+ * marks, could be sufficient.\r
+ */\r
+ key->comp = xsltXPathCompile(style, pattern);\r
+ if (key->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:key : XPath pattern compilation failed '%s'\n",\r
+ pattern);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ key->usecomp = xsltXPathCompile(style, use);\r
+ if (key->usecomp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:key : XPath pattern compilation failed '%s'\n",\r
+ use);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ key->next = style->keys;\r
+ style->keys = key;\r
+error:\r
+ if (pattern != NULL)\r
+ xmlFree(pattern);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltGetKey:\r
+ * @ctxt: an XSLT transformation context\r
+ * @name: the key name or NULL\r
+ * @nameURI: the name URI or NULL\r
+ * @value: the key value to look for\r
+ *\r
+ * Looks up a key of the in current source doc (the document info\r
+ * on @ctxt->document). Computes the key if not already done\r
+ * for the current source doc.\r
+ *\r
+ * Returns the nodeset resulting from the query or NULL\r
+ */\r
+xmlNodeSetPtr\r
+xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,\r
+ const xmlChar *nameURI, const xmlChar *value) {\r
+ xmlNodeSetPtr ret;\r
+ xsltKeyTablePtr table;\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+ int found = 0;\r
+#endif\r
+\r
+ if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||\r
+ (ctxt->document == NULL))\r
+ return(NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Get key %s, value %s\n", name, value);\r
+#endif\r
+\r
+ table = (xsltKeyTablePtr) ctxt->document->keys;\r
+ while (table != NULL) {\r
+ if (((nameURI != NULL) == (table->nameURI != NULL)) &&\r
+ xmlStrEqual(table->name, name) &&\r
+ xmlStrEqual(table->nameURI, nameURI))\r
+ {\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+ found = 1;\r
+#endif\r
+ ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);\r
+ return(ret);\r
+ }\r
+ table = table->next;\r
+ }\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+ if (! found) {\r
+ xsltStylesheetPtr style = ctxt->style; \r
+ xsltKeyDefPtr keyd;\r
+ /*\r
+ * This might be the first call to the key with the specified\r
+ * name and the specified document.\r
+ * Find all keys with a matching name and compute them for the\r
+ * current tree.\r
+ */\r
+ found = 0;\r
+ while (style != NULL) {\r
+ keyd = (xsltKeyDefPtr) style->keys;\r
+ while (keyd != NULL) {\r
+ if (((nameURI != NULL) == (keyd->nameURI != NULL)) &&\r
+ xmlStrEqual(keyd->name, name) &&\r
+ xmlStrEqual(keyd->nameURI, nameURI))\r
+ {\r
+ found = 1;\r
+ xsltInitCtxtKey(ctxt, ctxt->document, keyd);\r
+ }\r
+ keyd = keyd->next; \r
+ } \r
+ style = xsltNextImport(style);\r
+ }\r
+ if (found) {\r
+ /*\r
+ * The key was computed, so look it up.\r
+ */\r
+ table = (xsltKeyTablePtr) ctxt->document->keys;\r
+ while (table != NULL) {\r
+ if (((nameURI != NULL) == (table->nameURI != NULL)) &&\r
+ xmlStrEqual(table->name, name) &&\r
+ xmlStrEqual(table->nameURI, nameURI))\r
+ {\r
+ ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);\r
+ return(ret);\r
+ }\r
+ table = table->next;\r
+ }\r
+\r
+ }\r
+ }\r
+#endif\r
+ return(NULL);\r
+}\r
+\r
+#if 0 /* Merged with xsltInitCtxtKey() */\r
+/**\r
+ * xsltEvalXPathKeys:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the compiled XPath expression\r
+ *\r
+ * Process the expression using XPath to get the list of keys\r
+ *\r
+ * Returns the array of computed string value or NULL, must be deallocated\r
+ * by the caller.\r
+ */\r
+static xmlChar **\r
+xsltEvalXPathKeys(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,\r
+ xsltKeyDefPtr keyd) {\r
+ xmlChar **ret = NULL;\r
+ xmlXPathObjectPtr res;\r
+ xmlNodePtr oldInst;\r
+ xmlNodePtr oldNode;\r
+ int oldPos, oldSize;\r
+ int oldNsNr;\r
+ xmlNsPtr *oldNamespaces;\r
+\r
+ oldInst = ctxt->inst;\r
+ oldNode = ctxt->node;\r
+ oldPos = ctxt->xpathCtxt->proximityPosition;\r
+ oldSize = ctxt->xpathCtxt->contextSize;\r
+ oldNsNr = ctxt->xpathCtxt->nsNr;\r
+ oldNamespaces = ctxt->xpathCtxt->namespaces;\r
+\r
+ ctxt->xpathCtxt->node = ctxt->node;\r
+ ctxt->xpathCtxt->namespaces = keyd->nsList;\r
+ ctxt->xpathCtxt->nsNr = keyd->nsNr;\r
+ res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);\r
+ if (res != NULL) {\r
+ if (res->type == XPATH_NODESET) {\r
+ int len, i, j;\r
+\r
+ if (res->nodesetval != NULL)\r
+ len = res->nodesetval->nodeNr;\r
+ else\r
+ len = 0;\r
+ if (len != 0) {\r
+ ret = (xmlChar **) xmlMalloc((len + 1) * sizeof(xmlChar *));\r
+ if (ret != NULL) {\r
+ for (i = 0,j = 0;i < len;i++) {\r
+ ret[j] = xmlXPathCastNodeToString(\r
+ res->nodesetval->nodeTab[i]);\r
+ if (ret[j] != NULL)\r
+ j++;\r
+ }\r
+ ret[j] = NULL;\r
+ }\r
+ }\r
+ } else {\r
+ if (res->type != XPATH_STRING)\r
+ res = xmlXPathConvertString(res);\r
+ if (res->type == XPATH_STRING) {\r
+ ret = (xmlChar **) xmlMalloc(2 * sizeof(xmlChar *));\r
+ if (ret != NULL) {\r
+ ret[0] = res->stringval;\r
+ ret[1] = NULL;\r
+ res->stringval = NULL;\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xpath : string() function didn't return a String\n");\r
+ }\r
+ }\r
+ xmlXPathFreeObject(res);\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_TEMPLATES\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltEvalXPathString: returns %s\n", ret);\r
+#endif\r
+ ctxt->inst = oldInst;\r
+ ctxt->node = oldNode;\r
+ ctxt->xpathCtxt->contextSize = oldSize;\r
+ ctxt->xpathCtxt->proximityPosition = oldPos;\r
+ ctxt->xpathCtxt->nsNr = oldNsNr;\r
+ ctxt->xpathCtxt->namespaces = oldNamespaces;\r
+ return(ret);\r
+}\r
+#endif\r
+\r
+/**\r
+ * xsltInitCtxtKey:\r
+ * @ctxt: an XSLT transformation context\r
+ * @idoc: the document information (holds key values)\r
+ * @keyDef: the key definition\r
+ *\r
+ * Computes the key tables this key and for the current input document.\r
+ */\r
+int\r
+xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,\r
+ xsltKeyDefPtr keyDef)\r
+{\r
+ int i, len, k; \r
+ xmlNodeSetPtr matchList = NULL, keylist;\r
+ xmlXPathObjectPtr matchRes = NULL, useRes = NULL;\r
+ xmlChar *str = NULL;\r
+ xsltKeyTablePtr table;\r
+ xmlNodePtr oldInst, cur;\r
+ xmlNodePtr oldContextNode;\r
+ xsltDocumentPtr oldDocInfo;\r
+ int oldXPPos, oldXPSize;\r
+ xmlDocPtr oldXPDoc;\r
+ int oldXPNsNr;\r
+ xmlNsPtr *oldXPNamespaces; \r
+ xmlXPathContextPtr xpctxt;\r
+\r
+ if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))\r
+ return(-1);\r
+\r
+ xpctxt = ctxt->xpathCtxt;\r
+ idoc->nbKeysComputed++;\r
+ /*\r
+ * Save context state.\r
+ */\r
+ oldInst = ctxt->inst;\r
+ oldDocInfo = ctxt->document;\r
+ oldContextNode = ctxt->node;\r
+\r
+ oldXPDoc = xpctxt->doc;\r
+ oldXPPos = xpctxt->proximityPosition;\r
+ oldXPSize = xpctxt->contextSize;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+\r
+ /*\r
+ * Set up contexts.\r
+ */\r
+ ctxt->document = idoc;\r
+ ctxt->node = (xmlNodePtr) idoc->doc;\r
+ ctxt->inst = keyDef->inst; \r
+\r
+ xpctxt->doc = idoc->doc;\r
+ xpctxt->node = (xmlNodePtr) idoc->doc; \r
+ /* TODO : clarify the use of namespaces in keys evaluation */\r
+ xpctxt->namespaces = keyDef->nsList;\r
+ xpctxt->nsNr = keyDef->nsNr;\r
+\r
+ /*\r
+ * Evaluate the 'match' expression of the xsl:key.\r
+ * TODO: The 'match' is a *pattern*.\r
+ */\r
+ matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);\r
+ if (matchRes == NULL) {\r
+\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));\r
+#endif\r
+ xsltTransformError(ctxt, NULL, keyDef->inst,\r
+ "Failed to evaluate the 'match' expression.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ } else {\r
+ if (matchRes->type == XPATH_NODESET) {\r
+ matchList = matchRes->nodesetval;\r
+\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ if (matchList != NULL)\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltInitCtxtKey: %s evaluates to %d nodes\n",\r
+ keyDef->match, matchList->nodeNr));\r
+#endif\r
+ } else {\r
+ /*\r
+ * Is not a node set, but must be.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltInitCtxtKey: %s is not a node set\n", keyDef->match));\r
+#endif\r
+ xsltTransformError(ctxt, NULL, keyDef->inst,\r
+ "The 'match' expression did not evaluate to a node set.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ }\r
+ if ((matchList == NULL) || (matchList->nodeNr <= 0))\r
+ goto exit;\r
+\r
+ /**\r
+ * Multiple key definitions for the same name are allowed, so\r
+ * we must check if the key is already present for this doc\r
+ */\r
+ table = (xsltKeyTablePtr) idoc->keys;\r
+ while (table != NULL) {\r
+ if (xmlStrEqual(table->name, keyDef->name) &&\r
+ (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||\r
+ ((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&\r
+ (xmlStrEqual(table->nameURI, keyDef->nameURI)))))\r
+ break;\r
+ table = table->next;\r
+ }\r
+ /**\r
+ * If the key was not previously defined, create it now and\r
+ * chain it to the list of keys for the doc\r
+ */\r
+ if (table == NULL) {\r
+ table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);\r
+ if (table == NULL)\r
+ goto error;\r
+ table->next = idoc->keys;\r
+ idoc->keys = table;\r
+ }\r
+\r
+ /*\r
+ * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)\r
+ * "...the use attribute of the xsl:key element is evaluated with x as\r
+ " the current node and with a node list containing just x as the\r
+ * current node list"\r
+ */\r
+ xpctxt->contextSize = 1;\r
+ xpctxt->proximityPosition = 1;\r
+ \r
+ for (i = 0; i < matchList->nodeNr; i++) {\r
+ cur = matchList->nodeTab[i];\r
+ if (! IS_XSLT_REAL_NODE(cur))\r
+ continue;\r
+ xpctxt->node = cur;\r
+ /*\r
+ * Process the 'use' of the xsl:key.\r
+ * SPEC XSLT 1.0:\r
+ * "The use attribute is an expression specifying the values of\r
+ * the key; the expression is evaluated once for each node that\r
+ * matches the pattern."\r
+ */\r
+ if (useRes != NULL)\r
+ xmlXPathFreeObject(useRes);\r
+ useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);\r
+ if (useRes == NULL) {\r
+ xsltTransformError(ctxt, NULL, keyDef->inst,\r
+ "Failed to evaluate the 'use' expression.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ break;\r
+ }\r
+ if (useRes->type == XPATH_NODESET) {\r
+ if ((useRes->nodesetval != NULL) &&\r
+ (useRes->nodesetval->nodeNr != 0))\r
+ {\r
+ len = useRes->nodesetval->nodeNr;\r
+ str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);\r
+ } else {\r
+ continue;\r
+ }\r
+ } else {\r
+ len = 1;\r
+ if (useRes->type == XPATH_STRING) {\r
+ /*\r
+ * Consume the string value.\r
+ */\r
+ str = useRes->stringval;\r
+ useRes->stringval = NULL;\r
+ } else {\r
+ str = xmlXPathCastToString(useRes);\r
+ }\r
+ } \r
+ /*\r
+ * Process all strings.\r
+ */\r
+ k = 0;\r
+ while (1) {\r
+ if (str == NULL)\r
+ goto next_string;\r
+\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));\r
+#endif\r
+ \r
+ keylist = xmlHashLookup(table->keys, str);\r
+ if (keylist == NULL) {\r
+ keylist = xmlXPathNodeSetCreate(cur);\r
+ if (keylist == NULL)\r
+ goto error;\r
+ xmlHashAddEntry(table->keys, str, keylist);\r
+ } else {\r
+ /*\r
+ * TODO: How do we know if this function failed?\r
+ */\r
+ xmlXPathNodeSetAdd(keylist, cur); \r
+ }\r
+ switch (cur->type) {\r
+ case XML_ELEMENT_NODE:\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ cur->psvi = keyDef;\r
+ break;\r
+ case XML_ATTRIBUTE_NODE:\r
+ ((xmlAttrPtr) cur)->psvi = keyDef;\r
+ break;\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ ((xmlDocPtr) cur)->psvi = keyDef;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ xmlFree(str);\r
+ str = NULL;\r
+\r
+next_string:\r
+ k++;\r
+ if (k >= len)\r
+ break;\r
+ str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]); \r
+ }\r
+ }\r
+\r
+exit:\r
+error:\r
+ /*\r
+ * Restore context state.\r
+ */\r
+ xpctxt->doc = oldXPDoc;\r
+ xpctxt->nsNr = oldXPNsNr;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ xpctxt->proximityPosition = oldXPPos;\r
+ xpctxt->contextSize = oldXPSize;\r
+\r
+ ctxt->node = oldContextNode;\r
+ ctxt->document = oldDocInfo;\r
+ ctxt->inst = oldInst;\r
+\r
+ if (str)\r
+ xmlFree(str);\r
+ if (useRes != NULL)\r
+ xmlXPathFreeObject(useRes);\r
+ if (matchRes != NULL)\r
+ xmlXPathFreeObject(matchRes);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltInitCtxtKeys:\r
+ * @ctxt: an XSLT transformation context\r
+ * @idoc: a document info\r
+ *\r
+ * Computes all the keys tables for the current input document.\r
+ * Should be done before global varibales are initialized.\r
+ * NOTE: Not used anymore in the refactored code.\r
+ */\r
+void\r
+xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {\r
+ xsltStylesheetPtr style;\r
+ xsltKeyDefPtr keyDef;\r
+\r
+ if ((ctxt == NULL) || (idoc == NULL))\r
+ return;\r
+#ifdef WITH_XSLT_DEBUG_KEYS\r
+ if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",\r
+ idoc->doc->URL));\r
+#endif\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ keyDef = (xsltKeyDefPtr) style->keys;\r
+ while (keyDef != NULL) {\r
+ xsltInitCtxtKey(ctxt, idoc, keyDef);\r
+\r
+ keyDef = keyDef->next;\r
+ }\r
+\r
+ style = xsltNextImport(style);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltFreeDocumentKeys:\r
+ * @doc: a XSLT document\r
+ *\r
+ * Free the keys associated to a document\r
+ */\r
+void \r
+xsltFreeDocumentKeys(xsltDocumentPtr idoc) {\r
+ if (idoc != NULL)\r
+ xsltFreeKeyTableList(idoc->keys);\r
+}\r
+\r
-/*
- * namespaces.c: Implementation of the XSLT namespaces handling
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_MATH_H
-#include <math.h>
-#endif
-#ifdef HAVE_FLOAT_H
-#include <float.h>
-#endif
-#ifdef HAVE_IEEEFP_H
-#include <ieeefp.h>
-#endif
-#ifdef HAVE_NAN_H
-#include <nan.h>
-#endif
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/uri.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "namespaces.h"
-#include "imports.h"
-
-
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-#ifdef XSLT_REFACTORED
-static xsltNsAliasPtr
-xsltNewNsAlias(xsltCompilerCtxtPtr cctxt)
-{
- xsltNsAliasPtr ret;
-
- if (cctxt == NULL)
- return(NULL);
-
- ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias));
- if (ret == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "Internal error in xsltNewNsAlias(): Memory allocation failed.\n");
- cctxt->style->errors++;
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltNsAlias));
- /*
- * TODO: Store the item at current stylesheet-level.
- */
- ret->next = cctxt->nsAliases;
- cctxt->nsAliases = ret;
-
- return(ret);
-}
-#endif /* XSLT_REFACTORED */
-/**
- * xsltNamespaceAlias:
- * @style: the XSLT stylesheet
- * @node: the xsl:namespace-alias node
- *
- * Read the stylesheet-prefix and result-prefix attributes, register
- * them as well as the corresponding namespace.
- */
-void
-xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node)
-{
- xmlChar *resultPrefix = NULL;
- xmlChar *stylePrefix = NULL;
- xmlNsPtr literalNs = NULL;
- xmlNsPtr targetNs = NULL;
-
-#ifdef XSLT_REFACTORED
- xsltNsAliasPtr alias;
-
- if ((style == NULL) || (node == NULL))
- return;
-
- /*
- * SPEC XSLT 1.0:
- * "If a namespace URI is declared to be an alias for multiple
- * different namespace URIs, then the declaration with the highest
- * import precedence is used. It is an error if there is more than
- * one such declaration. An XSLT processor may signal the error;
- * if it does not signal the error, it must recover by choosing,
- * from amongst the declarations with the highest import precedence,
- * the one that occurs last in the stylesheet."
- *
- * SPEC TODO: Check for the errors mentioned above.
- */
- /*
- * NOTE that the XSLT 2.0 also *does* use the NULL namespace if
- * "#default" is used and there's no default namespace is scope.
- * I.e., this is *not* an error.
- * Most XSLT 1.0 implementations work this way.
- * The XSLT 1.0 spec has nothing to say on the subject.
- */
- /*
- * Attribute "stylesheet-prefix".
- */
- stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
- if (stylePrefix == NULL) {
- xsltTransformError(NULL, style, node,
- "The attribute 'stylesheet-prefix' is missing.\n");
- return;
- }
- if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default"))
- literalNs = xmlSearchNs(node->doc, node, NULL);
- else {
- literalNs = xmlSearchNs(node->doc, node, stylePrefix);
- if (literalNs == NULL) {
- xsltTransformError(NULL, style, node,
- "Attribute 'stylesheet-prefix': There's no namespace "
- "declaration in scope for the prefix '%s'.\n",
- stylePrefix);
- goto error;
- }
- }
- /*
- * Attribute "result-prefix".
- */
- resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
- if (resultPrefix == NULL) {
- xsltTransformError(NULL, style, node,
- "The attribute 'result-prefix' is missing.\n");
- goto error;
- }
- if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default"))
- targetNs = xmlSearchNs(node->doc, node, NULL);
- else {
- targetNs = xmlSearchNs(node->doc, node, resultPrefix);
-
- if (targetNs == NULL) {
- xsltTransformError(NULL, style, node,
- "Attribute 'result-prefix': There's no namespace "
- "declaration in scope for the prefix '%s'.\n",
- stylePrefix);
- goto error;
- }
- }
- /*
- *
- * Same alias for multiple different target namespace URIs:
- * TODO: The one with the highest import precedence is used.
- * Example:
- * <xsl:namespace-alias stylesheet-prefix="foo"
- * result-prefix="bar"/>
- *
- * <xsl:namespace-alias stylesheet-prefix="foo"
- * result-prefix="zar"/>
- *
- * Same target namespace URI for multiple different aliases:
- * All alias-definitions will be used.
- * Example:
- * <xsl:namespace-alias stylesheet-prefix="bar"
- * result-prefix="foo"/>
- *
- * <xsl:namespace-alias stylesheet-prefix="zar"
- * result-prefix="foo"/>
- * Cases using #default:
- * <xsl:namespace-alias stylesheet-prefix="#default"
- * result-prefix="#default"/>
- * TODO: Has this an effect at all?
- *
- * <xsl:namespace-alias stylesheet-prefix="foo"
- * result-prefix="#default"/>
- * From namespace to no namespace.
- *
- * <xsl:namespace-alias stylesheet-prefix="#default"
- * result-prefix="foo"/>
- * From no namespace to namespace.
- */
-
-
- /*
- * Store the ns-node in the alias-object.
- */
- alias = xsltNewNsAlias(XSLT_CCTXT(style));
- if (alias == NULL)
- return;
- alias->literalNs = literalNs;
- alias->targetNs = targetNs;
- XSLT_CCTXT(style)->hasNsAliases = 1;
-
-
-#else /* XSLT_REFACTORED */
- const xmlChar *literalNsName;
- const xmlChar *targetNsName;
-
-
- if ((style == NULL) || (node == NULL))
- return;
-
- stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
- if (stylePrefix == NULL) {
- xsltTransformError(NULL, style, node,
- "namespace-alias: stylesheet-prefix attribute missing\n");
- return;
- }
- resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
- if (resultPrefix == NULL) {
- xsltTransformError(NULL, style, node,
- "namespace-alias: result-prefix attribute missing\n");
- goto error;
- }
-
- if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) {
- literalNs = xmlSearchNs(node->doc, node, NULL);
- if (literalNs == NULL) {
- literalNsName = NULL;
- } else
- literalNsName = literalNs->href; /* Yes - set for nsAlias table */
- } else {
- literalNs = xmlSearchNs(node->doc, node, stylePrefix);
-
- if ((literalNs == NULL) || (literalNs->href == NULL)) {
- xsltTransformError(NULL, style, node,
- "namespace-alias: prefix %s not bound to any namespace\n",
- stylePrefix);
- goto error;
- } else
- literalNsName = literalNs->href;
- }
-
- /*
- * When "#default" is used for result, if a default namespace has not
- * been explicitly declared the special value UNDEFINED_DEFAULT_NS is
- * put into the nsAliases table
- */
- if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) {
- targetNs = xmlSearchNs(node->doc, node, NULL);
- if (targetNs == NULL) {
- targetNsName = UNDEFINED_DEFAULT_NS;
- } else
- targetNsName = targetNs->href;
- } else {
- targetNs = xmlSearchNs(node->doc, node, resultPrefix);
-
- if ((targetNs == NULL) || (targetNs->href == NULL)) {
- xsltTransformError(NULL, style, node,
- "namespace-alias: prefix %s not bound to any namespace\n",
- resultPrefix);
- goto error;
- } else
- targetNsName = targetNs->href;
- }
- /*
- * Special case: if #default is used for
- * the stylesheet-prefix (literal namespace) and there's no default
- * namespace in scope, we'll use style->defaultAlias for this.
- */
- if (literalNsName == NULL) {
- if (targetNs != NULL) {
- /*
- * BUG TODO: Is it not sufficient to have only 1 field for
- * this, since subsequently alias declarations will
- * overwrite this.
- * Example:
- * <xsl:namespace-alias result-prefix="foo"
- * stylesheet-prefix="#default"/>
- * <xsl:namespace-alias result-prefix="bar"
- * stylesheet-prefix="#default"/>
- * The mapping for "foo" won't be visible anymore.
- */
- style->defaultAlias = targetNs->href;
- }
- } else {
- if (style->nsAliases == NULL)
- style->nsAliases = xmlHashCreate(10);
- if (style->nsAliases == NULL) {
- xsltTransformError(NULL, style, node,
- "namespace-alias: cannot create hash table\n");
- goto error;
- }
- xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
- literalNsName, (void *) targetNsName);
- }
-#endif /* else of XSLT_REFACTORED */
-
-error:
- if (stylePrefix != NULL)
- xmlFree(stylePrefix);
- if (resultPrefix != NULL)
- xmlFree(resultPrefix);
-}
-
-/**
- * xsltGetSpecialNamespace:
- * @ctxt: the transformation context
- * @invocNode: the invoking node; e.g. a literal result element/attr;
- * only used for error reports
- * @nsName: the namespace name (or NULL)
- * @nsPrefix: the suggested namespace prefix (or NULL)
- * @target: the result element on which to anchor a namespace
- *
- * Find a matching (prefix and ns-name) ns-declaration
- * for the requested @nsName and @nsPrefix in the result tree.
- * If none is found then a new ns-declaration will be
- * added to @resultElem. If, in this case, the given prefix is
- * already in use, then a ns-declaration with a modified ns-prefix
- * be we created. Note that this function's priority is to
- * preserve ns-prefixes; it will only change a prefix if there's
- * a namespace clash.
- * If both @nsName and @nsPrefix are NULL, then this will try to
- * "undeclare" a default namespace by declaring an xmlns="".
- *
- * Returns a namespace declaration or NULL.
- */
-xmlNsPtr
-xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
- const xmlChar *nsName, const xmlChar *nsPrefix,
- xmlNodePtr target)
-{
- xmlNsPtr ns;
- int prefixOccupied = 0;
-
- if ((ctxt == NULL) || (target == NULL) ||
- (target->type != XML_ELEMENT_NODE))
- return(NULL);
-
- /*
- * NOTE: Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code; so this need not be done
- * here (it was in the old code).
- * NOTE: @invocNode was named @cur in the old code and was documented to
- * be an input node; since it was only used to anchor an error report
- * somewhere, we can safely change this to @invocNode, which now
- * will be the XSLT instruction (also a literal result element/attribute),
- * which was responsible for this call.
- */
- /*
- * OPTIMIZE TODO: This all could be optimized by keeping track of
- * the ns-decls currently in-scope via a specialized context.
- */
- if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) {
- /*
- * NOTE: the "undeclaration" of the default namespace was
- * part of the logic of the old xsltGetSpecialNamespace() code,
- * so we'll keep that mechanism.
- * Related to the old code: bug #302020:
- */
- /*
- * OPTIMIZE TODO: This all could be optimized by keeping track of
- * the ns-decls currently in-scope via a specialized context.
- */
- /*
- * Search on the result element itself.
- */
- if (target->nsDef != NULL) {
- ns = target->nsDef;
- do {
- if (ns->prefix == NULL) {
- if ((ns->href != NULL) && (ns->href[0] != 0)) {
- /*
- * Raise a namespace normalization error.
- */
- xsltTransformError(ctxt, NULL, invocNode,
- "Namespace normalization error: Cannot undeclare "
- "the default namespace, since the default namespace "
- "'%s' is already declared on the result element "
- "'%s'.\n", ns->href, target->name);
- return(NULL);
- } else {
- /*
- * The default namespace was undeclared on the
- * result element.
- */
- return(NULL);
- }
- break;
- }
- ns = ns->next;
- } while (ns != NULL);
- }
- if ((target->parent != NULL) &&
- (target->parent->type == XML_ELEMENT_NODE))
- {
- /*
- * The parent element is in no namespace, so assume
- * that there is no default namespace in scope.
- */
- if (target->parent->ns == NULL)
- return(NULL);
-
- ns = xmlSearchNs(target->doc, target->parent,
- NULL);
- /*
- * Fine if there's no default ns is scope, or if the
- * default ns was undeclared.
- */
- if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
- return(NULL);
-
- /*
- * Undeclare the default namespace.
- */
- xmlNewNs(target, BAD_CAST "", NULL);
- /* TODO: Check result */
- return(NULL);
- }
- return(NULL);
- }
- /*
- * Handle the XML namespace.
- * QUESTION: Is this faster than using xmlStrEqual() anyway?
- */
- if ((nsPrefix != NULL) &&
- (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') &&
- (nsPrefix[2] == 'l') && (nsPrefix[3] == 0))
- {
- return(xmlSearchNs(target->doc, target, nsPrefix));
- }
- /*
- * First: search on the result element itself.
- */
- if (target->nsDef != NULL) {
- ns = target->nsDef;
- do {
- if ((ns->prefix == NULL) == (nsPrefix == NULL)) {
- if (ns->prefix == nsPrefix) {
- if (xmlStrEqual(ns->href, nsName))
- return(ns);
- prefixOccupied = 1;
- break;
- } else if (xmlStrEqual(ns->prefix, nsPrefix)) {
- if (xmlStrEqual(ns->href, nsName))
- return(ns);
- prefixOccupied = 1;
- break;
- }
- }
- ns = ns->next;
- } while (ns != NULL);
- }
- if (prefixOccupied) {
- /*
- * If the ns-prefix is occupied by an other ns-decl on the
- * result element, then this means:
- * 1) The desired prefix is shadowed
- * 2) There's no way around changing the prefix
- *
- * Try a desperate search for an in-scope ns-decl
- * with a matching ns-name before we use the last option,
- * which is to recreate the ns-decl with a modified prefix.
- */
- ns = xmlSearchNsByHref(target->doc, target, nsName);
- if (ns != NULL)
- return(ns);
-
- /*
- * Fallback to changing the prefix.
- */
- } else if ((target->parent != NULL) &&
- (target->parent->type == XML_ELEMENT_NODE))
- {
- /*
- * Try to find a matching ns-decl in the ancestor-axis.
- *
- * Check the common case: The parent element of the current
- * result element is in the same namespace (with an equal ns-prefix).
- */
- if ((target->parent->ns != NULL) &&
- ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL)))
- {
- ns = target->parent->ns;
-
- if (nsPrefix == NULL) {
- if (xmlStrEqual(ns->href, nsName))
- return(ns);
- } else if (xmlStrEqual(ns->prefix, nsPrefix) &&
- xmlStrEqual(ns->href, nsName))
- {
- return(ns);
- }
- }
- /*
- * Lookup the remaining in-scope namespaces.
- */
- ns = xmlSearchNs(target->doc, target->parent, nsPrefix);
- if (ns != NULL) {
- if (xmlStrEqual(ns->href, nsName))
- return(ns);
- /*
- * Now check for a nasty case: We need to ensure that the new
- * ns-decl won't shadow a prefix in-use by an existing attribute.
- * <foo xmlns:a="urn:test:a">
- * <bar a:a="val-a">
- * <xsl:attribute xmlns:a="urn:test:b" name="a:b">
- * val-b</xsl:attribute>
- * </bar>
- * </foo>
- */
- if (target->properties) {
- xmlAttrPtr attr = target->properties;
- do {
- if ((attr->ns) &&
- xmlStrEqual(attr->ns->prefix, nsPrefix))
- {
- /*
- * Bad, this prefix is already in use.
- * Since we'll change the prefix anyway, try
- * a search for a matching ns-decl based on the
- * namespace name.
- */
- ns = xmlSearchNsByHref(target->doc, target, nsName);
- if (ns != NULL)
- return(ns);
- goto declare_new_prefix;
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- } else {
- /*
- * Either no matching ns-prefix was found or the namespace is
- * shadowed.
- * Create a new ns-decl on the current result element.
- *
- * Hmm, we could also try to reuse an in-scope
- * namespace with a matching ns-name but a different
- * ns-prefix.
- * What has higher priority?
- * 1) If keeping the prefix: create a new ns-decl.
- * 2) If reusal: first lookup ns-names; then fallback
- * to creation of a new ns-decl.
- * REVISIT: this currently uses case 1) although
- * the old way was use xmlSearchNsByHref() and to let change
- * the prefix.
- */
-#if 0
- ns = xmlSearchNsByHref(target->doc, target, nsName);
- if (ns != NULL)
- return(ns);
-#endif
- }
- /*
- * Create the ns-decl on the current result element.
- */
- ns = xmlNewNs(target, nsName, nsPrefix);
- /* TODO: check errors */
- return(ns);
- } else {
- /*
- * This is either the root of the tree or something weird is going on.
- */
- ns = xmlNewNs(target, nsName, nsPrefix);
- /* TODO: Check result */
- return(ns);
- }
-
-declare_new_prefix:
- /*
- * Fallback: we need to generate a new prefix and declare the namespace
- * on the result element.
- */
- {
- xmlChar pref[30];
- int counter = 1;
-
- do {
- snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++);
- ns = xmlSearchNs(target->doc, target, BAD_CAST pref);
- if (counter > 1000) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Internal error in xsltAcquireResultInScopeNs(): "
- "Failed to compute a unique ns-prefix for the "
- "generated element");
- return(NULL);
- }
- } while (ns != NULL);
- ns = xmlNewNs(target, nsName, BAD_CAST pref);
- /* TODO: Check result */
- return(ns);
- }
- return(NULL);
-}
-
-/**
- * xsltGetNamespace:
- * @ctxt: a transformation context
- * @cur: the input node
- * @ns: the namespace
- * @out: the output node (or its parent)
- *
- * Find a matching (prefix and ns-name) ns-declaration
- * for the requested @ns->prefix and @ns->href in the result tree.
- * If none is found then a new ns-declaration will be
- * added to @resultElem. If, in this case, the given prefix is
- * already in use, then a ns-declaration with a modified ns-prefix
- * be we created.
- *
- * Called by:
- * - xsltCopyPropList() (*not* anymore)
- * - xsltShallowCopyElement()
- * - xsltCopyTreeInternal() (*not* anymore)
- * - xsltApplyOneTemplateInt() (*not* in the refactored code),
- * - xsltElement() (*not* anymore)
- *
- * Returns a namespace declaration or NULL in case of
- * namespace fixup failures or API or internal errors.
- */
-xmlNsPtr
-xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
- xmlNodePtr out)
-{
-
- if (ns == NULL)
- return(NULL);
-
-#ifdef XSLT_REFACTORED
- /*
- * Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code.
- * Additionally, aliasing is not intended for non Literal
- * Result Elements.
- */
- return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out));
-#else
- {
- xsltStylesheetPtr style;
- const xmlChar *URI = NULL; /* the replacement URI */
-
- if ((ctxt == NULL) || (cur == NULL) || (out == NULL))
- return(NULL);
-
- 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) {
- return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out));
-#if 0
- /*
- * TODO: Removed, since wrong. If there was no default
- * namespace in the stylesheet then this must resolve to
- * the NULL namespace.
- */
- xmlNsPtr dflt;
- dflt = xmlSearchNs(cur->doc, cur, NULL);
- if (dflt != NULL)
- URI = dflt->href;
- else
- return NULL;
-#endif
- } else if (URI == NULL)
- URI = ns->href;
-
- return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out));
- }
-#endif
-}
-
-/**
- * xsltGetPlainNamespace:
- * @ctxt: a transformation context
- * @cur: the input node
- * @ns: the namespace
- * @out: the result element
- *
- * Obsolete.
- * *Not* called by any Libxslt/Libexslt function.
- * Exaclty the same as xsltGetNamespace().
- *
- * Returns a namespace declaration or NULL in case of
- * namespace fixup failures or API or internal errors.
- */
-xmlNsPtr
-xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
- xmlNsPtr ns, xmlNodePtr out)
-{
- return(xsltGetNamespace(ctxt, cur, ns, out));
-}
-
-/**
- * xsltCopyNamespaceList:
- * @ctxt: a transformation context
- * @node: the target node
- * @cur: the first namespace
- *
- * Do a copy of an namespace list. If @node is non-NULL the
- * new namespaces are added automatically. This handles namespaces
- * aliases.
- * This function is intended only for *internal* use at
- * transformation-time for copying ns-declarations of Literal
- * Result Elements.
- *
- * Called by:
- * xsltCopyTreeInternal() (transform.c)
- * xsltShallowCopyElem() (transform.c)
- *
- * REVISIT: This function won't be used in the refactored code.
- *
- * Returns: a new xmlNsPtr, or NULL in case of error.
- */
-xmlNsPtr
-xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNsPtr cur) {
- xmlNsPtr ret = NULL, tmp;
- xmlNsPtr p = NULL,q;
-
- if (cur == NULL)
- return(NULL);
- if (cur->type != XML_NAMESPACE_DECL)
- return(NULL);
-
- /*
- * One can add namespaces only on element nodes
- */
- if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
- node = NULL;
-
- while (cur != NULL) {
- if (cur->type != XML_NAMESPACE_DECL)
- break;
-
- /*
- * Avoid duplicating namespace declarations in the tree if
- * a matching declaration is in scope.
- */
- if (node != NULL) {
- if ((node->ns != NULL) &&
- (xmlStrEqual(node->ns->prefix, cur->prefix)) &&
- (xmlStrEqual(node->ns->href, cur->href))) {
- cur = cur->next;
- continue;
- }
- tmp = xmlSearchNs(node->doc, node, cur->prefix);
- if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) {
- cur = cur->next;
- continue;
- }
- }
-#ifdef XSLT_REFACTORED
- /*
- * Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code.
- */
- q = xmlNewNs(node, cur->href, cur->prefix);
- if (p == NULL) {
- ret = p = q;
- } else {
- p->next = q;
- p = q;
- }
-#else
- /*
- * TODO: Remove this if the refactored code gets enabled.
- */
- if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
- const xmlChar *URI;
- /* TODO apply cascading */
- URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
- cur->href);
- if (URI == UNDEFINED_DEFAULT_NS)
- continue;
- if (URI != NULL) {
- q = xmlNewNs(node, URI, cur->prefix);
- } else {
- q = xmlNewNs(node, cur->href, cur->prefix);
- }
- if (p == NULL) {
- ret = p = q;
- } else {
- p->next = q;
- p = q;
- }
- }
-#endif
- cur = cur->next;
- }
- return(ret);
-}
-
-/**
- * xsltCopyNamespace:
- * @ctxt: a transformation context
- * @elem: the target element node
- * @ns: the namespace node
- *
- * Copies a namespace node (declaration). If @elem is not NULL,
- * then the new namespace will be declared on @elem.
- *
- * Returns: a new xmlNsPtr, or NULL in case of an error.
- */
-xmlNsPtr
-xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr elem,
- xmlNsPtr ns)
-{
- if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
- return(NULL);
- /*
- * One can add namespaces only on element nodes
- */
- if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
- return(xmlNewNs(NULL, ns->href, ns->prefix));
- else
- return(xmlNewNs(elem, ns->href, ns->prefix));
-}
-
-
-/**
- * xsltFreeNamespaceAliasHashes:
- * @style: an XSLT stylesheet
- *
- * Free up the memory used by namespaces aliases
- */
-void
-xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) {
- if (style->nsAliases != NULL)
- xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL);
- style->nsAliases = NULL;
-}
+/*\r
+ * namespaces.c: Implementation of the XSLT namespaces handling\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#ifdef HAVE_SYS_TYPES_H\r
+#include <sys/types.h>\r
+#endif\r
+#ifdef HAVE_MATH_H\r
+#include <math.h>\r
+#endif\r
+#ifdef HAVE_FLOAT_H\r
+#include <float.h>\r
+#endif\r
+#ifdef HAVE_IEEEFP_H\r
+#include <ieeefp.h>\r
+#endif\r
+#ifdef HAVE_NAN_H\r
+#include <nan.h>\r
+#endif\r
+#ifdef HAVE_CTYPE_H\r
+#include <ctype.h>\r
+#endif\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/uri.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "namespaces.h"\r
+#include "imports.h"\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#ifdef XSLT_REFACTORED \r
+static xsltNsAliasPtr\r
+xsltNewNsAlias(xsltCompilerCtxtPtr cctxt)\r
+{\r
+ xsltNsAliasPtr ret;\r
+\r
+ if (cctxt == NULL)\r
+ return(NULL);\r
+\r
+ ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "Internal error in xsltNewNsAlias(): Memory allocation failed.\n");\r
+ cctxt->style->errors++;\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltNsAlias)); \r
+ /*\r
+ * TODO: Store the item at current stylesheet-level.\r
+ */\r
+ ret->next = cctxt->nsAliases;\r
+ cctxt->nsAliases = ret; \r
+\r
+ return(ret);\r
+}\r
+#endif /* XSLT_REFACTORED */\r
+/**\r
+ * xsltNamespaceAlias:\r
+ * @style: the XSLT stylesheet\r
+ * @node: the xsl:namespace-alias node\r
+ *\r
+ * Read the stylesheet-prefix and result-prefix attributes, register\r
+ * them as well as the corresponding namespace.\r
+ */\r
+void\r
+xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node)\r
+{\r
+ xmlChar *resultPrefix = NULL;\r
+ xmlChar *stylePrefix = NULL;\r
+ xmlNsPtr literalNs = NULL;\r
+ xmlNsPtr targetNs = NULL;\r
+ \r
+#ifdef XSLT_REFACTORED \r
+ xsltNsAliasPtr alias;\r
+\r
+ if ((style == NULL) || (node == NULL))\r
+ return;\r
+\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If a namespace URI is declared to be an alias for multiple\r
+ * different namespace URIs, then the declaration with the highest\r
+ * import precedence is used. It is an error if there is more than\r
+ * one such declaration. An XSLT processor may signal the error;\r
+ * if it does not signal the error, it must recover by choosing,\r
+ * from amongst the declarations with the highest import precedence,\r
+ * the one that occurs last in the stylesheet."\r
+ *\r
+ * SPEC TODO: Check for the errors mentioned above.\r
+ */\r
+ /*\r
+ * NOTE that the XSLT 2.0 also *does* use the NULL namespace if\r
+ * "#default" is used and there's no default namespace is scope.\r
+ * I.e., this is *not* an error. \r
+ * Most XSLT 1.0 implementations work this way.\r
+ * The XSLT 1.0 spec has nothing to say on the subject. \r
+ */\r
+ /*\r
+ * Attribute "stylesheet-prefix".\r
+ */\r
+ stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);\r
+ if (stylePrefix == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "The attribute 'stylesheet-prefix' is missing.\n");\r
+ return;\r
+ }\r
+ if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default"))\r
+ literalNs = xmlSearchNs(node->doc, node, NULL); \r
+ else {\r
+ literalNs = xmlSearchNs(node->doc, node, stylePrefix);\r
+ if (literalNs == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "Attribute 'stylesheet-prefix': There's no namespace "\r
+ "declaration in scope for the prefix '%s'.\n",\r
+ stylePrefix);\r
+ goto error;\r
+ }\r
+ }\r
+ /*\r
+ * Attribute "result-prefix".\r
+ */\r
+ resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);\r
+ if (resultPrefix == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "The attribute 'result-prefix' is missing.\n");\r
+ goto error;\r
+ } \r
+ if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default"))\r
+ targetNs = xmlSearchNs(node->doc, node, NULL);\r
+ else {\r
+ targetNs = xmlSearchNs(node->doc, node, resultPrefix);\r
+\r
+ if (targetNs == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "Attribute 'result-prefix': There's no namespace "\r
+ "declaration in scope for the prefix '%s'.\n",\r
+ stylePrefix);\r
+ goto error;\r
+ }\r
+ }\r
+ /*\r
+ *\r
+ * Same alias for multiple different target namespace URIs:\r
+ * TODO: The one with the highest import precedence is used.\r
+ * Example:\r
+ * <xsl:namespace-alias stylesheet-prefix="foo"\r
+ * result-prefix="bar"/>\r
+ *\r
+ * <xsl:namespace-alias stylesheet-prefix="foo"\r
+ * result-prefix="zar"/>\r
+ *\r
+ * Same target namespace URI for multiple different aliases:\r
+ * All alias-definitions will be used.\r
+ * Example:\r
+ * <xsl:namespace-alias stylesheet-prefix="bar"\r
+ * result-prefix="foo"/>\r
+ *\r
+ * <xsl:namespace-alias stylesheet-prefix="zar"\r
+ * result-prefix="foo"/>\r
+ * Cases using #default:\r
+ * <xsl:namespace-alias stylesheet-prefix="#default"\r
+ * result-prefix="#default"/>\r
+ * TODO: Has this an effect at all?\r
+ *\r
+ * <xsl:namespace-alias stylesheet-prefix="foo"\r
+ * result-prefix="#default"/>\r
+ * From namespace to no namespace.\r
+ *\r
+ * <xsl:namespace-alias stylesheet-prefix="#default"\r
+ * result-prefix="foo"/>\r
+ * From no namespace to namespace.\r
+ */\r
+ \r
+ \r
+ /*\r
+ * Store the ns-node in the alias-object.\r
+ */\r
+ alias = xsltNewNsAlias(XSLT_CCTXT(style));\r
+ if (alias == NULL)\r
+ return;\r
+ alias->literalNs = literalNs;\r
+ alias->targetNs = targetNs;\r
+ XSLT_CCTXT(style)->hasNsAliases = 1;\r
+\r
+\r
+#else /* XSLT_REFACTORED */\r
+ const xmlChar *literalNsName;\r
+ const xmlChar *targetNsName;\r
+ \r
+\r
+ if ((style == NULL) || (node == NULL))\r
+ return;\r
+\r
+ stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);\r
+ if (stylePrefix == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "namespace-alias: stylesheet-prefix attribute missing\n");\r
+ return;\r
+ }\r
+ resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);\r
+ if (resultPrefix == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "namespace-alias: result-prefix attribute missing\n");\r
+ goto error;\r
+ }\r
+ \r
+ if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) {\r
+ literalNs = xmlSearchNs(node->doc, node, NULL);\r
+ if (literalNs == NULL) {\r
+ literalNsName = NULL;\r
+ } else\r
+ literalNsName = literalNs->href; /* Yes - set for nsAlias table */\r
+ } else {\r
+ literalNs = xmlSearchNs(node->doc, node, stylePrefix);\r
+ \r
+ if ((literalNs == NULL) || (literalNs->href == NULL)) {\r
+ xsltTransformError(NULL, style, node,\r
+ "namespace-alias: prefix %s not bound to any namespace\n",\r
+ stylePrefix);\r
+ goto error;\r
+ } else\r
+ literalNsName = literalNs->href;\r
+ }\r
+\r
+ /*\r
+ * When "#default" is used for result, if a default namespace has not\r
+ * been explicitly declared the special value UNDEFINED_DEFAULT_NS is\r
+ * put into the nsAliases table\r
+ */\r
+ if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) {\r
+ targetNs = xmlSearchNs(node->doc, node, NULL);\r
+ if (targetNs == NULL) {\r
+ targetNsName = UNDEFINED_DEFAULT_NS;\r
+ } else\r
+ targetNsName = targetNs->href;\r
+ } else {\r
+ targetNs = xmlSearchNs(node->doc, node, resultPrefix);\r
+\r
+ if ((targetNs == NULL) || (targetNs->href == NULL)) {\r
+ xsltTransformError(NULL, style, node,\r
+ "namespace-alias: prefix %s not bound to any namespace\n",\r
+ resultPrefix);\r
+ goto error;\r
+ } else\r
+ targetNsName = targetNs->href;\r
+ }\r
+ /*\r
+ * Special case: if #default is used for\r
+ * the stylesheet-prefix (literal namespace) and there's no default\r
+ * namespace in scope, we'll use style->defaultAlias for this.\r
+ */ \r
+ if (literalNsName == NULL) {\r
+ if (targetNs != NULL) {\r
+ /*\r
+ * BUG TODO: Is it not sufficient to have only 1 field for\r
+ * this, since subsequently alias declarations will\r
+ * overwrite this. \r
+ * Example:\r
+ * <xsl:namespace-alias result-prefix="foo"\r
+ * stylesheet-prefix="#default"/>\r
+ * <xsl:namespace-alias result-prefix="bar"\r
+ * stylesheet-prefix="#default"/>\r
+ * The mapping for "foo" won't be visible anymore.\r
+ */\r
+ style->defaultAlias = targetNs->href;\r
+ }\r
+ } else {\r
+ if (style->nsAliases == NULL)\r
+ style->nsAliases = xmlHashCreate(10);\r
+ if (style->nsAliases == NULL) {\r
+ xsltTransformError(NULL, style, node,\r
+ "namespace-alias: cannot create hash table\n");\r
+ goto error;\r
+ }\r
+ xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,\r
+ literalNsName, (void *) targetNsName);\r
+ }\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+error:\r
+ if (stylePrefix != NULL)\r
+ xmlFree(stylePrefix);\r
+ if (resultPrefix != NULL)\r
+ xmlFree(resultPrefix);\r
+}\r
+\r
+/**\r
+ * xsltGetSpecialNamespace:\r
+ * @ctxt: the transformation context\r
+ * @invocNode: the invoking node; e.g. a literal result element/attr;\r
+ * only used for error reports\r
+ * @nsName: the namespace name (or NULL)\r
+ * @nsPrefix: the suggested namespace prefix (or NULL)\r
+ * @target: the result element on which to anchor a namespace\r
+ *\r
+ * Find a matching (prefix and ns-name) ns-declaration\r
+ * for the requested @nsName and @nsPrefix in the result tree.\r
+ * If none is found then a new ns-declaration will be\r
+ * added to @resultElem. If, in this case, the given prefix is\r
+ * already in use, then a ns-declaration with a modified ns-prefix\r
+ * be we created. Note that this function's priority is to\r
+ * preserve ns-prefixes; it will only change a prefix if there's\r
+ * a namespace clash.\r
+ * If both @nsName and @nsPrefix are NULL, then this will try to\r
+ * "undeclare" a default namespace by declaring an xmlns="".\r
+ *\r
+ * Returns a namespace declaration or NULL.\r
+ */\r
+xmlNsPtr\r
+xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,\r
+ const xmlChar *nsName, const xmlChar *nsPrefix,\r
+ xmlNodePtr target)\r
+{\r
+ xmlNsPtr ns;\r
+ int prefixOccupied = 0;\r
+\r
+ if ((ctxt == NULL) || (target == NULL) ||\r
+ (target->type != XML_ELEMENT_NODE))\r
+ return(NULL);\r
+\r
+ /*\r
+ * NOTE: Namespace exclusion and ns-aliasing is performed at\r
+ * compilation-time in the refactored code; so this need not be done\r
+ * here (it was in the old code).\r
+ * NOTE: @invocNode was named @cur in the old code and was documented to\r
+ * be an input node; since it was only used to anchor an error report\r
+ * somewhere, we can safely change this to @invocNode, which now\r
+ * will be the XSLT instruction (also a literal result element/attribute),\r
+ * which was responsible for this call.\r
+ */\r
+ /*\r
+ * OPTIMIZE TODO: This all could be optimized by keeping track of\r
+ * the ns-decls currently in-scope via a specialized context.\r
+ */ \r
+ if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) {\r
+ /*\r
+ * NOTE: the "undeclaration" of the default namespace was\r
+ * part of the logic of the old xsltGetSpecialNamespace() code,\r
+ * so we'll keep that mechanism.\r
+ * Related to the old code: bug #302020:\r
+ */\r
+ /*\r
+ * OPTIMIZE TODO: This all could be optimized by keeping track of\r
+ * the ns-decls currently in-scope via a specialized context.\r
+ */\r
+ /*\r
+ * Search on the result element itself.\r
+ */\r
+ if (target->nsDef != NULL) {\r
+ ns = target->nsDef;\r
+ do {\r
+ if (ns->prefix == NULL) {\r
+ if ((ns->href != NULL) && (ns->href[0] != 0)) {\r
+ /*\r
+ * Raise a namespace normalization error.\r
+ */\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Namespace normalization error: Cannot undeclare "\r
+ "the default namespace, since the default namespace "\r
+ "'%s' is already declared on the result element "\r
+ "'%s'.\n", ns->href, target->name);\r
+ return(NULL);\r
+ } else {\r
+ /*\r
+ * The default namespace was undeclared on the\r
+ * result element.\r
+ */\r
+ return(NULL);\r
+ }\r
+ break;\r
+ }\r
+ ns = ns->next;\r
+ } while (ns != NULL);\r
+ } \r
+ if ((target->parent != NULL) &&\r
+ (target->parent->type == XML_ELEMENT_NODE))\r
+ {\r
+ /*\r
+ * The parent element is in no namespace, so assume\r
+ * that there is no default namespace in scope.\r
+ */\r
+ if (target->parent->ns == NULL)\r
+ return(NULL);\r
+ \r
+ ns = xmlSearchNs(target->doc, target->parent,\r
+ NULL);\r
+ /*\r
+ * Fine if there's no default ns is scope, or if the\r
+ * default ns was undeclared.\r
+ */\r
+ if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))\r
+ return(NULL);\r
+ \r
+ /*\r
+ * Undeclare the default namespace.\r
+ */\r
+ xmlNewNs(target, BAD_CAST "", NULL);\r
+ /* TODO: Check result */ \r
+ return(NULL);\r
+ }\r
+ return(NULL);\r
+ }\r
+ /*\r
+ * Handle the XML namespace.\r
+ * QUESTION: Is this faster than using xmlStrEqual() anyway?\r
+ */\r
+ if ((nsPrefix != NULL) &&\r
+ (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') &&\r
+ (nsPrefix[2] == 'l') && (nsPrefix[3] == 0))\r
+ {\r
+ return(xmlSearchNs(target->doc, target, nsPrefix));\r
+ }\r
+ /*\r
+ * First: search on the result element itself.\r
+ */\r
+ if (target->nsDef != NULL) {\r
+ ns = target->nsDef;\r
+ do {\r
+ if ((ns->prefix == NULL) == (nsPrefix == NULL)) {\r
+ if (ns->prefix == nsPrefix) {\r
+ if (xmlStrEqual(ns->href, nsName))\r
+ return(ns);\r
+ prefixOccupied = 1;\r
+ break;\r
+ } else if (xmlStrEqual(ns->prefix, nsPrefix)) {\r
+ if (xmlStrEqual(ns->href, nsName))\r
+ return(ns);\r
+ prefixOccupied = 1;\r
+ break;\r
+ }\r
+ }\r
+ ns = ns->next;\r
+ } while (ns != NULL);\r
+ }\r
+ if (prefixOccupied) {\r
+ /*\r
+ * If the ns-prefix is occupied by an other ns-decl on the\r
+ * result element, then this means:\r
+ * 1) The desired prefix is shadowed\r
+ * 2) There's no way around changing the prefix \r
+ *\r
+ * Try a desperate search for an in-scope ns-decl\r
+ * with a matching ns-name before we use the last option,\r
+ * which is to recreate the ns-decl with a modified prefix.\r
+ */\r
+ ns = xmlSearchNsByHref(target->doc, target, nsName);\r
+ if (ns != NULL)\r
+ return(ns);\r
+\r
+ /*\r
+ * Fallback to changing the prefix.\r
+ */ \r
+ } else if ((target->parent != NULL) &&\r
+ (target->parent->type == XML_ELEMENT_NODE))\r
+ {\r
+ /*\r
+ * Try to find a matching ns-decl in the ancestor-axis.\r
+ *\r
+ * Check the common case: The parent element of the current\r
+ * result element is in the same namespace (with an equal ns-prefix).\r
+ */ \r
+ if ((target->parent->ns != NULL) &&\r
+ ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL)))\r
+ {\r
+ ns = target->parent->ns;\r
+ \r
+ if (nsPrefix == NULL) {\r
+ if (xmlStrEqual(ns->href, nsName))\r
+ return(ns);\r
+ } else if (xmlStrEqual(ns->prefix, nsPrefix) &&\r
+ xmlStrEqual(ns->href, nsName))\r
+ {\r
+ return(ns);\r
+ }\r
+ }\r
+ /*\r
+ * Lookup the remaining in-scope namespaces.\r
+ */ \r
+ ns = xmlSearchNs(target->doc, target->parent, nsPrefix);\r
+ if (ns != NULL) {\r
+ if (xmlStrEqual(ns->href, nsName))\r
+ return(ns); \r
+ /*\r
+ * Now check for a nasty case: We need to ensure that the new\r
+ * ns-decl won't shadow a prefix in-use by an existing attribute.\r
+ * <foo xmlns:a="urn:test:a">\r
+ * <bar a:a="val-a">\r
+ * <xsl:attribute xmlns:a="urn:test:b" name="a:b">\r
+ * val-b</xsl:attribute>\r
+ * </bar>\r
+ * </foo>\r
+ */\r
+ if (target->properties) {\r
+ xmlAttrPtr attr = target->properties;\r
+ do {\r
+ if ((attr->ns) &&\r
+ xmlStrEqual(attr->ns->prefix, nsPrefix))\r
+ {\r
+ /*\r
+ * Bad, this prefix is already in use.\r
+ * Since we'll change the prefix anyway, try\r
+ * a search for a matching ns-decl based on the\r
+ * namespace name.\r
+ */\r
+ ns = xmlSearchNsByHref(target->doc, target, nsName);\r
+ if (ns != NULL)\r
+ return(ns);\r
+ goto declare_new_prefix;\r
+ }\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+ }\r
+ } else {\r
+ /*\r
+ * Either no matching ns-prefix was found or the namespace is\r
+ * shadowed.\r
+ * Create a new ns-decl on the current result element.\r
+ *\r
+ * Hmm, we could also try to reuse an in-scope\r
+ * namespace with a matching ns-name but a different\r
+ * ns-prefix.\r
+ * What has higher priority? \r
+ * 1) If keeping the prefix: create a new ns-decl.\r
+ * 2) If reusal: first lookup ns-names; then fallback\r
+ * to creation of a new ns-decl.\r
+ * REVISIT: this currently uses case 1) although\r
+ * the old way was use xmlSearchNsByHref() and to let change\r
+ * the prefix.\r
+ */\r
+#if 0\r
+ ns = xmlSearchNsByHref(target->doc, target, nsName);\r
+ if (ns != NULL)\r
+ return(ns);\r
+#endif\r
+ }\r
+ /*\r
+ * Create the ns-decl on the current result element.\r
+ */\r
+ ns = xmlNewNs(target, nsName, nsPrefix);\r
+ /* TODO: check errors */\r
+ return(ns);\r
+ } else {\r
+ /*\r
+ * This is either the root of the tree or something weird is going on.\r
+ */\r
+ ns = xmlNewNs(target, nsName, nsPrefix);\r
+ /* TODO: Check result */\r
+ return(ns);\r
+ }\r
+\r
+declare_new_prefix:\r
+ /*\r
+ * Fallback: we need to generate a new prefix and declare the namespace\r
+ * on the result element.\r
+ */\r
+ {\r
+ xmlChar pref[30];\r
+ int counter = 1;\r
+ \r
+ do {\r
+ snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++);\r
+ ns = xmlSearchNs(target->doc, target, BAD_CAST pref);\r
+ if (counter > 1000) {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Internal error in xsltAcquireResultInScopeNs(): " \r
+ "Failed to compute a unique ns-prefix for the "\r
+ "generated element");\r
+ return(NULL);\r
+ }\r
+ } while (ns != NULL);\r
+ ns = xmlNewNs(target, nsName, BAD_CAST pref);\r
+ /* TODO: Check result */\r
+ return(ns);\r
+ }\r
+ return(NULL); \r
+}\r
+\r
+/**\r
+ * xsltGetNamespace:\r
+ * @ctxt: a transformation context\r
+ * @cur: the input node\r
+ * @ns: the namespace\r
+ * @out: the output node (or its parent)\r
+ *\r
+ * Find a matching (prefix and ns-name) ns-declaration\r
+ * for the requested @ns->prefix and @ns->href in the result tree.\r
+ * If none is found then a new ns-declaration will be\r
+ * added to @resultElem. If, in this case, the given prefix is\r
+ * already in use, then a ns-declaration with a modified ns-prefix\r
+ * be we created.\r
+ *\r
+ * Called by:\r
+ * - xsltCopyPropList() (*not* anymore)\r
+ * - xsltShallowCopyElement()\r
+ * - xsltCopyTreeInternal() (*not* anymore)\r
+ * - xsltApplySequenceConstructor() (*not* in the refactored code),\r
+ * - xsltElement() (*not* anymore)\r
+ *\r
+ * Returns a namespace declaration or NULL in case of\r
+ * namespace fixup failures or API or internal errors.\r
+ */\r
+xmlNsPtr\r
+xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,\r
+ xmlNodePtr out)\r
+{ \r
+ \r
+ if (ns == NULL)\r
+ return(NULL);\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Namespace exclusion and ns-aliasing is performed at\r
+ * compilation-time in the refactored code.\r
+ * Additionally, aliasing is not intended for non Literal\r
+ * Result Elements.\r
+ */\r
+ return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out));\r
+#else\r
+ {\r
+ xsltStylesheetPtr style;\r
+ const xmlChar *URI = NULL; /* the replacement URI */\r
+\r
+ if ((ctxt == NULL) || (cur == NULL) || (out == NULL))\r
+ return(NULL);\r
+\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ if (style->nsAliases != NULL)\r
+ URI = (const xmlChar *) \r
+ xmlHashLookup(style->nsAliases, ns->href);\r
+ if (URI != NULL)\r
+ break;\r
+ \r
+ style = xsltNextImport(style);\r
+ }\r
+ \r
+ \r
+ if (URI == UNDEFINED_DEFAULT_NS) {\r
+ return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out));\r
+#if 0\r
+ /*\r
+ * TODO: Removed, since wrong. If there was no default\r
+ * namespace in the stylesheet then this must resolve to\r
+ * the NULL namespace.\r
+ */\r
+ xmlNsPtr dflt; \r
+ dflt = xmlSearchNs(cur->doc, cur, NULL);\r
+ if (dflt != NULL)\r
+ URI = dflt->href;\r
+ else\r
+ return NULL;\r
+#endif\r
+ } else if (URI == NULL)\r
+ URI = ns->href;\r
+\r
+ return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out));\r
+ }\r
+#endif\r
+}\r
+\r
+/**\r
+ * xsltGetPlainNamespace:\r
+ * @ctxt: a transformation context\r
+ * @cur: the input node\r
+ * @ns: the namespace\r
+ * @out: the result element\r
+ *\r
+ * Obsolete. \r
+ * *Not* called by any Libxslt/Libexslt function.\r
+ * Exaclty the same as xsltGetNamespace(). \r
+ *\r
+ * Returns a namespace declaration or NULL in case of\r
+ * namespace fixup failures or API or internal errors.\r
+ */\r
+xmlNsPtr\r
+xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,\r
+ xmlNsPtr ns, xmlNodePtr out)\r
+{ \r
+ return(xsltGetNamespace(ctxt, cur, ns, out));\r
+}\r
+\r
+/**\r
+ * xsltCopyNamespaceList:\r
+ * @ctxt: a transformation context\r
+ * @node: the target node\r
+ * @cur: the first namespace\r
+ *\r
+ * Do a copy of an namespace list. If @node is non-NULL the\r
+ * new namespaces are added automatically. This handles namespaces\r
+ * aliases.\r
+ * This function is intended only for *internal* use at\r
+ * transformation-time for copying ns-declarations of Literal\r
+ * Result Elements.\r
+ * \r
+ * Called by:\r
+ * xsltCopyTreeInternal() (transform.c)\r
+ * xsltShallowCopyElem() (transform.c)\r
+ *\r
+ * REVISIT: This function won't be used in the refactored code.\r
+ *\r
+ * Returns: a new xmlNsPtr, or NULL in case of error.\r
+ */\r
+xmlNsPtr\r
+xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNsPtr cur) {\r
+ xmlNsPtr ret = NULL, tmp;\r
+ xmlNsPtr p = NULL,q; \r
+\r
+ if (cur == NULL)\r
+ return(NULL);\r
+ if (cur->type != XML_NAMESPACE_DECL)\r
+ return(NULL);\r
+\r
+ /*\r
+ * One can add namespaces only on element nodes\r
+ */\r
+ if ((node != NULL) && (node->type != XML_ELEMENT_NODE))\r
+ node = NULL;\r
+\r
+ while (cur != NULL) {\r
+ if (cur->type != XML_NAMESPACE_DECL)\r
+ break;\r
+\r
+ /*\r
+ * Avoid duplicating namespace declarations in the tree if\r
+ * a matching declaration is in scope.\r
+ */\r
+ if (node != NULL) {\r
+ if ((node->ns != NULL) &&\r
+ (xmlStrEqual(node->ns->prefix, cur->prefix)) &&\r
+ (xmlStrEqual(node->ns->href, cur->href))) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ tmp = xmlSearchNs(node->doc, node, cur->prefix);\r
+ if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ }\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Namespace exclusion and ns-aliasing is performed at\r
+ * compilation-time in the refactored code.\r
+ */\r
+ q = xmlNewNs(node, cur->href, cur->prefix);\r
+ if (p == NULL) {\r
+ ret = p = q;\r
+ } else {\r
+ p->next = q;\r
+ p = q;\r
+ }\r
+#else\r
+ /*\r
+ * TODO: Remove this if the refactored code gets enabled.\r
+ */\r
+ if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {\r
+ const xmlChar *URI;\r
+ /* TODO apply cascading */\r
+ URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,\r
+ cur->href);\r
+ if (URI == UNDEFINED_DEFAULT_NS)\r
+ continue;\r
+ if (URI != NULL) {\r
+ q = xmlNewNs(node, URI, cur->prefix);\r
+ } else {\r
+ q = xmlNewNs(node, cur->href, cur->prefix);\r
+ }\r
+ if (p == NULL) {\r
+ ret = p = q;\r
+ } else {\r
+ p->next = q;\r
+ p = q;\r
+ }\r
+ }\r
+#endif\r
+ cur = cur->next;\r
+ }\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltCopyNamespace:\r
+ * @ctxt: a transformation context\r
+ * @elem: the target element node\r
+ * @ns: the namespace node\r
+ *\r
+ * Copies a namespace node (declaration). If @elem is not NULL,\r
+ * then the new namespace will be declared on @elem.\r
+ *\r
+ * Returns: a new xmlNsPtr, or NULL in case of an error.\r
+ */\r
+xmlNsPtr\r
+xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr elem,\r
+ xmlNsPtr ns)\r
+{ \r
+ if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))\r
+ return(NULL);\r
+ /*\r
+ * One can add namespaces only on element nodes\r
+ */\r
+ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))\r
+ return(xmlNewNs(NULL, ns->href, ns->prefix));\r
+ else\r
+ return(xmlNewNs(elem, ns->href, ns->prefix));\r
+}\r
+\r
+\r
+/**\r
+ * xsltFreeNamespaceAliasHashes:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Free up the memory used by namespaces aliases\r
+ */\r
+void\r
+xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) {\r
+ if (style->nsAliases != NULL)\r
+ xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL);\r
+ style->nsAliases = NULL;\r
+}\r
-/*
- * pattern.c: Implemetation of the template match compilation and lookup
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-/*
- * TODO: handle pathological cases like *[*[@a="b"]]
- * TODO: detect [number] at compilation, optimize accordingly
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parserInternals.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "imports.h"
-#include "templates.h"
-#include "keys.h"
-#include "pattern.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_PATTERN
-#endif
-
-/*
- * Types are private:
- */
-
-typedef enum {
- XSLT_OP_END=0,
- XSLT_OP_ROOT,
- XSLT_OP_ELEM,
- XSLT_OP_CHILD,
- XSLT_OP_ATTR,
- XSLT_OP_PARENT,
- XSLT_OP_ANCESTOR,
- XSLT_OP_ID,
- XSLT_OP_KEY,
- XSLT_OP_NS,
- XSLT_OP_ALL,
- XSLT_OP_PI,
- XSLT_OP_COMMENT,
- XSLT_OP_TEXT,
- XSLT_OP_NODE,
- XSLT_OP_PREDICATE
-} xsltOp;
-
-typedef struct _xsltStepState xsltStepState;
-typedef xsltStepState *xsltStepStatePtr;
-struct _xsltStepState {
- int step;
- xmlNodePtr node;
-};
-
-typedef struct _xsltStepStates xsltStepStates;
-typedef xsltStepStates *xsltStepStatesPtr;
-struct _xsltStepStates {
- int nbstates;
- int maxstates;
- xsltStepStatePtr states;
-};
-
-typedef struct _xsltStepOp xsltStepOp;
-typedef xsltStepOp *xsltStepOpPtr;
-struct _xsltStepOp {
- xsltOp op;
- xmlChar *value;
- xmlChar *value2;
- xmlChar *value3;
- xmlXPathCompExprPtr comp;
- /*
- * Optimisations for count
- */
- int previousExtra;
- int indexExtra;
- int lenExtra;
-};
-
-struct _xsltCompMatch {
- struct _xsltCompMatch *next; /* siblings in the name hash */
- float priority; /* the priority */
- const xmlChar *pattern; /* the pattern */
- const xmlChar *mode; /* the mode */
- const xmlChar *modeURI; /* the mode URI */
- xsltTemplatePtr template; /* the associated template */
-
- int direct;
- /* TODO fix the statically allocated size steps[] */
- int nbStep;
- int maxStep;
- xmlNsPtr *nsList; /* the namespaces in scope */
- int nsNr; /* the number of namespaces in scope */
- xsltStepOp steps[40]; /* ops for computation */
-};
-
-typedef struct _xsltParserContext xsltParserContext;
-typedef xsltParserContext *xsltParserContextPtr;
-struct _xsltParserContext {
- xsltStylesheetPtr style; /* the stylesheet */
- xsltTransformContextPtr ctxt; /* the transformation or NULL */
- const xmlChar *cur; /* the current char being parsed */
- const xmlChar *base; /* the full expression */
- xmlDocPtr doc; /* the source document */
- xmlNodePtr elem; /* the source element */
- int error; /* error code */
- xsltCompMatchPtr comp; /* the result */
-};
-
-/************************************************************************
- * *
- * Type functions *
- * *
- ************************************************************************/
-
-/**
- * xsltNewCompMatch:
- *
- * Create a new XSLT CompMatch
- *
- * Returns the newly allocated xsltCompMatchPtr or NULL in case of error
- */
-static xsltCompMatchPtr
-xsltNewCompMatch(void) {
- xsltCompMatchPtr cur;
-
- cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewCompMatch : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltCompMatch));
- cur->maxStep = 40;
- cur->nsNr = 0;
- cur->nsList = NULL;
- cur->direct = 0;
- return(cur);
-}
-
-/**
- * xsltFreeCompMatch:
- * @comp: an XSLT comp
- *
- * Free up the memory allocated by @comp
- */
-static void
-xsltFreeCompMatch(xsltCompMatchPtr comp) {
- xsltStepOpPtr op;
- int i;
-
- if (comp == NULL)
- return;
- if (comp->pattern != NULL)
- xmlFree((xmlChar *)comp->pattern);
- if (comp->nsList != NULL)
- xmlFree(comp->nsList);
- for (i = 0;i < comp->nbStep;i++) {
- op = &comp->steps[i];
- if (op->value != NULL)
- xmlFree(op->value);
- if (op->value2 != NULL)
- xmlFree(op->value2);
- if (op->value3 != NULL)
- xmlFree(op->value3);
- if (op->comp != NULL)
- xmlXPathFreeCompExpr(op->comp);
- }
- memset(comp, -1, sizeof(xsltCompMatch));
- xmlFree(comp);
-}
-
-/**
- * xsltFreeCompMatchList:
- * @comp: an XSLT comp list
- *
- * Free up the memory allocated by all the elements of @comp
- */
-void
-xsltFreeCompMatchList(xsltCompMatchPtr comp) {
- xsltCompMatchPtr cur;
-
- while (comp != NULL) {
- cur = comp;
- comp = comp->next;
- xsltFreeCompMatch(cur);
- }
-}
-
-/**
- * xsltNormalizeCompSteps:
- * @payload: pointer to template hash table entry
- * @data: pointer to the stylesheet
- * @name: template match name
- *
- * This is a hashtable scanner function to normalize the compiled
- * steps of an imported stylesheet.
- */
-void xsltNormalizeCompSteps(void *payload,
- void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
- xsltCompMatchPtr comp = payload;
- xsltStylesheetPtr style = data;
- int ix;
-
- for (ix = 0; ix < comp->nbStep; ix++) {
- comp->steps[ix].previousExtra += style->extrasNr;
- comp->steps[ix].indexExtra += style->extrasNr;
- comp->steps[ix].lenExtra += style->extrasNr;
- }
-}
-
-/**
- * xsltNewParserContext:
- * @style: the stylesheet
- * @ctxt: the transformation context, if done at run-time
- *
- * Create a new XSLT ParserContext
- *
- * Returns the newly allocated xsltParserContextPtr or NULL in case of error
- */
-static xsltParserContextPtr
-xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) {
- xsltParserContextPtr cur;
-
- cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewParserContext : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltParserContext));
- cur->style = style;
- cur->ctxt = ctxt;
- return(cur);
-}
-
-/**
- * xsltFreeParserContext:
- * @ctxt: an XSLT parser context
- *
- * Free up the memory allocated by @ctxt
- */
-static void
-xsltFreeParserContext(xsltParserContextPtr ctxt) {
- if (ctxt == NULL)
- return;
- memset(ctxt, -1, sizeof(xsltParserContext));
- xmlFree(ctxt);
-}
-
-/**
- * xsltCompMatchAdd:
- * @comp: the compiled match expression
- * @op: an op
- * @value: the first value
- * @value2: the second value
- * @novar: flag to set XML_XPATH_NOVAR
- *
- * Add an step to an XSLT Compiled Match
- *
- * Returns -1 in case of failure, 0 otherwise.
- */
-static int
-xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
- xsltOp op, xmlChar * value, xmlChar * value2, int novar)
-{
- if (comp->nbStep >= 40) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompMatchAdd: overflow\n");
- return (-1);
- }
- comp->steps[comp->nbStep].op = op;
- comp->steps[comp->nbStep].value = value;
- comp->steps[comp->nbStep].value2 = value2;
- if (ctxt->ctxt != NULL) {
- comp->steps[comp->nbStep].previousExtra =
- xsltAllocateExtraCtxt(ctxt->ctxt);
- comp->steps[comp->nbStep].indexExtra =
- xsltAllocateExtraCtxt(ctxt->ctxt);
- comp->steps[comp->nbStep].lenExtra =
- xsltAllocateExtraCtxt(ctxt->ctxt);
- } else {
- comp->steps[comp->nbStep].previousExtra =
- xsltAllocateExtra(ctxt->style);
- comp->steps[comp->nbStep].indexExtra =
- xsltAllocateExtra(ctxt->style);
- comp->steps[comp->nbStep].lenExtra =
- xsltAllocateExtra(ctxt->style);
- }
- if (op == XSLT_OP_PREDICATE) {
- xmlXPathContextPtr xctxt;
-
- if (ctxt->style != NULL)
- xctxt = xmlXPathNewContext(ctxt->style->doc);
- else
- xctxt = xmlXPathNewContext(NULL);
-#ifdef XML_XPATH_NOVAR
- if (novar != 0)
- xctxt->flags = XML_XPATH_NOVAR;
-#endif
- if (ctxt->style != NULL)
- xctxt->dict = ctxt->style->dict;
- comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);
- xmlXPathFreeContext(xctxt);
- if (comp->steps[comp->nbStep].comp == NULL) {
- xsltTransformError(NULL, ctxt->style, ctxt->elem,
- "Failed to compile predicate\n");
- if (ctxt->style != NULL)
- ctxt->style->errors++;
- }
- }
- comp->nbStep++;
- return (0);
-}
-
-/**
- * xsltSwapTopCompMatch:
- * @comp: the compiled match expression
- *
- * reverse the two top steps.
- */
-static void
-xsltSwapTopCompMatch(xsltCompMatchPtr comp) {
- int i;
- int j = comp->nbStep - 1;
-
- if (j > 0) {
- register xmlChar *tmp;
- register xsltOp op;
- register xmlXPathCompExprPtr expr;
- i = j - 1;
- tmp = comp->steps[i].value;
- comp->steps[i].value = comp->steps[j].value;
- comp->steps[j].value = tmp;
- tmp = comp->steps[i].value2;
- comp->steps[i].value2 = comp->steps[j].value2;
- comp->steps[j].value2 = tmp;
- op = comp->steps[i].op;
- comp->steps[i].op = comp->steps[j].op;
- comp->steps[j].op = op;
- expr = comp->steps[i].comp;
- comp->steps[i].comp = comp->steps[j].comp;
- comp->steps[j].comp = expr;
- }
-}
-
-/**
- * xsltReverseCompMatch:
- * @comp: the compiled match expression
- *
- * reverse all the stack of expressions
- */
-static void
-xsltReverseCompMatch(xsltCompMatchPtr comp) {
- int i = 0;
- int j = comp->nbStep - 1;
-
- while (j > i) {
- register xmlChar *tmp;
- register xsltOp op;
- register xmlXPathCompExprPtr expr;
- tmp = comp->steps[i].value;
- comp->steps[i].value = comp->steps[j].value;
- comp->steps[j].value = tmp;
- tmp = comp->steps[i].value2;
- comp->steps[i].value2 = comp->steps[j].value2;
- comp->steps[j].value2 = tmp;
- op = comp->steps[i].op;
- comp->steps[i].op = comp->steps[j].op;
- comp->steps[j].op = op;
- expr = comp->steps[i].comp;
- comp->steps[i].comp = comp->steps[j].comp;
- comp->steps[j].comp = expr;
- j--;
- i++;
- }
- comp->steps[comp->nbStep++].op = XSLT_OP_END;
- /*
- * detect consecutive XSLT_OP_PREDICATE indicating a direct
- * matching should be done.
- */
- for (i = 0;i < comp->nbStep - 1;i++) {
- if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
- (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
-
- comp->direct = 1;
- if (comp->pattern[0] != '/') {
- xmlChar *query;
-
- query = xmlStrdup((const xmlChar *)"//");
- query = xmlStrcat(query, comp->pattern);
-
- xmlFree((xmlChar *) comp->pattern);
- comp->pattern = query;
- }
- break;
- }
- }
-}
-
-/************************************************************************
- * *
- * The interpreter for the precompiled patterns *
- * *
- ************************************************************************/
-
-static int
-xsltPatPushState(xsltStepStates *states, int step, xmlNodePtr node) {
- if ((states->states == NULL) || (states->maxstates <= 0)) {
- states->maxstates = 4;
- states->nbstates = 0;
- states->states = xmlMalloc(4 * sizeof(xsltStepState));
- }
- else if (states->maxstates <= states->nbstates) {
- xsltStepState *tmp;
-
- tmp = (xsltStepStatePtr) xmlRealloc(states->states,
- 2 * states->maxstates * sizeof(xsltStepState));
- if (tmp == NULL)
- return(-1);
- states->states = tmp;
- states->maxstates *= 2;
- }
- states->states[states->nbstates].step = step;
- states->states[states->nbstates++].node = node;
-#if 0
- fprintf(stderr, "Push: %d, %s\n", step, node->name);
-#endif
- return(0);
-}
-
-/**
- * xsltTestCompMatchDirect:
- * @ctxt: a XSLT process context
- * @comp: the precompiled pattern
- * @node: a node
- *
- * Test whether the node matches the pattern, do a direct evalutation
- * and not a step by step evaluation.
- *
- * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
- */
-static int
-xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
- xmlNodePtr node) {
- xsltStepOpPtr sel = NULL;
- xmlDocPtr prevdoc;
- xmlDocPtr doc;
- xmlXPathObjectPtr list;
- int ix, j;
- int nocache = 0;
- int isRVT;
-
- doc = node->doc;
- if (XSLT_IS_RES_TREE_FRAG(doc))
- isRVT = 1;
- else
- isRVT = 0;
- sel = &comp->steps[0]; /* store extra in first step arbitrarily */
-
- prevdoc = (xmlDocPtr)
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
- ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
- list = (xmlXPathObjectPtr)
- XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
-
- if ((list == NULL) || (prevdoc != doc)) {
- xmlXPathObjectPtr newlist;
- xmlNodePtr parent = node->parent;
- xmlDocPtr olddoc;
- xmlNodePtr oldnode;
-
- oldnode = ctxt->xpathCtxt->node;
- olddoc = ctxt->xpathCtxt->doc;
- ctxt->xpathCtxt->node = node;
- ctxt->xpathCtxt->doc = doc;
- newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
- ctxt->xpathCtxt->node = oldnode;
- ctxt->xpathCtxt->doc = olddoc;
- if (newlist == NULL)
- return(-1);
- if (newlist->type != XPATH_NODESET) {
- xmlXPathFreeObject(newlist);
- return(-1);
- }
- ix = 0;
-
- if ((parent == NULL) || (node->doc == NULL) || isRVT)
- nocache = 1;
-
- if (nocache == 0) {
- if (list != NULL)
- xmlXPathFreeObject(list);
- list = newlist;
-
- XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
- (void *) list;
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
- (void *) doc;
- XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
- 0;
- XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
- (xmlFreeFunc) xmlXPathFreeObject;
- } else
- list = newlist;
- }
- if ((list->nodesetval == NULL) ||
- (list->nodesetval->nodeNr <= 0)) {
- if (nocache == 1)
- xmlXPathFreeObject(list);
- return(0);
- }
- /* TODO: store the index and use it for the scan */
- if (ix == 0) {
- for (j = 0;j < list->nodesetval->nodeNr;j++) {
- if (list->nodesetval->nodeTab[j] == node) {
- if (nocache == 1)
- xmlXPathFreeObject(list);
- return(1);
- }
- }
- } else {
- }
- if (nocache == 1)
- xmlXPathFreeObject(list);
- return(0);
-}
-
-/**
- * xsltTestCompMatch:
- * @ctxt: a XSLT process context
- * @comp: the precompiled pattern
- * @node: a node
- * @mode: the mode name or NULL
- * @modeURI: the mode URI or NULL
- *
- * Test whether the node matches the pattern
- *
- * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
- */
-static int
-xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
- xmlNodePtr node, const xmlChar *mode,
- const xmlChar *modeURI) {
- int i;
- xsltStepOpPtr step, sel = NULL;
- xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
-
- if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
- xsltTransformError(ctxt, NULL, node,
- "xsltTestCompMatch: null arg\n");
- return(-1);
- }
- if (mode != NULL) {
- if (comp->mode == NULL)
- return(0);
- /*
- * both mode strings must be interned on the stylesheet dictionary
- */
- if (comp->mode != mode)
- return(0);
- } else {
- if (comp->mode != NULL)
- return(0);
- }
- if (modeURI != NULL) {
- if (comp->modeURI == NULL)
- return(0);
- /*
- * both modeURI strings must be interned on the stylesheet dictionary
- */
- if (comp->modeURI != modeURI)
- return(0);
- } else {
- if (comp->modeURI != NULL)
- return(0);
- }
-
- i = 0;
-restart:
- for (;i < comp->nbStep;i++) {
- step = &comp->steps[i];
- if (step->op != XSLT_OP_PREDICATE)
- sel = step;
- switch (step->op) {
- case XSLT_OP_END:
- goto found;
- case XSLT_OP_ROOT:
- if ((node->type == XML_DOCUMENT_NODE) ||
-#ifdef LIBXML_DOCB_ENABLED
- (node->type == XML_DOCB_DOCUMENT_NODE) ||
-#endif
- (node->type == XML_HTML_DOCUMENT_NODE))
- continue;
- if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
- continue;
- goto rollback;
- case XSLT_OP_ELEM:
- if (node->type != XML_ELEMENT_NODE)
- goto rollback;
- if (step->value == NULL)
- continue;
- if (step->value[0] != node->name[0])
- goto rollback;
- if (!xmlStrEqual(step->value, node->name))
- goto rollback;
-
- /* Namespace test */
- if (node->ns == NULL) {
- if (step->value2 != NULL)
- goto rollback;
- } else if (node->ns->href != NULL) {
- if (step->value2 == NULL)
- goto rollback;
- if (!xmlStrEqual(step->value2, node->ns->href))
- goto rollback;
- }
- continue;
- case XSLT_OP_CHILD: {
- xmlNodePtr lst;
-
- if ((node->type != XML_ELEMENT_NODE) &&
- (node->type != XML_DOCUMENT_NODE) &&
-#ifdef LIBXML_DOCB_ENABLED
- (node->type != XML_DOCB_DOCUMENT_NODE) &&
-#endif
- (node->type != XML_HTML_DOCUMENT_NODE))
- goto rollback;
-
- lst = node->children;
-
- if (step->value != NULL) {
- while (lst != NULL) {
- if ((lst->type == XML_ELEMENT_NODE) &&
- (step->value[0] == lst->name[0]) &&
- (xmlStrEqual(step->value, lst->name)))
- break;
- lst = lst->next;
- }
- if (lst != NULL)
- continue;
- }
- goto rollback;
- }
- case XSLT_OP_ATTR:
- if (node->type != XML_ATTRIBUTE_NODE)
- goto rollback;
- if (step->value != NULL) {
- if (step->value[0] != node->name[0])
- goto rollback;
- if (!xmlStrEqual(step->value, node->name))
- goto rollback;
- }
- /* Namespace test */
- if (node->ns == NULL) {
- if (step->value2 != NULL)
- goto rollback;
- } else if (step->value2 != NULL) {
- if (!xmlStrEqual(step->value2, node->ns->href))
- goto rollback;
- }
- continue;
- case XSLT_OP_PARENT:
- if ((node->type == XML_DOCUMENT_NODE) ||
- (node->type == XML_HTML_DOCUMENT_NODE) ||
-#ifdef LIBXML_DOCB_ENABLED
- (node->type == XML_DOCB_DOCUMENT_NODE) ||
-#endif
- (node->type == XML_NAMESPACE_DECL))
- goto rollback;
- node = node->parent;
- if (node == NULL)
- goto rollback;
- if (step->value == NULL)
- continue;
- if (step->value[0] != node->name[0])
- goto rollback;
- if (!xmlStrEqual(step->value, node->name))
- goto rollback;
- /* Namespace test */
- if (node->ns == NULL) {
- if (step->value2 != NULL)
- goto rollback;
- } else if (node->ns->href != NULL) {
- if (step->value2 == NULL)
- goto rollback;
- if (!xmlStrEqual(step->value2, node->ns->href))
- goto rollback;
- }
- continue;
- case XSLT_OP_ANCESTOR:
- /* TODO: implement coalescing of ANCESTOR/NODE ops */
- if (step->value == NULL) {
- step = &comp->steps[i+1];
- if (step->op == XSLT_OP_ROOT)
- goto found;
- /* added NS, ID and KEY as a result of bug 168208 */
- if ((step->op != XSLT_OP_ELEM) &&
- (step->op != XSLT_OP_ALL) &&
- (step->op != XSLT_OP_NS) &&
- (step->op != XSLT_OP_ID) &&
- (step->op != XSLT_OP_KEY))
- goto rollback;
- }
- if (node == NULL)
- goto rollback;
- if ((node->type == XML_DOCUMENT_NODE) ||
- (node->type == XML_HTML_DOCUMENT_NODE) ||
-#ifdef LIBXML_DOCB_ENABLED
- (node->type == XML_DOCB_DOCUMENT_NODE) ||
-#endif
- (node->type == XML_NAMESPACE_DECL))
- goto rollback;
- node = node->parent;
- if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
- xsltPatPushState(&states, i, node);
- continue;
- }
- i++;
- if (step->value == NULL) {
- xsltPatPushState(&states, i - 1, node);
- continue;
- }
- while (node != NULL) {
- if ((node->type == XML_ELEMENT_NODE) &&
- (step->value[0] == node->name[0]) &&
- (xmlStrEqual(step->value, node->name))) {
- /* Namespace test */
- if (node->ns == NULL) {
- if (step->value2 == NULL)
- break;
- } else if (node->ns->href != NULL) {
- if ((step->value2 != NULL) &&
- (xmlStrEqual(step->value2, node->ns->href)))
- break;
- }
- }
- node = node->parent;
- }
- if (node == NULL)
- goto rollback;
- xsltPatPushState(&states, i - 1, node);
- continue;
- case XSLT_OP_ID: {
- /* TODO Handle IDs decently, must be done differently */
- xmlAttrPtr id;
-
- if (node->type != XML_ELEMENT_NODE)
- goto rollback;
-
- id = xmlGetID(node->doc, step->value);
- if ((id == NULL) || (id->parent != node))
- goto rollback;
- break;
- }
- case XSLT_OP_KEY: {
- xmlNodeSetPtr list;
- int indx;
-
- list = xsltGetKey(ctxt, step->value,
- step->value3, step->value2);
- if (list == NULL)
- goto rollback;
- for (indx = 0;indx < list->nodeNr;indx++)
- if (list->nodeTab[indx] == node)
- break;
- if (indx >= list->nodeNr)
- goto rollback;
- break;
- }
- case XSLT_OP_NS:
- if (node->type != XML_ELEMENT_NODE)
- goto rollback;
- if (node->ns == NULL) {
- if (step->value != NULL)
- goto rollback;
- } else if (node->ns->href != NULL) {
- if (step->value == NULL)
- goto rollback;
- if (!xmlStrEqual(step->value, node->ns->href))
- goto rollback;
- }
- break;
- case XSLT_OP_ALL:
- if (node->type != XML_ELEMENT_NODE)
- goto rollback;
- break;
- case XSLT_OP_PREDICATE: {
- xmlNodePtr oldNode;
- xmlDocPtr doc;
- int oldCS, oldCP;
- int pos = 0, len = 0;
- int isRVT;
-
- /*
- * when there is cascading XSLT_OP_PREDICATE, then use a
- * direct computation approach. It's not done directly
- * at the beginning of the routine to filter out as much
- * as possible this costly computation.
- */
- if (comp->direct) {
- if (states.states != NULL) {
- /* Free the rollback states */
- xmlFree(states.states);
- }
- return(xsltTestCompMatchDirect(ctxt, comp, node));
- }
-
- doc = node->doc;
- if (XSLT_IS_RES_TREE_FRAG(doc))
- isRVT = 1;
- else
- isRVT = 0;
-
- /*
- * Depending on the last selection, one may need to
- * recompute contextSize and proximityPosition.
- */
- oldCS = ctxt->xpathCtxt->contextSize;
- oldCP = ctxt->xpathCtxt->proximityPosition;
- if ((sel != NULL) &&
- (sel->op == XSLT_OP_ELEM) &&
- (sel->value != NULL) &&
- (node->type == XML_ELEMENT_NODE) &&
- (node->parent != NULL)) {
- xmlNodePtr previous;
- int ix, nocache = 0;
-
- previous = (xmlNodePtr)
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
- ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
- if ((previous != NULL) &&
- (previous->parent == node->parent)) {
- /*
- * just walk back to adjust the index
- */
- int indx = 0;
- xmlNodePtr sibling = node;
-
- while (sibling != NULL) {
- if (sibling == previous)
- break;
- if ((previous->type == XML_ELEMENT_NODE) &&
- (previous->name != NULL) &&
- (sibling->name != NULL) &&
- (previous->name[0] == sibling->name[0]) &&
- (xmlStrEqual(previous->name, sibling->name))) {
- if ((sel->value2 == NULL) ||
- ((sibling->ns != NULL) &&
- (xmlStrEqual(sel->value2,
- sibling->ns->href))))
- indx++;
- }
- sibling = sibling->prev;
- }
- if (sibling == NULL) {
- /* hum going backward in document order ... */
- indx = 0;
- sibling = node;
- while (sibling != NULL) {
- if (sibling == previous)
- break;
- if ((sel->value2 == NULL) ||
- ((sibling->ns != NULL) &&
- (xmlStrEqual(sel->value2,
- sibling->ns->href))))
- indx--;
- sibling = sibling->next;
- }
- }
- if (sibling != NULL) {
- pos = ix + indx;
- /*
- * If the node is in a Value Tree we need to
- * save len, but cannot cache the node!
- * (bugs 153137 and 158840)
- */
- if (node->doc != NULL) {
- len = XSLT_RUNTIME_EXTRA(ctxt,
- sel->lenExtra, ival);
- if (!isRVT) {
- XSLT_RUNTIME_EXTRA(ctxt,
- sel->previousExtra, ptr) = node;
- XSLT_RUNTIME_EXTRA(ctxt,
- sel->indexExtra, ival) = pos;
- }
- }
- ix = pos;
- } else
- pos = 0;
- } else {
- /*
- * recompute the index
- */
- xmlNodePtr siblings = node->parent->children;
- xmlNodePtr parent = node->parent;
-
- while (siblings != NULL) {
- if (siblings->type == XML_ELEMENT_NODE) {
- if (siblings == node) {
- len++;
- pos = len;
- } else if ((node->name != NULL) &&
- (siblings->name != NULL) &&
- (node->name[0] == siblings->name[0]) &&
- (xmlStrEqual(node->name, siblings->name))) {
- if ((sel->value2 == NULL) ||
- ((siblings->ns != NULL) &&
- (xmlStrEqual(sel->value2,
- siblings->ns->href))))
- len++;
- }
- }
- siblings = siblings->next;
- }
- if ((parent == NULL) || (node->doc == NULL))
- nocache = 1;
- else {
- while (parent->parent != NULL)
- parent = parent->parent;
- if (((parent->type != XML_DOCUMENT_NODE) &&
- (parent->type != XML_HTML_DOCUMENT_NODE)) ||
- (parent != (xmlNodePtr) node->doc))
- nocache = 1;
- }
- }
- if (pos != 0) {
- ctxt->xpathCtxt->contextSize = len;
- ctxt->xpathCtxt->proximityPosition = pos;
- /*
- * If the node is in a Value Tree we cannot
- * cache it !
- */
- if ((!isRVT) && (node->doc != NULL) &&
- (nocache == 0)) {
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
- node;
- XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
- pos;
- XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
- len;
- }
- }
- } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
- (node->type == XML_ELEMENT_NODE)) {
- xmlNodePtr previous;
- int ix, nocache = 0;
-
- previous = (xmlNodePtr)
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
- ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
- if ((previous != NULL) &&
- (previous->parent == node->parent)) {
- /*
- * just walk back to adjust the index
- */
- int indx = 0;
- xmlNodePtr sibling = node;
-
- while (sibling != NULL) {
- if (sibling == previous)
- break;
- if (sibling->type == XML_ELEMENT_NODE)
- indx++;
- sibling = sibling->prev;
- }
- if (sibling == NULL) {
- /* hum going backward in document order ... */
- indx = 0;
- sibling = node;
- while (sibling != NULL) {
- if (sibling == previous)
- break;
- if (sibling->type == XML_ELEMENT_NODE)
- indx--;
- sibling = sibling->next;
- }
- }
- if (sibling != NULL) {
- pos = ix + indx;
- /*
- * If the node is in a Value Tree we cannot
- * cache it !
- */
- if ((node->doc != NULL) && !isRVT) {
- len = XSLT_RUNTIME_EXTRA(ctxt,
- sel->lenExtra, ival);
- XSLT_RUNTIME_EXTRA(ctxt,
- sel->previousExtra, ptr) = node;
- XSLT_RUNTIME_EXTRA(ctxt,
- sel->indexExtra, ival) = pos;
- }
- } else
- pos = 0;
- } else {
- /*
- * recompute the index
- */
- xmlNodePtr siblings = node->parent->children;
- xmlNodePtr parent = node->parent;
-
- while (siblings != NULL) {
- if (siblings->type == XML_ELEMENT_NODE) {
- len++;
- if (siblings == node) {
- pos = len;
- }
- }
- siblings = siblings->next;
- }
- if ((parent == NULL) || (node->doc == NULL))
- nocache = 1;
- else {
- while (parent->parent != NULL)
- parent = parent->parent;
- if (((parent->type != XML_DOCUMENT_NODE) &&
- (parent->type != XML_HTML_DOCUMENT_NODE)) ||
- (parent != (xmlNodePtr) node->doc))
- nocache = 1;
- }
- }
- if (pos != 0) {
- ctxt->xpathCtxt->contextSize = len;
- ctxt->xpathCtxt->proximityPosition = pos;
- /*
- * If the node is in a Value Tree we cannot
- * cache it !
- */
- if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
- XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
- node;
- XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
- pos;
- XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
- len;
- }
- }
- }
- oldNode = ctxt->node;
- ctxt->node = node;
-
- if (step->value == NULL)
- goto wrong_index;
- if (step->comp == NULL)
- goto wrong_index;
-
- if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,
- comp->nsNr))
- goto wrong_index;
-
- if (pos != 0) {
- ctxt->xpathCtxt->contextSize = oldCS;
- ctxt->xpathCtxt->proximityPosition = oldCP;
- }
- ctxt->node = oldNode;
- break;
-wrong_index:
- if (pos != 0) {
- ctxt->xpathCtxt->contextSize = oldCS;
- ctxt->xpathCtxt->proximityPosition = oldCP;
- }
- ctxt->node = oldNode;
- goto rollback;
- }
- case XSLT_OP_PI:
- if (node->type != XML_PI_NODE)
- goto rollback;
- if (step->value != NULL) {
- if (!xmlStrEqual(step->value, node->name))
- goto rollback;
- }
- break;
- case XSLT_OP_COMMENT:
- if (node->type != XML_COMMENT_NODE)
- goto rollback;
- break;
- case XSLT_OP_TEXT:
- if ((node->type != XML_TEXT_NODE) &&
- (node->type != XML_CDATA_SECTION_NODE))
- goto rollback;
- break;
- case XSLT_OP_NODE:
- switch (node->type) {
- case XML_ELEMENT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_PI_NODE:
- case XML_COMMENT_NODE:
- case XML_TEXT_NODE:
- break;
- default:
- goto rollback;
- }
- break;
- }
- }
-found:
- if (states.states != NULL) {
- /* Free the rollback states */
- xmlFree(states.states);
- }
- return(1);
-rollback:
- /* got an error try to rollback */
- if (states.states == NULL)
- return(0);
- if (states.nbstates <= 0) {
- xmlFree(states.states);
- return(0);
- }
- states.nbstates--;
- i = states.states[states.nbstates].step;
- node = states.states[states.nbstates].node;
-#if 0
- fprintf(stderr, "Pop: %d, %s\n", i, node->name);
-#endif
- goto restart;
-}
-
-/**
- * xsltTestCompMatchList:
- * @ctxt: a XSLT process context
- * @node: a node
- * @comp: the precompiled pattern list
- *
- * Test whether the node matches one of the patterns in the list
- *
- * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
- */
-int
-xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltCompMatchPtr comp) {
- int ret;
-
- if ((ctxt == NULL) || (node == NULL))
- return(-1);
- while (comp != NULL) {
- ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);
- if (ret == 1)
- return(1);
- comp = comp->next;
- }
- return(0);
-}
-
-/************************************************************************
- * *
- * Dedicated parser for templates *
- * *
- ************************************************************************/
-
-#define CUR (*ctxt->cur)
-#define SKIP(val) ctxt->cur += (val)
-#define NXT(val) ctxt->cur[(val)]
-#define CUR_PTR ctxt->cur
-
-#define SKIP_BLANKS \
- while (IS_BLANK_CH(CUR)) NEXT
-
-#define CURRENT (*ctxt->cur)
-#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
-
-
-#define PUSH(op, val, val2, novar) \
- if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
-
-#define SWAP() \
- xsltSwapTopCompMatch(ctxt->comp);
-
-#define XSLT_ERROR(X) \
- { xsltError(ctxt, __FILE__, __LINE__, X); \
- ctxt->error = (X); return; }
-
-#define XSLT_ERROR0(X) \
- { xsltError(ctxt, __FILE__, __LINE__, X); \
- ctxt->error = (X); return(0); }
-
-/**
- * xsltScanLiteral:
- * @ctxt: the XPath Parser context
- *
- * Parse an XPath Litteral:
- *
- * [29] Literal ::= '"' [^"]* '"'
- * | "'" [^']* "'"
- *
- * Returns the Literal parsed or NULL
- */
-
-static xmlChar *
-xsltScanLiteral(xsltParserContextPtr ctxt) {
- const xmlChar *q, *cur;
- xmlChar *ret = NULL;
- int val, len;
-
- SKIP_BLANKS;
- if (CUR == '"') {
- NEXT;
- cur = q = CUR_PTR;
- val = xmlStringCurrentChar(NULL, cur, &len);
- while ((IS_CHAR(val)) && (val != '"')) {
- cur += len;
- val = xmlStringCurrentChar(NULL, cur, &len);
- }
- if (!IS_CHAR(val)) {
- ctxt->error = 1;
- return(NULL);
- } else {
- ret = xmlStrndup(q, cur - q);
- }
- cur += len;
- CUR_PTR = cur;
- } else if (CUR == '\'') {
- NEXT;
- cur = q = CUR_PTR;
- val = xmlStringCurrentChar(NULL, cur, &len);
- while ((IS_CHAR(val)) && (val != '\'')) {
- cur += len;
- val = xmlStringCurrentChar(NULL, cur, &len);
- }
- if (!IS_CHAR(val)) {
- ctxt->error = 1;
- return(NULL);
- } else {
- ret = xmlStrndup(q, cur - q);
- }
- cur += len;
- CUR_PTR = cur;
- } else {
- /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
- ctxt->error = 1;
- return(NULL);
- }
- return(ret);
-}
-
-/**
- * xsltScanName:
- * @ctxt: the XPath Parser context
- *
- * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' |
- * CombiningChar | Extender
- *
- * [5] Name ::= (Letter | '_' | ':') (NameChar)*
- *
- * [6] Names ::= Name (S Name)*
- *
- * Returns the Name parsed or NULL
- */
-
-static xmlChar *
-xsltScanName(xsltParserContextPtr ctxt) {
- const xmlChar *q, *cur;
- xmlChar *ret = NULL;
- int val, len;
-
- SKIP_BLANKS;
-
- cur = q = CUR_PTR;
- val = xmlStringCurrentChar(NULL, cur, &len);
- if (!IS_LETTER(val) && (val != '_') && (val != ':'))
- return(NULL);
-
- while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
- (val == '.') || (val == '-') ||
- (val == '_') ||
- (IS_COMBINING(val)) ||
- (IS_EXTENDER(val))) {
- cur += len;
- val = xmlStringCurrentChar(NULL, cur, &len);
- }
- ret = xmlStrndup(q, cur - q);
- CUR_PTR = cur;
- return(ret);
-}
-
-/**
- * xsltScanNCName:
- * @ctxt: the XPath Parser context
- *
- * Parses a non qualified name
- *
- * Returns the Name parsed or NULL
- */
-
-static xmlChar *
-xsltScanNCName(xsltParserContextPtr ctxt) {
- const xmlChar *q, *cur;
- xmlChar *ret = NULL;
- int val, len;
-
- SKIP_BLANKS;
-
- cur = q = CUR_PTR;
- val = xmlStringCurrentChar(NULL, cur, &len);
- if (!IS_LETTER(val) && (val != '_'))
- return(NULL);
-
- while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
- (val == '.') || (val == '-') ||
- (val == '_') ||
- (IS_COMBINING(val)) ||
- (IS_EXTENDER(val))) {
- cur += len;
- val = xmlStringCurrentChar(NULL, cur, &len);
- }
- ret = xmlStrndup(q, cur - q);
- CUR_PTR = cur;
- return(ret);
-}
-
-/**
- * xsltScanQName:
- * @ctxt: the XPath Parser context
- * @prefix: the place to store the prefix
- *
- * Parse a qualified name
- *
- * Returns the Name parsed or NULL
- */
-
-static xmlChar *
-xsltScanQName(xsltParserContextPtr ctxt, xmlChar **prefix) {
- xmlChar *ret = NULL;
-
- *prefix = NULL;
- ret = xsltScanNCName(ctxt);
- if (CUR == ':') {
- *prefix = ret;
- NEXT;
- ret = xsltScanNCName(ctxt);
- }
- return(ret);
-}
-
-/*
- * xsltCompileIdKeyPattern:
- * @ctxt: the compilation context
- * @name: a preparsed name
- * @aid: whether id/key are allowed there
- * @novar: flag to prohibit xslt var
- *
- * Compile the XSLT LocationIdKeyPattern
- * [3] IdKeyPattern ::= 'id' '(' Literal ')'
- * | 'key' '(' Literal ',' Literal ')'
- *
- * also handle NodeType and PI from:
- *
- * [7] NodeTest ::= NameTest
- * | NodeType '(' ')'
- * | 'processing-instruction' '(' Literal ')'
- */
-static void
-xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
- int aid, int novar) {
- xmlChar *lit = NULL;
- xmlChar *lit2 = NULL;
-
- if (CUR != '(') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ( expected\n");
- ctxt->error = 1;
- return;
- }
- if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
- NEXT;
- SKIP_BLANKS;
- lit = xsltScanLiteral(ctxt);
- if (ctxt->error)
- return;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- PUSH(XSLT_OP_ID, lit, NULL, novar);
- } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
- NEXT;
- SKIP_BLANKS;
- lit = xsltScanLiteral(ctxt);
- if (ctxt->error)
- return;
- SKIP_BLANKS;
- if (CUR != ',') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : , expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- SKIP_BLANKS;
- lit2 = xsltScanLiteral(ctxt);
- if (ctxt->error)
- return;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- /* URGENT TODO: support namespace in keys */
- PUSH(XSLT_OP_KEY, lit, lit2, novar);
- } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
- NEXT;
- SKIP_BLANKS;
- if (CUR != ')') {
- lit = xsltScanLiteral(ctxt);
- if (ctxt->error)
- return;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- }
- NEXT;
- PUSH(XSLT_OP_PI, lit, NULL, novar);
- } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
- NEXT;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- PUSH(XSLT_OP_TEXT, NULL, NULL, novar);
- } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
- NEXT;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- PUSH(XSLT_OP_COMMENT, NULL, NULL, novar);
- } else if (xmlStrEqual(name, (const xmlChar *)"node")) {
- NEXT;
- SKIP_BLANKS;
- if (CUR != ')') {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : ) expected\n");
- ctxt->error = 1;
- return;
- }
- NEXT;
- PUSH(XSLT_OP_NODE, NULL, NULL, novar);
- } else if (aid) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
- ctxt->error = 1;
- return;
- } else {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileIdKeyPattern : node type\n");
- ctxt->error = 1;
- return;
- }
-error:
- if (name != NULL)
- xmlFree(name);
-}
-
-/**
- * xsltCompileStepPattern:
- * @ctxt: the compilation context
- * @token: a posible precompiled name
- * @novar: flag to prohibit xslt variables from pattern
- *
- * Compile the XSLT StepPattern and generates a precompiled
- * form suitable for fast matching.
- *
- * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
- * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
- * | ('child' | 'attribute') '::'
- * from XPath
- * [7] NodeTest ::= NameTest
- * | NodeType '(' ')'
- * | 'processing-instruction' '(' Literal ')'
- * [8] Predicate ::= '[' PredicateExpr ']'
- * [9] PredicateExpr ::= Expr
- * [13] AbbreviatedAxisSpecifier ::= '@'?
- * [37] NameTest ::= '*' | NCName ':' '*' | QName
- */
-
-static void
-xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
- xmlChar *name = NULL;
- const xmlChar *URI = NULL;
- xmlChar *URL = NULL;
- int level;
-
- SKIP_BLANKS;
- if ((token == NULL) && (CUR == '@')) {
- xmlChar *prefix = NULL;
-
- NEXT;
- if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
- goto parse_predicate;
- }
- token = xsltScanQName(ctxt, &prefix);
- if (prefix != NULL) {
- xmlNsPtr ns;
-
- ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : no namespace bound to prefix %s\n",
- prefix);
- } else {
- URL = xmlStrdup(ns->href);
- }
- xmlFree(prefix);
- }
- if (token == NULL) {
- if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_ATTR, NULL, URL, novar);
- return;
- }
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : Name expected\n");
- ctxt->error = 1;
- goto error;
- }
- PUSH(XSLT_OP_ATTR, token, URL, novar);
- goto parse_predicate;
- }
- if (token == NULL)
- token = xsltScanName(ctxt);
- if (token == NULL) {
- if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_ALL, token, NULL, novar);
- goto parse_predicate;
- } else {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : Name expected\n");
- ctxt->error = 1;
- goto error;
- }
- }
-
-
- SKIP_BLANKS;
- if (CUR == '(') {
- xsltCompileIdKeyPattern(ctxt, token, 0, novar);
- if (ctxt->error)
- goto error;
- } else if (CUR == ':') {
- NEXT;
- if (CUR != ':') {
- xmlChar *prefix = token;
- xmlNsPtr ns;
-
- /*
- * This is a namespace match
- */
- token = xsltScanName(ctxt);
- ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : no namespace bound to prefix %s\n",
- prefix);
- ctxt->error = 1;
- goto error;
- } else {
- URL = xmlStrdup(ns->href);
- }
- xmlFree(prefix);
- if (token == NULL) {
- if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_NS, URL, NULL, novar);
- } else {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : Name expected\n");
- ctxt->error = 1;
- goto error;
- }
- } else {
- PUSH(XSLT_OP_ELEM, token, URL, novar);
- }
- } else {
- NEXT;
- if (xmlStrEqual(token, (const xmlChar *) "child")) {
- xmlFree(token);
- token = xsltScanName(ctxt);
- if (token == NULL) {
- if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_ALL, token, NULL, novar);
- goto parse_predicate;
- } else {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : QName expected\n");
- ctxt->error = 1;
- goto error;
- }
- }
- URI = xsltGetQNameURI(ctxt->elem, &token);
- if (token == NULL) {
- ctxt->error = 1;
- goto error;
- } else {
- name = xmlStrdup(token);
- if (URI != NULL)
- URL = xmlStrdup(URI);
- }
- PUSH(XSLT_OP_CHILD, name, URL, novar);
- } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
- xmlFree(token);
- token = xsltScanName(ctxt);
- if (token == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : QName expected\n");
- ctxt->error = 1;
- goto error;
- }
- URI = xsltGetQNameURI(ctxt->elem, &token);
- if (token == NULL) {
- ctxt->error = 1;
- goto error;
- } else {
- name = xmlStrdup(token);
- if (URI != NULL)
- URL = xmlStrdup(URI);
- }
- PUSH(XSLT_OP_ATTR, name, URL, novar);
- } else {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
- ctxt->error = 1;
- goto error;
- }
- xmlFree(token);
- }
- } else if (CUR == '*') {
- NEXT;
- PUSH(XSLT_OP_ALL, token, NULL, novar);
- } else {
- URI = xsltGetQNameURI(ctxt->elem, &token);
- if (token == NULL) {
- ctxt->error = 1;
- goto error;
- }
- if (URI != NULL)
- URL = xmlStrdup(URI);
- PUSH(XSLT_OP_ELEM, token, URL, novar);
- }
-parse_predicate:
- SKIP_BLANKS;
- level = 0;
- while (CUR == '[') {
- const xmlChar *q;
- xmlChar *ret = NULL;
-
- level++;
- NEXT;
- q = CUR_PTR;
- while (CUR != 0) {
- /* Skip over nested predicates */
- if (CUR == '[')
- level++;
- else if (CUR == ']') {
- level--;
- if (level == 0)
- break;
- } else if (CUR == '"') {
- NEXT;
- while ((CUR != 0) && (CUR != '"'))
- NEXT;
- } else if (CUR == '\'') {
- NEXT;
- while ((CUR != 0) && (CUR != '\''))
- NEXT;
- }
- NEXT;
- }
- if (CUR == 0) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileStepPattern : ']' expected\n");
- ctxt->error = 1;
- return;
- }
- ret = xmlStrndup(q, CUR_PTR - q);
- PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);
- /* push the predicate lower than local test */
- SWAP();
- NEXT;
- SKIP_BLANKS;
- }
- return;
-error:
- if (token != NULL)
- xmlFree(token);
- if (name != NULL)
- xmlFree(name);
-}
-
-/**
- * xsltCompileRelativePathPattern:
- * @comp: the compilation context
- * @token: a posible precompiled name
- * @novar: flag to prohibit xslt variables
- *
- * Compile the XSLT RelativePathPattern and generates a precompiled
- * form suitable for fast matching.
- *
- * [4] RelativePathPattern ::= StepPattern
- * | RelativePathPattern '/' StepPattern
- * | RelativePathPattern '//' StepPattern
- */
-static void
-xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
- xsltCompileStepPattern(ctxt, token, novar);
- if (ctxt->error)
- goto error;
- SKIP_BLANKS;
- while ((CUR != 0) && (CUR != '|')) {
- if ((CUR == '/') && (NXT(1) == '/')) {
- PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
- NEXT;
- NEXT;
- SKIP_BLANKS;
- xsltCompileStepPattern(ctxt, NULL, novar);
- } else if (CUR == '/') {
- PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
- NEXT;
- SKIP_BLANKS;
- if ((CUR != 0) && (CUR != '|')) {
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- }
- } else {
- ctxt->error = 1;
- }
- if (ctxt->error)
- goto error;
- SKIP_BLANKS;
- }
-error:
- return;
-}
-
-/**
- * xsltCompileLocationPathPattern:
- * @ctxt: the compilation context
- * @novar: flag to prohibit xslt variables
- *
- * Compile the XSLT LocationPathPattern and generates a precompiled
- * form suitable for fast matching.
- *
- * [2] LocationPathPattern ::= '/' RelativePathPattern?
- * | IdKeyPattern (('/' | '//') RelativePathPattern)?
- * | '//'? RelativePathPattern
- */
-static void
-xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {
- SKIP_BLANKS;
- if ((CUR == '/') && (NXT(1) == '/')) {
- /*
- * since we reverse the query
- * a leading // can be safely ignored
- */
- NEXT;
- NEXT;
- ctxt->comp->priority = 0.5; /* '//' means not 0 priority */
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- } else if (CUR == '/') {
- /*
- * We need to find root as the parent
- */
- NEXT;
- SKIP_BLANKS;
- PUSH(XSLT_OP_ROOT, NULL, NULL, novar);
- if ((CUR != 0) && (CUR != '|')) {
- PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- }
- } else if (CUR == '*') {
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- } else if (CUR == '@') {
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- } else {
- xmlChar *name;
- name = xsltScanName(ctxt);
- if (name == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCompileLocationPathPattern : Name expected\n");
- ctxt->error = 1;
- return;
- }
- SKIP_BLANKS;
- if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
- xsltCompileIdKeyPattern(ctxt, name, 1, novar);
- if ((CUR == '/') && (NXT(1) == '/')) {
- PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
- NEXT;
- NEXT;
- SKIP_BLANKS;
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- } else if (CUR == '/') {
- PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
- NEXT;
- SKIP_BLANKS;
- xsltCompileRelativePathPattern(ctxt, NULL, novar);
- }
- return;
- }
- xsltCompileRelativePathPattern(ctxt, name, novar);
- }
-error:
- return;
-}
-
-/**
- * xsltCompilePatternInternal:
- * @pattern: an XSLT pattern
- * @doc: the containing document
- * @node: the containing element
- * @style: the stylesheet
- * @runtime: the transformation context, if done at run-time
- * @novar: flag to prohibit xslt variables
- *
- * Compile the XSLT pattern and generates a list of precompiled form suitable
- * for fast matching.
- *
- * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
- *
- * Returns the generated pattern list or NULL in case of failure
- */
-
-static xsltCompMatchPtr
-xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
- xmlNodePtr node, xsltStylesheetPtr style,
- xsltTransformContextPtr runtime, int novar) {
- xsltParserContextPtr ctxt = NULL;
- xsltCompMatchPtr element, first = NULL, previous = NULL;
- int current, start, end, level, j;
-
- if (pattern == NULL) {
- xsltTransformError(NULL, NULL, node,
- "xsltCompilePattern : NULL pattern\n");
- return(NULL);
- }
-
- ctxt = xsltNewParserContext(style, runtime);
- if (ctxt == NULL)
- return(NULL);
- ctxt->doc = doc;
- ctxt->elem = node;
- current = end = 0;
- while (pattern[current] != 0) {
- start = current;
- while (IS_BLANK_CH(pattern[current]))
- current++;
- end = current;
- level = 0;
- while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {
- if (pattern[end] == '[')
- level++;
- else if (pattern[end] == ']')
- level--;
- else if (pattern[end] == '\'') {
- end++;
- while ((pattern[end] != 0) && (pattern[end] != '\''))
- end++;
- } else if (pattern[end] == '"') {
- end++;
- while ((pattern[end] != 0) && (pattern[end] != '"'))
- end++;
- }
- end++;
- }
- if (current == end) {
- xsltTransformError(NULL, NULL, node,
- "xsltCompilePattern : NULL pattern\n");
- goto error;
- }
- element = xsltNewCompMatch();
- if (element == NULL) {
- goto error;
- }
- if (first == NULL)
- first = element;
- else if (previous != NULL)
- previous->next = element;
- previous = element;
-
- ctxt->comp = element;
- ctxt->base = xmlStrndup(&pattern[start], end - start);
- if (ctxt->base == NULL)
- goto error;
- ctxt->cur = &(ctxt->base)[current - start];
- element->pattern = ctxt->base;
- element->nsList = xmlGetNsList(doc, node);
- j = 0;
- if (element->nsList != NULL) {
- while (element->nsList[j] != NULL)
- j++;
- }
- element->nsNr = j;
-
-
-#ifdef WITH_XSLT_DEBUG_PATTERN
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltCompilePattern : parsing '%s'\n",
- element->pattern);
-#endif
- /*
- Preset default priority to be zero.
- This may be changed by xsltCompileLocationPathPattern.
- */
- element->priority = 0;
- xsltCompileLocationPathPattern(ctxt, novar);
- if (ctxt->error) {
- xsltTransformError(NULL, style, node,
- "xsltCompilePattern : failed to compile '%s'\n",
- element->pattern);
- if (style != NULL) style->errors++;
- goto error;
- }
-
- /*
- * Reverse for faster interpretation.
- */
- xsltReverseCompMatch(element);
-
- /*
- * Set-up the priority
- */
- if (element->priority == 0) { /* if not yet determined */
- if (((element->steps[0].op == XSLT_OP_ELEM) ||
- (element->steps[0].op == XSLT_OP_ATTR) ||
- (element->steps[0].op == XSLT_OP_PI)) &&
- (element->steps[0].value != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- ; /* previously preset */
- } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
- (element->steps[0].value2 != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.25;
- } else if ((element->steps[0].op == XSLT_OP_NS) &&
- (element->steps[0].value != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.25;
- } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
- (element->steps[0].value == NULL) &&
- (element->steps[0].value2 == NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.5;
- } else if (((element->steps[0].op == XSLT_OP_PI) ||
- (element->steps[0].op == XSLT_OP_TEXT) ||
- (element->steps[0].op == XSLT_OP_ALL) ||
- (element->steps[0].op == XSLT_OP_NODE) ||
- (element->steps[0].op == XSLT_OP_COMMENT)) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.5;
- } else {
- element->priority = 0.5;
- }
- }
-#ifdef WITH_XSLT_DEBUG_PATTERN
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltCompilePattern : parsed %s, default priority %f\n",
- element->pattern, element->priority);
-#endif
- if (pattern[end] == '|')
- end++;
- current = end;
- }
- if (end == 0) {
- xsltTransformError(NULL, style, node,
- "xsltCompilePattern : NULL pattern\n");
- if (style != NULL) style->errors++;
- goto error;
- }
-
- xsltFreeParserContext(ctxt);
- return(first);
-
-error:
- if (ctxt != NULL)
- xsltFreeParserContext(ctxt);
- if (first != NULL)
- xsltFreeCompMatchList(first);
- return(NULL);
-}
-
-/**
- * xsltCompilePattern:
- * @pattern: an XSLT pattern
- * @doc: the containing document
- * @node: the containing element
- * @style: the stylesheet
- * @runtime: the transformation context, if done at run-time
- *
- * Compile the XSLT pattern and generates a list of precompiled form suitable
- * for fast matching.
- *
- * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
- *
- * Returns the generated pattern list or NULL in case of failure
- */
-
-xsltCompMatchPtr
-xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc,
- xmlNodePtr node, xsltStylesheetPtr style,
- xsltTransformContextPtr runtime) {
- return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));
-}
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltAddTemplate:
- * @style: an XSLT stylesheet
- * @cur: an XSLT template
- * @mode: the mode name or NULL
- * @modeURI: the mode URI or NULL
- *
- * Register the XSLT pattern associated to @cur
- *
- * Returns -1 in case of error, 0 otherwise
- */
-int
-xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
- const xmlChar *mode, const xmlChar *modeURI) {
- xsltCompMatchPtr pat, list, *top = NULL, next;
- const xmlChar *name = NULL;
- float priority; /* the priority */
-
- if ((style == NULL) || (cur == NULL) || (cur->match == NULL))
- return(-1);
-
- priority = cur->priority;
- pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
- style, NULL, 1);
- while (pat) {
- next = pat->next;
- pat->next = NULL;
- name = NULL;
-
- pat->template = cur;
- if (mode != NULL)
- pat->mode = xmlDictLookup(style->dict, mode, -1);
- if (modeURI != NULL)
- pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
- if (priority != XSLT_PAT_NO_PRIORITY)
- pat->priority = priority;
-
- /*
- * insert it in the hash table list corresponding to its lookup name
- */
- switch (pat->steps[0].op) {
- case XSLT_OP_ATTR:
- if (pat->steps[0].value != NULL)
- name = pat->steps[0].value;
- else
- top = (xsltCompMatchPtr *) &(style->attrMatch);
- break;
- case XSLT_OP_CHILD:
- case XSLT_OP_PARENT:
- case XSLT_OP_ANCESTOR:
- top = (xsltCompMatchPtr *) &(style->elemMatch);
- break;
- case XSLT_OP_ROOT:
- top = (xsltCompMatchPtr *) &(style->rootMatch);
- break;
- case XSLT_OP_KEY:
- top = (xsltCompMatchPtr *) &(style->keyMatch);
- break;
- case XSLT_OP_ID:
- /* TODO optimize ID !!! */
- case XSLT_OP_NS:
- case XSLT_OP_ALL:
- top = (xsltCompMatchPtr *) &(style->elemMatch);
- break;
- case XSLT_OP_END:
- case XSLT_OP_PREDICATE:
- xsltTransformError(NULL, style, NULL,
- "xsltAddTemplate: invalid compiled pattern\n");
- xsltFreeCompMatch(pat);
- return(-1);
- /*
- * TODO: some flags at the top level about type based patterns
- * would be faster than inclusion in the hash table.
- */
- case XSLT_OP_PI:
- if (pat->steps[0].value != NULL)
- name = pat->steps[0].value;
- else
- top = (xsltCompMatchPtr *) &(style->piMatch);
- break;
- case XSLT_OP_COMMENT:
- top = (xsltCompMatchPtr *) &(style->commentMatch);
- break;
- case XSLT_OP_TEXT:
- top = (xsltCompMatchPtr *) &(style->textMatch);
- break;
- case XSLT_OP_ELEM:
- case XSLT_OP_NODE:
- if (pat->steps[0].value != NULL)
- name = pat->steps[0].value;
- else
- top = (xsltCompMatchPtr *) &(style->elemMatch);
- break;
- }
- if (name != NULL) {
- if (style->templatesHash == NULL) {
- style->templatesHash = xmlHashCreate(1024);
- if (style->templatesHash == NULL) {
- xsltFreeCompMatch(pat);
- return(-1);
- }
- xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
- } else {
- list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
- name, mode, modeURI);
- if (list == NULL) {
- xmlHashAddEntry3(style->templatesHash, name,
- mode, modeURI, pat);
- } else {
- /*
- * Note '<=' since one must choose among the matching
- * template rules that are left, the one that occurs
- * last in the stylesheet
- */
- if (list->priority <= pat->priority) {
- pat->next = list;
- xmlHashUpdateEntry3(style->templatesHash, name,
- mode, modeURI, pat, NULL);
- } else {
- while (list->next != NULL) {
- if (list->next->priority <= pat->priority)
- break;
- list = list->next;
- }
- pat->next = list->next;
- list->next = pat;
- }
- }
- }
- } else if (top != NULL) {
- list = *top;
- if (list == NULL) {
- *top = pat;
- pat->next = NULL;
- } else if (list->priority <= pat->priority) {
- pat->next = list;
- *top = pat;
- } else {
- while (list->next != NULL) {
- if (list->next->priority <= pat->priority)
- break;
- list = list->next;
- }
- pat->next = list->next;
- list->next = pat;
- }
- } else {
- xsltTransformError(NULL, style, NULL,
- "xsltAddTemplate: invalid compiled pattern\n");
- xsltFreeCompMatch(pat);
- return(-1);
- }
-#ifdef WITH_XSLT_DEBUG_PATTERN
- if (mode)
- xsltGenericDebug(xsltGenericDebugContext,
- "added pattern : '%s' mode '%s' priority %f\n",
- pat->pattern, pat->mode, pat->priority);
- else
- xsltGenericDebug(xsltGenericDebugContext,
- "added pattern : '%s' priority %f\n",
- pat->pattern, pat->priority);
-#endif
-
- pat = next;
- }
- return(0);
-}
-
-#ifdef XSLT_REFACTORED_KEYCOMP
-static int
-xsltComputeAllKeys(xsltTransformContextPtr ctxt,
- xsltDocumentPtr document)
-{
- xsltStylesheetPtr style, style2;
- xsltKeyDefPtr keyd, keyd2;
- xsltKeyTablePtr table;
-
- if ((ctxt == NULL) || (document == NULL))
- return(-1);
-
- if (document->nbKeysComputed == ctxt->nbKeys)
- return(0);
- /*
- * TODO: This could be further optimized
- */
- style = ctxt->style;
- while (style) {
- keyd = (xsltKeyDefPtr) style->keys;
- while (keyd != NULL) {
- /*
- * Check if keys with this QName have been already
- * computed.
- */
- table = (xsltKeyTablePtr) document->keys;
- while (table) {
- if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
- xmlStrEqual(keyd->name, table->name) &&
- xmlStrEqual(keyd->nameURI, table->nameURI))
- {
- break;
- }
- table = table->next;
- }
- if (table == NULL) {
- /*
- * Keys with this QName have not been yet computed.
- */
- style2 = ctxt->style;
- while (style2 != NULL) {
- keyd2 = (xsltKeyDefPtr) style2->keys;
- while (keyd2 != NULL) {
- if (((keyd2->nameURI != NULL) ==
- (keyd->nameURI != NULL)) &&
- xmlStrEqual(keyd2->name, keyd->name) &&
- xmlStrEqual(keyd2->nameURI, keyd->nameURI))
- {
- xsltInitCtxtKey(ctxt, document, keyd2);
- if (document->nbKeysComputed == ctxt->nbKeys)
- return(0);
- }
- keyd2 = keyd2->next;
- }
- style2 = xsltNextImport(style2);
- }
- }
- keyd = keyd->next;
- }
- style = xsltNextImport(style);
- }
- return(0);
-}
-#endif
-
-/**
- * xsltGetTemplate:
- * @ctxt: a XSLT process context
- * @node: the node being processed
- * @style: the current style
- *
- * Finds the template applying to this node, if @style is non-NULL
- * it means one needs to look for the next imported template in scope.
- *
- * Returns the xsltTemplatePtr or NULL if not found
- */
-xsltTemplatePtr
-xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStylesheetPtr style) {
- xsltStylesheetPtr curstyle;
- xsltTemplatePtr ret = NULL;
- const xmlChar *name = NULL;
- xsltCompMatchPtr list = NULL;
- float priority;
- int keyed = 0;
-
- if ((ctxt == NULL) || (node == NULL))
- return(NULL);
-
- if (style == NULL) {
- curstyle = ctxt->style;
- } else {
- curstyle = xsltNextImport(style);
- }
-
- while ((curstyle != NULL) && (curstyle != style)) {
- priority = XSLT_PAT_NO_PRIORITY;
- /* TODO : handle IDs/keys here ! */
- if (curstyle->templatesHash != NULL) {
- /*
- * Use the top name as selector
- */
- switch (node->type) {
- case XML_ELEMENT_NODE:
- if (node->name[0] == ' ')
- break;
- case XML_ATTRIBUTE_NODE:
- case XML_PI_NODE:
- name = node->name;
- break;
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_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_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- break;
- default:
- return(NULL);
-
- }
- }
- if (name != NULL) {
- /*
- * find the list of applicable expressions based on the name
- */
- list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
- name, ctxt->mode, ctxt->modeURI);
- } else
- list = NULL;
- while (list != NULL) {
- if (xsltTestCompMatch(ctxt, list, node,
- ctxt->mode, ctxt->modeURI)) {
- ret = list->template;
- priority = list->priority;
- break;
- }
- list = list->next;
- }
- list = NULL;
-
- /*
- * find alternate generic matches
- */
- switch (node->type) {
- case XML_ELEMENT_NODE:
- if (node->name[0] == ' ')
- list = curstyle->rootMatch;
- else
- list = curstyle->elemMatch;
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_ATTRIBUTE_NODE: {
- xmlAttrPtr attr;
-
- list = curstyle->attrMatch;
- attr = (xmlAttrPtr) node;
- if (attr->psvi != NULL) keyed = 1;
- break;
- }
- case XML_PI_NODE:
- list = curstyle->piMatch;
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE: {
- xmlDocPtr doc;
-
- list = curstyle->rootMatch;
- doc = (xmlDocPtr) node;
- if (doc->psvi != NULL) keyed = 1;
- break;
- }
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- list = curstyle->textMatch;
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_COMMENT_NODE:
- list = curstyle->commentMatch;
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_ENTITY_REF_NODE:
- case XML_ENTITY_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_NAMESPACE_DECL:
- case XML_XINCLUDE_START:
- case XML_XINCLUDE_END:
- break;
- default:
- break;
- }
- while ((list != NULL) &&
- ((ret == NULL) || (list->priority > priority))) {
- if (xsltTestCompMatch(ctxt, list, node,
- ctxt->mode, ctxt->modeURI)) {
- ret = list->template;
- priority = list->priority;
- break;
- }
- list = list->next;
- }
- /*
- * Some of the tests for elements can also apply to documents
- */
- if ((node->type == XML_DOCUMENT_NODE) ||
- (node->type == XML_HTML_DOCUMENT_NODE) ||
- (node->type == XML_TEXT_NODE)) {
- list = curstyle->elemMatch;
- while ((list != NULL) &&
- ((ret == NULL) || (list->priority > priority))) {
- if (xsltTestCompMatch(ctxt, list, node,
- ctxt->mode, ctxt->modeURI)) {
- ret = list->template;
- priority = list->priority;
- break;
- }
- list = list->next;
- }
- } else if ((node->type == XML_PI_NODE) ||
- (node->type == XML_COMMENT_NODE)) {
- list = curstyle->elemMatch;
- while ((list != NULL) &&
- ((ret == NULL) || (list->priority > priority))) {
- if (xsltTestCompMatch(ctxt, list, node,
- ctxt->mode, ctxt->modeURI)) {
- ret = list->template;
- priority = list->priority;
- break;
- }
- list = list->next;
- }
- }
-
-#ifdef XSLT_REFACTORED_KEYCOMP
-keyed_match:
-#endif
- if (keyed) {
- list = curstyle->keyMatch;
- while ((list != NULL) &&
- ((ret == NULL) || (list->priority > priority))) {
- if (xsltTestCompMatch(ctxt, list, node,
- ctxt->mode, ctxt->modeURI)) {
- ret = list->template;
- priority = list->priority;
- break;
- }
- list = list->next;
- }
- }
-#ifdef XSLT_REFACTORED_KEYCOMP
- else if (ctxt->hasTemplKeyPatterns &&
- (ctxt->document->nbKeysComputed < ctxt->nbKeys))
- {
- /*
- * Compute all remaining keys for this document.
- *
- * REVISIT TODO: I think this could be further optimized.
- */
- xsltComputeAllKeys(ctxt, ctxt->document);
-
- switch (node->type) {
- case XML_ELEMENT_NODE:
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_ATTRIBUTE_NODE:
- if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
- break;
- case XML_TEXT_NODE:
- case XML_CDATA_SECTION_NODE:
- case XML_COMMENT_NODE:
- case XML_PI_NODE:
- if (node->psvi != NULL) keyed = 1;
- break;
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
- if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
- break;
- default:
- break;
- }
- if (keyed)
- goto keyed_match;
- }
-#endif /* XSLT_REFACTORED_KEYCOMP */
- if (ret != NULL)
- return(ret);
-
- /*
- * Cycle on next curstylesheet import.
- */
- curstyle = xsltNextImport(curstyle);
- }
- return(NULL);
-}
-
-/**
- * xsltCleanupTemplates:
- * @style: an XSLT stylesheet
- *
- * Cleanup the state of the templates used by the stylesheet and
- * the ones it imports.
- */
-void
-xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) {
-}
-
-/**
- * xsltFreeTemplateHashes:
- * @style: an XSLT stylesheet
- *
- * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism
- */
-void
-xsltFreeTemplateHashes(xsltStylesheetPtr style) {
- if (style->templatesHash != NULL)
- xmlHashFree((xmlHashTablePtr) style->templatesHash,
- (xmlHashDeallocator) xsltFreeCompMatchList);
- if (style->rootMatch != NULL)
- xsltFreeCompMatchList(style->rootMatch);
- if (style->keyMatch != NULL)
- xsltFreeCompMatchList(style->keyMatch);
- if (style->elemMatch != NULL)
- xsltFreeCompMatchList(style->elemMatch);
- if (style->attrMatch != NULL)
- xsltFreeCompMatchList(style->attrMatch);
- if (style->parentMatch != NULL)
- xsltFreeCompMatchList(style->parentMatch);
- if (style->textMatch != NULL)
- xsltFreeCompMatchList(style->textMatch);
- if (style->piMatch != NULL)
- xsltFreeCompMatchList(style->piMatch);
- if (style->commentMatch != NULL)
- xsltFreeCompMatchList(style->commentMatch);
-}
-
+/*\r
+ * pattern.c: Implemetation of the template match compilation and lookup\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+/*\r
+ * TODO: handle pathological cases like *[*[@a="b"]]\r
+ * TODO: detect [number] at compilation, optimize accordingly\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/parserInternals.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "imports.h"\r
+#include "templates.h"\r
+#include "keys.h"\r
+#include "pattern.h"\r
+#include "documents.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_PATTERN\r
+#endif\r
+\r
+/*\r
+ * Types are private:\r
+ */\r
+\r
+typedef enum {\r
+ XSLT_OP_END=0,\r
+ XSLT_OP_ROOT,\r
+ XSLT_OP_ELEM,\r
+ XSLT_OP_CHILD,\r
+ XSLT_OP_ATTR,\r
+ XSLT_OP_PARENT,\r
+ XSLT_OP_ANCESTOR,\r
+ XSLT_OP_ID,\r
+ XSLT_OP_KEY,\r
+ XSLT_OP_NS,\r
+ XSLT_OP_ALL,\r
+ XSLT_OP_PI,\r
+ XSLT_OP_COMMENT,\r
+ XSLT_OP_TEXT,\r
+ XSLT_OP_NODE,\r
+ XSLT_OP_PREDICATE\r
+} xsltOp;\r
+\r
+typedef struct _xsltStepState xsltStepState;\r
+typedef xsltStepState *xsltStepStatePtr;\r
+struct _xsltStepState {\r
+ int step;\r
+ xmlNodePtr node;\r
+};\r
+\r
+typedef struct _xsltStepStates xsltStepStates;\r
+typedef xsltStepStates *xsltStepStatesPtr;\r
+struct _xsltStepStates {\r
+ int nbstates;\r
+ int maxstates;\r
+ xsltStepStatePtr states;\r
+};\r
+\r
+typedef struct _xsltStepOp xsltStepOp;\r
+typedef xsltStepOp *xsltStepOpPtr;\r
+struct _xsltStepOp {\r
+ xsltOp op;\r
+ xmlChar *value;\r
+ xmlChar *value2;\r
+ xmlChar *value3;\r
+ xmlXPathCompExprPtr comp;\r
+ /*\r
+ * Optimisations for count\r
+ */\r
+ int previousExtra;\r
+ int indexExtra;\r
+ int lenExtra;\r
+};\r
+\r
+struct _xsltCompMatch {\r
+ struct _xsltCompMatch *next; /* siblings in the name hash */\r
+ float priority; /* the priority */\r
+ const xmlChar *pattern; /* the pattern */\r
+ const xmlChar *mode; /* the mode */\r
+ const xmlChar *modeURI; /* the mode URI */\r
+ xsltTemplatePtr template; /* the associated template */\r
+\r
+ int direct;\r
+ /* TODO fix the statically allocated size steps[] */\r
+ int nbStep;\r
+ int maxStep;\r
+ xmlNsPtr *nsList; /* the namespaces in scope */\r
+ int nsNr; /* the number of namespaces in scope */\r
+ xsltStepOp steps[40]; /* ops for computation */\r
+};\r
+\r
+typedef struct _xsltParserContext xsltParserContext;\r
+typedef xsltParserContext *xsltParserContextPtr;\r
+struct _xsltParserContext {\r
+ xsltStylesheetPtr style; /* the stylesheet */\r
+ xsltTransformContextPtr ctxt; /* the transformation or NULL */\r
+ const xmlChar *cur; /* the current char being parsed */\r
+ const xmlChar *base; /* the full expression */\r
+ xmlDocPtr doc; /* the source document */\r
+ xmlNodePtr elem; /* the source element */\r
+ int error; /* error code */\r
+ xsltCompMatchPtr comp; /* the result */\r
+};\r
+\r
+/************************************************************************\r
+ * *\r
+ * Type functions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewCompMatch:\r
+ *\r
+ * Create a new XSLT CompMatch\r
+ *\r
+ * Returns the newly allocated xsltCompMatchPtr or NULL in case of error\r
+ */\r
+static xsltCompMatchPtr\r
+xsltNewCompMatch(void) {\r
+ xsltCompMatchPtr cur;\r
+\r
+ cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewCompMatch : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltCompMatch));\r
+ cur->maxStep = 40;\r
+ cur->nsNr = 0;\r
+ cur->nsList = NULL;\r
+ cur->direct = 0;\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeCompMatch:\r
+ * @comp: an XSLT comp\r
+ *\r
+ * Free up the memory allocated by @comp\r
+ */\r
+static void\r
+xsltFreeCompMatch(xsltCompMatchPtr comp) {\r
+ xsltStepOpPtr op;\r
+ int i;\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ if (comp->pattern != NULL)\r
+ xmlFree((xmlChar *)comp->pattern);\r
+ if (comp->nsList != NULL)\r
+ xmlFree(comp->nsList);\r
+ for (i = 0;i < comp->nbStep;i++) {\r
+ op = &comp->steps[i];\r
+ if (op->value != NULL)\r
+ xmlFree(op->value);\r
+ if (op->value2 != NULL)\r
+ xmlFree(op->value2);\r
+ if (op->value3 != NULL)\r
+ xmlFree(op->value3);\r
+ if (op->comp != NULL)\r
+ xmlXPathFreeCompExpr(op->comp);\r
+ }\r
+ memset(comp, -1, sizeof(xsltCompMatch));\r
+ xmlFree(comp);\r
+}\r
+\r
+/**\r
+ * xsltFreeCompMatchList:\r
+ * @comp: an XSLT comp list\r
+ *\r
+ * Free up the memory allocated by all the elements of @comp\r
+ */\r
+void\r
+xsltFreeCompMatchList(xsltCompMatchPtr comp) {\r
+ xsltCompMatchPtr cur;\r
+\r
+ while (comp != NULL) {\r
+ cur = comp;\r
+ comp = comp->next;\r
+ xsltFreeCompMatch(cur);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltNormalizeCompSteps:\r
+ * @payload: pointer to template hash table entry\r
+ * @data: pointer to the stylesheet\r
+ * @name: template match name\r
+ *\r
+ * This is a hashtable scanner function to normalize the compiled\r
+ * steps of an imported stylesheet.\r
+ */\r
+void xsltNormalizeCompSteps(void *payload,\r
+ void *data, const xmlChar *name ATTRIBUTE_UNUSED) {\r
+ xsltCompMatchPtr comp = payload;\r
+ xsltStylesheetPtr style = data;\r
+ int ix;\r
+\r
+ for (ix = 0; ix < comp->nbStep; ix++) {\r
+ comp->steps[ix].previousExtra += style->extrasNr;\r
+ comp->steps[ix].indexExtra += style->extrasNr;\r
+ comp->steps[ix].lenExtra += style->extrasNr;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltNewParserContext:\r
+ * @style: the stylesheet\r
+ * @ctxt: the transformation context, if done at run-time\r
+ *\r
+ * Create a new XSLT ParserContext\r
+ *\r
+ * Returns the newly allocated xsltParserContextPtr or NULL in case of error\r
+ */\r
+static xsltParserContextPtr\r
+xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) {\r
+ xsltParserContextPtr cur;\r
+\r
+ cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewParserContext : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltParserContext));\r
+ cur->style = style;\r
+ cur->ctxt = ctxt;\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeParserContext:\r
+ * @ctxt: an XSLT parser context\r
+ *\r
+ * Free up the memory allocated by @ctxt\r
+ */\r
+static void\r
+xsltFreeParserContext(xsltParserContextPtr ctxt) {\r
+ if (ctxt == NULL)\r
+ return;\r
+ memset(ctxt, -1, sizeof(xsltParserContext));\r
+ xmlFree(ctxt);\r
+}\r
+\r
+/**\r
+ * xsltCompMatchAdd:\r
+ * @comp: the compiled match expression\r
+ * @op: an op\r
+ * @value: the first value\r
+ * @value2: the second value\r
+ * @novar: flag to set XML_XPATH_NOVAR\r
+ *\r
+ * Add an step to an XSLT Compiled Match\r
+ *\r
+ * Returns -1 in case of failure, 0 otherwise.\r
+ */\r
+static int\r
+xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,\r
+ xsltOp op, xmlChar * value, xmlChar * value2, int novar)\r
+{\r
+ if (comp->nbStep >= 40) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompMatchAdd: overflow\n");\r
+ return (-1);\r
+ }\r
+ comp->steps[comp->nbStep].op = op;\r
+ comp->steps[comp->nbStep].value = value;\r
+ comp->steps[comp->nbStep].value2 = value2;\r
+ if (ctxt->ctxt != NULL) {\r
+ comp->steps[comp->nbStep].previousExtra =\r
+ xsltAllocateExtraCtxt(ctxt->ctxt);\r
+ comp->steps[comp->nbStep].indexExtra =\r
+ xsltAllocateExtraCtxt(ctxt->ctxt);\r
+ comp->steps[comp->nbStep].lenExtra =\r
+ xsltAllocateExtraCtxt(ctxt->ctxt);\r
+ } else {\r
+ comp->steps[comp->nbStep].previousExtra =\r
+ xsltAllocateExtra(ctxt->style);\r
+ comp->steps[comp->nbStep].indexExtra =\r
+ xsltAllocateExtra(ctxt->style);\r
+ comp->steps[comp->nbStep].lenExtra =\r
+ xsltAllocateExtra(ctxt->style);\r
+ }\r
+ if (op == XSLT_OP_PREDICATE) {\r
+ xmlXPathContextPtr xctxt;\r
+\r
+ if (ctxt->style != NULL)\r
+ xctxt = xmlXPathNewContext(ctxt->style->doc);\r
+ else\r
+ xctxt = xmlXPathNewContext(NULL);\r
+#ifdef XML_XPATH_NOVAR\r
+ if (novar != 0)\r
+ xctxt->flags = XML_XPATH_NOVAR;\r
+#endif\r
+ if (ctxt->style != NULL)\r
+ xctxt->dict = ctxt->style->dict;\r
+ comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);\r
+ xmlXPathFreeContext(xctxt);\r
+ if (comp->steps[comp->nbStep].comp == NULL) {\r
+ xsltTransformError(NULL, ctxt->style, ctxt->elem,\r
+ "Failed to compile predicate\n");\r
+ if (ctxt->style != NULL)\r
+ ctxt->style->errors++;\r
+ }\r
+ }\r
+ comp->nbStep++;\r
+ return (0);\r
+}\r
+\r
+/**\r
+ * xsltSwapTopCompMatch:\r
+ * @comp: the compiled match expression\r
+ *\r
+ * reverse the two top steps.\r
+ */\r
+static void\r
+xsltSwapTopCompMatch(xsltCompMatchPtr comp) {\r
+ int i;\r
+ int j = comp->nbStep - 1;\r
+\r
+ if (j > 0) {\r
+ register xmlChar *tmp;\r
+ register xsltOp op;\r
+ register xmlXPathCompExprPtr expr; \r
+ i = j - 1;\r
+ tmp = comp->steps[i].value;\r
+ comp->steps[i].value = comp->steps[j].value;\r
+ comp->steps[j].value = tmp;\r
+ tmp = comp->steps[i].value2;\r
+ comp->steps[i].value2 = comp->steps[j].value2;\r
+ comp->steps[j].value2 = tmp;\r
+ op = comp->steps[i].op;\r
+ comp->steps[i].op = comp->steps[j].op;\r
+ comp->steps[j].op = op;\r
+ expr = comp->steps[i].comp;\r
+ comp->steps[i].comp = comp->steps[j].comp;\r
+ comp->steps[j].comp = expr;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltReverseCompMatch:\r
+ * @comp: the compiled match expression\r
+ *\r
+ * reverse all the stack of expressions\r
+ */\r
+static void\r
+xsltReverseCompMatch(xsltCompMatchPtr comp) {\r
+ int i = 0;\r
+ int j = comp->nbStep - 1;\r
+\r
+ while (j > i) {\r
+ register xmlChar *tmp;\r
+ register xsltOp op;\r
+ register xmlXPathCompExprPtr expr; \r
+ tmp = comp->steps[i].value;\r
+ comp->steps[i].value = comp->steps[j].value;\r
+ comp->steps[j].value = tmp;\r
+ tmp = comp->steps[i].value2;\r
+ comp->steps[i].value2 = comp->steps[j].value2;\r
+ comp->steps[j].value2 = tmp;\r
+ op = comp->steps[i].op;\r
+ comp->steps[i].op = comp->steps[j].op;\r
+ comp->steps[j].op = op;\r
+ expr = comp->steps[i].comp;\r
+ comp->steps[i].comp = comp->steps[j].comp;\r
+ comp->steps[j].comp = expr;\r
+ j--;\r
+ i++;\r
+ }\r
+ comp->steps[comp->nbStep++].op = XSLT_OP_END;\r
+ /*\r
+ * detect consecutive XSLT_OP_PREDICATE indicating a direct\r
+ * matching should be done.\r
+ */\r
+ for (i = 0;i < comp->nbStep - 1;i++) {\r
+ if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&\r
+ (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {\r
+\r
+ comp->direct = 1;\r
+ if (comp->pattern[0] != '/') {\r
+ xmlChar *query;\r
+\r
+ query = xmlStrdup((const xmlChar *)"//");\r
+ query = xmlStrcat(query, comp->pattern);\r
+\r
+ xmlFree((xmlChar *) comp->pattern);\r
+ comp->pattern = query;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * The interpreter for the precompiled patterns *\r
+ * *\r
+ ************************************************************************/\r
+\r
+static int\r
+xsltPatPushState(xsltStepStates *states, int step, xmlNodePtr node) {\r
+ if ((states->states == NULL) || (states->maxstates <= 0)) {\r
+ states->maxstates = 4;\r
+ states->nbstates = 0;\r
+ states->states = xmlMalloc(4 * sizeof(xsltStepState));\r
+ }\r
+ else if (states->maxstates <= states->nbstates) {\r
+ xsltStepState *tmp;\r
+\r
+ tmp = (xsltStepStatePtr) xmlRealloc(states->states,\r
+ 2 * states->maxstates * sizeof(xsltStepState));\r
+ if (tmp == NULL)\r
+ return(-1);\r
+ states->states = tmp;\r
+ states->maxstates *= 2;\r
+ }\r
+ states->states[states->nbstates].step = step;\r
+ states->states[states->nbstates++].node = node;\r
+#if 0\r
+ fprintf(stderr, "Push: %d, %s\n", step, node->name);\r
+#endif\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltTestCompMatchDirect:\r
+ * @ctxt: a XSLT process context\r
+ * @comp: the precompiled pattern\r
+ * @node: a node\r
+ *\r
+ * Test whether the node matches the pattern, do a direct evalutation\r
+ * and not a step by step evaluation.\r
+ *\r
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure\r
+ */\r
+static int\r
+xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,\r
+ xmlNodePtr node) {\r
+ xsltStepOpPtr sel = NULL;\r
+ xmlDocPtr prevdoc;\r
+ xmlDocPtr doc;\r
+ xmlXPathObjectPtr list;\r
+ int ix, j;\r
+ int nocache = 0;\r
+ int isRVT;\r
+\r
+ doc = node->doc;\r
+ if (XSLT_IS_RES_TREE_FRAG(doc))\r
+ isRVT = 1;\r
+ else\r
+ isRVT = 0;\r
+ sel = &comp->steps[0]; /* store extra in first step arbitrarily */\r
+\r
+ prevdoc = (xmlDocPtr)\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);\r
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);\r
+ list = (xmlXPathObjectPtr)\r
+ XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);\r
+ \r
+ if ((list == NULL) || (prevdoc != doc)) {\r
+ xmlXPathObjectPtr newlist;\r
+ xmlNodePtr parent = node->parent;\r
+ xmlDocPtr olddoc;\r
+ xmlNodePtr oldnode;\r
+\r
+ oldnode = ctxt->xpathCtxt->node;\r
+ olddoc = ctxt->xpathCtxt->doc;\r
+ ctxt->xpathCtxt->node = node;\r
+ ctxt->xpathCtxt->doc = doc;\r
+ newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);\r
+ ctxt->xpathCtxt->node = oldnode;\r
+ ctxt->xpathCtxt->doc = olddoc;\r
+ if (newlist == NULL)\r
+ return(-1);\r
+ if (newlist->type != XPATH_NODESET) {\r
+ xmlXPathFreeObject(newlist);\r
+ return(-1);\r
+ }\r
+ ix = 0;\r
+\r
+ if ((parent == NULL) || (node->doc == NULL) || isRVT)\r
+ nocache = 1;\r
+ \r
+ if (nocache == 0) {\r
+ if (list != NULL)\r
+ xmlXPathFreeObject(list);\r
+ list = newlist;\r
+\r
+ XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =\r
+ (void *) list;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =\r
+ (void *) doc;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =\r
+ 0;\r
+ XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =\r
+ (xmlFreeFunc) xmlXPathFreeObject;\r
+ } else\r
+ list = newlist;\r
+ }\r
+ if ((list->nodesetval == NULL) ||\r
+ (list->nodesetval->nodeNr <= 0)) {\r
+ if (nocache == 1)\r
+ xmlXPathFreeObject(list);\r
+ return(0);\r
+ }\r
+ /* TODO: store the index and use it for the scan */\r
+ if (ix == 0) {\r
+ for (j = 0;j < list->nodesetval->nodeNr;j++) {\r
+ if (list->nodesetval->nodeTab[j] == node) {\r
+ if (nocache == 1)\r
+ xmlXPathFreeObject(list);\r
+ return(1);\r
+ }\r
+ }\r
+ } else {\r
+ }\r
+ if (nocache == 1)\r
+ xmlXPathFreeObject(list);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltTestCompMatch:\r
+ * @ctxt: a XSLT process context\r
+ * @comp: the precompiled pattern\r
+ * @node: a node\r
+ * @mode: the mode name or NULL\r
+ * @modeURI: the mode URI or NULL\r
+ *\r
+ * Test whether the node matches the pattern\r
+ *\r
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure\r
+ */\r
+static int\r
+xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,\r
+ xmlNodePtr node, const xmlChar *mode,\r
+ const xmlChar *modeURI) {\r
+ int i;\r
+ xsltStepOpPtr step, sel = NULL;\r
+ xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */\r
+\r
+ if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltTestCompMatch: null arg\n");\r
+ return(-1);\r
+ }\r
+ if (mode != NULL) {\r
+ if (comp->mode == NULL)\r
+ return(0);\r
+ /*\r
+ * both mode strings must be interned on the stylesheet dictionary\r
+ */\r
+ if (comp->mode != mode)\r
+ return(0);\r
+ } else {\r
+ if (comp->mode != NULL)\r
+ return(0);\r
+ }\r
+ if (modeURI != NULL) {\r
+ if (comp->modeURI == NULL)\r
+ return(0);\r
+ /*\r
+ * both modeURI strings must be interned on the stylesheet dictionary\r
+ */\r
+ if (comp->modeURI != modeURI)\r
+ return(0);\r
+ } else {\r
+ if (comp->modeURI != NULL)\r
+ return(0);\r
+ }\r
+\r
+ i = 0;\r
+restart:\r
+ for (;i < comp->nbStep;i++) {\r
+ step = &comp->steps[i];\r
+ if (step->op != XSLT_OP_PREDICATE)\r
+ sel = step;\r
+ switch (step->op) {\r
+ case XSLT_OP_END:\r
+ goto found;\r
+ case XSLT_OP_ROOT:\r
+ if ((node->type == XML_DOCUMENT_NODE) ||\r
+#ifdef LIBXML_DOCB_ENABLED\r
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||\r
+#endif\r
+ (node->type == XML_HTML_DOCUMENT_NODE))\r
+ continue;\r
+ if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))\r
+ continue;\r
+ goto rollback;\r
+ case XSLT_OP_ELEM:\r
+ if (node->type != XML_ELEMENT_NODE)\r
+ goto rollback;\r
+ if (step->value == NULL)\r
+ continue;\r
+ if (step->value[0] != node->name[0])\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value, node->name))\r
+ goto rollback;\r
+\r
+ /* Namespace test */\r
+ if (node->ns == NULL) {\r
+ if (step->value2 != NULL)\r
+ goto rollback;\r
+ } else if (node->ns->href != NULL) {\r
+ if (step->value2 == NULL)\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value2, node->ns->href))\r
+ goto rollback;\r
+ }\r
+ continue;\r
+ case XSLT_OP_CHILD: {\r
+ xmlNodePtr lst;\r
+\r
+ if ((node->type != XML_ELEMENT_NODE) &&\r
+ (node->type != XML_DOCUMENT_NODE) &&\r
+#ifdef LIBXML_DOCB_ENABLED\r
+ (node->type != XML_DOCB_DOCUMENT_NODE) &&\r
+#endif\r
+ (node->type != XML_HTML_DOCUMENT_NODE))\r
+ goto rollback;\r
+\r
+ lst = node->children;\r
+\r
+ if (step->value != NULL) {\r
+ while (lst != NULL) {\r
+ if ((lst->type == XML_ELEMENT_NODE) &&\r
+ (step->value[0] == lst->name[0]) &&\r
+ (xmlStrEqual(step->value, lst->name)))\r
+ break;\r
+ lst = lst->next;\r
+ }\r
+ if (lst != NULL)\r
+ continue;\r
+ }\r
+ goto rollback;\r
+ }\r
+ case XSLT_OP_ATTR:\r
+ if (node->type != XML_ATTRIBUTE_NODE)\r
+ goto rollback;\r
+ if (step->value != NULL) {\r
+ if (step->value[0] != node->name[0])\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value, node->name))\r
+ goto rollback;\r
+ }\r
+ /* Namespace test */\r
+ if (node->ns == NULL) {\r
+ if (step->value2 != NULL)\r
+ goto rollback;\r
+ } else if (step->value2 != NULL) {\r
+ if (!xmlStrEqual(step->value2, node->ns->href))\r
+ goto rollback;\r
+ }\r
+ continue;\r
+ case XSLT_OP_PARENT:\r
+ if ((node->type == XML_DOCUMENT_NODE) ||\r
+ (node->type == XML_HTML_DOCUMENT_NODE) ||\r
+#ifdef LIBXML_DOCB_ENABLED\r
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||\r
+#endif\r
+ (node->type == XML_NAMESPACE_DECL))\r
+ goto rollback;\r
+ node = node->parent;\r
+ if (node == NULL)\r
+ goto rollback;\r
+ if (step->value == NULL)\r
+ continue;\r
+ if (step->value[0] != node->name[0])\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value, node->name))\r
+ goto rollback;\r
+ /* Namespace test */\r
+ if (node->ns == NULL) {\r
+ if (step->value2 != NULL)\r
+ goto rollback;\r
+ } else if (node->ns->href != NULL) {\r
+ if (step->value2 == NULL)\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value2, node->ns->href))\r
+ goto rollback;\r
+ }\r
+ continue;\r
+ case XSLT_OP_ANCESTOR:\r
+ /* TODO: implement coalescing of ANCESTOR/NODE ops */\r
+ if (step->value == NULL) {\r
+ step = &comp->steps[i+1];\r
+ if (step->op == XSLT_OP_ROOT)\r
+ goto found;\r
+ /* added NS, ID and KEY as a result of bug 168208 */\r
+ if ((step->op != XSLT_OP_ELEM) && \r
+ (step->op != XSLT_OP_ALL) && \r
+ (step->op != XSLT_OP_NS) &&\r
+ (step->op != XSLT_OP_ID) &&\r
+ (step->op != XSLT_OP_KEY))\r
+ goto rollback;\r
+ }\r
+ if (node == NULL)\r
+ goto rollback;\r
+ if ((node->type == XML_DOCUMENT_NODE) ||\r
+ (node->type == XML_HTML_DOCUMENT_NODE) ||\r
+#ifdef LIBXML_DOCB_ENABLED\r
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||\r
+#endif\r
+ (node->type == XML_NAMESPACE_DECL))\r
+ goto rollback;\r
+ node = node->parent;\r
+ if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {\r
+ xsltPatPushState(&states, i, node);\r
+ continue;\r
+ }\r
+ i++;\r
+ if (step->value == NULL) {\r
+ xsltPatPushState(&states, i - 1, node);\r
+ continue;\r
+ }\r
+ while (node != NULL) {\r
+ if ((node->type == XML_ELEMENT_NODE) &&\r
+ (step->value[0] == node->name[0]) &&\r
+ (xmlStrEqual(step->value, node->name))) {\r
+ /* Namespace test */\r
+ if (node->ns == NULL) {\r
+ if (step->value2 == NULL)\r
+ break;\r
+ } else if (node->ns->href != NULL) {\r
+ if ((step->value2 != NULL) &&\r
+ (xmlStrEqual(step->value2, node->ns->href)))\r
+ break;\r
+ }\r
+ }\r
+ node = node->parent;\r
+ }\r
+ if (node == NULL)\r
+ goto rollback;\r
+ xsltPatPushState(&states, i - 1, node);\r
+ continue;\r
+ case XSLT_OP_ID: {\r
+ /* TODO Handle IDs decently, must be done differently */\r
+ xmlAttrPtr id;\r
+\r
+ if (node->type != XML_ELEMENT_NODE)\r
+ goto rollback;\r
+\r
+ id = xmlGetID(node->doc, step->value);\r
+ if ((id == NULL) || (id->parent != node))\r
+ goto rollback;\r
+ break;\r
+ }\r
+ case XSLT_OP_KEY: {\r
+ xmlNodeSetPtr list;\r
+ int indx;\r
+\r
+ list = xsltGetKey(ctxt, step->value,\r
+ step->value3, step->value2);\r
+ if (list == NULL)\r
+ goto rollback;\r
+ for (indx = 0;indx < list->nodeNr;indx++)\r
+ if (list->nodeTab[indx] == node)\r
+ break;\r
+ if (indx >= list->nodeNr)\r
+ goto rollback;\r
+ break;\r
+ }\r
+ case XSLT_OP_NS:\r
+ if (node->type != XML_ELEMENT_NODE)\r
+ goto rollback;\r
+ if (node->ns == NULL) {\r
+ if (step->value != NULL)\r
+ goto rollback;\r
+ } else if (node->ns->href != NULL) {\r
+ if (step->value == NULL)\r
+ goto rollback;\r
+ if (!xmlStrEqual(step->value, node->ns->href))\r
+ goto rollback;\r
+ }\r
+ break;\r
+ case XSLT_OP_ALL:\r
+ if (node->type != XML_ELEMENT_NODE)\r
+ goto rollback;\r
+ break;\r
+ case XSLT_OP_PREDICATE: {\r
+ xmlNodePtr oldNode;\r
+ xmlDocPtr doc;\r
+ int oldCS, oldCP;\r
+ int pos = 0, len = 0;\r
+ int isRVT;\r
+\r
+ /*\r
+ * when there is cascading XSLT_OP_PREDICATE, then use a\r
+ * direct computation approach. It's not done directly\r
+ * at the beginning of the routine to filter out as much\r
+ * as possible this costly computation.\r
+ */\r
+ if (comp->direct) {\r
+ if (states.states != NULL) {\r
+ /* Free the rollback states */\r
+ xmlFree(states.states);\r
+ }\r
+ return(xsltTestCompMatchDirect(ctxt, comp, node));\r
+ }\r
+\r
+ doc = node->doc;\r
+ if (XSLT_IS_RES_TREE_FRAG(doc))\r
+ isRVT = 1;\r
+ else\r
+ isRVT = 0;\r
+\r
+ /*\r
+ * Depending on the last selection, one may need to\r
+ * recompute contextSize and proximityPosition.\r
+ */\r
+ oldCS = ctxt->xpathCtxt->contextSize;\r
+ oldCP = ctxt->xpathCtxt->proximityPosition;\r
+ if ((sel != NULL) &&\r
+ (sel->op == XSLT_OP_ELEM) &&\r
+ (sel->value != NULL) &&\r
+ (node->type == XML_ELEMENT_NODE) &&\r
+ (node->parent != NULL)) {\r
+ xmlNodePtr previous;\r
+ int ix, nocache = 0;\r
+\r
+ previous = (xmlNodePtr)\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);\r
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);\r
+ if ((previous != NULL) &&\r
+ (previous->parent == node->parent)) {\r
+ /*\r
+ * just walk back to adjust the index\r
+ */\r
+ int indx = 0;\r
+ xmlNodePtr sibling = node;\r
+\r
+ while (sibling != NULL) {\r
+ if (sibling == previous)\r
+ break;\r
+ if ((previous->type == XML_ELEMENT_NODE) &&\r
+ (previous->name != NULL) &&\r
+ (sibling->name != NULL) &&\r
+ (previous->name[0] == sibling->name[0]) &&\r
+ (xmlStrEqual(previous->name, sibling->name)))\r
+ {\r
+ if ((sel->value2 == NULL) ||\r
+ ((sibling->ns != NULL) &&\r
+ (xmlStrEqual(sel->value2,\r
+ sibling->ns->href))))\r
+ indx++;\r
+ }\r
+ sibling = sibling->prev;\r
+ }\r
+ if (sibling == NULL) {\r
+ /* hum going backward in document order ... */\r
+ indx = 0;\r
+ sibling = node;\r
+ while (sibling != NULL) {\r
+ if (sibling == previous)\r
+ break;\r
+ if ((previous->type == XML_ELEMENT_NODE) &&\r
+ (previous->name != NULL) &&\r
+ (sibling->name != NULL) &&\r
+ (previous->name[0] == sibling->name[0]) &&\r
+ (xmlStrEqual(previous->name, sibling->name)))\r
+ {\r
+ if ((sel->value2 == NULL) ||\r
+ ((sibling->ns != NULL) &&\r
+ (xmlStrEqual(sel->value2,\r
+ sibling->ns->href))))\r
+ {\r
+ indx--;\r
+ }\r
+ }\r
+ sibling = sibling->next;\r
+ }\r
+ }\r
+ if (sibling != NULL) {\r
+ pos = ix + indx;\r
+ /*\r
+ * If the node is in a Value Tree we need to\r
+ * save len, but cannot cache the node!\r
+ * (bugs 153137 and 158840)\r
+ */\r
+ if (node->doc != NULL) {\r
+ len = XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->lenExtra, ival);\r
+ if (!isRVT) {\r
+ XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->previousExtra, ptr) = node;\r
+ XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->indexExtra, ival) = pos;\r
+ }\r
+ }\r
+ ix = pos;\r
+ } else\r
+ pos = 0;\r
+ } else {\r
+ /*\r
+ * recompute the index\r
+ */\r
+ xmlNodePtr siblings = node->parent->children;\r
+ xmlNodePtr parent = node->parent;\r
+\r
+ while (siblings != NULL) {\r
+ if (siblings->type == XML_ELEMENT_NODE) {\r
+ if (siblings == node) {\r
+ len++;\r
+ pos = len;\r
+ } else if ((node->name != NULL) &&\r
+ (siblings->name != NULL) &&\r
+ (node->name[0] == siblings->name[0]) &&\r
+ (xmlStrEqual(node->name, siblings->name))) {\r
+ if ((sel->value2 == NULL) ||\r
+ ((siblings->ns != NULL) &&\r
+ (xmlStrEqual(sel->value2,\r
+ siblings->ns->href))))\r
+ len++;\r
+ }\r
+ }\r
+ siblings = siblings->next;\r
+ }\r
+ if ((parent == NULL) || (node->doc == NULL))\r
+ nocache = 1;\r
+ else {\r
+ while (parent->parent != NULL)\r
+ parent = parent->parent;\r
+ if (((parent->type != XML_DOCUMENT_NODE) &&\r
+ (parent->type != XML_HTML_DOCUMENT_NODE)) ||\r
+ (parent != (xmlNodePtr) node->doc))\r
+ nocache = 1;\r
+ }\r
+ }\r
+ if (pos != 0) {\r
+ ctxt->xpathCtxt->contextSize = len;\r
+ ctxt->xpathCtxt->proximityPosition = pos;\r
+ /*\r
+ * If the node is in a Value Tree we cannot\r
+ * cache it !\r
+ */\r
+ if ((!isRVT) && (node->doc != NULL) &&\r
+ (nocache == 0)) {\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =\r
+ node;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =\r
+ pos;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =\r
+ len;\r
+ }\r
+ }\r
+ } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&\r
+ (node->type == XML_ELEMENT_NODE)) {\r
+ xmlNodePtr previous;\r
+ int ix, nocache = 0;\r
+\r
+ previous = (xmlNodePtr)\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);\r
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);\r
+ if ((previous != NULL) &&\r
+ (previous->parent == node->parent)) {\r
+ /*\r
+ * just walk back to adjust the index\r
+ */\r
+ int indx = 0;\r
+ xmlNodePtr sibling = node;\r
+\r
+ while (sibling != NULL) {\r
+ if (sibling == previous)\r
+ break;\r
+ if (sibling->type == XML_ELEMENT_NODE)\r
+ indx++;\r
+ sibling = sibling->prev;\r
+ }\r
+ if (sibling == NULL) {\r
+ /* hum going backward in document order ... */\r
+ indx = 0;\r
+ sibling = node;\r
+ while (sibling != NULL) {\r
+ if (sibling == previous)\r
+ break;\r
+ if (sibling->type == XML_ELEMENT_NODE)\r
+ indx--;\r
+ sibling = sibling->next;\r
+ }\r
+ }\r
+ if (sibling != NULL) {\r
+ pos = ix + indx;\r
+ /*\r
+ * If the node is in a Value Tree we cannot\r
+ * cache it !\r
+ */\r
+ if ((node->doc != NULL) && !isRVT) {\r
+ len = XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->lenExtra, ival);\r
+ XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->previousExtra, ptr) = node;\r
+ XSLT_RUNTIME_EXTRA(ctxt,\r
+ sel->indexExtra, ival) = pos;\r
+ }\r
+ } else\r
+ pos = 0;\r
+ } else {\r
+ /*\r
+ * recompute the index\r
+ */\r
+ xmlNodePtr siblings = node->parent->children;\r
+ xmlNodePtr parent = node->parent;\r
+\r
+ while (siblings != NULL) {\r
+ if (siblings->type == XML_ELEMENT_NODE) {\r
+ len++;\r
+ if (siblings == node) {\r
+ pos = len;\r
+ }\r
+ }\r
+ siblings = siblings->next;\r
+ }\r
+ if ((parent == NULL) || (node->doc == NULL))\r
+ nocache = 1;\r
+ else {\r
+ while (parent->parent != NULL)\r
+ parent = parent->parent;\r
+ if (((parent->type != XML_DOCUMENT_NODE) &&\r
+ (parent->type != XML_HTML_DOCUMENT_NODE)) ||\r
+ (parent != (xmlNodePtr) node->doc))\r
+ nocache = 1;\r
+ }\r
+ }\r
+ if (pos != 0) {\r
+ ctxt->xpathCtxt->contextSize = len;\r
+ ctxt->xpathCtxt->proximityPosition = pos;\r
+ /*\r
+ * If the node is in a Value Tree we cannot\r
+ * cache it !\r
+ */\r
+ if ((node->doc != NULL) && (nocache == 0) && !isRVT) {\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =\r
+ node;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =\r
+ pos;\r
+ XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =\r
+ len;\r
+ }\r
+ }\r
+ }\r
+ oldNode = ctxt->node;\r
+ ctxt->node = node;\r
+\r
+ if (step->value == NULL)\r
+ goto wrong_index;\r
+ if (step->comp == NULL)\r
+ goto wrong_index;\r
+\r
+ if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,\r
+ comp->nsNr))\r
+ goto wrong_index;\r
+\r
+ if (pos != 0) {\r
+ ctxt->xpathCtxt->contextSize = oldCS;\r
+ ctxt->xpathCtxt->proximityPosition = oldCP;\r
+ }\r
+ ctxt->node = oldNode;\r
+ break;\r
+wrong_index:\r
+ if (pos != 0) {\r
+ ctxt->xpathCtxt->contextSize = oldCS;\r
+ ctxt->xpathCtxt->proximityPosition = oldCP;\r
+ }\r
+ ctxt->node = oldNode;\r
+ goto rollback;\r
+ }\r
+ case XSLT_OP_PI:\r
+ if (node->type != XML_PI_NODE)\r
+ goto rollback;\r
+ if (step->value != NULL) {\r
+ if (!xmlStrEqual(step->value, node->name))\r
+ goto rollback;\r
+ }\r
+ break;\r
+ case XSLT_OP_COMMENT:\r
+ if (node->type != XML_COMMENT_NODE)\r
+ goto rollback;\r
+ break;\r
+ case XSLT_OP_TEXT:\r
+ if ((node->type != XML_TEXT_NODE) &&\r
+ (node->type != XML_CDATA_SECTION_NODE))\r
+ goto rollback;\r
+ break;\r
+ case XSLT_OP_NODE:\r
+ switch (node->type) {\r
+ case XML_ELEMENT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ case XML_TEXT_NODE:\r
+ break;\r
+ default:\r
+ goto rollback;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+found:\r
+ if (states.states != NULL) {\r
+ /* Free the rollback states */\r
+ xmlFree(states.states);\r
+ }\r
+ return(1);\r
+rollback:\r
+ /* got an error try to rollback */\r
+ if (states.states == NULL)\r
+ return(0);\r
+ if (states.nbstates <= 0) {\r
+ xmlFree(states.states);\r
+ return(0);\r
+ }\r
+ states.nbstates--;\r
+ i = states.states[states.nbstates].step;\r
+ node = states.states[states.nbstates].node;\r
+#if 0\r
+ fprintf(stderr, "Pop: %d, %s\n", i, node->name);\r
+#endif\r
+ goto restart;\r
+}\r
+\r
+/**\r
+ * xsltTestCompMatchList:\r
+ * @ctxt: a XSLT process context\r
+ * @node: a node\r
+ * @comp: the precompiled pattern list\r
+ *\r
+ * Test whether the node matches one of the patterns in the list\r
+ *\r
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure\r
+ */\r
+int\r
+xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xsltCompMatchPtr comp) {\r
+ int ret;\r
+\r
+ if ((ctxt == NULL) || (node == NULL))\r
+ return(-1);\r
+ while (comp != NULL) {\r
+ ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);\r
+ if (ret == 1)\r
+ return(1);\r
+ comp = comp->next;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Dedicated parser for templates *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#define CUR (*ctxt->cur)\r
+#define SKIP(val) ctxt->cur += (val)\r
+#define NXT(val) ctxt->cur[(val)]\r
+#define CUR_PTR ctxt->cur\r
+\r
+#define SKIP_BLANKS \\r
+ while (IS_BLANK_CH(CUR)) NEXT\r
+\r
+#define CURRENT (*ctxt->cur)\r
+#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)\r
+\r
+\r
+#define PUSH(op, val, val2, novar) \\r
+ if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;\r
+\r
+#define SWAP() \\r
+ xsltSwapTopCompMatch(ctxt->comp);\r
+\r
+#define XSLT_ERROR(X) \\r
+ { xsltError(ctxt, __FILE__, __LINE__, X); \\r
+ ctxt->error = (X); return; }\r
+\r
+#define XSLT_ERROR0(X) \\r
+ { xsltError(ctxt, __FILE__, __LINE__, X); \\r
+ ctxt->error = (X); return(0); }\r
+\r
+/**\r
+ * xsltScanLiteral:\r
+ * @ctxt: the XPath Parser context\r
+ *\r
+ * Parse an XPath Litteral:\r
+ *\r
+ * [29] Literal ::= '"' [^"]* '"'\r
+ * | "'" [^']* "'"\r
+ *\r
+ * Returns the Literal parsed or NULL\r
+ */\r
+\r
+static xmlChar *\r
+xsltScanLiteral(xsltParserContextPtr ctxt) {\r
+ const xmlChar *q, *cur;\r
+ xmlChar *ret = NULL;\r
+ int val, len;\r
+\r
+ SKIP_BLANKS;\r
+ if (CUR == '"') {\r
+ NEXT;\r
+ cur = q = CUR_PTR;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ while ((IS_CHAR(val)) && (val != '"')) {\r
+ cur += len;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ }\r
+ if (!IS_CHAR(val)) {\r
+ ctxt->error = 1;\r
+ return(NULL);\r
+ } else {\r
+ ret = xmlStrndup(q, cur - q);\r
+ }\r
+ cur += len;\r
+ CUR_PTR = cur;\r
+ } else if (CUR == '\'') {\r
+ NEXT;\r
+ cur = q = CUR_PTR;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ while ((IS_CHAR(val)) && (val != '\'')) {\r
+ cur += len;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ }\r
+ if (!IS_CHAR(val)) {\r
+ ctxt->error = 1;\r
+ return(NULL);\r
+ } else {\r
+ ret = xmlStrndup(q, cur - q);\r
+ }\r
+ cur += len;\r
+ CUR_PTR = cur;\r
+ } else {\r
+ /* XP_ERROR(XPATH_START_LITERAL_ERROR); */\r
+ ctxt->error = 1;\r
+ return(NULL);\r
+ }\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltScanName:\r
+ * @ctxt: the XPath Parser context\r
+ *\r
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | \r
+ * CombiningChar | Extender\r
+ *\r
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*\r
+ *\r
+ * [6] Names ::= Name (S Name)*\r
+ *\r
+ * Returns the Name parsed or NULL\r
+ */\r
+\r
+static xmlChar *\r
+xsltScanName(xsltParserContextPtr ctxt) {\r
+ const xmlChar *q, *cur;\r
+ xmlChar *ret = NULL;\r
+ int val, len;\r
+\r
+ SKIP_BLANKS;\r
+\r
+ cur = q = CUR_PTR;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ if (!IS_LETTER(val) && (val != '_') && (val != ':'))\r
+ return(NULL);\r
+\r
+ while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||\r
+ (val == '.') || (val == '-') ||\r
+ (val == '_') || \r
+ (IS_COMBINING(val)) ||\r
+ (IS_EXTENDER(val))) {\r
+ cur += len;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ }\r
+ ret = xmlStrndup(q, cur - q);\r
+ CUR_PTR = cur;\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltScanNCName:\r
+ * @ctxt: the XPath Parser context\r
+ *\r
+ * Parses a non qualified name\r
+ *\r
+ * Returns the Name parsed or NULL\r
+ */\r
+\r
+static xmlChar *\r
+xsltScanNCName(xsltParserContextPtr ctxt) {\r
+ const xmlChar *q, *cur;\r
+ xmlChar *ret = NULL;\r
+ int val, len;\r
+\r
+ SKIP_BLANKS;\r
+\r
+ cur = q = CUR_PTR;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ if (!IS_LETTER(val) && (val != '_'))\r
+ return(NULL);\r
+\r
+ while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||\r
+ (val == '.') || (val == '-') ||\r
+ (val == '_') ||\r
+ (IS_COMBINING(val)) ||\r
+ (IS_EXTENDER(val))) {\r
+ cur += len;\r
+ val = xmlStringCurrentChar(NULL, cur, &len);\r
+ }\r
+ ret = xmlStrndup(q, cur - q);\r
+ CUR_PTR = cur;\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltScanQName:\r
+ * @ctxt: the XPath Parser context\r
+ * @prefix: the place to store the prefix\r
+ *\r
+ * Parse a qualified name\r
+ *\r
+ * Returns the Name parsed or NULL\r
+ */\r
+\r
+static xmlChar *\r
+xsltScanQName(xsltParserContextPtr ctxt, xmlChar **prefix) {\r
+ xmlChar *ret = NULL;\r
+\r
+ *prefix = NULL;\r
+ ret = xsltScanNCName(ctxt);\r
+ if (CUR == ':') {\r
+ *prefix = ret;\r
+ NEXT;\r
+ ret = xsltScanNCName(ctxt);\r
+ }\r
+ return(ret);\r
+}\r
+\r
+/*\r
+ * xsltCompileIdKeyPattern:\r
+ * @ctxt: the compilation context\r
+ * @name: a preparsed name\r
+ * @aid: whether id/key are allowed there\r
+ * @novar: flag to prohibit xslt var\r
+ *\r
+ * Compile the XSLT LocationIdKeyPattern\r
+ * [3] IdKeyPattern ::= 'id' '(' Literal ')'\r
+ * | 'key' '(' Literal ',' Literal ')'\r
+ *\r
+ * also handle NodeType and PI from:\r
+ *\r
+ * [7] NodeTest ::= NameTest\r
+ * | NodeType '(' ')'\r
+ * | 'processing-instruction' '(' Literal ')'\r
+ */\r
+static void\r
+xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,\r
+ int aid, int novar) {\r
+ xmlChar *lit = NULL;\r
+ xmlChar *lit2 = NULL;\r
+\r
+ if (CUR != '(') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ( expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ lit = xsltScanLiteral(ctxt);\r
+ if (ctxt->error)\r
+ return;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ PUSH(XSLT_OP_ID, lit, NULL, novar);\r
+ } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ lit = xsltScanLiteral(ctxt);\r
+ if (ctxt->error)\r
+ return;\r
+ SKIP_BLANKS;\r
+ if (CUR != ',') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : , expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ lit2 = xsltScanLiteral(ctxt);\r
+ if (ctxt->error)\r
+ return;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ /* URGENT TODO: support namespace in keys */\r
+ PUSH(XSLT_OP_KEY, lit, lit2, novar);\r
+ } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ lit = xsltScanLiteral(ctxt);\r
+ if (ctxt->error)\r
+ return;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ }\r
+ NEXT;\r
+ PUSH(XSLT_OP_PI, lit, NULL, novar);\r
+ } else if (xmlStrEqual(name, (const xmlChar *)"text")) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ PUSH(XSLT_OP_TEXT, NULL, NULL, novar);\r
+ } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ PUSH(XSLT_OP_COMMENT, NULL, NULL, novar);\r
+ } else if (xmlStrEqual(name, (const xmlChar *)"node")) {\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ if (CUR != ')') {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : ) expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ NEXT;\r
+ PUSH(XSLT_OP_NODE, NULL, NULL, novar);\r
+ } else if (aid) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ } else {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileIdKeyPattern : node type\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+error:\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+}\r
+\r
+/**\r
+ * xsltCompileStepPattern:\r
+ * @ctxt: the compilation context\r
+ * @token: a posible precompiled name\r
+ * @novar: flag to prohibit xslt variables from pattern\r
+ *\r
+ * Compile the XSLT StepPattern and generates a precompiled\r
+ * form suitable for fast matching.\r
+ *\r
+ * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* \r
+ * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier\r
+ * | ('child' | 'attribute') '::'\r
+ * from XPath\r
+ * [7] NodeTest ::= NameTest\r
+ * | NodeType '(' ')'\r
+ * | 'processing-instruction' '(' Literal ')'\r
+ * [8] Predicate ::= '[' PredicateExpr ']'\r
+ * [9] PredicateExpr ::= Expr\r
+ * [13] AbbreviatedAxisSpecifier ::= '@'?\r
+ * [37] NameTest ::= '*' | NCName ':' '*' | QName\r
+ */\r
+\r
+static void\r
+xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {\r
+ xmlChar *name = NULL;\r
+ const xmlChar *URI = NULL;\r
+ xmlChar *URL = NULL;\r
+ int level;\r
+\r
+ SKIP_BLANKS;\r
+ if ((token == NULL) && (CUR == '@')) {\r
+ xmlChar *prefix = NULL;\r
+\r
+ NEXT;\r
+ if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_ATTR, NULL, NULL, novar);\r
+ goto parse_predicate;\r
+ }\r
+ token = xsltScanQName(ctxt, &prefix);\r
+ if (prefix != NULL) {\r
+ xmlNsPtr ns;\r
+\r
+ ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : no namespace bound to prefix %s\n",\r
+ prefix);\r
+ } else {\r
+ URL = xmlStrdup(ns->href);\r
+ }\r
+ xmlFree(prefix);\r
+ }\r
+ if (token == NULL) {\r
+ if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_ATTR, NULL, URL, novar);\r
+ return;\r
+ }\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : Name expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ PUSH(XSLT_OP_ATTR, token, URL, novar);\r
+ goto parse_predicate;\r
+ }\r
+ if (token == NULL)\r
+ token = xsltScanName(ctxt);\r
+ if (token == NULL) {\r
+ if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_ALL, token, NULL, novar);\r
+ goto parse_predicate;\r
+ } else {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : Name expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ }\r
+\r
+\r
+ SKIP_BLANKS;\r
+ if (CUR == '(') {\r
+ xsltCompileIdKeyPattern(ctxt, token, 0, novar);\r
+ if (ctxt->error)\r
+ goto error;\r
+ } else if (CUR == ':') {\r
+ NEXT;\r
+ if (CUR != ':') {\r
+ xmlChar *prefix = token;\r
+ xmlNsPtr ns;\r
+\r
+ /*\r
+ * This is a namespace match\r
+ */\r
+ token = xsltScanName(ctxt);\r
+ ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : no namespace bound to prefix %s\n",\r
+ prefix);\r
+ ctxt->error = 1;\r
+ goto error;\r
+ } else {\r
+ URL = xmlStrdup(ns->href);\r
+ }\r
+ xmlFree(prefix);\r
+ if (token == NULL) {\r
+ if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_NS, URL, NULL, novar);\r
+ } else {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : Name expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ } else {\r
+ PUSH(XSLT_OP_ELEM, token, URL, novar);\r
+ }\r
+ } else {\r
+ NEXT;\r
+ if (xmlStrEqual(token, (const xmlChar *) "child")) {\r
+ xmlFree(token);\r
+ token = xsltScanName(ctxt);\r
+ if (token == NULL) {\r
+ if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_ALL, token, NULL, novar);\r
+ goto parse_predicate;\r
+ } else {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : QName expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ }\r
+ URI = xsltGetQNameURI(ctxt->elem, &token);\r
+ if (token == NULL) {\r
+ ctxt->error = 1;\r
+ goto error;\r
+ } else {\r
+ name = xmlStrdup(token);\r
+ if (URI != NULL)\r
+ URL = xmlStrdup(URI);\r
+ }\r
+ PUSH(XSLT_OP_CHILD, name, URL, novar);\r
+ } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {\r
+ xmlFree(token);\r
+ token = xsltScanName(ctxt);\r
+ if (token == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : QName expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ URI = xsltGetQNameURI(ctxt->elem, &token);\r
+ if (token == NULL) {\r
+ ctxt->error = 1;\r
+ goto error;\r
+ } else {\r
+ name = xmlStrdup(token);\r
+ if (URI != NULL)\r
+ URL = xmlStrdup(URI);\r
+ }\r
+ PUSH(XSLT_OP_ATTR, name, URL, novar);\r
+ } else {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : 'child' or 'attribute' expected\n");\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ xmlFree(token);\r
+ }\r
+ } else if (CUR == '*') {\r
+ NEXT;\r
+ PUSH(XSLT_OP_ALL, token, NULL, novar);\r
+ } else {\r
+ URI = xsltGetQNameURI(ctxt->elem, &token);\r
+ if (token == NULL) {\r
+ ctxt->error = 1;\r
+ goto error;\r
+ }\r
+ if (URI != NULL)\r
+ URL = xmlStrdup(URI);\r
+ PUSH(XSLT_OP_ELEM, token, URL, novar);\r
+ }\r
+parse_predicate:\r
+ SKIP_BLANKS;\r
+ level = 0;\r
+ while (CUR == '[') {\r
+ const xmlChar *q;\r
+ xmlChar *ret = NULL;\r
+\r
+ level++;\r
+ NEXT;\r
+ q = CUR_PTR;\r
+ while (CUR != 0) {\r
+ /* Skip over nested predicates */\r
+ if (CUR == '[')\r
+ level++;\r
+ else if (CUR == ']') {\r
+ level--;\r
+ if (level == 0)\r
+ break;\r
+ } else if (CUR == '"') {\r
+ NEXT;\r
+ while ((CUR != 0) && (CUR != '"'))\r
+ NEXT;\r
+ } else if (CUR == '\'') {\r
+ NEXT;\r
+ while ((CUR != 0) && (CUR != '\''))\r
+ NEXT;\r
+ }\r
+ NEXT;\r
+ }\r
+ if (CUR == 0) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileStepPattern : ']' expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ ret = xmlStrndup(q, CUR_PTR - q);\r
+ PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);\r
+ /* push the predicate lower than local test */\r
+ SWAP();\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ }\r
+ return;\r
+error:\r
+ if (token != NULL)\r
+ xmlFree(token);\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+}\r
+\r
+/**\r
+ * xsltCompileRelativePathPattern:\r
+ * @comp: the compilation context\r
+ * @token: a posible precompiled name\r
+ * @novar: flag to prohibit xslt variables\r
+ *\r
+ * Compile the XSLT RelativePathPattern and generates a precompiled\r
+ * form suitable for fast matching.\r
+ *\r
+ * [4] RelativePathPattern ::= StepPattern\r
+ * | RelativePathPattern '/' StepPattern\r
+ * | RelativePathPattern '//' StepPattern\r
+ */\r
+static void\r
+xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {\r
+ xsltCompileStepPattern(ctxt, token, novar);\r
+ if (ctxt->error)\r
+ goto error;\r
+ SKIP_BLANKS;\r
+ while ((CUR != 0) && (CUR != '|')) {\r
+ if ((CUR == '/') && (NXT(1) == '/')) {\r
+ PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);\r
+ NEXT;\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ xsltCompileStepPattern(ctxt, NULL, novar);\r
+ } else if (CUR == '/') {\r
+ PUSH(XSLT_OP_PARENT, NULL, NULL, novar);\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ if ((CUR != 0) && (CUR != '|')) {\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ }\r
+ } else {\r
+ ctxt->error = 1;\r
+ }\r
+ if (ctxt->error)\r
+ goto error;\r
+ SKIP_BLANKS;\r
+ }\r
+error:\r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltCompileLocationPathPattern:\r
+ * @ctxt: the compilation context\r
+ * @novar: flag to prohibit xslt variables\r
+ *\r
+ * Compile the XSLT LocationPathPattern and generates a precompiled\r
+ * form suitable for fast matching.\r
+ *\r
+ * [2] LocationPathPattern ::= '/' RelativePathPattern?\r
+ * | IdKeyPattern (('/' | '//') RelativePathPattern)?\r
+ * | '//'? RelativePathPattern\r
+ */\r
+static void\r
+xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {\r
+ SKIP_BLANKS;\r
+ if ((CUR == '/') && (NXT(1) == '/')) {\r
+ /*\r
+ * since we reverse the query\r
+ * a leading // can be safely ignored\r
+ */\r
+ NEXT;\r
+ NEXT;\r
+ ctxt->comp->priority = 0.5; /* '//' means not 0 priority */\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ } else if (CUR == '/') {\r
+ /*\r
+ * We need to find root as the parent\r
+ */\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ PUSH(XSLT_OP_ROOT, NULL, NULL, novar);\r
+ if ((CUR != 0) && (CUR != '|')) {\r
+ PUSH(XSLT_OP_PARENT, NULL, NULL, novar);\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ }\r
+ } else if (CUR == '*') {\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ } else if (CUR == '@') {\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ } else {\r
+ xmlChar *name;\r
+ name = xsltScanName(ctxt);\r
+ if (name == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCompileLocationPathPattern : Name expected\n");\r
+ ctxt->error = 1;\r
+ return;\r
+ }\r
+ SKIP_BLANKS;\r
+ if ((CUR == '(') && !xmlXPathIsNodeType(name)) {\r
+ xsltCompileIdKeyPattern(ctxt, name, 1, novar);\r
+ if ((CUR == '/') && (NXT(1) == '/')) {\r
+ PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);\r
+ NEXT;\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ } else if (CUR == '/') {\r
+ PUSH(XSLT_OP_PARENT, NULL, NULL, novar);\r
+ NEXT;\r
+ SKIP_BLANKS;\r
+ xsltCompileRelativePathPattern(ctxt, NULL, novar);\r
+ }\r
+ return;\r
+ }\r
+ xsltCompileRelativePathPattern(ctxt, name, novar);\r
+ }\r
+error:\r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltCompilePatternInternal:\r
+ * @pattern: an XSLT pattern\r
+ * @doc: the containing document\r
+ * @node: the containing element\r
+ * @style: the stylesheet\r
+ * @runtime: the transformation context, if done at run-time\r
+ * @novar: flag to prohibit xslt variables\r
+ *\r
+ * Compile the XSLT pattern and generates a list of precompiled form suitable\r
+ * for fast matching.\r
+ *\r
+ * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern\r
+ *\r
+ * Returns the generated pattern list or NULL in case of failure\r
+ */\r
+\r
+static xsltCompMatchPtr\r
+xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,\r
+ xmlNodePtr node, xsltStylesheetPtr style,\r
+ xsltTransformContextPtr runtime, int novar) {\r
+ xsltParserContextPtr ctxt = NULL;\r
+ xsltCompMatchPtr element, first = NULL, previous = NULL;\r
+ int current, start, end, level, j;\r
+\r
+ if (pattern == NULL) {\r
+ xsltTransformError(NULL, NULL, node,\r
+ "xsltCompilePattern : NULL pattern\n");\r
+ return(NULL);\r
+ }\r
+\r
+ ctxt = xsltNewParserContext(style, runtime);\r
+ if (ctxt == NULL)\r
+ return(NULL);\r
+ ctxt->doc = doc;\r
+ ctxt->elem = node;\r
+ current = end = 0;\r
+ while (pattern[current] != 0) {\r
+ start = current;\r
+ while (IS_BLANK_CH(pattern[current]))\r
+ current++;\r
+ end = current;\r
+ level = 0;\r
+ while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {\r
+ if (pattern[end] == '[')\r
+ level++;\r
+ else if (pattern[end] == ']')\r
+ level--;\r
+ else if (pattern[end] == '\'') {\r
+ end++;\r
+ while ((pattern[end] != 0) && (pattern[end] != '\''))\r
+ end++;\r
+ } else if (pattern[end] == '"') {\r
+ end++;\r
+ while ((pattern[end] != 0) && (pattern[end] != '"'))\r
+ end++;\r
+ }\r
+ end++;\r
+ }\r
+ if (current == end) {\r
+ xsltTransformError(NULL, NULL, node,\r
+ "xsltCompilePattern : NULL pattern\n");\r
+ goto error;\r
+ }\r
+ element = xsltNewCompMatch();\r
+ if (element == NULL) {\r
+ goto error;\r
+ }\r
+ if (first == NULL)\r
+ first = element;\r
+ else if (previous != NULL)\r
+ previous->next = element;\r
+ previous = element;\r
+\r
+ ctxt->comp = element;\r
+ ctxt->base = xmlStrndup(&pattern[start], end - start);\r
+ if (ctxt->base == NULL)\r
+ goto error;\r
+ ctxt->cur = &(ctxt->base)[current - start];\r
+ element->pattern = ctxt->base;\r
+ element->nsList = xmlGetNsList(doc, node);\r
+ j = 0;\r
+ if (element->nsList != NULL) {\r
+ while (element->nsList[j] != NULL)\r
+ j++;\r
+ }\r
+ element->nsNr = j;\r
+\r
+\r
+#ifdef WITH_XSLT_DEBUG_PATTERN\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCompilePattern : parsing '%s'\n",\r
+ element->pattern);\r
+#endif\r
+ /*\r
+ Preset default priority to be zero.\r
+ This may be changed by xsltCompileLocationPathPattern.\r
+ */\r
+ element->priority = 0;\r
+ xsltCompileLocationPathPattern(ctxt, novar);\r
+ if (ctxt->error) {\r
+ xsltTransformError(NULL, style, node,\r
+ "xsltCompilePattern : failed to compile '%s'\n",\r
+ element->pattern);\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ /*\r
+ * Reverse for faster interpretation.\r
+ */\r
+ xsltReverseCompMatch(element);\r
+\r
+ /*\r
+ * Set-up the priority\r
+ */\r
+ if (element->priority == 0) { /* if not yet determined */\r
+ if (((element->steps[0].op == XSLT_OP_ELEM) ||\r
+ (element->steps[0].op == XSLT_OP_ATTR) ||\r
+ (element->steps[0].op == XSLT_OP_PI)) &&\r
+ (element->steps[0].value != NULL) &&\r
+ (element->steps[1].op == XSLT_OP_END)) {\r
+ ; /* previously preset */\r
+ } else if ((element->steps[0].op == XSLT_OP_ATTR) &&\r
+ (element->steps[0].value2 != NULL) &&\r
+ (element->steps[1].op == XSLT_OP_END)) {\r
+ element->priority = -0.25;\r
+ } else if ((element->steps[0].op == XSLT_OP_NS) &&\r
+ (element->steps[0].value != NULL) &&\r
+ (element->steps[1].op == XSLT_OP_END)) {\r
+ element->priority = -0.25;\r
+ } else if ((element->steps[0].op == XSLT_OP_ATTR) &&\r
+ (element->steps[0].value == NULL) &&\r
+ (element->steps[0].value2 == NULL) &&\r
+ (element->steps[1].op == XSLT_OP_END)) {\r
+ element->priority = -0.5;\r
+ } else if (((element->steps[0].op == XSLT_OP_PI) ||\r
+ (element->steps[0].op == XSLT_OP_TEXT) ||\r
+ (element->steps[0].op == XSLT_OP_ALL) ||\r
+ (element->steps[0].op == XSLT_OP_NODE) ||\r
+ (element->steps[0].op == XSLT_OP_COMMENT)) &&\r
+ (element->steps[1].op == XSLT_OP_END)) {\r
+ element->priority = -0.5;\r
+ } else {\r
+ element->priority = 0.5;\r
+ }\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PATTERN\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCompilePattern : parsed %s, default priority %f\n",\r
+ element->pattern, element->priority);\r
+#endif\r
+ if (pattern[end] == '|')\r
+ end++;\r
+ current = end;\r
+ }\r
+ if (end == 0) {\r
+ xsltTransformError(NULL, style, node,\r
+ "xsltCompilePattern : NULL pattern\n");\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ xsltFreeParserContext(ctxt);\r
+ return(first);\r
+\r
+error:\r
+ if (ctxt != NULL)\r
+ xsltFreeParserContext(ctxt);\r
+ if (first != NULL)\r
+ xsltFreeCompMatchList(first);\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltCompilePattern:\r
+ * @pattern: an XSLT pattern\r
+ * @doc: the containing document\r
+ * @node: the containing element\r
+ * @style: the stylesheet\r
+ * @runtime: the transformation context, if done at run-time\r
+ *\r
+ * Compile the XSLT pattern and generates a list of precompiled form suitable\r
+ * for fast matching.\r
+ *\r
+ * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern\r
+ *\r
+ * Returns the generated pattern list or NULL in case of failure\r
+ */\r
+\r
+xsltCompMatchPtr\r
+xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc,\r
+ xmlNodePtr node, xsltStylesheetPtr style,\r
+ xsltTransformContextPtr runtime) {\r
+ return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltAddTemplate:\r
+ * @style: an XSLT stylesheet\r
+ * @cur: an XSLT template\r
+ * @mode: the mode name or NULL\r
+ * @modeURI: the mode URI or NULL\r
+ *\r
+ * Register the XSLT pattern associated to @cur\r
+ *\r
+ * Returns -1 in case of error, 0 otherwise\r
+ */\r
+int\r
+xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,\r
+ const xmlChar *mode, const xmlChar *modeURI) {\r
+ xsltCompMatchPtr pat, list, *top = NULL, next;\r
+ const xmlChar *name = NULL;\r
+ float priority; /* the priority */\r
+\r
+ if ((style == NULL) || (cur == NULL) || (cur->match == NULL))\r
+ return(-1);\r
+\r
+ priority = cur->priority;\r
+ pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,\r
+ style, NULL, 1);\r
+ while (pat) {\r
+ next = pat->next;\r
+ pat->next = NULL;\r
+ name = NULL;\r
+ \r
+ pat->template = cur;\r
+ if (mode != NULL)\r
+ pat->mode = xmlDictLookup(style->dict, mode, -1);\r
+ if (modeURI != NULL)\r
+ pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);\r
+ if (priority != XSLT_PAT_NO_PRIORITY)\r
+ pat->priority = priority;\r
+\r
+ /*\r
+ * insert it in the hash table list corresponding to its lookup name\r
+ */\r
+ switch (pat->steps[0].op) {\r
+ case XSLT_OP_ATTR:\r
+ if (pat->steps[0].value != NULL)\r
+ name = pat->steps[0].value;\r
+ else\r
+ top = (xsltCompMatchPtr *) &(style->attrMatch);\r
+ break;\r
+ case XSLT_OP_CHILD:\r
+ case XSLT_OP_PARENT:\r
+ case XSLT_OP_ANCESTOR:\r
+ top = (xsltCompMatchPtr *) &(style->elemMatch);\r
+ break;\r
+ case XSLT_OP_ROOT:\r
+ top = (xsltCompMatchPtr *) &(style->rootMatch);\r
+ break;\r
+ case XSLT_OP_KEY:\r
+ top = (xsltCompMatchPtr *) &(style->keyMatch);\r
+ break;\r
+ case XSLT_OP_ID:\r
+ /* TODO optimize ID !!! */\r
+ case XSLT_OP_NS:\r
+ case XSLT_OP_ALL:\r
+ top = (xsltCompMatchPtr *) &(style->elemMatch);\r
+ break;\r
+ case XSLT_OP_END:\r
+ case XSLT_OP_PREDICATE:\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltAddTemplate: invalid compiled pattern\n");\r
+ xsltFreeCompMatch(pat);\r
+ return(-1);\r
+ /*\r
+ * TODO: some flags at the top level about type based patterns\r
+ * would be faster than inclusion in the hash table.\r
+ */\r
+ case XSLT_OP_PI:\r
+ if (pat->steps[0].value != NULL)\r
+ name = pat->steps[0].value;\r
+ else\r
+ top = (xsltCompMatchPtr *) &(style->piMatch);\r
+ break;\r
+ case XSLT_OP_COMMENT:\r
+ top = (xsltCompMatchPtr *) &(style->commentMatch);\r
+ break;\r
+ case XSLT_OP_TEXT:\r
+ top = (xsltCompMatchPtr *) &(style->textMatch);\r
+ break;\r
+ case XSLT_OP_ELEM:\r
+ case XSLT_OP_NODE:\r
+ if (pat->steps[0].value != NULL)\r
+ name = pat->steps[0].value;\r
+ else\r
+ top = (xsltCompMatchPtr *) &(style->elemMatch);\r
+ break;\r
+ }\r
+ if (name != NULL) {\r
+ if (style->templatesHash == NULL) {\r
+ style->templatesHash = xmlHashCreate(1024);\r
+ if (style->templatesHash == NULL) {\r
+ xsltFreeCompMatch(pat);\r
+ return(-1);\r
+ }\r
+ xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);\r
+ } else {\r
+ list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,\r
+ name, mode, modeURI);\r
+ if (list == NULL) {\r
+ xmlHashAddEntry3(style->templatesHash, name,\r
+ mode, modeURI, pat);\r
+ } else {\r
+ /*\r
+ * Note '<=' since one must choose among the matching\r
+ * template rules that are left, the one that occurs\r
+ * last in the stylesheet\r
+ */\r
+ if (list->priority <= pat->priority) {\r
+ pat->next = list;\r
+ xmlHashUpdateEntry3(style->templatesHash, name,\r
+ mode, modeURI, pat, NULL);\r
+ } else {\r
+ while (list->next != NULL) {\r
+ if (list->next->priority <= pat->priority)\r
+ break;\r
+ list = list->next;\r
+ }\r
+ pat->next = list->next;\r
+ list->next = pat;\r
+ }\r
+ }\r
+ }\r
+ } else if (top != NULL) {\r
+ list = *top;\r
+ if (list == NULL) {\r
+ *top = pat;\r
+ pat->next = NULL;\r
+ } else if (list->priority <= pat->priority) {\r
+ pat->next = list;\r
+ *top = pat;\r
+ } else {\r
+ while (list->next != NULL) {\r
+ if (list->next->priority <= pat->priority)\r
+ break;\r
+ list = list->next;\r
+ }\r
+ pat->next = list->next;\r
+ list->next = pat;\r
+ }\r
+ } else {\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltAddTemplate: invalid compiled pattern\n");\r
+ xsltFreeCompMatch(pat);\r
+ return(-1);\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PATTERN\r
+ if (mode)\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "added pattern : '%s' mode '%s' priority %f\n",\r
+ pat->pattern, pat->mode, pat->priority);\r
+ else\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "added pattern : '%s' priority %f\n",\r
+ pat->pattern, pat->priority);\r
+#endif\r
+\r
+ pat = next;\r
+ }\r
+ return(0);\r
+}\r
+\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+static int\r
+xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)\r
+{\r
+ xsltStylesheetPtr style, style2;\r
+ xsltKeyDefPtr keyd, keyd2;\r
+ xsltKeyTablePtr table;\r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL)) {\r
+ xsltTransformError(ctxt, NULL, ctxt->inst,\r
+ "Internal error in xsltComputeAllKeys(): "\r
+ "Bad arguments.\n");\r
+ return(-1);\r
+ }\r
+ \r
+ if (ctxt->document == NULL) {\r
+ /*\r
+ * The document info will only be NULL if we have a RTF.\r
+ */\r
+ if (contextNode->doc->_private != NULL)\r
+ goto doc_info_mismatch;\r
+ /*\r
+ * On-demand creation of the document info (needed for keys).\r
+ */\r
+ ctxt->document = xsltNewDocument(ctxt, contextNode->doc);\r
+ if (ctxt->document == NULL)\r
+ return(-1);\r
+ }\r
+\r
+ if (ctxt->document->nbKeysComputed == ctxt->nbKeys)\r
+ return(0);\r
+ /*\r
+ * TODO: This could be further optimized\r
+ */\r
+ style = ctxt->style;\r
+ while (style) {\r
+ keyd = (xsltKeyDefPtr) style->keys;\r
+ while (keyd != NULL) {\r
+ /*\r
+ * Check if keys with this QName have been already\r
+ * computed.\r
+ */\r
+ table = (xsltKeyTablePtr) ctxt->document->keys;\r
+ while (table) {\r
+ if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&\r
+ xmlStrEqual(keyd->name, table->name) &&\r
+ xmlStrEqual(keyd->nameURI, table->nameURI))\r
+ {\r
+ break;\r
+ } \r
+ table = table->next;\r
+ }\r
+ if (table == NULL) {\r
+ /*\r
+ * Keys with this QName have not been yet computed.\r
+ */\r
+ style2 = ctxt->style;\r
+ while (style2 != NULL) {\r
+ keyd2 = (xsltKeyDefPtr) style2->keys;\r
+ while (keyd2 != NULL) {\r
+ if (((keyd2->nameURI != NULL) ==\r
+ (keyd->nameURI != NULL)) &&\r
+ xmlStrEqual(keyd2->name, keyd->name) &&\r
+ xmlStrEqual(keyd2->nameURI, keyd->nameURI))\r
+ {\r
+ xsltInitCtxtKey(ctxt, ctxt->document, keyd2);\r
+ if (ctxt->document->nbKeysComputed == ctxt->nbKeys)\r
+ return(0);\r
+ }\r
+ keyd2 = keyd2->next;\r
+ }\r
+ style2 = xsltNextImport(style2);\r
+ }\r
+ }\r
+ keyd = keyd->next;\r
+ }\r
+ style = xsltNextImport(style);\r
+ }\r
+ return(0);\r
+\r
+doc_info_mismatch:\r
+ xsltTransformError(ctxt, NULL, ctxt->inst,\r
+ "Internal error in xsltComputeAllKeys(): "\r
+ "The context's document info doesn't match the "\r
+ "document info of the current result tree.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ return(-1);\r
+}\r
+#endif\r
+\r
+/**\r
+ * xsltGetTemplate:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node being processed\r
+ * @style: the current style\r
+ *\r
+ * Finds the template applying to this node, if @style is non-NULL\r
+ * it means one needs to look for the next imported template in scope.\r
+ *\r
+ * Returns the xsltTemplatePtr or NULL if not found\r
+ */\r
+xsltTemplatePtr\r
+xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xsltStylesheetPtr style)\r
+{\r
+ xsltStylesheetPtr curstyle;\r
+ xsltTemplatePtr ret = NULL;\r
+ const xmlChar *name = NULL;\r
+ xsltCompMatchPtr list = NULL;\r
+ float priority;\r
+ int keyed = 0;\r
+\r
+ if ((ctxt == NULL) || (node == NULL))\r
+ return(NULL);\r
+\r
+ if (style == NULL) {\r
+ curstyle = ctxt->style;\r
+ } else {\r
+ curstyle = xsltNextImport(style);\r
+ }\r
+\r
+ while ((curstyle != NULL) && (curstyle != style)) {\r
+ priority = XSLT_PAT_NO_PRIORITY;\r
+ /* TODO : handle IDs/keys here ! */\r
+ if (curstyle->templatesHash != NULL) {\r
+ /*\r
+ * Use the top name as selector\r
+ */\r
+ switch (node->type) {\r
+ case XML_ELEMENT_NODE:\r
+ if (node->name[0] == ' ')\r
+ break;\r
+ case XML_ATTRIBUTE_NODE:\r
+ case XML_PI_NODE:\r
+ name = node->name;\r
+ break;\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_COMMENT_NODE:\r
+ case XML_ENTITY_REF_NODE:\r
+ case XML_ENTITY_NODE:\r
+ case XML_DOCUMENT_TYPE_NODE:\r
+ case XML_DOCUMENT_FRAG_NODE:\r
+ case XML_NOTATION_NODE:\r
+ case XML_DTD_NODE:\r
+ case XML_ELEMENT_DECL:\r
+ case XML_ATTRIBUTE_DECL:\r
+ case XML_ENTITY_DECL:\r
+ case XML_NAMESPACE_DECL:\r
+ case XML_XINCLUDE_START:\r
+ case XML_XINCLUDE_END:\r
+ break;\r
+ default:\r
+ return(NULL);\r
+\r
+ }\r
+ }\r
+ if (name != NULL) {\r
+ /*\r
+ * find the list of applicable expressions based on the name\r
+ */\r
+ list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,\r
+ name, ctxt->mode, ctxt->modeURI);\r
+ } else\r
+ list = NULL;\r
+ while (list != NULL) {\r
+ if (xsltTestCompMatch(ctxt, list, node,\r
+ ctxt->mode, ctxt->modeURI)) {\r
+ ret = list->template;\r
+ priority = list->priority;\r
+ break;\r
+ }\r
+ list = list->next;\r
+ }\r
+ list = NULL;\r
+\r
+ /*\r
+ * find alternate generic matches\r
+ */\r
+ switch (node->type) {\r
+ case XML_ELEMENT_NODE:\r
+ if (node->name[0] == ' ')\r
+ list = curstyle->rootMatch;\r
+ else\r
+ list = curstyle->elemMatch;\r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_ATTRIBUTE_NODE: {\r
+ xmlAttrPtr attr;\r
+\r
+ list = curstyle->attrMatch;\r
+ attr = (xmlAttrPtr) node;\r
+ if (attr->psvi != NULL) keyed = 1;\r
+ break;\r
+ }\r
+ case XML_PI_NODE:\r
+ list = curstyle->piMatch;\r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE: {\r
+ xmlDocPtr doc;\r
+\r
+ list = curstyle->rootMatch;\r
+ doc = (xmlDocPtr) node;\r
+ if (doc->psvi != NULL) keyed = 1;\r
+ break;\r
+ }\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ list = curstyle->textMatch;\r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_COMMENT_NODE:\r
+ list = curstyle->commentMatch;\r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_ENTITY_REF_NODE:\r
+ case XML_ENTITY_NODE:\r
+ case XML_DOCUMENT_TYPE_NODE:\r
+ case XML_DOCUMENT_FRAG_NODE:\r
+ case XML_NOTATION_NODE:\r
+ case XML_DTD_NODE:\r
+ case XML_ELEMENT_DECL:\r
+ case XML_ATTRIBUTE_DECL:\r
+ case XML_ENTITY_DECL:\r
+ case XML_NAMESPACE_DECL:\r
+ case XML_XINCLUDE_START:\r
+ case XML_XINCLUDE_END:\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ while ((list != NULL) &&\r
+ ((ret == NULL) || (list->priority > priority))) {\r
+ if (xsltTestCompMatch(ctxt, list, node,\r
+ ctxt->mode, ctxt->modeURI)) {\r
+ ret = list->template;\r
+ priority = list->priority;\r
+ break;\r
+ }\r
+ list = list->next;\r
+ }\r
+ /*\r
+ * Some of the tests for elements can also apply to documents\r
+ */\r
+ if ((node->type == XML_DOCUMENT_NODE) ||\r
+ (node->type == XML_HTML_DOCUMENT_NODE) ||\r
+ (node->type == XML_TEXT_NODE)) {\r
+ list = curstyle->elemMatch;\r
+ while ((list != NULL) &&\r
+ ((ret == NULL) || (list->priority > priority))) {\r
+ if (xsltTestCompMatch(ctxt, list, node,\r
+ ctxt->mode, ctxt->modeURI)) {\r
+ ret = list->template;\r
+ priority = list->priority;\r
+ break;\r
+ }\r
+ list = list->next;\r
+ }\r
+ } else if ((node->type == XML_PI_NODE) ||\r
+ (node->type == XML_COMMENT_NODE)) {\r
+ list = curstyle->elemMatch;\r
+ while ((list != NULL) &&\r
+ ((ret == NULL) || (list->priority > priority))) {\r
+ if (xsltTestCompMatch(ctxt, list, node,\r
+ ctxt->mode, ctxt->modeURI)) {\r
+ ret = list->template;\r
+ priority = list->priority;\r
+ break;\r
+ }\r
+ list = list->next;\r
+ }\r
+ }\r
+\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+keyed_match:\r
+#endif\r
+ if (keyed) {\r
+ list = curstyle->keyMatch;\r
+ while ((list != NULL) &&\r
+ ((ret == NULL) || (list->priority > priority))) {\r
+ if (xsltTestCompMatch(ctxt, list, node,\r
+ ctxt->mode, ctxt->modeURI)) {\r
+ ret = list->template;\r
+ priority = list->priority;\r
+ break;\r
+ }\r
+ list = list->next;\r
+ }\r
+ }\r
+#ifdef XSLT_REFACTORED_KEYCOMP \r
+ else if (ctxt->hasTemplKeyPatterns &&\r
+ ((ctxt->document == NULL) ||\r
+ (ctxt->document->nbKeysComputed < ctxt->nbKeys)))\r
+ {\r
+ /*\r
+ * Compute all remaining keys for this document.\r
+ *\r
+ * REVISIT TODO: I think this could be further optimized.\r
+ */\r
+ if (xsltComputeAllKeys(ctxt, node) == -1)\r
+ goto error;\r
+\r
+ switch (node->type) {\r
+ case XML_ELEMENT_NODE: \r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_ATTRIBUTE_NODE:\r
+ if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_COMMENT_NODE:\r
+ case XML_PI_NODE: \r
+ if (node->psvi != NULL) keyed = 1;\r
+ break;\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;\r
+ break; \r
+ default:\r
+ break;\r
+ }\r
+ if (keyed)\r
+ goto keyed_match;\r
+ }\r
+#endif /* XSLT_REFACTORED_KEYCOMP */\r
+ if (ret != NULL)\r
+ return(ret);\r
+\r
+ /*\r
+ * Cycle on next curstylesheet import.\r
+ */\r
+ curstyle = xsltNextImport(curstyle);\r
+ }\r
+\r
+error:\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltCleanupTemplates:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Cleanup the state of the templates used by the stylesheet and\r
+ * the ones it imports.\r
+ */\r
+void\r
+xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) {\r
+}\r
+\r
+/**\r
+ * xsltFreeTemplateHashes:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism\r
+ */\r
+void\r
+xsltFreeTemplateHashes(xsltStylesheetPtr style) {\r
+ if (style->templatesHash != NULL)\r
+ xmlHashFree((xmlHashTablePtr) style->templatesHash,\r
+ (xmlHashDeallocator) xsltFreeCompMatchList);\r
+ if (style->rootMatch != NULL)\r
+ xsltFreeCompMatchList(style->rootMatch);\r
+ if (style->keyMatch != NULL)\r
+ xsltFreeCompMatchList(style->keyMatch);\r
+ if (style->elemMatch != NULL)\r
+ xsltFreeCompMatchList(style->elemMatch);\r
+ if (style->attrMatch != NULL)\r
+ xsltFreeCompMatchList(style->attrMatch);\r
+ if (style->parentMatch != NULL)\r
+ xsltFreeCompMatchList(style->parentMatch);\r
+ if (style->textMatch != NULL)\r
+ xsltFreeCompMatchList(style->textMatch);\r
+ if (style->piMatch != NULL)\r
+ xsltFreeCompMatchList(style->piMatch);\r
+ if (style->commentMatch != NULL)\r
+ xsltFreeCompMatchList(style->commentMatch);\r
+}\r
+\r
-/*
- * preproc.c: Preprocessing of style operations
- *
- * References:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * Michael Kay "XSLT Programmer's Reference" pp 637-643
- * Writing Multiple Output Files
- *
- * XSLT-1.1 Working Draft
- * http://www.w3.org/TR/xslt11#multiple-output
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/uri.h>
-#include <libxml/encoding.h>
-#include <libxml/xmlerror.h>
-#include "xslt.h"
-#include "xsltutils.h"
-#include "xsltInternals.h"
-#include "transform.h"
-#include "templates.h"
-#include "variables.h"
-#include "numbersInternals.h"
-#include "preproc.h"
-#include "extra.h"
-#include "imports.h"
-#include "extensions.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_PREPROC
-#endif
-
-const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
-
-/************************************************************************
- * *
- * Grammar checks *
- * *
- ************************************************************************/
-
-#ifdef XSLT_REFACTORED
- /*
- * Grammar checks are now performed in xslt.c.
- */
-#else
-/**
- * xsltCheckTopLevelElement:
- * @style: the XSLT stylesheet
- * @inst: the XSLT instruction
- * @err: raise an error or not
- *
- * Check that the instruction is instanciated as a top level element.
- *
- * Returns -1 in case of error, 0 if failed and 1 in case of success
- */
-static int
-xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
- xmlNodePtr parent;
- if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
- return(-1);
-
- parent = inst->parent;
- if (parent == NULL) {
- if (err) {
- xsltTransformError(NULL, style, inst,
- "internal problem: element has no parent\n");
- style->errors++;
- }
- return(0);
- }
- if ((parent->ns == NULL) ||
- ((parent->ns != inst->ns) &&
- (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
- ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&
- (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {
- if (err) {
- xsltTransformError(NULL, style, inst,
- "element %s only allowed as child of stylesheet\n",
- inst->name);
- style->errors++;
- }
- return(0);
- }
- return(1);
-}
-
-/**
- * xsltCheckInstructionElement:
- * @style: the XSLT stylesheet
- * @inst: the XSLT instruction
- *
- * Check that the instruction is instanciated as an instruction element.
- */
-static void
-xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
- xmlNodePtr parent;
- int has_ext;
-
- if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
- (style->literal_result))
- return;
-
- has_ext = (style->extInfos != NULL);
-
- parent = inst->parent;
- if (parent == NULL) {
- xsltTransformError(NULL, style, inst,
- "internal problem: element has no parent\n");
- style->errors++;
- return;
- }
- while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
- if (((parent->ns == inst->ns) ||
- ((parent->ns != NULL) &&
- (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
- ((xmlStrEqual(parent->name, BAD_CAST "template")) ||
- (xmlStrEqual(parent->name, BAD_CAST "param")) ||
- (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||
- (xmlStrEqual(parent->name, BAD_CAST "variable")))) {
- return;
- }
-
- /*
- * if we are within an extension element all bets are off
- * about the semantic there e.g. xsl:param within func:function
- */
- if ((has_ext) && (parent->ns != NULL) &&
- (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
- return;
-
- parent = parent->parent;
- }
- xsltTransformError(NULL, style, inst,
- "element %s only allowed within a template, variable or param\n",
- inst->name);
- style->errors++;
-}
-
-/**
- * xsltCheckParentElement:
- * @style: the XSLT stylesheet
- * @inst: the XSLT instruction
- * @allow1: allowed parent1
- * @allow2: allowed parent2
- *
- * Check that the instruction is instanciated as the childre of one of the
- * possible parents.
- */
-static void
-xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
- const xmlChar *allow1, const xmlChar *allow2) {
- xmlNodePtr parent;
-
- if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
- (style->literal_result))
- return;
-
- parent = inst->parent;
- if (parent == NULL) {
- xsltTransformError(NULL, style, inst,
- "internal problem: element has no parent\n");
- style->errors++;
- return;
- }
- if (((parent->ns == inst->ns) ||
- ((parent->ns != NULL) &&
- (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
- ((xmlStrEqual(parent->name, allow1)) ||
- (xmlStrEqual(parent->name, allow2)))) {
- return;
- }
-
- if (style->extInfos != NULL) {
- while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
- /*
- * if we are within an extension element all bets are off
- * about the semantic there e.g. xsl:param within func:function
- */
- if ((parent->ns != NULL) &&
- (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
- return;
-
- parent = parent->parent;
- }
- }
- xsltTransformError(NULL, style, inst,
- "element %s is not allowed within that context\n",
- inst->name);
- style->errors++;
-}
-#endif
-
-/************************************************************************
- * *
- * handling of precomputed data *
- * *
- ************************************************************************/
-
-/**
- * xsltNewStylePreComp:
- * @style: the XSLT stylesheet
- * @type: the construct type
- *
- * Create a new XSLT Style precomputed block
- *
- * Returns the newly allocated specialized structure
- * or NULL in case of error
- */
-static xsltStylePreCompPtr
-xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
- xsltStylePreCompPtr cur;
-#ifdef XSLT_REFACTORED
- size_t size;
-#endif
-
- if (style == NULL)
- return(NULL);
-
-#ifdef XSLT_REFACTORED
- /*
- * URGENT TODO: Use specialized factory functions in order
- * to avoid this ugliness.
- */
- switch (type) {
- case XSLT_FUNC_COPY:
- size = sizeof(xsltStyleItemCopy); break;
- case XSLT_FUNC_SORT:
- size = sizeof(xsltStyleItemSort); break;
- case XSLT_FUNC_TEXT:
- size = sizeof(xsltStyleItemText); break;
- case XSLT_FUNC_ELEMENT:
- size = sizeof(xsltStyleItemElement); break;
- case XSLT_FUNC_ATTRIBUTE:
- size = sizeof(xsltStyleItemAttribute); break;
- case XSLT_FUNC_COMMENT:
- size = sizeof(xsltStyleItemComment); break;
- case XSLT_FUNC_PI:
- size = sizeof(xsltStyleItemPI); break;
- case XSLT_FUNC_COPYOF:
- size = sizeof(xsltStyleItemCopyOf); break;
- case XSLT_FUNC_VALUEOF:
- size = sizeof(xsltStyleItemValueOf); break;;
- case XSLT_FUNC_NUMBER:
- size = sizeof(xsltStyleItemNumber); break;
- case XSLT_FUNC_APPLYIMPORTS:
- size = sizeof(xsltStyleItemApplyImports); break;
- case XSLT_FUNC_CALLTEMPLATE:
- size = sizeof(xsltStyleItemCallTemplate); break;
- case XSLT_FUNC_APPLYTEMPLATES:
- size = sizeof(xsltStyleItemApplyTemplates); break;
- case XSLT_FUNC_CHOOSE:
- size = sizeof(xsltStyleItemChoose); break;
- case XSLT_FUNC_IF:
- size = sizeof(xsltStyleItemIf); break;
- case XSLT_FUNC_FOREACH:
- size = sizeof(xsltStyleItemForEach); break;
- case XSLT_FUNC_DOCUMENT:
- size = sizeof(xsltStyleItemDocument); break;
- case XSLT_FUNC_WITHPARAM:
- size = sizeof(xsltStyleItemWithParam); break;
- case XSLT_FUNC_PARAM:
- size = sizeof(xsltStyleItemParam); break;
- case XSLT_FUNC_VARIABLE:
- size = sizeof(xsltStyleItemVariable); break;
- case XSLT_FUNC_WHEN:
- size = sizeof(xsltStyleItemWhen); break;
- case XSLT_FUNC_OTHERWISE:
- size = sizeof(xsltStyleItemOtherwise); break;
- default:
- xsltTransformError(NULL, style, NULL,
- "xsltNewStylePreComp : invalid type %d\n", type);
- style->errors++;
- return(NULL);
- }
- /*
- * Create the structure.
- */
- cur = (xsltStylePreCompPtr) xmlMalloc(size);
- if (cur == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltNewStylePreComp : malloc failed\n");
- style->errors++;
- return(NULL);
- }
- memset(cur, 0, size);
-
-#else /* XSLT_REFACTORED */
- /*
- * Old behaviour.
- */
- cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
- if (cur == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltNewStylePreComp : malloc failed\n");
- style->errors++;
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltStylePreComp));
-#endif /* XSLT_REFACTORED */
-
- /*
- * URGENT TODO: Better to move this to spezialized factory functions.
- */
- cur->type = type;
- switch (cur->type) {
- case XSLT_FUNC_COPY:
- cur->func = (xsltTransformFunction) xsltCopy;break;
- case XSLT_FUNC_SORT:
- cur->func = (xsltTransformFunction) xsltSort;break;
- case XSLT_FUNC_TEXT:
- cur->func = (xsltTransformFunction) xsltText;break;
- case XSLT_FUNC_ELEMENT:
- cur->func = (xsltTransformFunction) xsltElement;break;
- case XSLT_FUNC_ATTRIBUTE:
- cur->func = (xsltTransformFunction) xsltAttribute;break;
- case XSLT_FUNC_COMMENT:
- cur->func = (xsltTransformFunction) xsltComment;break;
- case XSLT_FUNC_PI:
- cur->func = (xsltTransformFunction) xsltProcessingInstruction;
- break;
- case XSLT_FUNC_COPYOF:
- cur->func = (xsltTransformFunction) xsltCopyOf;break;
- case XSLT_FUNC_VALUEOF:
- cur->func = (xsltTransformFunction) xsltValueOf;break;
- case XSLT_FUNC_NUMBER:
- cur->func = (xsltTransformFunction) xsltNumber;break;
- case XSLT_FUNC_APPLYIMPORTS:
- cur->func = (xsltTransformFunction) xsltApplyImports;break;
- case XSLT_FUNC_CALLTEMPLATE:
- cur->func = (xsltTransformFunction) xsltCallTemplate;break;
- case XSLT_FUNC_APPLYTEMPLATES:
- cur->func = (xsltTransformFunction) xsltApplyTemplates;break;
- case XSLT_FUNC_CHOOSE:
- cur->func = (xsltTransformFunction) xsltChoose;break;
- case XSLT_FUNC_IF:
- cur->func = (xsltTransformFunction) xsltIf;break;
- case XSLT_FUNC_FOREACH:
- cur->func = (xsltTransformFunction) xsltForEach;break;
- case XSLT_FUNC_DOCUMENT:
- cur->func = (xsltTransformFunction) xsltDocumentElem;break;
- case XSLT_FUNC_WITHPARAM:
- case XSLT_FUNC_PARAM:
- case XSLT_FUNC_VARIABLE:
- case XSLT_FUNC_WHEN:
- break;
- default:
- if (cur->func == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltNewStylePreComp : no function for type %d\n", type);
- style->errors++;
- }
- }
- cur->next = style->preComps;
- style->preComps = (xsltElemPreCompPtr) cur;
-
- return(cur);
-}
-
-/**
- * xsltFreeStylePreComp:
- * @comp: an XSLT Style precomputed block
- *
- * Free up the memory allocated by @comp
- */
-static void
-xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
- if (comp == NULL)
- return;
-#ifdef XSLT_REFACTORED
- /*
- * URGENT TODO: Implement destructors.
- */
- switch (comp->type) {
- case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
- break;
- case XSLT_FUNC_COPY:
- break;
- case XSLT_FUNC_SORT: {
- xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_TEXT:
- break;
- case XSLT_FUNC_ELEMENT:
- break;
- case XSLT_FUNC_ATTRIBUTE:
- break;
- case XSLT_FUNC_COMMENT:
- break;
- case XSLT_FUNC_PI:
- break;
- case XSLT_FUNC_COPYOF: {
- xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_VALUEOF: {
- xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_NUMBER:
- break;
- case XSLT_FUNC_APPLYIMPORTS:
- break;
- case XSLT_FUNC_CALLTEMPLATE:
- break;
- case XSLT_FUNC_APPLYTEMPLATES: {
- xsltStyleItemApplyTemplatesPtr item =
- (xsltStyleItemApplyTemplatesPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_CHOOSE:
- break;
- case XSLT_FUNC_IF: {
- xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_FOREACH: {
- xsltStyleItemForEachPtr item =
- (xsltStyleItemForEachPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_DOCUMENT:
- break;
- case XSLT_FUNC_WITHPARAM: {
- xsltStyleItemWithParamPtr item =
- (xsltStyleItemWithParamPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_PARAM: {
- xsltStyleItemParamPtr item =
- (xsltStyleItemParamPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_VARIABLE: {
- xsltStyleItemVariablePtr item =
- (xsltStyleItemVariablePtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_WHEN: {
- xsltStyleItemWhenPtr item =
- (xsltStyleItemWhenPtr) comp;
- if (item->comp != NULL)
- xmlXPathFreeCompExpr(item->comp);
- }
- break;
- case XSLT_FUNC_OTHERWISE:
- case XSLT_FUNC_FALLBACK:
- case XSLT_FUNC_MESSAGE:
- case XSLT_FUNC_INCLUDE:
- case XSLT_FUNC_ATTRSET:
-
- break;
- default:
- /* TODO: Raise error. */
- break;
- }
-#else
- if (comp->comp != NULL)
- xmlXPathFreeCompExpr(comp->comp);
- if (comp->nsList != NULL)
- xmlFree(comp->nsList);
-#endif
-
- xmlFree(comp);
-}
-
-
-/************************************************************************
- * *
- * XSLT-1.1 extensions *
- * *
- ************************************************************************/
-
-/**
- * xsltDocumentComp:
- * @style: the XSLT stylesheet
- * @inst: the instruction in the stylesheet
- * @function: unused
- *
- * Pre process an XSLT-1.1 document element
- *
- * Returns a precompiled data structure for the element
- */
-xsltElemPreCompPtr
-xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
- xsltTransformFunction function ATTRIBUTE_UNUSED) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemDocumentPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *filename = NULL;
-
- /*
- * As of 2006-03-30, this function is currently defined in Libxslt
- * to be used for:
- * (in libxslt/extra.c)
- * "output" in XSLT_SAXON_NAMESPACE
- * "write" XSLT_XALAN_NAMESPACE
- * "document" XSLT_XT_NAMESPACE
- * "document" XSLT_NAMESPACE (from the abandoned old working
- * draft of XSLT 1.1)
- * (in libexslt/common.c)
- * "document" in EXSLT_COMMON_NAMESPACE
- */
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemDocumentPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
-#endif
-
- if (comp == NULL)
- return (NULL);
- comp->inst = inst;
- comp->ver11 = 0;
-
- if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
-#ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found saxon:output extension\n");
-#endif
- /*
- * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
- * (http://icl.com/saxon)
- * The @file is in no namespace; it is an AVT.
- * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)
- *
- * TODO: Do we need not to check the namespace here?
- */
- filename = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"file",
- NULL, &comp->has_filename);
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
-#ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found xalan:write extension\n");
-#endif
- /* the filename need to be interpreted */
- /*
- * TODO: Is "filename need to be interpreted" meant to be a todo?
- * Where will be the filename of xalan:write be processed?
- *
- * TODO: Do we need not to check the namespace here?
- * The extension ns is "http://xml.apache.org/xalan/redirect".
- * See http://xml.apache.org/xalan-j/extensionslib.html.
- */
- } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
- if (inst->ns != NULL) {
- if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {
- /*
- * Mark the instruction as being of
- * XSLT version 1.1 (abandoned).
- */
- comp->ver11 = 1;
-#ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found xslt11:document construct\n");
-#endif
- } else {
- if (xmlStrEqual(inst->ns->href,
- (const xmlChar *)"http://exslt.org/common")) {
- /* EXSLT. */
-#ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found exslt:document extension\n");
-#endif
- } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {
- /* James Clark's XT. */
-#ifdef WITH_XSLT_DEBUG_EXTRA
- xsltGenericDebug(xsltGenericDebugContext,
- "Found xt:document extension\n");
-#endif
- }
- }
- }
- /*
- * The element "document" is used in conjunction with the
- * following namespaces:
- *
- * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)
- * <!ELEMENT xsl:document %template;>
- * <!ATTLIST xsl:document
- * href %avt; #REQUIRED
- * @href is an AVT
- * IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,
- * it was removed and isn't available in XSLT 1.1 anymore.
- * In XSLT 2.0 it was renamed to xsl:result-document.
- *
- * All other attributes are identical to the attributes
- * on xsl:output
- *
- * 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)
- * <exsl:document
- * href = { uri-reference }
- * TODO: is @href is an AVT?
- *
- * 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)
- * Example: <xt:document method="xml" href="myFile.xml">
- * TODO: is @href is an AVT?
- *
- * In all cases @href is in no namespace.
- */
- filename = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"href", NULL, &comp->has_filename);
- }
- if (!comp->has_filename) {
- goto error;
- }
- comp->filename = filename;
-
-error:
- return ((xsltElemPreCompPtr) comp);
-}
-
-/************************************************************************
- * *
- * Most of the XSLT-1.0 transformations *
- * *
- ************************************************************************/
-
-/**
- * xsltSortComp:
- * @style: the XSLT stylesheet
- * @inst: the xslt sort node
- *
- * Process the xslt sort node on the source node
- */
-static void
-xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemSortPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"data-type",
- NULL, &comp->has_stype);
- if (comp->stype != NULL) {
- if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
- comp->number = 0;
- else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
- comp->number = 1;
- else {
- xsltTransformError(NULL, style, inst,
- "xsltSortComp: no support for data-type = %s\n", comp->stype);
- comp->number = 0; /* use default */
- if (style != NULL) style->warnings++;
- }
- }
- comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"order",
- NULL, &comp->has_order);
- if (comp->order != NULL) {
- if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
- comp->descending = 0;
- else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
- comp->descending = 1;
- else {
- xsltTransformError(NULL, style, inst,
- "xsltSortComp: invalid value %s for order\n", comp->order);
- comp->descending = 0; /* use default */
- if (style != NULL) style->warnings++;
- }
- }
- comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"case-order",
- NULL, &comp->has_use);
- if (comp->case_order != NULL) {
- if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))
- comp->lower_first = 0;
- else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))
- comp->lower_first = 1;
- else {
- xsltTransformError(NULL, style, inst,
- "xsltSortComp: invalid value %s for order\n", comp->order);
- comp->lower_first = 0; /* use default */
- if (style != NULL) style->warnings++;
- }
- }
-
- comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"lang",
- NULL, &comp->has_lang);
-
- comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
- if (comp->select == NULL) {
- /*
- * The default value of the select attribute is ., which will
- * cause the string-value of the current node to be used as
- * the sort key.
- */
- comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
- }
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsltSortComp: could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- if (inst->children != NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:sort : is not empty\n");
- if (style != NULL) style->errors++;
- }
-}
-
-/**
- * xsltCopyComp:
- * @style: the XSLT stylesheet
- * @inst: the xslt copy node
- *
- * Process the xslt copy node on the source node
- */
-static void
-xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemCopyPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
-
- comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
- XSLT_NAMESPACE);
- if (comp->use == NULL)
- comp->has_use = 0;
- else
- comp->has_use = 1;
-}
-
-#ifdef XSLT_REFACTORED
- /* Enable if ever needed for xsl:text. */
-#else
-/**
- * xsltTextComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt text node
- *
- * TODO: This function is obsolete, since xsl:text won't
- * be compiled, but removed from the tree.
- *
- * Process the xslt text node on the source node
- */
-static void
-xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemTextPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
-#endif
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
- comp->noescape = 0;
-
- prop = xsltGetCNsProp(style, inst,
- (const xmlChar *)"disable-output-escaping",
- XSLT_NAMESPACE);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
- comp->noescape = 1;
- } else if (!xmlStrEqual(prop,
- (const xmlChar *)"no")){
- xsltTransformError(NULL, style, inst,
- "xsl:text: disable-output-escaping allows only yes or no\n");
- if (style != NULL) style->warnings++;
- }
- }
-}
-#endif /* else of XSLT_REFACTORED */
-
-/**
- * xsltElementComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt element node
- *
- * Process the xslt element node on the source node
- */
-static void
-xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemElementPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- /*
- * <xsl:element
- * name = { qname }
- * namespace = { uri-reference }
- * use-attribute-sets = qnames>
- * <!-- Content: template -->
- * </xsl:element>
- */
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * Attribute "name".
- */
- /*
- * TODO: Precompile the AVT. See bug #344894.
- */
- comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"name", NULL, &comp->has_name);
- if (! comp->has_name) {
- xsltTransformError(NULL, style, inst,
- "xsl:element: The attribute 'name' is missing.\n");
- style->errors++;
- goto error;
- }
- /*
- * Attribute "namespace".
- */
- /*
- * TODO: Precompile the AVT. See bug #344894.
- */
- comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"namespace", NULL, &comp->has_ns);
-
- if (comp->name != NULL) {
- if (xmlValidateQName(comp->name, 0)) {
- xsltTransformError(NULL, style, inst,
- "xsl:element: The value '%s' of the attribute 'name' is "
- "not a valid QName.\n", comp->name);
- style->errors++;
- } else {
- const xmlChar *prefix = NULL, *name;
-
- name = xsltSplitQName(style->dict, comp->name, &prefix);
- if (comp->has_ns == 0) {
- xmlNsPtr ns;
-
- /*
- * SPEC XSLT 1.0:
- * "If the namespace attribute is not present, then the QName is
- * expanded into an expanded-name using the namespace declarations
- * in effect for the xsl:element element, including any default
- * namespace declaration.
- */
- ns = xmlSearchNs(inst->doc, inst, prefix);
- if (ns != NULL) {
- comp->ns = xmlDictLookup(style->dict, ns->href, -1);
- comp->has_ns = 1;
-#ifdef XSLT_REFACTORED
- comp->nsPrefix = prefix;
- comp->name = name;
-#endif
- } else if (prefix != NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:element: The prefixed QName '%s' "
- "has no namespace binding in scope in the "
- "stylesheet; this is an error, since the namespace was "
- "not specified by the instruction itself.\n", comp->name);
- style->errors++;
- }
- }
- if ((prefix != NULL) &&
- (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
- {
- /*
- * Mark is to be skipped.
- */
- comp->has_name = 0;
- }
- }
- }
- /*
- * Attribute "use-attribute-sets",
- */
- comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"use-attribute-sets",
- NULL, &comp->has_use);
-
-error:
- return;
-}
-
-/**
- * xsltAttributeComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt attribute node
- *
- * Process the xslt attribute node on the source node
- */
-static void
-xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemAttributePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- /*
- * <xsl:attribute
- * name = { qname }
- * namespace = { uri-reference }>
- * <!-- Content: template -->
- * </xsl:attribute>
- */
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
- XSLT_FUNC_ATTRIBUTE);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * Attribute "name".
- */
- /*
- * TODO: Precompile the AVT. See bug #344894.
- */
- comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"name",
- NULL, &comp->has_name);
- if (! comp->has_name) {
- xsltTransformError(NULL, style, inst,
- "xsl:attribute: The attribute 'name' is missing.\n");
- style->errors++;
- return;
- }
- /*
- * Attribute "namespace".
- */
- /*
- * TODO: Precompile the AVT. See bug #344894.
- */
- comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"namespace",
- NULL, &comp->has_ns);
-
- if (comp->name != NULL) {
- if (xmlValidateQName(comp->name, 0)) {
- xsltTransformError(NULL, style, inst,
- "xsl:attribute: The value '%s' of the attribute 'name' is "
- "not a valid QName.\n", comp->name);
- style->errors++;
- } else {
- const xmlChar *prefix = NULL, *name;
-
- name = xsltSplitQName(style->dict, comp->name, &prefix);
- if (prefix != NULL) {
- if (comp->has_ns == 0) {
- xmlNsPtr ns;
-
- /*
- * SPEC XSLT 1.0:
- * "If the namespace attribute is not present, then the
- * QName is expanded into an expanded-name using the
- * namespace declarations in effect for the xsl:element
- * element, including any default namespace declaration.
- */
- ns = xmlSearchNs(inst->doc, inst, prefix);
- if (ns != NULL) {
- comp->ns = xmlDictLookup(style->dict, ns->href, -1);
- comp->has_ns = 1;
-#ifdef XSLT_REFACTORED
- comp->nsPrefix = prefix;
- comp->name = name;
-#endif
- } else {
- xsltTransformError(NULL, style, inst,
- "xsl:attribute: The prefixed QName '%s' "
- "has no namespace binding in scope in the "
- "stylesheet; this is an error, since the "
- "namespace was not specified by the instruction "
- "itself.\n", comp->name);
- style->errors++;
- }
- }
- if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
- /*
- * SPEC XSLT 1.0:
- * "It is an error if the string that results from
- * instantiating the attribute value template is not a
- * QName or is the string xmlns. An XSLT processor may
- * signal the error; if it does not signal the error,
- * it must recover by not adding the attribute to the
- * result tree."
- *
- * Reject a prefix of "xmlns". Mark to be skipped.
- */
- comp->has_name = 0;
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAttribute: xmlns prefix forbidden\n");
-#endif
- return;
- }
-
- }
- }
- }
-}
-
-/**
- * xsltCommentComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt comment node
- *
- * Process the xslt comment node on the source node
- */
-static void
-xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemCommentPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-}
-
-/**
- * xsltProcessingInstructionComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt processing-instruction node
- *
- * Process the xslt processing-instruction node on the source node
- */
-static void
-xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemPIPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"name",
- XSLT_NAMESPACE, &comp->has_name);
-}
-
-/**
- * xsltCopyOfComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt copy-of node
- *
- * Process the xslt copy-of node on the source node
- */
-static void
-xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemCopyOfPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:copy-of : select is missing\n");
- if (style != NULL) style->errors++;
- return;
- }
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:copy-of : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
-}
-
-/**
- * xsltValueOfComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt value-of node
- *
- * Process the xslt value-of node on the source node
- */
-static void
-xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemValueOfPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- prop = xsltGetCNsProp(style, inst,
- (const xmlChar *)"disable-output-escaping",
- XSLT_NAMESPACE);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
- comp->noescape = 1;
- } else if (!xmlStrEqual(prop,
- (const xmlChar *)"no")){
- xsltTransformError(NULL, style, inst,
-"xsl:value-of : disable-output-escaping allows only yes or no\n");
- if (style != NULL) style->warnings++;
- }
- }
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:value-of : select is missing\n");
- if (style != NULL) style->errors++;
- return;
- }
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:value-of : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
-}
-
-/**
- * xsltWithParamComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt with-param node
- *
- * Process the xslt with-param node on the source node
- * Allowed parents: xsl:call-template, xsl:apply-templates.
- * <xsl:with-param
- * name = qname
- * select = expression>
- * <!-- Content: template -->
- * </xsl:with-param>
- */
-static void
-xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemWithParamPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * The full namespace resolution can be done statically
- */
- prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:with-param : name is missing\n");
- if (style != NULL) style->errors++;
- } else {
- const xmlChar *URI;
-
- URI = xsltGetQNameURI2(style, inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else {
- comp->name = prop;
- comp->has_name = 1;
- if (URI != NULL) {
- comp->ns = xmlStrdup(URI);
- comp->has_ns = 1;
- } else {
- comp->has_ns = 0;
- }
- }
- }
-
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select != NULL) {
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:param : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- if (inst->children != NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:param : content should be empty since select is present \n");
- if (style != NULL) style->warnings++;
- }
- }
-}
-
-/**
- * xsltNumberComp:
- * @style: an XSLT compiled stylesheet
- * @cur: the xslt number node
- *
- * Process the xslt number node on the source node
- */
-static void
-xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemNumberPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (cur == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
-#endif
-
- if (comp == NULL)
- return;
- cur->psvi = comp;
-
- if ((style == NULL) || (cur == NULL))
- return;
-
- comp->numdata.doc = cur->doc;
- comp->numdata.node = cur;
- comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
- XSLT_NAMESPACE);
-
- prop = xsltEvalStaticAttrValueTemplate(style, cur,
- (const xmlChar *)"format",
- XSLT_NAMESPACE, &comp->numdata.has_format);
- if (comp->numdata.has_format == 0) {
- comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);
- } else {
- comp->numdata.format = prop;
- }
-
- comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
- XSLT_NAMESPACE);
- comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
- XSLT_NAMESPACE);
-
- prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
- if (prop != NULL) {
- if (xmlStrEqual(prop, BAD_CAST("single")) ||
- xmlStrEqual(prop, BAD_CAST("multiple")) ||
- xmlStrEqual(prop, BAD_CAST("any"))) {
- comp->numdata.level = prop;
- } else {
- xsltTransformError(NULL, style, cur,
- "xsl:number : invalid value %s for level\n", prop);
- if (style != NULL) style->warnings++;
- xmlFree((void *)(prop));
- }
- }
-
- prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
- if (prop != NULL) {
- XSLT_TODO; /* xsl:number lang attribute */
- xmlFree((void *)prop);
- }
-
- prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
- if (prop != NULL) {
- if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
- xsltTransformError(NULL, style, cur,
- "xsl:number : letter-value 'alphabetic' not implemented\n");
- if (style != NULL) style->warnings++;
- XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
- } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
- xsltTransformError(NULL, style, cur,
- "xsl:number : letter-value 'traditional' not implemented\n");
- if (style != NULL) style->warnings++;
- XSLT_TODO; /* xsl:number letter-value attribute traditional */
- } else {
- xsltTransformError(NULL, style, cur,
- "xsl:number : invalid value %s for letter-value\n", prop);
- if (style != NULL) style->warnings++;
- }
- }
-
- prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
- XSLT_NAMESPACE);
- if (prop != NULL) {
- comp->numdata.groupingCharacterLen = xmlStrlen(prop);
- comp->numdata.groupingCharacter =
- xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
- }
-
- prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
- if (prop != NULL) {
- sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
- } else {
- comp->numdata.groupingCharacter = 0;
- }
-
- /* Set default values */
- if (comp->numdata.value == NULL) {
- if (comp->numdata.level == NULL) {
- comp->numdata.level = xmlDictLookup(style->dict,
- BAD_CAST"single", 6);
- }
- }
-
-}
-
-/**
- * xsltApplyImportsComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt apply-imports node
- *
- * Process the xslt apply-imports node on the source node
- */
-static void
-xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemApplyImportsPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-}
-
-/**
- * xsltCallTemplateComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt call-template node
- *
- * Process the xslt call-template node on the source node
- */
-static void
-xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemCallTemplatePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemCallTemplatePtr)
- xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * The full template resolution can be done statically
- */
- prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:call-template : name is missing\n");
- if (style != NULL) style->errors++;
- } else {
- const xmlChar *URI;
-
- URI = xsltGetQNameURI2(style, inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else {
- comp->name = prop;
- comp->has_name = 1;
- if (URI != NULL) {
- comp->ns = URI;
- comp->has_ns = 1;
- } else {
- comp->has_ns = 0;
- }
- }
- comp->templ = NULL;
- }
-}
-
-/**
- * xsltApplyTemplatesComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the apply-templates node
- *
- * Process the apply-templates node on the source node
- */
-static void
-xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemApplyTemplatesPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemApplyTemplatesPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * Get mode if any
- */
- prop = xsltGetCNsProp(style, inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
- if (prop != NULL) {
- const xmlChar *URI;
-
- URI = xsltGetQNameURI2(style, inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else {
- comp->mode = xmlDictLookup(style->dict, prop, -1);
- if (URI != NULL) {
- comp->modeURI = xmlDictLookup(style->dict, URI, -1);
- } else {
- comp->modeURI = NULL;
- }
- }
- }
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select != NULL) {
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:apply-templates : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- }
-
- /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
-}
-
-/**
- * xsltChooseComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt choose node
- *
- * Process the xslt choose node on the source node
- */
-static void
-xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemChoosePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemChoosePtr)
- xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-}
-
-/**
- * xsltIfComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt if node
- *
- * Process the xslt if node on the source node
- */
-static void
-xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemIfPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemIfPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_IF);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
- if (comp->test == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:if : test is not defined\n");
- if (style != NULL) style->errors++;
- return;
- }
- comp->comp = xsltXPathCompile(style, comp->test);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:if : could not compile test expression '%s'\n",
- comp->test);
- if (style != NULL) style->errors++;
- }
-}
-
-/**
- * xsltWhenComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt if node
- *
- * Process the xslt if node on the source node
- */
-static void
-xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemWhenPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemWhenPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
- if (comp->test == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:when : test is not defined\n");
- if (style != NULL) style->errors++;
- return;
- }
- comp->comp = xsltXPathCompile(style, comp->test);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:when : could not compile test expression '%s'\n",
- comp->test);
- if (style != NULL) style->errors++;
- }
-}
-
-/**
- * xsltForEachComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt for-each node
- *
- * Process the xslt for-each node on the source node
- */
-static void
-xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemForEachPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemForEachPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:for-each : select is missing\n");
- if (style != NULL) style->errors++;
- } else {
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:for-each : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- }
- /* TODO: handle and skip the xsl:sort */
-}
-
-/**
- * xsltVariableComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt variable node
- *
- * Process the xslt variable node on the source node
- */
-static void
-xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemVariablePtr)
- xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * The full template resolution can be done statically
- */
- prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:variable : name is missing\n");
- if (style != NULL) style->errors++;
- } else {
- const xmlChar *URI;
-
- URI = xsltGetQNameURI2(style, inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else {
- comp->name = prop;
- comp->has_name = 1;
- if (URI != NULL) {
- comp->ns = xmlDictLookup(style->dict, URI, -1);
- comp->has_ns = 1;
- } else {
- comp->has_ns = 0;
- }
- }
- }
-
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select != NULL) {
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:variable : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- if (inst->children != NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:variable : content should be empty since select is present \n");
- if (style != NULL) style->warnings++;
- }
- }
-}
-
-/**
- * xsltParamComp:
- * @style: an XSLT compiled stylesheet
- * @inst: the xslt param node
- *
- * Process the xslt param node on the source node
- */
-static void
-xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- const xmlChar *prop;
-
- if ((style == NULL) || (inst == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemParamPtr)
- xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
-#else
- comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
-#endif
-
- if (comp == NULL)
- return;
- inst->psvi = comp;
- comp->inst = inst;
-
- /*
- * The full template resolution can be done statically
- */
- prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:param : name is missing\n");
- if (style != NULL) style->errors++;
- } else {
- const xmlChar *URI;
-
- URI = xsltGetQNameURI2(style, inst, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- } else {
- comp->name = prop;
- comp->has_name = 1;
- if (URI != NULL) {
- comp->ns = xmlStrdup(URI);
- comp->has_ns = 1;
- } else {
- comp->has_ns = 0;
- }
- }
- }
-
- comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
- XSLT_NAMESPACE);
- if (comp->select != NULL) {
- comp->comp = xsltXPathCompile(style, comp->select);
- if (comp->comp == NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:param : could not compile select expression '%s'\n",
- comp->select);
- if (style != NULL) style->errors++;
- }
- if (inst->children != NULL) {
- xsltTransformError(NULL, style, inst,
- "xsl:param : content should be empty since select is present \n");
- if (style != NULL) style->warnings++;
- }
- }
-}
-
-/************************************************************************
- * *
- * Generic interface *
- * *
- ************************************************************************/
-
-/**
- * xsltFreeStylePreComps:
- * @style: an XSLT transformation context
- *
- * Free up the memory allocated by all precomputed blocks
- */
-void
-xsltFreeStylePreComps(xsltStylesheetPtr style) {
- xsltElemPreCompPtr cur, next;
-
- if (style == NULL)
- return;
-
- cur = style->preComps;
- while (cur != NULL) {
- next = cur->next;
- if (cur->type == XSLT_FUNC_EXTENSION)
- cur->free(cur);
- else
- xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
- cur = next;
- }
-}
-
-#ifdef XSLT_REFACTORED
-
-/**
- * xsltStylePreCompute:
- * @style: the XSLT stylesheet
- * @node: the element in the XSLT namespace
- *
- * Precompute an XSLT element.
- * This expects the type of the element to be already
- * set in style->compCtxt->inode->type;
- */
-void
-xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {
- /*
- * The xsltXSLTElemMarker marker was set beforehand by
- * the parsing mechanism for all elements in the XSLT namespace.
- */
- if (style == NULL) {
- if (node != NULL)
- node->psvi = NULL;
- return;
- }
- if (node == NULL)
- return;
- if (! IS_XSLT_ELEM_FAST(node))
- return;
-
- node->psvi = NULL;
- if (XSLT_CCTXT(style)->inode->type != 0) {
- switch (XSLT_CCTXT(style)->inode->type) {
- case XSLT_FUNC_APPLYTEMPLATES:
- xsltApplyTemplatesComp(style, node);
- break;
- case XSLT_FUNC_WITHPARAM:
- xsltWithParamComp(style, node);
- break;
- case XSLT_FUNC_VALUEOF:
- xsltValueOfComp(style, node);
- break;
- case XSLT_FUNC_COPY:
- xsltCopyComp(style, node);
- break;
- case XSLT_FUNC_COPYOF:
- xsltCopyOfComp(style, node);
- break;
- case XSLT_FUNC_IF:
- xsltIfComp(style, node);
- break;
- case XSLT_FUNC_CHOOSE:
- xsltChooseComp(style, node);
- break;
- case XSLT_FUNC_WHEN:
- xsltWhenComp(style, node);
- break;
- case XSLT_FUNC_OTHERWISE:
- /* NOP yet */
- return;
- case XSLT_FUNC_FOREACH:
- xsltForEachComp(style, node);
- break;
- case XSLT_FUNC_APPLYIMPORTS:
- xsltApplyImportsComp(style, node);
- break;
- case XSLT_FUNC_ATTRIBUTE:
- xsltAttributeComp(style, node);
- break;
- case XSLT_FUNC_ELEMENT:
- xsltElementComp(style, node);
- break;
- case XSLT_FUNC_SORT:
- xsltSortComp(style, node);
- break;
- case XSLT_FUNC_COMMENT:
- xsltCommentComp(style, node);
- break;
- case XSLT_FUNC_NUMBER:
- xsltNumberComp(style, node);
- break;
- case XSLT_FUNC_PI:
- xsltProcessingInstructionComp(style, node);
- break;
- case XSLT_FUNC_CALLTEMPLATE:
- xsltCallTemplateComp(style, node);
- break;
- case XSLT_FUNC_PARAM:
- xsltParamComp(style, node);
- break;
- case XSLT_FUNC_VARIABLE:
- xsltVariableComp(style, node);
- break;
- case XSLT_FUNC_FALLBACK:
- /* NOP yet */
- return;
- case XSLT_FUNC_DOCUMENT:
- /* The extra one */
- node->psvi = (void *) xsltDocumentComp(style, node,
- (xsltTransformFunction) xsltDocumentElem);
- break;
- case XSLT_FUNC_MESSAGE:
- /* NOP yet */
- return;
- default:
- /*
- * NOTE that xsl:text, xsl:template, xsl:stylesheet,
- * xsl:transform, xsl:import, xsl:include are not expected
- * to be handed over to this function.
- */
- xsltTransformError(NULL, style, node,
- "Internal error: (xsltStylePreCompute) cannot handle "
- "the XSLT element '%s'.\n", node->name);
- style->errors++;
- return;
- }
- } else {
- /*
- * Fallback to string comparison.
- */
- if (IS_XSLT_NAME(node, "apply-templates")) {
- xsltApplyTemplatesComp(style, node);
- } else if (IS_XSLT_NAME(node, "with-param")) {
- xsltWithParamComp(style, node);
- } else if (IS_XSLT_NAME(node, "value-of")) {
- xsltValueOfComp(style, node);
- } else if (IS_XSLT_NAME(node, "copy")) {
- xsltCopyComp(style, node);
- } else if (IS_XSLT_NAME(node, "copy-of")) {
- xsltCopyOfComp(style, node);
- } else if (IS_XSLT_NAME(node, "if")) {
- xsltIfComp(style, node);
- } else if (IS_XSLT_NAME(node, "choose")) {
- xsltChooseComp(style, node);
- } else if (IS_XSLT_NAME(node, "when")) {
- xsltWhenComp(style, node);
- } else if (IS_XSLT_NAME(node, "otherwise")) {
- /* NOP yet */
- return;
- } else if (IS_XSLT_NAME(node, "for-each")) {
- xsltForEachComp(style, node);
- } else if (IS_XSLT_NAME(node, "apply-imports")) {
- xsltApplyImportsComp(style, node);
- } else if (IS_XSLT_NAME(node, "attribute")) {
- xsltAttributeComp(style, node);
- } else if (IS_XSLT_NAME(node, "element")) {
- xsltElementComp(style, node);
- } else if (IS_XSLT_NAME(node, "sort")) {
- xsltSortComp(style, node);
- } else if (IS_XSLT_NAME(node, "comment")) {
- xsltCommentComp(style, node);
- } else if (IS_XSLT_NAME(node, "number")) {
- xsltNumberComp(style, node);
- } else if (IS_XSLT_NAME(node, "processing-instruction")) {
- xsltProcessingInstructionComp(style, node);
- } else if (IS_XSLT_NAME(node, "call-template")) {
- xsltCallTemplateComp(style, node);
- } else if (IS_XSLT_NAME(node, "param")) {
- xsltParamComp(style, node);
- } else if (IS_XSLT_NAME(node, "variable")) {
- xsltVariableComp(style, node);
- } else if (IS_XSLT_NAME(node, "fallback")) {
- /* NOP yet */
- return;
- } else if (IS_XSLT_NAME(node, "document")) {
- /* The extra one */
- node->psvi = (void *) xsltDocumentComp(style, node,
- (xsltTransformFunction) xsltDocumentElem);
- } else if (IS_XSLT_NAME(node, "output")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "preserve-space")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "strip-space")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "key")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "message")) {
- return;
- } else if (IS_XSLT_NAME(node, "attribute-set")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "namespace-alias")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "decimal-format")) {
- /* Top-level */
- return;
- } else if (IS_XSLT_NAME(node, "include")) {
- /* Top-level */
- } else {
- /*
- * NOTE that xsl:text, xsl:template, xsl:stylesheet,
- * xsl:transform, xsl:import, xsl:include are not expected
- * to be handed over to this function.
- */
- xsltTransformError(NULL, style, node,
- "Internal error: (xsltStylePreCompute) cannot handle "
- "the XSLT element '%s'.\n", node->name);
- style->errors++;
- return;
- }
- }
- /*
- * Assign the current list of in-scope namespaces to the
- * item. This is needed for XPath expressions.
- */
- if (node->psvi != NULL) {
- ((xsltStylePreCompPtr) node->psvi)->inScopeNs =
- XSLT_CCTXT(style)->inode->inScopeNs;
- }
-}
-
-#else
-
-/**
- * xsltStylePreCompute:
- * @style: the XSLT stylesheet
- * @inst: the instruction in the stylesheet
- *
- * Precompute an XSLT stylesheet element
- */
-void
-xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
- /*
- * URGENT TODO: Normally inst->psvi Should never be reserved here,
- * BUT: since if we include the same stylesheet from
- * multiple imports, then the stylesheet will be parsed
- * again. We simply must not try to compute the stylesheet again.
- * TODO: Get to the point where we don't need to query the
- * namespace- and local-name of the node, but can evaluate this
- * using cctxt->style->inode->category;
- */
- if (inst->psvi != NULL)
- return;
-
- if (IS_XSLT_ELEM(inst)) {
- xsltStylePreCompPtr cur;
-
- if (IS_XSLT_NAME(inst, "apply-templates")) {
- xsltCheckInstructionElement(style, inst);
- xsltApplyTemplatesComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "with-param")) {
- xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
- BAD_CAST "call-template");
- xsltWithParamComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "value-of")) {
- xsltCheckInstructionElement(style, inst);
- xsltValueOfComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "copy")) {
- xsltCheckInstructionElement(style, inst);
- xsltCopyComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "copy-of")) {
- xsltCheckInstructionElement(style, inst);
- xsltCopyOfComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "if")) {
- xsltCheckInstructionElement(style, inst);
- xsltIfComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "when")) {
- xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
- xsltWhenComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "choose")) {
- xsltCheckInstructionElement(style, inst);
- xsltChooseComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "for-each")) {
- xsltCheckInstructionElement(style, inst);
- xsltForEachComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "apply-imports")) {
- xsltCheckInstructionElement(style, inst);
- xsltApplyImportsComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "attribute")) {
- xmlNodePtr parent = inst->parent;
-
- if ((parent == NULL) || (parent->ns == NULL) ||
- ((parent->ns != inst->ns) &&
- (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
- (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {
- xsltCheckInstructionElement(style, inst);
- }
- xsltAttributeComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "element")) {
- xsltCheckInstructionElement(style, inst);
- xsltElementComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "text")) {
- xsltCheckInstructionElement(style, inst);
- xsltTextComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "sort")) {
- xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
- BAD_CAST "for-each");
- xsltSortComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "comment")) {
- xsltCheckInstructionElement(style, inst);
- xsltCommentComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "number")) {
- xsltCheckInstructionElement(style, inst);
- xsltNumberComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
- xsltCheckInstructionElement(style, inst);
- xsltProcessingInstructionComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "call-template")) {
- xsltCheckInstructionElement(style, inst);
- xsltCallTemplateComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "param")) {
- if (xsltCheckTopLevelElement(style, inst, 0) == 0)
- xsltCheckInstructionElement(style, inst);
- xsltParamComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "variable")) {
- if (xsltCheckTopLevelElement(style, inst, 0) == 0)
- xsltCheckInstructionElement(style, inst);
- xsltVariableComp(style, inst);
- } else if (IS_XSLT_NAME(inst, "otherwise")) {
- xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
- xsltCheckInstructionElement(style, inst);
- return;
- } else if (IS_XSLT_NAME(inst, "template")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "output")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "preserve-space")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "strip-space")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
- (IS_XSLT_NAME(inst, "transform"))) {
- xmlNodePtr parent = inst->parent;
-
- if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
- xsltTransformError(NULL, style, inst,
- "element %s only allowed only as root element\n",
- inst->name);
- style->errors++;
- }
- return;
- } else if (IS_XSLT_NAME(inst, "key")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "message")) {
- xsltCheckInstructionElement(style, inst);
- return;
- } else if (IS_XSLT_NAME(inst, "attribute-set")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "include")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "import")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "decimal-format")) {
- xsltCheckTopLevelElement(style, inst, 1);
- return;
- } else if (IS_XSLT_NAME(inst, "fallback")) {
- xsltCheckInstructionElement(style, inst);
- return;
- } else if (IS_XSLT_NAME(inst, "document")) {
- xsltCheckInstructionElement(style, inst);
- inst->psvi = (void *) xsltDocumentComp(style, inst,
- (xsltTransformFunction) xsltDocumentElem);
- } else {
- xsltTransformError(NULL, style, inst,
- "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
- if (style != NULL) style->warnings++;
- }
-
- cur = (xsltStylePreCompPtr) inst->psvi;
- /*
- * A ns-list is build for every XSLT item in the
- * node-tree. This is needed for XPath expressions.
- */
- if (cur != NULL) {
- int i = 0;
-
- cur->nsList = xmlGetNsList(inst->doc, inst);
- if (cur->nsList != NULL) {
- while (cur->nsList[i] != NULL)
- i++;
- }
- cur->nsNr = i;
- }
- } else {
- inst->psvi =
- (void *) xsltPreComputeExtModuleElement(style, inst);
-
- /*
- * Unknown element, maybe registered at the context
- * level. Mark it for later recognition.
- */
- if (inst->psvi == NULL)
- inst->psvi = (void *) xsltExtMarker;
- }
-}
-#endif /* XSLT_REFACTORED */
+/*\r
+ * preproc.c: Preprocessing of style operations\r
+ *\r
+ * References:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * Michael Kay "XSLT Programmer's Reference" pp 637-643\r
+ * Writing Multiple Output Files\r
+ *\r
+ * XSLT-1.1 Working Draft\r
+ * http://www.w3.org/TR/xslt11#multiple-output\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/uri.h>\r
+#include <libxml/encoding.h>\r
+#include <libxml/xmlerror.h>\r
+#include "xslt.h"\r
+#include "xsltutils.h"\r
+#include "xsltInternals.h"\r
+#include "transform.h"\r
+#include "templates.h"\r
+#include "variables.h"\r
+#include "numbersInternals.h"\r
+#include "preproc.h"\r
+#include "extra.h"\r
+#include "imports.h"\r
+#include "extensions.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_PREPROC\r
+#endif\r
+\r
+const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";\r
+\r
+/************************************************************************\r
+ * *\r
+ * Grammar checks *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Grammar checks are now performed in xslt.c.\r
+ */\r
+#else\r
+/**\r
+ * xsltCheckTopLevelElement:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the XSLT instruction\r
+ * @err: raise an error or not\r
+ *\r
+ * Check that the instruction is instanciated as a top level element.\r
+ *\r
+ * Returns -1 in case of error, 0 if failed and 1 in case of success\r
+ */\r
+static int\r
+xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {\r
+ xmlNodePtr parent;\r
+ if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))\r
+ return(-1);\r
+ \r
+ parent = inst->parent;\r
+ if (parent == NULL) {\r
+ if (err) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "internal problem: element has no parent\n");\r
+ style->errors++;\r
+ }\r
+ return(0);\r
+ }\r
+ if ((parent->ns == NULL) ||\r
+ ((parent->ns != inst->ns) &&\r
+ (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||\r
+ ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&\r
+ (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {\r
+ if (err) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "element %s only allowed as child of stylesheet\n",\r
+ inst->name);\r
+ style->errors++;\r
+ }\r
+ return(0);\r
+ }\r
+ return(1);\r
+}\r
+\r
+/**\r
+ * xsltCheckInstructionElement:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the XSLT instruction\r
+ *\r
+ * Check that the instruction is instanciated as an instruction element.\r
+ */\r
+static void\r
+xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+ xmlNodePtr parent;\r
+ int has_ext;\r
+\r
+ if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||\r
+ (style->literal_result))\r
+ return;\r
+\r
+ has_ext = (style->extInfos != NULL);\r
+ \r
+ parent = inst->parent;\r
+ if (parent == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "internal problem: element has no parent\n");\r
+ style->errors++;\r
+ return;\r
+ }\r
+ while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {\r
+ if (((parent->ns == inst->ns) ||\r
+ ((parent->ns != NULL) &&\r
+ (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&\r
+ ((xmlStrEqual(parent->name, BAD_CAST "template")) ||\r
+ (xmlStrEqual(parent->name, BAD_CAST "param")) ||\r
+ (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||\r
+ (xmlStrEqual(parent->name, BAD_CAST "variable")))) {\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * if we are within an extension element all bets are off\r
+ * about the semantic there e.g. xsl:param within func:function\r
+ */\r
+ if ((has_ext) && (parent->ns != NULL) &&\r
+ (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))\r
+ return;\r
+ \r
+ parent = parent->parent;\r
+ }\r
+ xsltTransformError(NULL, style, inst,\r
+ "element %s only allowed within a template, variable or param\n",\r
+ inst->name);\r
+ style->errors++;\r
+}\r
+\r
+/**\r
+ * xsltCheckParentElement:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the XSLT instruction\r
+ * @allow1: allowed parent1\r
+ * @allow2: allowed parent2\r
+ *\r
+ * Check that the instruction is instanciated as the childre of one of the\r
+ * possible parents.\r
+ */\r
+static void\r
+xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,\r
+ const xmlChar *allow1, const xmlChar *allow2) {\r
+ xmlNodePtr parent;\r
+\r
+ if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||\r
+ (style->literal_result))\r
+ return;\r
+\r
+ parent = inst->parent;\r
+ if (parent == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "internal problem: element has no parent\n");\r
+ style->errors++;\r
+ return;\r
+ }\r
+ if (((parent->ns == inst->ns) ||\r
+ ((parent->ns != NULL) &&\r
+ (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&\r
+ ((xmlStrEqual(parent->name, allow1)) ||\r
+ (xmlStrEqual(parent->name, allow2)))) {\r
+ return;\r
+ }\r
+\r
+ if (style->extInfos != NULL) {\r
+ while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {\r
+ /*\r
+ * if we are within an extension element all bets are off\r
+ * about the semantic there e.g. xsl:param within func:function\r
+ */\r
+ if ((parent->ns != NULL) &&\r
+ (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))\r
+ return;\r
+ \r
+ parent = parent->parent;\r
+ }\r
+ }\r
+ xsltTransformError(NULL, style, inst,\r
+ "element %s is not allowed within that context\n",\r
+ inst->name);\r
+ style->errors++;\r
+}\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * handling of precomputed data *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewStylePreComp:\r
+ * @style: the XSLT stylesheet\r
+ * @type: the construct type\r
+ *\r
+ * Create a new XSLT Style precomputed block\r
+ *\r
+ * Returns the newly allocated specialized structure\r
+ * or NULL in case of error\r
+ */\r
+static xsltStylePreCompPtr\r
+xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {\r
+ xsltStylePreCompPtr cur;\r
+#ifdef XSLT_REFACTORED\r
+ size_t size;\r
+#endif\r
+\r
+ if (style == NULL)\r
+ return(NULL);\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * URGENT TODO: Use specialized factory functions in order\r
+ * to avoid this ugliness.\r
+ */\r
+ switch (type) {\r
+ case XSLT_FUNC_COPY:\r
+ size = sizeof(xsltStyleItemCopy); break;\r
+ case XSLT_FUNC_SORT:\r
+ size = sizeof(xsltStyleItemSort); break;\r
+ case XSLT_FUNC_TEXT:\r
+ size = sizeof(xsltStyleItemText); break;\r
+ case XSLT_FUNC_ELEMENT:\r
+ size = sizeof(xsltStyleItemElement); break;\r
+ case XSLT_FUNC_ATTRIBUTE:\r
+ size = sizeof(xsltStyleItemAttribute); break;\r
+ case XSLT_FUNC_COMMENT:\r
+ size = sizeof(xsltStyleItemComment); break;\r
+ case XSLT_FUNC_PI:\r
+ size = sizeof(xsltStyleItemPI); break;\r
+ case XSLT_FUNC_COPYOF:\r
+ size = sizeof(xsltStyleItemCopyOf); break;\r
+ case XSLT_FUNC_VALUEOF:\r
+ size = sizeof(xsltStyleItemValueOf); break;;\r
+ case XSLT_FUNC_NUMBER:\r
+ size = sizeof(xsltStyleItemNumber); break;\r
+ case XSLT_FUNC_APPLYIMPORTS:\r
+ size = sizeof(xsltStyleItemApplyImports); break;\r
+ case XSLT_FUNC_CALLTEMPLATE:\r
+ size = sizeof(xsltStyleItemCallTemplate); break;\r
+ case XSLT_FUNC_APPLYTEMPLATES:\r
+ size = sizeof(xsltStyleItemApplyTemplates); break;\r
+ case XSLT_FUNC_CHOOSE:\r
+ size = sizeof(xsltStyleItemChoose); break;\r
+ case XSLT_FUNC_IF:\r
+ size = sizeof(xsltStyleItemIf); break;\r
+ case XSLT_FUNC_FOREACH:\r
+ size = sizeof(xsltStyleItemForEach); break;\r
+ case XSLT_FUNC_DOCUMENT:\r
+ size = sizeof(xsltStyleItemDocument); break;\r
+ case XSLT_FUNC_WITHPARAM:\r
+ size = sizeof(xsltStyleItemWithParam); break;\r
+ case XSLT_FUNC_PARAM:\r
+ size = sizeof(xsltStyleItemParam); break;\r
+ case XSLT_FUNC_VARIABLE:\r
+ size = sizeof(xsltStyleItemVariable); break;\r
+ case XSLT_FUNC_WHEN:\r
+ size = sizeof(xsltStyleItemWhen); break;\r
+ case XSLT_FUNC_OTHERWISE:\r
+ size = sizeof(xsltStyleItemOtherwise); break;\r
+ default: \r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltNewStylePreComp : invalid type %d\n", type);\r
+ style->errors++;\r
+ return(NULL);\r
+ }\r
+ /*\r
+ * Create the structure.\r
+ */\r
+ cur = (xsltStylePreCompPtr) xmlMalloc(size);\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltNewStylePreComp : malloc failed\n");\r
+ style->errors++;\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, size);\r
+\r
+#else /* XSLT_REFACTORED */\r
+ /*\r
+ * Old behaviour.\r
+ */\r
+ cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltNewStylePreComp : malloc failed\n");\r
+ style->errors++;\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltStylePreComp));\r
+#endif /* XSLT_REFACTORED */\r
+\r
+ /*\r
+ * URGENT TODO: Better to move this to spezialized factory functions.\r
+ */\r
+ cur->type = type;\r
+ switch (cur->type) {\r
+ case XSLT_FUNC_COPY:\r
+ cur->func = (xsltTransformFunction) xsltCopy;break;\r
+ case XSLT_FUNC_SORT:\r
+ cur->func = (xsltTransformFunction) xsltSort;break;\r
+ case XSLT_FUNC_TEXT:\r
+ cur->func = (xsltTransformFunction) xsltText;break;\r
+ case XSLT_FUNC_ELEMENT:\r
+ cur->func = (xsltTransformFunction) xsltElement;break;\r
+ case XSLT_FUNC_ATTRIBUTE:\r
+ cur->func = (xsltTransformFunction) xsltAttribute;break;\r
+ case XSLT_FUNC_COMMENT:\r
+ cur->func = (xsltTransformFunction) xsltComment;break;\r
+ case XSLT_FUNC_PI:\r
+ cur->func = (xsltTransformFunction) xsltProcessingInstruction;\r
+ break;\r
+ case XSLT_FUNC_COPYOF:\r
+ cur->func = (xsltTransformFunction) xsltCopyOf;break;\r
+ case XSLT_FUNC_VALUEOF:\r
+ cur->func = (xsltTransformFunction) xsltValueOf;break;\r
+ case XSLT_FUNC_NUMBER:\r
+ cur->func = (xsltTransformFunction) xsltNumber;break;\r
+ case XSLT_FUNC_APPLYIMPORTS:\r
+ cur->func = (xsltTransformFunction) xsltApplyImports;break;\r
+ case XSLT_FUNC_CALLTEMPLATE:\r
+ cur->func = (xsltTransformFunction) xsltCallTemplate;break;\r
+ case XSLT_FUNC_APPLYTEMPLATES:\r
+ cur->func = (xsltTransformFunction) xsltApplyTemplates;break;\r
+ case XSLT_FUNC_CHOOSE:\r
+ cur->func = (xsltTransformFunction) xsltChoose;break;\r
+ case XSLT_FUNC_IF:\r
+ cur->func = (xsltTransformFunction) xsltIf;break;\r
+ case XSLT_FUNC_FOREACH:\r
+ cur->func = (xsltTransformFunction) xsltForEach;break;\r
+ case XSLT_FUNC_DOCUMENT:\r
+ cur->func = (xsltTransformFunction) xsltDocumentElem;break;\r
+ case XSLT_FUNC_WITHPARAM:\r
+ case XSLT_FUNC_PARAM: \r
+ case XSLT_FUNC_VARIABLE: \r
+ case XSLT_FUNC_WHEN:\r
+ break;\r
+ default:\r
+ if (cur->func == NULL) {\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltNewStylePreComp : no function for type %d\n", type);\r
+ style->errors++;\r
+ }\r
+ }\r
+ cur->next = style->preComps;\r
+ style->preComps = (xsltElemPreCompPtr) cur;\r
+\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeStylePreComp:\r
+ * @comp: an XSLT Style precomputed block\r
+ *\r
+ * Free up the memory allocated by @comp\r
+ */\r
+static void\r
+xsltFreeStylePreComp(xsltStylePreCompPtr comp) {\r
+ if (comp == NULL)\r
+ return;\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * URGENT TODO: Implement destructors.\r
+ */\r
+ switch (comp->type) {\r
+ case XSLT_FUNC_LITERAL_RESULT_ELEMENT:\r
+ break;\r
+ case XSLT_FUNC_COPY:\r
+ break;\r
+ case XSLT_FUNC_SORT: {\r
+ xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_TEXT:\r
+ break;\r
+ case XSLT_FUNC_ELEMENT:\r
+ break;\r
+ case XSLT_FUNC_ATTRIBUTE:\r
+ break;\r
+ case XSLT_FUNC_COMMENT:\r
+ break;\r
+ case XSLT_FUNC_PI:\r
+ break;\r
+ case XSLT_FUNC_COPYOF: {\r
+ xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_VALUEOF: {\r
+ xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_NUMBER:\r
+ break;\r
+ case XSLT_FUNC_APPLYIMPORTS:\r
+ break;\r
+ case XSLT_FUNC_CALLTEMPLATE:\r
+ break;\r
+ case XSLT_FUNC_APPLYTEMPLATES: {\r
+ xsltStyleItemApplyTemplatesPtr item =\r
+ (xsltStyleItemApplyTemplatesPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_CHOOSE:\r
+ break;\r
+ case XSLT_FUNC_IF: {\r
+ xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_FOREACH: {\r
+ xsltStyleItemForEachPtr item =\r
+ (xsltStyleItemForEachPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_DOCUMENT:\r
+ break;\r
+ case XSLT_FUNC_WITHPARAM: {\r
+ xsltStyleItemWithParamPtr item =\r
+ (xsltStyleItemWithParamPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_PARAM: {\r
+ xsltStyleItemParamPtr item =\r
+ (xsltStyleItemParamPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_VARIABLE: {\r
+ xsltStyleItemVariablePtr item =\r
+ (xsltStyleItemVariablePtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_WHEN: {\r
+ xsltStyleItemWhenPtr item =\r
+ (xsltStyleItemWhenPtr) comp;\r
+ if (item->comp != NULL)\r
+ xmlXPathFreeCompExpr(item->comp);\r
+ }\r
+ break;\r
+ case XSLT_FUNC_OTHERWISE: \r
+ case XSLT_FUNC_FALLBACK:\r
+ case XSLT_FUNC_MESSAGE:\r
+ case XSLT_FUNC_INCLUDE:\r
+ case XSLT_FUNC_ATTRSET:\r
+ \r
+ break;\r
+ default:\r
+ /* TODO: Raise error. */\r
+ break;\r
+ }\r
+#else \r
+ if (comp->comp != NULL)\r
+ xmlXPathFreeCompExpr(comp->comp);\r
+ if (comp->nsList != NULL)\r
+ xmlFree(comp->nsList);\r
+#endif\r
+\r
+ xmlFree(comp);\r
+}\r
+\r
+\r
+/************************************************************************\r
+ * *\r
+ * XSLT-1.1 extensions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltDocumentComp:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the instruction in the stylesheet\r
+ * @function: unused\r
+ *\r
+ * Pre process an XSLT-1.1 document element\r
+ *\r
+ * Returns a precompiled data structure for the element\r
+ */\r
+xsltElemPreCompPtr\r
+xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,\r
+ xsltTransformFunction function ATTRIBUTE_UNUSED) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemDocumentPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *filename = NULL;\r
+\r
+ /*\r
+ * As of 2006-03-30, this function is currently defined in Libxslt\r
+ * to be used for:\r
+ * (in libxslt/extra.c)\r
+ * "output" in XSLT_SAXON_NAMESPACE\r
+ * "write" XSLT_XALAN_NAMESPACE\r
+ * "document" XSLT_XT_NAMESPACE\r
+ * "document" XSLT_NAMESPACE (from the abandoned old working\r
+ * draft of XSLT 1.1)\r
+ * (in libexslt/common.c)\r
+ * "document" in EXSLT_COMMON_NAMESPACE\r
+ */\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemDocumentPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);\r
+#endif\r
+ \r
+ if (comp == NULL)\r
+ return (NULL);\r
+ comp->inst = inst;\r
+ comp->ver11 = 0;\r
+\r
+ if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found saxon:output extension\n");\r
+#endif\r
+ /*\r
+ * The element "output" is in the namespace XSLT_SAXON_NAMESPACE\r
+ * (http://icl.com/saxon)\r
+ * The @file is in no namespace; it is an AVT.\r
+ * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)\r
+ *\r
+ * TODO: Do we need not to check the namespace here?\r
+ */\r
+ filename = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"file",\r
+ NULL, &comp->has_filename);\r
+ } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found xalan:write extension\n");\r
+#endif\r
+ /* the filename need to be interpreted */\r
+ /*\r
+ * TODO: Is "filename need to be interpreted" meant to be a todo?\r
+ * Where will be the filename of xalan:write be processed?\r
+ *\r
+ * TODO: Do we need not to check the namespace here?\r
+ * The extension ns is "http://xml.apache.org/xalan/redirect".\r
+ * See http://xml.apache.org/xalan-j/extensionslib.html.\r
+ */\r
+ } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {\r
+ if (inst->ns != NULL) {\r
+ if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {\r
+ /*\r
+ * Mark the instruction as being of\r
+ * XSLT version 1.1 (abandoned).\r
+ */\r
+ comp->ver11 = 1;\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found xslt11:document construct\n");\r
+#endif \r
+ } else { \r
+ if (xmlStrEqual(inst->ns->href,\r
+ (const xmlChar *)"http://exslt.org/common")) {\r
+ /* EXSLT. */\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found exslt:document extension\n");\r
+#endif\r
+ } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {\r
+ /* James Clark's XT. */\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found xt:document extension\n");\r
+#endif\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * The element "document" is used in conjunction with the\r
+ * following namespaces:\r
+ *\r
+ * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)\r
+ * <!ELEMENT xsl:document %template;>\r
+ * <!ATTLIST xsl:document\r
+ * href %avt; #REQUIRED\r
+ * @href is an AVT\r
+ * IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,\r
+ * it was removed and isn't available in XSLT 1.1 anymore.\r
+ * In XSLT 2.0 it was renamed to xsl:result-document.\r
+ *\r
+ * All other attributes are identical to the attributes\r
+ * on xsl:output\r
+ *\r
+ * 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)\r
+ * <exsl:document\r
+ * href = { uri-reference }\r
+ * TODO: is @href is an AVT?\r
+ *\r
+ * 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)\r
+ * Example: <xt:document method="xml" href="myFile.xml">\r
+ * TODO: is @href is an AVT?\r
+ * \r
+ * In all cases @href is in no namespace.\r
+ */\r
+ filename = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"href", NULL, &comp->has_filename);\r
+ } \r
+ if (!comp->has_filename) {\r
+ goto error;\r
+ }\r
+ comp->filename = filename;\r
+\r
+error:\r
+ return ((xsltElemPreCompPtr) comp);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Most of the XSLT-1.0 transformations *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltSortComp:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the xslt sort node\r
+ *\r
+ * Process the xslt sort node on the source node\r
+ */\r
+static void\r
+xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemSortPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);\r
+#endif\r
+ \r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"data-type",\r
+ NULL, &comp->has_stype);\r
+ if (comp->stype != NULL) {\r
+ if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))\r
+ comp->number = 0;\r
+ else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))\r
+ comp->number = 1;\r
+ else {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsltSortComp: no support for data-type = %s\n", comp->stype);\r
+ comp->number = 0; /* use default */\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+ comp->order = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"order",\r
+ NULL, &comp->has_order);\r
+ if (comp->order != NULL) {\r
+ if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))\r
+ comp->descending = 0;\r
+ else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))\r
+ comp->descending = 1;\r
+ else {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsltSortComp: invalid value %s for order\n", comp->order);\r
+ comp->descending = 0; /* use default */\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+ comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"case-order",\r
+ NULL, &comp->has_use);\r
+ if (comp->case_order != NULL) {\r
+ if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))\r
+ comp->lower_first = 0;\r
+ else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))\r
+ comp->lower_first = 1;\r
+ else {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsltSortComp: invalid value %s for order\n", comp->order);\r
+ comp->lower_first = 0; /* use default */\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+\r
+ comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"lang",\r
+ NULL, &comp->has_lang);\r
+\r
+ comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);\r
+ if (comp->select == NULL) {\r
+ /*\r
+ * The default value of the select attribute is ., which will\r
+ * cause the string-value of the current node to be used as\r
+ * the sort key.\r
+ */\r
+ comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);\r
+ }\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsltSortComp: could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ if (inst->children != NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:sort : is not empty\n");\r
+ if (style != NULL) style->errors++;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltCopyComp:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the xslt copy node\r
+ *\r
+ * Process the xslt copy node on the source node\r
+ */\r
+static void\r
+xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCopyPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);\r
+#endif\r
+ \r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+\r
+ comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",\r
+ XSLT_NAMESPACE);\r
+ if (comp->use == NULL)\r
+ comp->has_use = 0;\r
+ else\r
+ comp->has_use = 1;\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /* Enable if ever needed for xsl:text. */\r
+#else\r
+/**\r
+ * xsltTextComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt text node\r
+ *\r
+ * TODO: This function is obsolete, since xsl:text won't\r
+ * be compiled, but removed from the tree.\r
+ *\r
+ * Process the xslt text node on the source node\r
+ */\r
+static void\r
+xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemTextPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);\r
+#endif \r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+ comp->noescape = 0;\r
+\r
+ prop = xsltGetCNsProp(style, inst,\r
+ (const xmlChar *)"disable-output-escaping",\r
+ XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *)"yes")) {\r
+ comp->noescape = 1;\r
+ } else if (!xmlStrEqual(prop,\r
+ (const xmlChar *)"no")){\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:text: disable-output-escaping allows only yes or no\n");\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+}\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltElementComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt element node\r
+ *\r
+ * Process the xslt element node on the source node\r
+ */\r
+static void\r
+xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemElementPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ /*\r
+ * <xsl:element\r
+ * name = { qname }\r
+ * namespace = { uri-reference }\r
+ * use-attribute-sets = qnames>\r
+ * <!-- Content: template -->\r
+ * </xsl:element>\r
+ */\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * Attribute "name".\r
+ */\r
+ /*\r
+ * TODO: Precompile the AVT. See bug #344894.\r
+ */\r
+ comp->name = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"name", NULL, &comp->has_name);\r
+ if (! comp->has_name) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:element: The attribute 'name' is missing.\n");\r
+ style->errors++;\r
+ goto error;\r
+ }\r
+ /*\r
+ * Attribute "namespace".\r
+ */\r
+ /*\r
+ * TODO: Precompile the AVT. See bug #344894.\r
+ */\r
+ comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"namespace", NULL, &comp->has_ns);\r
+ \r
+ if (comp->name != NULL) { \r
+ if (xmlValidateQName(comp->name, 0)) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:element: The value '%s' of the attribute 'name' is "\r
+ "not a valid QName.\n", comp->name);\r
+ style->errors++;\r
+ } else {\r
+ const xmlChar *prefix = NULL, *name;\r
+\r
+ name = xsltSplitQName(style->dict, comp->name, &prefix);\r
+ if (comp->has_ns == 0) { \r
+ xmlNsPtr ns;\r
+\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If the namespace attribute is not present, then the QName is\r
+ * expanded into an expanded-name using the namespace declarations\r
+ * in effect for the xsl:element element, including any default\r
+ * namespace declaration.\r
+ */ \r
+ ns = xmlSearchNs(inst->doc, inst, prefix);\r
+ if (ns != NULL) {\r
+ comp->ns = xmlDictLookup(style->dict, ns->href, -1);\r
+ comp->has_ns = 1;\r
+#ifdef XSLT_REFACTORED\r
+ comp->nsPrefix = prefix;\r
+ comp->name = name;\r
+#endif\r
+ } else if (prefix != NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:element: The prefixed QName '%s' "\r
+ "has no namespace binding in scope in the "\r
+ "stylesheet; this is an error, since the namespace was "\r
+ "not specified by the instruction itself.\n", comp->name);\r
+ style->errors++;\r
+ }\r
+ } \r
+ if ((prefix != NULL) &&\r
+ (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))\r
+ {\r
+ /*\r
+ * Mark is to be skipped.\r
+ */\r
+ comp->has_name = 0; \r
+ }\r
+ }\r
+ } \r
+ /*\r
+ * Attribute "use-attribute-sets",\r
+ */\r
+ comp->use = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"use-attribute-sets",\r
+ NULL, &comp->has_use);\r
+\r
+error: \r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltAttributeComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt attribute node\r
+ *\r
+ * Process the xslt attribute node on the source node\r
+ */\r
+static void\r
+xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemAttributePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ /*\r
+ * <xsl:attribute\r
+ * name = { qname }\r
+ * namespace = { uri-reference }>\r
+ * <!-- Content: template -->\r
+ * </xsl:attribute>\r
+ */\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,\r
+ XSLT_FUNC_ATTRIBUTE);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);\r
+#endif\r
+ \r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * Attribute "name".\r
+ */\r
+ /*\r
+ * TODO: Precompile the AVT. See bug #344894.\r
+ */\r
+ comp->name = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"name",\r
+ NULL, &comp->has_name);\r
+ if (! comp->has_name) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "XSLT-attribute: The attribute 'name' is missing.\n");\r
+ style->errors++;\r
+ return;\r
+ } \r
+ /*\r
+ * Attribute "namespace".\r
+ */\r
+ /*\r
+ * TODO: Precompile the AVT. See bug #344894.\r
+ */\r
+ comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"namespace",\r
+ NULL, &comp->has_ns);\r
+\r
+ if (comp->name != NULL) {\r
+ if (xmlValidateQName(comp->name, 0)) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:attribute: The value '%s' of the attribute 'name' is "\r
+ "not a valid QName.\n", comp->name);\r
+ style->errors++;\r
+ } else {\r
+ const xmlChar *prefix = NULL, *name;\r
+\r
+ name = xsltSplitQName(style->dict, comp->name, &prefix);\r
+ if (prefix != NULL) {\r
+ if (comp->has_ns == 0) {\r
+ xmlNsPtr ns;\r
+\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If the namespace attribute is not present, then the\r
+ * QName is expanded into an expanded-name using the\r
+ * namespace declarations in effect for the xsl:element\r
+ * element, including any default namespace declaration.\r
+ */ \r
+ ns = xmlSearchNs(inst->doc, inst, prefix);\r
+ if (ns != NULL) {\r
+ comp->ns = xmlDictLookup(style->dict, ns->href, -1);\r
+ comp->has_ns = 1;\r
+#ifdef XSLT_REFACTORED\r
+ comp->nsPrefix = prefix;\r
+ comp->name = name;\r
+#endif\r
+ } else {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:attribute: The prefixed QName '%s' "\r
+ "has no namespace binding in scope in the "\r
+ "stylesheet; this is an error, since the "\r
+ "namespace was not specified by the instruction "\r
+ "itself.\n", comp->name);\r
+ style->errors++;\r
+ }\r
+ }\r
+ if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "It is an error if the string that results from\r
+ * instantiating the attribute value template is not a\r
+ * QName or is the string xmlns. An XSLT processor may\r
+ * signal the error; if it does not signal the error,\r
+ * it must recover by not adding the attribute to the\r
+ * result tree."\r
+ *\r
+ * Reject a prefix of "xmlns". Mark to be skipped.\r
+ */\r
+ comp->has_name = 0;\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltAttribute: xmlns prefix forbidden\n");\r
+#endif \r
+ return;\r
+ }\r
+ \r
+ }\r
+ } \r
+ }\r
+}\r
+\r
+/**\r
+ * xsltCommentComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt comment node\r
+ *\r
+ * Process the xslt comment node on the source node\r
+ */\r
+static void\r
+xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCommentPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+}\r
+\r
+/**\r
+ * xsltProcessingInstructionComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt processing-instruction node\r
+ *\r
+ * Process the xslt processing-instruction node on the source node\r
+ */\r
+static void\r
+xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemPIPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->name = xsltEvalStaticAttrValueTemplate(style, inst,\r
+ (const xmlChar *)"name",\r
+ XSLT_NAMESPACE, &comp->has_name);\r
+}\r
+\r
+/**\r
+ * xsltCopyOfComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt copy-of node\r
+ *\r
+ * Process the xslt copy-of node on the source node\r
+ */\r
+static void\r
+xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCopyOfPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:copy-of : select is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ return;\r
+ }\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:copy-of : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltValueOfComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt value-of node\r
+ *\r
+ * Process the xslt value-of node on the source node\r
+ */\r
+static void\r
+xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemValueOfPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ prop = xsltGetCNsProp(style, inst,\r
+ (const xmlChar *)"disable-output-escaping",\r
+ XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *)"yes")) {\r
+ comp->noescape = 1;\r
+ } else if (!xmlStrEqual(prop,\r
+ (const xmlChar *)"no")){\r
+ xsltTransformError(NULL, style, inst,\r
+"xsl:value-of : disable-output-escaping allows only yes or no\n");\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:value-of : select is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ return;\r
+ }\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:value-of : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltWithParamComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt with-param node\r
+ *\r
+ * Process the xslt with-param node on the source node\r
+ * Allowed parents: xsl:call-template, xsl:apply-templates.\r
+ * <xsl:with-param\r
+ * name = qname\r
+ * select = expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:with-param>\r
+ */\r
+static void\r
+xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemWithParamPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * The full namespace resolution can be done statically\r
+ */\r
+ prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:with-param : name is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * @prop will be in the string dict afterwards, @URI not.\r
+ */\r
+ URI = xsltGetQNameURI2(style, inst, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ comp->name = prop;\r
+ comp->has_name = 1;\r
+ if (URI != NULL) {\r
+ /*\r
+ * Fixes bug #308441: Put the ns-name in the dict\r
+ * in order to pointer compare names during XPath's\r
+ * variable lookup.\r
+ */\r
+ comp->ns = xmlDictLookup(style->dict, URI, -1);\r
+ comp->has_ns = 1;\r
+ } else {\r
+ comp->has_ns = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select != NULL) {\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:param : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ if (inst->children != NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:param : content should be empty since select is present \n");\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltNumberComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @cur: the xslt number node\r
+ *\r
+ * Process the xslt number node on the source node\r
+ */\r
+static void\r
+xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemNumberPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (cur == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ cur->psvi = comp;\r
+\r
+ if ((style == NULL) || (cur == NULL))\r
+ return;\r
+\r
+ comp->numdata.doc = cur->doc;\r
+ comp->numdata.node = cur;\r
+ comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",\r
+ XSLT_NAMESPACE);\r
+ \r
+ prop = xsltEvalStaticAttrValueTemplate(style, cur,\r
+ (const xmlChar *)"format",\r
+ XSLT_NAMESPACE, &comp->numdata.has_format);\r
+ if (comp->numdata.has_format == 0) {\r
+ comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);\r
+ } else {\r
+ comp->numdata.format = prop;\r
+ }\r
+\r
+ comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",\r
+ XSLT_NAMESPACE);\r
+ comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",\r
+ XSLT_NAMESPACE);\r
+ \r
+ prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, BAD_CAST("single")) ||\r
+ xmlStrEqual(prop, BAD_CAST("multiple")) ||\r
+ xmlStrEqual(prop, BAD_CAST("any"))) {\r
+ comp->numdata.level = prop;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:number : invalid value %s for level\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ xmlFree((void *)(prop));\r
+ }\r
+ }\r
+ \r
+ prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ XSLT_TODO; /* xsl:number lang attribute */\r
+ xmlFree((void *)prop);\r
+ }\r
+ \r
+ prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:number : letter-value 'alphabetic' not implemented\n");\r
+ if (style != NULL) style->warnings++;\r
+ XSLT_TODO; /* xsl:number letter-value attribute alphabetic */\r
+ } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:number : letter-value 'traditional' not implemented\n");\r
+ if (style != NULL) style->warnings++;\r
+ XSLT_TODO; /* xsl:number letter-value attribute traditional */\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:number : invalid value %s for letter-value\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+ \r
+ prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",\r
+ XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ comp->numdata.groupingCharacterLen = xmlStrlen(prop);\r
+ comp->numdata.groupingCharacter =\r
+ xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));\r
+ }\r
+ \r
+ prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);\r
+ } else {\r
+ comp->numdata.groupingCharacter = 0;\r
+ }\r
+\r
+ /* Set default values */\r
+ if (comp->numdata.value == NULL) {\r
+ if (comp->numdata.level == NULL) {\r
+ comp->numdata.level = xmlDictLookup(style->dict,\r
+ BAD_CAST"single", 6);\r
+ }\r
+ }\r
+ \r
+}\r
+\r
+/**\r
+ * xsltApplyImportsComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt apply-imports node\r
+ *\r
+ * Process the xslt apply-imports node on the source node\r
+ */\r
+static void\r
+xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemApplyImportsPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+}\r
+\r
+/**\r
+ * xsltCallTemplateComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt call-template node\r
+ *\r
+ * Process the xslt call-template node on the source node\r
+ */\r
+static void\r
+xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCallTemplatePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemCallTemplatePtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * The full template resolution can be done statically\r
+ */\r
+ prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:call-template : name is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ URI = xsltGetQNameURI2(style, inst, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ comp->name = prop;\r
+ comp->has_name = 1;\r
+ if (URI != NULL) {\r
+ comp->ns = xmlDictLookup(style->dict, URI, -1);\r
+ comp->has_ns = 1;\r
+ } else {\r
+ comp->has_ns = 0;\r
+ }\r
+ }\r
+ comp->templ = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltApplyTemplatesComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the apply-templates node\r
+ *\r
+ * Process the apply-templates node on the source node\r
+ */\r
+static void\r
+xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemApplyTemplatesPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemApplyTemplatesPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * Get mode if any\r
+ */\r
+ prop = xsltGetCNsProp(style, inst, (const xmlChar *)"mode", XSLT_NAMESPACE);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+\r
+ URI = xsltGetQNameURI2(style, inst, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ comp->mode = xmlDictLookup(style->dict, prop, -1);\r
+ if (URI != NULL) {\r
+ comp->modeURI = xmlDictLookup(style->dict, URI, -1);\r
+ } else {\r
+ comp->modeURI = NULL;\r
+ }\r
+ }\r
+ }\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select != NULL) {\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:apply-templates : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ }\r
+\r
+ /* TODO: handle (or skip) the xsl:sort and xsl:with-param */\r
+}\r
+\r
+/**\r
+ * xsltChooseComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt choose node\r
+ *\r
+ * Process the xslt choose node on the source node\r
+ */\r
+static void\r
+xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemChoosePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemChoosePtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+}\r
+\r
+/**\r
+ * xsltIfComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt if node\r
+ *\r
+ * Process the xslt if node on the source node\r
+ */\r
+static void\r
+xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemIfPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemIfPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_IF);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);\r
+ if (comp->test == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:if : test is not defined\n");\r
+ if (style != NULL) style->errors++;\r
+ return;\r
+ }\r
+ comp->comp = xsltXPathCompile(style, comp->test);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:if : could not compile test expression '%s'\n",\r
+ comp->test);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltWhenComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt if node\r
+ *\r
+ * Process the xslt if node on the source node\r
+ */\r
+static void\r
+xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemWhenPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemWhenPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_WHEN);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);\r
+ if (comp->test == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:when : test is not defined\n");\r
+ if (style != NULL) style->errors++;\r
+ return;\r
+ }\r
+ comp->comp = xsltXPathCompile(style, comp->test);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:when : could not compile test expression '%s'\n",\r
+ comp->test);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltForEachComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt for-each node\r
+ *\r
+ * Process the xslt for-each node on the source node\r
+ */\r
+static void\r
+xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemForEachPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemForEachPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:for-each : select is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:for-each : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ }\r
+ /* TODO: handle and skip the xsl:sort */\r
+}\r
+\r
+/**\r
+ * xsltVariableComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt variable node\r
+ *\r
+ * Process the xslt variable node on the source node\r
+ */\r
+static void\r
+xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemVariablePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+ const xmlChar *URI;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemVariablePtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+ /*\r
+ * The full template resolution can be done statically\r
+ */\r
+\r
+ /*\r
+ * Attribute "name".\r
+ */\r
+ prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "XSLT-variable: The attribute 'name' is missing.\n");\r
+ style->errors++;\r
+ goto error;\r
+ } \r
+ if (xmlValidateQName(prop, 0)) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "XSLT-variable: The value '%s' of the attribute 'name' is "\r
+ "not a valid QName.\n", prop);\r
+ style->errors++;\r
+ goto error;\r
+ }\r
+ URI = xsltGetQNameURI2(style, inst, &prop);\r
+ if (prop == NULL) {\r
+ goto error;\r
+ }\r
+ comp->name = prop;\r
+ comp->has_name = 1;\r
+\r
+ if (URI != NULL) {\r
+ comp->ns = xmlDictLookup(style->dict, URI, -1);\r
+ comp->has_ns = 1;\r
+ } else {\r
+ comp->has_ns = 0;\r
+ }\r
+ /*\r
+ * Attribute "select".\r
+ */\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select != NULL) {\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "XSLT-variable: Failed to compile the XPath expression '%s'.\n",\r
+ comp->select);\r
+ style->errors++;\r
+ }\r
+ if (inst->children != NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "XSLT-variable: The must be no child nodes, since the "\r
+ "attribute 'select' was specified.\n");\r
+ style->errors++;\r
+ }\r
+ }\r
+error:\r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltParamComp:\r
+ * @style: an XSLT compiled stylesheet\r
+ * @inst: the xslt param node\r
+ *\r
+ * Process the xslt param node on the source node\r
+ */\r
+static void\r
+xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemParamPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ const xmlChar *prop;\r
+\r
+ if ((style == NULL) || (inst == NULL))\r
+ return;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleItemParamPtr)\r
+ xsltNewStylePreComp(style, XSLT_FUNC_PARAM);\r
+#else\r
+ comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);\r
+#endif\r
+\r
+ if (comp == NULL)\r
+ return;\r
+ inst->psvi = comp;\r
+ comp->inst = inst;\r
+\r
+ /*\r
+ * The full template resolution can be done statically\r
+ */\r
+ prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:param : name is missing\n");\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ URI = xsltGetQNameURI2(style, inst, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else {\r
+ comp->name = prop;\r
+ comp->has_name = 1;\r
+ if (URI != NULL) {\r
+ comp->ns = xmlDictLookup(style->dict, URI, -1);\r
+ comp->has_ns = 1;\r
+ } else {\r
+ comp->has_ns = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",\r
+ XSLT_NAMESPACE);\r
+ if (comp->select != NULL) {\r
+ comp->comp = xsltXPathCompile(style, comp->select);\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:param : could not compile select expression '%s'\n",\r
+ comp->select);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ if (inst->children != NULL) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsl:param : content should be empty since select is present \n");\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Generic interface *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltFreeStylePreComps:\r
+ * @style: an XSLT transformation context\r
+ *\r
+ * Free up the memory allocated by all precomputed blocks\r
+ */\r
+void\r
+xsltFreeStylePreComps(xsltStylesheetPtr style) {\r
+ xsltElemPreCompPtr cur, next;\r
+\r
+ if (style == NULL)\r
+ return; \r
+ \r
+ cur = style->preComps;\r
+ while (cur != NULL) {\r
+ next = cur->next; \r
+ if (cur->type == XSLT_FUNC_EXTENSION)\r
+ cur->free(cur);\r
+ else\r
+ xsltFreeStylePreComp((xsltStylePreCompPtr) cur);\r
+ cur = next;\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+/**\r
+ * xsltStylePreCompute:\r
+ * @style: the XSLT stylesheet\r
+ * @node: the element in the XSLT namespace\r
+ *\r
+ * Precompute an XSLT element.\r
+ * This expects the type of the element to be already\r
+ * set in style->compCtxt->inode->type;\r
+ */\r
+void\r
+xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {\r
+ /* \r
+ * The xsltXSLTElemMarker marker was set beforehand by\r
+ * the parsing mechanism for all elements in the XSLT namespace.\r
+ */\r
+ if (style == NULL) {\r
+ if (node != NULL)\r
+ node->psvi = NULL;\r
+ return;\r
+ }\r
+ if (node == NULL)\r
+ return;\r
+ if (! IS_XSLT_ELEM_FAST(node))\r
+ return;\r
+\r
+ node->psvi = NULL;\r
+ if (XSLT_CCTXT(style)->inode->type != 0) {\r
+ switch (XSLT_CCTXT(style)->inode->type) {\r
+ case XSLT_FUNC_APPLYTEMPLATES:\r
+ xsltApplyTemplatesComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_WITHPARAM: \r
+ xsltWithParamComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_VALUEOF: \r
+ xsltValueOfComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_COPY: \r
+ xsltCopyComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_COPYOF:\r
+ xsltCopyOfComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_IF: \r
+ xsltIfComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_CHOOSE: \r
+ xsltChooseComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_WHEN: \r
+ xsltWhenComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_OTHERWISE: \r
+ /* NOP yet */\r
+ return;\r
+ case XSLT_FUNC_FOREACH: \r
+ xsltForEachComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_APPLYIMPORTS: \r
+ xsltApplyImportsComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_ATTRIBUTE: \r
+ xsltAttributeComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_ELEMENT: \r
+ xsltElementComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_SORT: \r
+ xsltSortComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_COMMENT: \r
+ xsltCommentComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_NUMBER: \r
+ xsltNumberComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_PI: \r
+ xsltProcessingInstructionComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_CALLTEMPLATE: \r
+ xsltCallTemplateComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_PARAM: \r
+ xsltParamComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_VARIABLE: \r
+ xsltVariableComp(style, node);\r
+ break;\r
+ case XSLT_FUNC_FALLBACK: \r
+ /* NOP yet */\r
+ return;\r
+ case XSLT_FUNC_DOCUMENT: \r
+ /* The extra one */\r
+ node->psvi = (void *) xsltDocumentComp(style, node,\r
+ (xsltTransformFunction) xsltDocumentElem);\r
+ break;\r
+ case XSLT_FUNC_MESSAGE:\r
+ /* NOP yet */\r
+ return;\r
+ default:\r
+ /*\r
+ * NOTE that xsl:text, xsl:template, xsl:stylesheet,\r
+ * xsl:transform, xsl:import, xsl:include are not expected\r
+ * to be handed over to this function.\r
+ */\r
+ xsltTransformError(NULL, style, node,\r
+ "Internal error: (xsltStylePreCompute) cannot handle "\r
+ "the XSLT element '%s'.\n", node->name);\r
+ style->errors++;\r
+ return;\r
+ }\r
+ } else {\r
+ /*\r
+ * Fallback to string comparison.\r
+ */ \r
+ if (IS_XSLT_NAME(node, "apply-templates")) {\r
+ xsltApplyTemplatesComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "with-param")) {\r
+ xsltWithParamComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "value-of")) {\r
+ xsltValueOfComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "copy")) {\r
+ xsltCopyComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "copy-of")) {\r
+ xsltCopyOfComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "if")) {\r
+ xsltIfComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "choose")) {\r
+ xsltChooseComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "when")) {\r
+ xsltWhenComp(style, node); \r
+ } else if (IS_XSLT_NAME(node, "otherwise")) {\r
+ /* NOP yet */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "for-each")) {\r
+ xsltForEachComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "apply-imports")) {\r
+ xsltApplyImportsComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "attribute")) {\r
+ xsltAttributeComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "element")) {\r
+ xsltElementComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "sort")) {\r
+ xsltSortComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "comment")) {\r
+ xsltCommentComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "number")) {\r
+ xsltNumberComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "processing-instruction")) {\r
+ xsltProcessingInstructionComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "call-template")) {\r
+ xsltCallTemplateComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "param")) {\r
+ xsltParamComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "variable")) {\r
+ xsltVariableComp(style, node);\r
+ } else if (IS_XSLT_NAME(node, "fallback")) {\r
+ /* NOP yet */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "document")) {\r
+ /* The extra one */\r
+ node->psvi = (void *) xsltDocumentComp(style, node,\r
+ (xsltTransformFunction) xsltDocumentElem); \r
+ } else if (IS_XSLT_NAME(node, "output")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "preserve-space")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "strip-space")) {\r
+ /* Top-level */\r
+ return; \r
+ } else if (IS_XSLT_NAME(node, "key")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "message")) {\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "attribute-set")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "namespace-alias")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "decimal-format")) {\r
+ /* Top-level */\r
+ return;\r
+ } else if (IS_XSLT_NAME(node, "include")) {\r
+ /* Top-level */ \r
+ } else {\r
+ /*\r
+ * NOTE that xsl:text, xsl:template, xsl:stylesheet,\r
+ * xsl:transform, xsl:import, xsl:include are not expected\r
+ * to be handed over to this function.\r
+ */\r
+ xsltTransformError(NULL, style, node,\r
+ "Internal error: (xsltStylePreCompute) cannot handle "\r
+ "the XSLT element '%s'.\n", node->name);\r
+ style->errors++;\r
+ return;\r
+ } \r
+ }\r
+ /*\r
+ * Assign the current list of in-scope namespaces to the\r
+ * item. This is needed for XPath expressions.\r
+ */\r
+ if (node->psvi != NULL) {\r
+ ((xsltStylePreCompPtr) node->psvi)->inScopeNs =\r
+ XSLT_CCTXT(style)->inode->inScopeNs;\r
+ }\r
+}\r
+\r
+#else\r
+\r
+/**\r
+ * xsltStylePreCompute:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the instruction in the stylesheet\r
+ *\r
+ * Precompute an XSLT stylesheet element\r
+ */\r
+void\r
+xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {\r
+ /*\r
+ * URGENT TODO: Normally inst->psvi Should never be reserved here,\r
+ * BUT: since if we include the same stylesheet from\r
+ * multiple imports, then the stylesheet will be parsed\r
+ * again. We simply must not try to compute the stylesheet again.\r
+ * TODO: Get to the point where we don't need to query the\r
+ * namespace- and local-name of the node, but can evaluate this\r
+ * using cctxt->style->inode->category;\r
+ */\r
+ if (inst->psvi != NULL)\r
+ return;\r
+\r
+ if (IS_XSLT_ELEM(inst)) {\r
+ xsltStylePreCompPtr cur;\r
+\r
+ if (IS_XSLT_NAME(inst, "apply-templates")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltApplyTemplatesComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "with-param")) {\r
+ xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",\r
+ BAD_CAST "call-template");\r
+ xsltWithParamComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "value-of")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltValueOfComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "copy")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltCopyComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "copy-of")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltCopyOfComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "if")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltIfComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "when")) {\r
+ xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);\r
+ xsltWhenComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "choose")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltChooseComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "for-each")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltForEachComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "apply-imports")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltApplyImportsComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "attribute")) {\r
+ xmlNodePtr parent = inst->parent;\r
+\r
+ if ((parent == NULL) || (parent->ns == NULL) ||\r
+ ((parent->ns != inst->ns) &&\r
+ (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||\r
+ (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ }\r
+ xsltAttributeComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "element")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltElementComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "text")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltTextComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "sort")) {\r
+ xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",\r
+ BAD_CAST "for-each");\r
+ xsltSortComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "comment")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltCommentComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "number")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltNumberComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "processing-instruction")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltProcessingInstructionComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "call-template")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltCallTemplateComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "param")) { \r
+ if (xsltCheckTopLevelElement(style, inst, 0) == 0)\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltParamComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "variable")) {\r
+ if (xsltCheckTopLevelElement(style, inst, 0) == 0)\r
+ xsltCheckInstructionElement(style, inst);\r
+ xsltVariableComp(style, inst);\r
+ } else if (IS_XSLT_NAME(inst, "otherwise")) {\r
+ xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);\r
+ xsltCheckInstructionElement(style, inst);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "template")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "output")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "preserve-space")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "strip-space")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if ((IS_XSLT_NAME(inst, "stylesheet")) ||\r
+ (IS_XSLT_NAME(inst, "transform"))) {\r
+ xmlNodePtr parent = inst->parent;\r
+\r
+ if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {\r
+ xsltTransformError(NULL, style, inst,\r
+ "element %s only allowed only as root element\n",\r
+ inst->name);\r
+ style->errors++;\r
+ }\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "key")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "message")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "attribute-set")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "namespace-alias")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "include")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "import")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "decimal-format")) {\r
+ xsltCheckTopLevelElement(style, inst, 1);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "fallback")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ return;\r
+ } else if (IS_XSLT_NAME(inst, "document")) {\r
+ xsltCheckInstructionElement(style, inst);\r
+ inst->psvi = (void *) xsltDocumentComp(style, inst,\r
+ (xsltTransformFunction) xsltDocumentElem);\r
+ } else {\r
+ xsltTransformError(NULL, style, inst,\r
+ "xsltStylePreCompute: unknown xsl:%s\n", inst->name);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ \r
+ cur = (xsltStylePreCompPtr) inst->psvi;\r
+ /*\r
+ * A ns-list is build for every XSLT item in the\r
+ * node-tree. This is needed for XPath expressions.\r
+ */\r
+ if (cur != NULL) {\r
+ int i = 0;\r
+\r
+ cur->nsList = xmlGetNsList(inst->doc, inst);\r
+ if (cur->nsList != NULL) {\r
+ while (cur->nsList[i] != NULL)\r
+ i++;\r
+ }\r
+ cur->nsNr = i;\r
+ }\r
+ } else {\r
+ inst->psvi =\r
+ (void *) xsltPreComputeExtModuleElement(style, inst);\r
+\r
+ /*\r
+ * Unknown element, maybe registered at the context\r
+ * level. Mark it for later recognition.\r
+ */\r
+ if (inst->psvi == NULL)\r
+ inst->psvi = (void *) xsltExtMarker;\r
+ }\r
+}\r
+#endif /* XSLT_REFACTORED */\r
-/*
- * templates.c: Implementation of the template processing
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/tree.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/parserInternals.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "variables.h"
-#include "functions.h"
-#include "templates.h"
-#include "transform.h"
-#include "namespaces.h"
-#include "attributes.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_TEMPLATES
-#endif
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltEvalXPathPredicate:
- * @ctxt: the XSLT transformation context
- * @comp: the XPath compiled expression
- * @nsList: the namespaces in scope
- * @nsNr: the number of namespaces in scope
- *
- * Process the expression using XPath and evaluate the result as
- * an XPath predicate
- *
- * Returns 1 is the predicate was true, 0 otherwise
- */
-int
-xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
- xmlNsPtr *nsList, int nsNr) {
- int ret;
- xmlXPathObjectPtr res;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
- xmlNodePtr oldInst;
- int oldProximityPosition, oldContextSize;
-
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- oldInst = ctxt->inst;
-
- ctxt->xpathCtxt->node = ctxt->node;
- ctxt->xpathCtxt->namespaces = nsList;
- ctxt->xpathCtxt->nsNr = nsNr;
-
- res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
-
- if (res != NULL) {
- ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
- xmlXPathFreeObject(res);
-#ifdef WITH_XSLT_DEBUG_TEMPLATES
- XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltEvalXPathPredicate: returns %d\n", ret));
-#endif
- } else {
-#ifdef WITH_XSLT_DEBUG_TEMPLATES
- XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltEvalXPathPredicate: failed\n"));
-#endif
- ctxt->state = XSLT_STATE_STOPPED;
- ret = 0;
- }
- ctxt->xpathCtxt->nsNr = oldNsNr;
-
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- ctxt->inst = oldInst;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
-
- return(ret);
-}
-
-/**
- * xsltEvalXPathStringNs:
- * @ctxt: the XSLT transformation context
- * @comp: the compiled XPath expression
- * @nsNr: the number of namespaces in the list
- * @nsList: the list of in-scope namespaces to use
- *
- * Process the expression using XPath, allowing to pass a namespace mapping
- * context and get a string
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
- int nsNr, xmlNsPtr *nsList) {
- xmlChar *ret = NULL;
- xmlXPathObjectPtr res;
- xmlNodePtr oldInst;
- xmlNodePtr oldNode;
- int oldPos, oldSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- oldInst = ctxt->inst;
- oldNode = ctxt->node;
- oldPos = ctxt->xpathCtxt->proximityPosition;
- oldSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
-
- ctxt->xpathCtxt->node = ctxt->node;
- /* TODO: do we need to propagate the namespaces here ? */
- ctxt->xpathCtxt->namespaces = nsList;
- ctxt->xpathCtxt->nsNr = nsNr;
- res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
- if (res != NULL) {
- if (res->type != XPATH_STRING)
- res = xmlXPathConvertString(res);
- if (res->type == XPATH_STRING) {
- ret = res->stringval;
- res->stringval = NULL;
- } else {
- xsltTransformError(ctxt, NULL, NULL,
- "xpath : string() function didn't return a String\n");
- }
- xmlXPathFreeObject(res);
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
-#ifdef WITH_XSLT_DEBUG_TEMPLATES
- XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltEvalXPathString: returns %s\n", ret));
-#endif
- ctxt->inst = oldInst;
- ctxt->node = oldNode;
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- return(ret);
-}
-
-/**
- * xsltEvalXPathString:
- * @ctxt: the XSLT transformation context
- * @comp: the compiled XPath expression
- *
- * Process the expression using XPath and get a string
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
- return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));
-}
-
-/**
- * xsltEvalTemplateString:
- * @ctxt: the XSLT transformation context
- * @currentNode: the current node in the source tree
- * @parent: the content parent
- *
- * Evaluate a template string value, i.e. the parent list is interpreted
- * as template content and the resulting tree string value is returned
- * This is needed for example by xsl:comment and xsl:processing-instruction
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltEvalTemplateString(xsltTransformContextPtr ctxt,
- xmlNodePtr currentNode,
- xmlNodePtr parent)
-{
- xmlNodePtr oldInsert, insert = NULL;
- xmlChar *ret;
-
- if ((ctxt == NULL) || (currentNode == NULL) || (parent == NULL))
- return(NULL);
-
- if (parent->children == NULL)
- return(NULL);
-
- /*
- * This creates a temporary element-node to add the resulting
- * text content to.
- * OPTIMIZE TODO: Keep such an element-node in the transformation
- * context to avoid creating it every time.
- */
- insert = xmlNewDocNode(ctxt->output, NULL,
- (const xmlChar *)"fake", NULL);
- if (insert == NULL) {
- xsltTransformError(ctxt, NULL, currentNode,
- "Failed to create temporary node\n");
- return(NULL);
- }
- oldInsert = ctxt->insert;
- ctxt->insert = insert;
- /* OPTIMIZE TODO: if parent->children consists only of text-nodes. */
- xsltApplyOneTemplate(ctxt, currentNode, parent->children, NULL, NULL);
-
- ctxt->insert = oldInsert;
-
- ret = xmlNodeGetContent(insert);
- if (insert != NULL)
- xmlFreeNode(insert);
- return(ret);
-}
-
-/**
- * xsltAttrTemplateValueProcessNode:
- * @ctxt: the XSLT transformation context
- * @str: the attribute template node value
- * @inst: the instruction (or LRE) in the stylesheet holding the
- * attribute with an AVT
- *
- * Process the given string, allowing to pass a namespace mapping
- * context and return the new string value.
- *
- * Called by:
- * - xsltAttrTemplateValueProcess() (templates.c)
- * - xsltEvalAttrValueTemplate() (templates.c)
- *
- * QUESTION: Why is this function public? It is not used outside
- * of templates.c.
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
- const xmlChar *str, xmlNodePtr inst)
-{
- xmlChar *ret = NULL;
- const xmlChar *cur;
- xmlChar *expr, *val;
- xmlNsPtr *nsList = NULL;
- int nsNr = 0;
-
- if (str == NULL) return(NULL);
- if (*str == 0)
- return(xmlStrndup((xmlChar *)"", 0));
-
- cur = str;
- while (*cur != 0) {
- if (*cur == '{') {
- if (*(cur+1) == '{') { /* escaped '{' */
- cur++;
- ret = xmlStrncat(ret, str, cur - str);
- cur++;
- str = cur;
- continue;
- }
- ret = xmlStrncat(ret, str, cur - str);
- str = cur;
- cur++;
- while ((*cur != 0) && (*cur != '}')) cur++;
- if (*cur == 0) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
- ret = xmlStrncat(ret, str, cur - str);
- return(ret);
- }
- str++;
- expr = xmlStrndup(str, cur - str);
- if (expr == NULL)
- return(ret);
- else if (*expr == '{') {
- ret = xmlStrcat(ret, expr);
- xmlFree(expr);
- } else {
- xmlXPathCompExprPtr comp;
- /*
- * TODO: keep precompiled form around
- */
- if ((nsList == NULL) && (inst != NULL)) {
- int i = 0;
-
- nsList = xmlGetNsList(inst->doc, inst);
- if (nsList != NULL) {
- while (nsList[i] != NULL)
- i++;
- nsNr = i;
- }
- }
- comp = xmlXPathCompile(expr);
- val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);
- xmlXPathFreeCompExpr(comp);
- xmlFree(expr);
- if (val != NULL) {
- ret = xmlStrcat(ret, val);
- xmlFree(val);
- }
- }
- cur++;
- str = cur;
- } else if (*cur == '}') {
- cur++;
- if (*cur == '}') { /* escaped '}' */
- ret = xmlStrncat(ret, str, cur - str);
- cur++;
- str = cur;
- continue;
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "xsltAttrTemplateValueProcessNode: unmatched '}'\n");
- }
- } else
- cur++;
- }
- if (cur != str) {
- ret = xmlStrncat(ret, str, cur - str);
- }
-
- if (nsList != NULL)
- xmlFree(nsList);
-
- return(ret);
-}
-
-/**
- * xsltAttrTemplateValueProcess:
- * @ctxt: the XSLT transformation context
- * @str: the attribute template node value
- *
- * Process the given node and return the new string value.
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
- return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));
-}
-
-/**
- * xsltEvalAttrValueTemplate:
- * @ctxt: the XSLT transformation context
- * @inst: the instruction (or LRE) in the stylesheet holding the
- * attribute with an AVT
- * @name: the attribute QName
- * @ns: the attribute namespace URI
- *
- * Evaluate a attribute value template, i.e. the attribute value can
- * contain expressions contained in curly braces ({}) and those are
- * substituted by they computed value.
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
-xmlChar *
-xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
- const xmlChar *name, const xmlChar *ns)
-{
- xmlChar *ret;
- xmlChar *expr;
-
- if ((ctxt == NULL) || (inst == NULL) || (name == NULL))
- return(NULL);
-
- expr = xsltGetNsProp(inst, name, ns);
- if (expr == NULL)
- return(NULL);
-
- /*
- * TODO: though now {} is detected ahead, it would still be good to
- * optimize both functions to keep the splitted value if the
- * attribute content and the XPath precompiled expressions around
- */
-
- ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);
-#ifdef WITH_XSLT_DEBUG_TEMPLATES
- XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));
-#endif
- if (expr != NULL)
- xmlFree(expr);
- return(ret);
-}
-
-/**
- * xsltEvalStaticAttrValueTemplate:
- * @style: the XSLT stylesheet
- * @inst: the instruction (or LRE) in the stylesheet holding the
- * attribute with an AVT
- * @name: the attribute Name
- * @ns: the attribute namespace URI
- * @found: indicator whether the attribute is present
- *
- * Check if an attribute value template has a static value, i.e. the
- * attribute value does not contain expressions contained in curly braces ({})
- *
- * Returns the static string value or NULL, must be deallocated by the
- * caller.
- */
-const xmlChar *
-xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
- const xmlChar *name, const xmlChar *ns, int *found) {
- const xmlChar *ret;
- xmlChar *expr;
-
- if ((style == NULL) || (inst == NULL) || (name == NULL))
- return(NULL);
-
- expr = xsltGetNsProp(inst, name, ns);
- if (expr == NULL) {
- *found = 0;
- return(NULL);
- }
- *found = 1;
-
- ret = xmlStrchr(expr, '{');
- if (ret != NULL) {
- xmlFree(expr);
- return(NULL);
- }
- ret = xmlDictLookup(style->dict, expr, -1);
- xmlFree(expr);
- return(ret);
-}
-
-/**
- * xsltAttrTemplateProcess:
- * @ctxt: the XSLT transformation context
- * @target: the element where the attribute will be grafted
- * @attr: the attribute node of a literal result element
- *
- * Process one attribute of a Literal Result Element (in the stylesheet).
- * Evaluates Attribute Value Templates and copies the attribute over to
- * the result element.
- * This does *not* process attribute sets (xsl:use-attribute-set).
- *
- *
- * Returns the generated attribute node.
- */
-xmlAttrPtr
-xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
- xmlAttrPtr attr)
-{
- const xmlChar *value;
- xmlAttrPtr ret;
-
- if ((ctxt == NULL) || (attr == NULL) || (target == NULL))
- return(NULL);
-
- if (attr->type != XML_ATTRIBUTE_NODE)
- return(NULL);
-
- /*
- * Skip all XSLT attributes.
- */
-#ifdef XSLT_REFACTORED
- if (attr->psvi == xsltXSLTAttrMarker)
- return(NULL);
-#else
- if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
- return(NULL);
-#endif
- /*
- * Get the value.
- */
- if (attr->children != NULL) {
- if ((attr->children->type != XML_TEXT_NODE) ||
- (attr->children->next != NULL))
- {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: The children of an attribute node of a "
- "literal result element are not in the expected form.\n");
- return(NULL);
- }
- value = attr->children->content;
- if (value == NULL)
- value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
- } else
- value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
- /*
- * Overwrite duplicates.
- */
- ret = target->properties;
- while (ret != NULL) {
- if (((attr->ns != NULL) == (ret->ns != NULL)) &&
- xmlStrEqual(ret->name, attr->name) &&
- ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))
- {
- break;
- }
- ret = ret->next;
- }
- if (ret != NULL) {
- /* free the existing value */
- xmlFreeNodeList(ret->children);
- ret->children = ret->last = NULL;
- /*
- * Adjust ns-prefix if needed.
- */
- if ((ret->ns != NULL) &&
- (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))
- {
- ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
- }
- } else {
- /* create a new attribute */
- if (attr->ns != NULL)
- ret = xmlNewNsProp(target,
- xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
- attr->name, NULL);
- else
- ret = xmlNewNsProp(target, NULL, attr->name, NULL);
- }
- /*
- * Set the value.
- */
- if (ret != NULL) {
- xmlNodePtr text;
-
- text = xmlNewText(NULL);
- if (text != NULL) {
- ret->last = ret->children = text;
- text->parent = (xmlNodePtr) ret;
- text->doc = ret->doc;
-
- if (attr->psvi != NULL) {
- /*
- * Evaluate the Attribute Value Template.
- */
- xmlChar *val;
- val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
- if (val == NULL) {
- /*
- * TODO: Damn, we need an easy mechanism to report
- * qualified names!
- */
- if (attr->ns) {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to evaluate the AVT "
- "of attribute '{%s}%s'.\n",
- attr->ns->href, attr->name);
- } else {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to evaluate the AVT "
- "of attribute '%s'.\n",
- attr->name);
- }
- text->content = xmlStrdup(BAD_CAST "");
- } else {
- text->content = val;
- }
- } else if ((ctxt->internalized) && (target != NULL) &&
- (target->doc != NULL) &&
- (target->doc->dict == ctxt->dict)) {
- text->content = (xmlChar *) value;
- } else {
- text->content = xmlStrdup(value);
- }
- }
- } else {
- if (attr->ns) {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to create attribute '{%s}%s'.\n",
- attr->ns->href, attr->name);
- } else {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to create attribute '%s'.\n",
- attr->name);
- }
- }
- return(ret);
-}
-
-
-/**
- * xsltAttrListTemplateProcess:
- * @ctxt: the XSLT transformation context
- * @target: the element where the attributes will be grafted
- * @cur: the first attribute
- *
- * Processes all attributes of a Literal Result Element.
- * Attribute references are applied via xsl:use-attribute-set
- * attributes.
- * Copies all non XSLT-attributes over to the @target element
- * and evaluates Attribute Value Templates.
- *
- * Called by xsltApplyOneTemplateInt() (transform.c).
- *
- * Returns a new list of attribute nodes, or NULL in case of error.
- * (Don't assign the result to @target->properties; if
- * the result is NULL, you'll get memory leaks, since the
- * attributes will be disattached.)
- */
-xmlAttrPtr
-xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt,
- xmlNodePtr target, xmlAttrPtr attrs)
-{
- xmlAttrPtr attr, copy, last;
- xmlNodePtr oldInsert, text;
- xmlNsPtr origNs = NULL, copyNs = NULL;
- const xmlChar *value;
- xmlChar *valueAVT;
-
- if ((ctxt == NULL) || (target == NULL) || (attrs == NULL))
- return(NULL);
-
- oldInsert = ctxt->insert;
- ctxt->insert = target;
-
- /*
- * Instantiate LRE-attributes.
- */
- if (target->properties) {
- last = target->properties;
- while (last->next != NULL)
- last = last->next;
- } else {
- last = NULL;
- }
- attr = attrs;
- do {
- /*
- * Skip XSLT attributes.
- */
-#ifdef XSLT_REFACTORED
- if (attr->psvi == xsltXSLTAttrMarker) {
- goto next_attribute;
- }
-#else
- if ((attr->ns != NULL) &&
- xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
- {
- goto next_attribute;
- }
-#endif
- /*
- * Get the value.
- */
- if (attr->children != NULL) {
- if ((attr->children->type != XML_TEXT_NODE) ||
- (attr->children->next != NULL))
- {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: The children of an attribute node of a "
- "literal result element are not in the expected form.\n");
- goto error;
- }
- value = attr->children->content;
- if (value == NULL)
- value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
- } else
- value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
-
- /*
- * Create a new attribute.
- */
- copy = xmlNewDocProp(target->doc, attr->name, NULL);
- if (copy == NULL) {
- if (attr->ns) {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to create attribute '{%s}%s'.\n",
- attr->ns->href, attr->name);
- } else {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to create attribute '%s'.\n",
- attr->name);
- }
- goto error;
- }
- /*
- * Attach it to the target element.
- */
- copy->parent = target;
- if (last == NULL) {
- target->properties = copy;
- last = copy;
- } else {
- last->next = copy;
- copy->prev = last;
- last = copy;
- }
- /*
- * Set the namespace. Avoid lookups of same namespaces.
- */
- if (attr->ns != origNs) {
- origNs = attr->ns;
- if (attr->ns != NULL) {
-#ifdef XSLT_REFACTORED
- copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,
- attr->ns->href, attr->ns->prefix, target);
-#else
- copyNs = xsltGetNamespace(ctxt, attr->parent,
- attr->ns, target);
-#endif
- if (copyNs == NULL)
- goto error;
- } else
- copyNs = NULL;
- }
- copy->ns = copyNs;
-
- /*
- * Set the value.
- */
- text = xmlNewText(NULL);
- if (text != NULL) {
- copy->last = copy->children = text;
- text->parent = (xmlNodePtr) copy;
- text->doc = copy->doc;
-
- if (attr->psvi != NULL) {
- /*
- * Evaluate the Attribute Value Template.
- */
- valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
- if (valueAVT == NULL) {
- /*
- * TODO: Damn, we need an easy mechanism to report
- * qualified names!
- */
- if (attr->ns) {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to evaluate the AVT "
- "of attribute '{%s}%s'.\n",
- attr->ns->href, attr->name);
- } else {
- xsltTransformError(ctxt, NULL, attr->parent,
- "Internal error: Failed to evaluate the AVT "
- "of attribute '%s'.\n",
- attr->name);
- }
- text->content = xmlStrdup(BAD_CAST "");
- goto error;
- } else {
- text->content = valueAVT;
- }
- } else if ((ctxt->internalized) &&
- (target->doc != NULL) &&
- (target->doc->dict == ctxt->dict))
- {
- text->content = (xmlChar *) value;
- } else {
- text->content = xmlStrdup(value);
- }
- }
-
-next_attribute:
- attr = attr->next;
- } while (attr != NULL);
-
- /*
- * Apply attribute-sets.
- * The creation of such attributes will not overwrite any existing
- * attribute.
- */
- attr = attrs;
- do {
-#ifdef XSLT_REFACTORED
- if ((attr->psvi == xsltXSLTAttrMarker) &&
- xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))
- {
- xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
- }
-#else
- if ((attr->ns != NULL) &&
- xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&
- xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
- {
- xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
- }
-#endif
- attr = attr->next;
- } while (attr != NULL);
-
- ctxt->insert = oldInsert;
- return(target->properties);
-
-error:
- ctxt->insert = oldInsert;
- return(NULL);
-}
-
-
-/**
- * xsltTemplateProcess:
- * @ctxt: the XSLT transformation context
- * @node: the attribute template node
- *
- * Obsolete. Does always return NULL. Don't use it.
- */
-xmlNodePtr *
-xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
- if (node == NULL)
- return(NULL);
-
- return(0);
-}
-
-
+/*\r
+ * templates.c: Implementation of the template processing\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/globals.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/parserInternals.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "variables.h"\r
+#include "functions.h"\r
+#include "templates.h"\r
+#include "transform.h"\r
+#include "namespaces.h"\r
+#include "attributes.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_TEMPLATES\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+ \r
+/**\r
+ * xsltEvalXPathPredicate:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the XPath compiled expression\r
+ * @nsList: the namespaces in scope\r
+ * @nsNr: the number of namespaces in scope\r
+ *\r
+ * Process the expression using XPath and evaluate the result as\r
+ * an XPath predicate\r
+ *\r
+ * Returns 1 is the predicate was true, 0 otherwise\r
+ */\r
+int\r
+xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,\r
+ xmlNsPtr *nsList, int nsNr) {\r
+ int ret;\r
+ xmlXPathObjectPtr res;\r
+ int oldNsNr;\r
+ xmlNsPtr *oldNamespaces;\r
+ xmlNodePtr oldInst;\r
+ int oldProximityPosition, oldContextSize;\r
+\r
+ oldContextSize = ctxt->xpathCtxt->contextSize;\r
+ oldProximityPosition = ctxt->xpathCtxt->proximityPosition;\r
+ oldNsNr = ctxt->xpathCtxt->nsNr;\r
+ oldNamespaces = ctxt->xpathCtxt->namespaces;\r
+ oldInst = ctxt->inst;\r
+\r
+ ctxt->xpathCtxt->node = ctxt->node;\r
+ ctxt->xpathCtxt->namespaces = nsList;\r
+ ctxt->xpathCtxt->nsNr = nsNr;\r
+\r
+ res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);\r
+\r
+ if (res != NULL) {\r
+ ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);\r
+ xmlXPathFreeObject(res);\r
+#ifdef WITH_XSLT_DEBUG_TEMPLATES\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltEvalXPathPredicate: returns %d\n", ret));\r
+#endif\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_TEMPLATES\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltEvalXPathPredicate: failed\n"));\r
+#endif\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ ret = 0;\r
+ }\r
+ ctxt->xpathCtxt->nsNr = oldNsNr;\r
+\r
+ ctxt->xpathCtxt->namespaces = oldNamespaces;\r
+ ctxt->inst = oldInst;\r
+ ctxt->xpathCtxt->contextSize = oldContextSize;\r
+ ctxt->xpathCtxt->proximityPosition = oldProximityPosition;\r
+\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltEvalXPathStringNs:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the compiled XPath expression\r
+ * @nsNr: the number of namespaces in the list\r
+ * @nsList: the list of in-scope namespaces to use\r
+ *\r
+ * Process the expression using XPath, allowing to pass a namespace mapping\r
+ * context and get a string\r
+ *\r
+ * Returns the computed string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+xmlChar *\r
+xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,\r
+ int nsNr, xmlNsPtr *nsList) {\r
+ xmlChar *ret = NULL;\r
+ xmlXPathObjectPtr res;\r
+ xmlNodePtr oldInst;\r
+ xmlNodePtr oldNode;\r
+ int oldPos, oldSize;\r
+ int oldNsNr;\r
+ xmlNsPtr *oldNamespaces;\r
+\r
+ oldInst = ctxt->inst;\r
+ oldNode = ctxt->node;\r
+ oldPos = ctxt->xpathCtxt->proximityPosition;\r
+ oldSize = ctxt->xpathCtxt->contextSize;\r
+ oldNsNr = ctxt->xpathCtxt->nsNr;\r
+ oldNamespaces = ctxt->xpathCtxt->namespaces;\r
+\r
+ ctxt->xpathCtxt->node = ctxt->node;\r
+ /* TODO: do we need to propagate the namespaces here ? */\r
+ ctxt->xpathCtxt->namespaces = nsList;\r
+ ctxt->xpathCtxt->nsNr = nsNr;\r
+ res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);\r
+ if (res != NULL) {\r
+ if (res->type != XPATH_STRING)\r
+ res = xmlXPathConvertString(res);\r
+ if (res->type == XPATH_STRING) {\r
+ ret = res->stringval;\r
+ res->stringval = NULL;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xpath : string() function didn't return a String\n");\r
+ }\r
+ xmlXPathFreeObject(res);\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_TEMPLATES\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltEvalXPathString: returns %s\n", ret));\r
+#endif\r
+ ctxt->inst = oldInst;\r
+ ctxt->node = oldNode;\r
+ ctxt->xpathCtxt->contextSize = oldSize;\r
+ ctxt->xpathCtxt->proximityPosition = oldPos;\r
+ ctxt->xpathCtxt->nsNr = oldNsNr;\r
+ ctxt->xpathCtxt->namespaces = oldNamespaces;\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltEvalXPathString:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the compiled XPath expression\r
+ *\r
+ * Process the expression using XPath and get a string\r
+ *\r
+ * Returns the computed string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+xmlChar *\r
+xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {\r
+ return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));\r
+}\r
+\r
+/**\r
+ * xsltEvalTemplateString:\r
+ * @ctxt: the XSLT transformation context\r
+ * @contextNode: the current node in the source tree\r
+ * @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction)\r
+ *\r
+ * Processes the sequence constructor of the given instruction on\r
+ * @contextNode and converts the resulting tree to a string.\r
+ * This is needed by e.g. xsl:comment and xsl:processing-instruction.\r
+ *\r
+ * Returns the computed string value or NULL; it's up to the caller to\r
+ * free the result.\r
+ */\r
+xmlChar *\r
+xsltEvalTemplateString(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr inst)\r
+{\r
+ xmlNodePtr oldInsert, insert = NULL;\r
+ xmlChar *ret;\r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))\r
+ return(NULL);\r
+\r
+ if (inst->children == NULL)\r
+ return(NULL);\r
+\r
+ /*\r
+ * This creates a temporary element-node to add the resulting\r
+ * text content to.\r
+ * OPTIMIZE TODO: Keep such an element-node in the transformation\r
+ * context to avoid creating it every time.\r
+ */\r
+ insert = xmlNewDocNode(ctxt->output, NULL,\r
+ (const xmlChar *)"fake", NULL);\r
+ if (insert == NULL) {\r
+ xsltTransformError(ctxt, NULL, contextNode,\r
+ "Failed to create temporary node\n");\r
+ return(NULL);\r
+ }\r
+ oldInsert = ctxt->insert;\r
+ ctxt->insert = insert;\r
+ /*\r
+ * OPTIMIZE TODO: if inst->children consists only of text-nodes.\r
+ */\r
+ xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);\r
+\r
+ ctxt->insert = oldInsert;\r
+\r
+ ret = xmlNodeGetContent(insert);\r
+ if (insert != NULL)\r
+ xmlFreeNode(insert);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltAttrTemplateValueProcessNode:\r
+ * @ctxt: the XSLT transformation context\r
+ * @str: the attribute template node value\r
+ * @inst: the instruction (or LRE) in the stylesheet holding the\r
+ * attribute with an AVT\r
+ *\r
+ * Process the given string, allowing to pass a namespace mapping\r
+ * context and return the new string value.\r
+ *\r
+ * Called by:\r
+ * - xsltAttrTemplateValueProcess() (templates.c)\r
+ * - xsltEvalAttrValueTemplate() (templates.c)\r
+ *\r
+ * QUESTION: Why is this function public? It is not used outside\r
+ * of templates.c.\r
+ *\r
+ * Returns the computed string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+xmlChar *\r
+xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,\r
+ const xmlChar *str, xmlNodePtr inst)\r
+{\r
+ xmlChar *ret = NULL;\r
+ const xmlChar *cur;\r
+ xmlChar *expr, *val;\r
+ xmlNsPtr *nsList = NULL;\r
+ int nsNr = 0;\r
+\r
+ if (str == NULL) return(NULL);\r
+ if (*str == 0)\r
+ return(xmlStrndup((xmlChar *)"", 0));\r
+\r
+ cur = str;\r
+ while (*cur != 0) {\r
+ if (*cur == '{') {\r
+ if (*(cur+1) == '{') { /* escaped '{' */\r
+ cur++;\r
+ ret = xmlStrncat(ret, str, cur - str);\r
+ cur++;\r
+ str = cur;\r
+ continue;\r
+ }\r
+ ret = xmlStrncat(ret, str, cur - str);\r
+ str = cur;\r
+ cur++;\r
+ while ((*cur != 0) && (*cur != '}')) cur++;\r
+ if (*cur == 0) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltAttrTemplateValueProcessNode: unmatched '{'\n");\r
+ ret = xmlStrncat(ret, str, cur - str);\r
+ return(ret);\r
+ }\r
+ str++;\r
+ expr = xmlStrndup(str, cur - str);\r
+ if (expr == NULL)\r
+ return(ret);\r
+ else if (*expr == '{') {\r
+ ret = xmlStrcat(ret, expr);\r
+ xmlFree(expr);\r
+ } else {\r
+ xmlXPathCompExprPtr comp;\r
+ /*\r
+ * TODO: keep precompiled form around\r
+ */\r
+ if ((nsList == NULL) && (inst != NULL)) {\r
+ int i = 0;\r
+\r
+ nsList = xmlGetNsList(inst->doc, inst);\r
+ if (nsList != NULL) {\r
+ while (nsList[i] != NULL)\r
+ i++;\r
+ nsNr = i;\r
+ }\r
+ }\r
+ comp = xmlXPathCompile(expr);\r
+ val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);\r
+ xmlXPathFreeCompExpr(comp);\r
+ xmlFree(expr);\r
+ if (val != NULL) {\r
+ ret = xmlStrcat(ret, val);\r
+ xmlFree(val);\r
+ }\r
+ }\r
+ cur++;\r
+ str = cur;\r
+ } else if (*cur == '}') {\r
+ cur++;\r
+ if (*cur == '}') { /* escaped '}' */\r
+ ret = xmlStrncat(ret, str, cur - str);\r
+ cur++;\r
+ str = cur;\r
+ continue;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltAttrTemplateValueProcessNode: unmatched '}'\n");\r
+ }\r
+ } else\r
+ cur++;\r
+ }\r
+ if (cur != str) {\r
+ ret = xmlStrncat(ret, str, cur - str);\r
+ }\r
+\r
+ if (nsList != NULL)\r
+ xmlFree(nsList);\r
+\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltAttrTemplateValueProcess:\r
+ * @ctxt: the XSLT transformation context\r
+ * @str: the attribute template node value\r
+ *\r
+ * Process the given node and return the new string value.\r
+ *\r
+ * Returns the computed string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+xmlChar *\r
+xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {\r
+ return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));\r
+}\r
+\r
+/**\r
+ * xsltEvalAttrValueTemplate:\r
+ * @ctxt: the XSLT transformation context\r
+ * @inst: the instruction (or LRE) in the stylesheet holding the\r
+ * attribute with an AVT\r
+ * @name: the attribute QName\r
+ * @ns: the attribute namespace URI\r
+ *\r
+ * Evaluate a attribute value template, i.e. the attribute value can\r
+ * contain expressions contained in curly braces ({}) and those are\r
+ * substituted by they computed value.\r
+ *\r
+ * Returns the computed string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+xmlChar *\r
+xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,\r
+ const xmlChar *name, const xmlChar *ns)\r
+{\r
+ xmlChar *ret;\r
+ xmlChar *expr;\r
+\r
+ if ((ctxt == NULL) || (inst == NULL) || (name == NULL))\r
+ return(NULL);\r
+\r
+ expr = xsltGetNsProp(inst, name, ns);\r
+ if (expr == NULL)\r
+ return(NULL);\r
+\r
+ /*\r
+ * TODO: though now {} is detected ahead, it would still be good to\r
+ * optimize both functions to keep the splitted value if the\r
+ * attribute content and the XPath precompiled expressions around\r
+ */\r
+\r
+ ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);\r
+#ifdef WITH_XSLT_DEBUG_TEMPLATES\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));\r
+#endif\r
+ if (expr != NULL)\r
+ xmlFree(expr);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltEvalStaticAttrValueTemplate:\r
+ * @style: the XSLT stylesheet\r
+ * @inst: the instruction (or LRE) in the stylesheet holding the\r
+ * attribute with an AVT\r
+ * @name: the attribute Name\r
+ * @ns: the attribute namespace URI\r
+ * @found: indicator whether the attribute is present\r
+ *\r
+ * Check if an attribute value template has a static value, i.e. the\r
+ * attribute value does not contain expressions contained in curly braces ({})\r
+ *\r
+ * Returns the static string value or NULL, must be deallocated by the\r
+ * caller.\r
+ */\r
+const xmlChar *\r
+xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,\r
+ const xmlChar *name, const xmlChar *ns, int *found) {\r
+ const xmlChar *ret;\r
+ xmlChar *expr;\r
+\r
+ if ((style == NULL) || (inst == NULL) || (name == NULL))\r
+ return(NULL);\r
+\r
+ expr = xsltGetNsProp(inst, name, ns);\r
+ if (expr == NULL) {\r
+ *found = 0;\r
+ return(NULL);\r
+ }\r
+ *found = 1;\r
+\r
+ ret = xmlStrchr(expr, '{');\r
+ if (ret != NULL) {\r
+ xmlFree(expr);\r
+ return(NULL);\r
+ }\r
+ ret = xmlDictLookup(style->dict, expr, -1);\r
+ xmlFree(expr);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltAttrTemplateProcess:\r
+ * @ctxt: the XSLT transformation context\r
+ * @target: the element where the attribute will be grafted\r
+ * @attr: the attribute node of a literal result element\r
+ *\r
+ * Process one attribute of a Literal Result Element (in the stylesheet).\r
+ * Evaluates Attribute Value Templates and copies the attribute over to\r
+ * the result element.\r
+ * This does *not* process attribute sets (xsl:use-attribute-set).\r
+ * \r
+ *\r
+ * Returns the generated attribute node.\r
+ */\r
+xmlAttrPtr\r
+xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,\r
+ xmlAttrPtr attr)\r
+{\r
+ const xmlChar *value;\r
+ xmlAttrPtr ret;\r
+\r
+ if ((ctxt == NULL) || (attr == NULL) || (target == NULL))\r
+ return(NULL);\r
+ \r
+ if (attr->type != XML_ATTRIBUTE_NODE)\r
+ return(NULL);\r
+\r
+ /*\r
+ * Skip all XSLT attributes.\r
+ */\r
+#ifdef XSLT_REFACTORED \r
+ if (attr->psvi == xsltXSLTAttrMarker)\r
+ return(NULL);\r
+#else\r
+ if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))\r
+ return(NULL);\r
+#endif\r
+ /*\r
+ * Get the value.\r
+ */\r
+ if (attr->children != NULL) {\r
+ if ((attr->children->type != XML_TEXT_NODE) ||\r
+ (attr->children->next != NULL))\r
+ {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: The children of an attribute node of a "\r
+ "literal result element are not in the expected form.\n");\r
+ return(NULL);\r
+ }\r
+ value = attr->children->content;\r
+ if (value == NULL)\r
+ value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);\r
+ } else\r
+ value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);\r
+ /*\r
+ * Overwrite duplicates.\r
+ */\r
+ ret = target->properties;\r
+ while (ret != NULL) {\r
+ if (((attr->ns != NULL) == (ret->ns != NULL)) &&\r
+ xmlStrEqual(ret->name, attr->name) &&\r
+ ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))\r
+ {\r
+ break;\r
+ }\r
+ ret = ret->next;\r
+ }\r
+ if (ret != NULL) { \r
+ /* free the existing value */\r
+ xmlFreeNodeList(ret->children);\r
+ ret->children = ret->last = NULL;\r
+ /*\r
+ * Adjust ns-prefix if needed.\r
+ */\r
+ if ((ret->ns != NULL) &&\r
+ (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))\r
+ {\r
+ ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);\r
+ }\r
+ } else {\r
+ /* create a new attribute */\r
+ if (attr->ns != NULL)\r
+ ret = xmlNewNsProp(target,\r
+ xsltGetNamespace(ctxt, attr->parent, attr->ns, target),\r
+ attr->name, NULL);\r
+ else\r
+ ret = xmlNewNsProp(target, NULL, attr->name, NULL); \r
+ }\r
+ /*\r
+ * Set the value.\r
+ */\r
+ if (ret != NULL) {\r
+ xmlNodePtr text;\r
+\r
+ text = xmlNewText(NULL);\r
+ if (text != NULL) {\r
+ ret->last = ret->children = text;\r
+ text->parent = (xmlNodePtr) ret;\r
+ text->doc = ret->doc;\r
+\r
+ if (attr->psvi != NULL) {\r
+ /*\r
+ * Evaluate the Attribute Value Template.\r
+ */\r
+ xmlChar *val;\r
+ val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);\r
+ if (val == NULL) {\r
+ /*\r
+ * TODO: Damn, we need an easy mechanism to report\r
+ * qualified names!\r
+ */\r
+ if (attr->ns) {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to evaluate the AVT "\r
+ "of attribute '{%s}%s'.\n",\r
+ attr->ns->href, attr->name);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to evaluate the AVT "\r
+ "of attribute '%s'.\n",\r
+ attr->name);\r
+ }\r
+ text->content = xmlStrdup(BAD_CAST "");\r
+ } else {\r
+ text->content = val;\r
+ }\r
+ } else if ((ctxt->internalized) && (target != NULL) &&\r
+ (target->doc != NULL) &&\r
+ (target->doc->dict == ctxt->dict)) {\r
+ text->content = (xmlChar *) value;\r
+ } else {\r
+ text->content = xmlStrdup(value);\r
+ }\r
+ }\r
+ } else {\r
+ if (attr->ns) {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to create attribute '{%s}%s'.\n",\r
+ attr->ns->href, attr->name);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to create attribute '%s'.\n",\r
+ attr->name);\r
+ }\r
+ }\r
+ return(ret);\r
+}\r
+\r
+\r
+/**\r
+ * xsltAttrListTemplateProcess:\r
+ * @ctxt: the XSLT transformation context\r
+ * @target: the element where the attributes will be grafted\r
+ * @cur: the first attribute\r
+ *\r
+ * Processes all attributes of a Literal Result Element.\r
+ * Attribute references are applied via xsl:use-attribute-set\r
+ * attributes.\r
+ * Copies all non XSLT-attributes over to the @target element\r
+ * and evaluates Attribute Value Templates.\r
+ *\r
+ * Called by xsltApplySequenceConstructor() (transform.c).\r
+ *\r
+ * Returns a new list of attribute nodes, or NULL in case of error.\r
+ * (Don't assign the result to @target->properties; if\r
+ * the result is NULL, you'll get memory leaks, since the\r
+ * attributes will be disattached.)\r
+ */\r
+xmlAttrPtr\r
+xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, \r
+ xmlNodePtr target, xmlAttrPtr attrs)\r
+{\r
+ xmlAttrPtr attr, copy, last;\r
+ xmlNodePtr oldInsert, text;\r
+ xmlNsPtr origNs = NULL, copyNs = NULL;\r
+ const xmlChar *value;\r
+ xmlChar *valueAVT;\r
+\r
+ if ((ctxt == NULL) || (target == NULL) || (attrs == NULL))\r
+ return(NULL);\r
+\r
+ oldInsert = ctxt->insert;\r
+ ctxt->insert = target; \r
+\r
+ /*\r
+ * Instantiate LRE-attributes.\r
+ */\r
+ if (target->properties) {\r
+ last = target->properties;\r
+ while (last->next != NULL)\r
+ last = last->next;\r
+ } else {\r
+ last = NULL;\r
+ } \r
+ attr = attrs;\r
+ do {\r
+ /*\r
+ * Skip XSLT attributes.\r
+ */\r
+#ifdef XSLT_REFACTORED\r
+ if (attr->psvi == xsltXSLTAttrMarker) {\r
+ goto next_attribute;\r
+ }\r
+#else\r
+ if ((attr->ns != NULL) &&\r
+ xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))\r
+ {\r
+ goto next_attribute;\r
+ }\r
+#endif\r
+ /*\r
+ * Get the value.\r
+ */\r
+ if (attr->children != NULL) {\r
+ if ((attr->children->type != XML_TEXT_NODE) ||\r
+ (attr->children->next != NULL))\r
+ {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: The children of an attribute node of a "\r
+ "literal result element are not in the expected form.\n");\r
+ goto error;\r
+ }\r
+ value = attr->children->content;\r
+ if (value == NULL)\r
+ value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);\r
+ } else\r
+ value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);\r
+\r
+ /*\r
+ * Create a new attribute.\r
+ */\r
+ copy = xmlNewDocProp(target->doc, attr->name, NULL);\r
+ if (copy == NULL) {\r
+ if (attr->ns) {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to create attribute '{%s}%s'.\n",\r
+ attr->ns->href, attr->name);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to create attribute '%s'.\n",\r
+ attr->name);\r
+ }\r
+ goto error;\r
+ }\r
+ /*\r
+ * Attach it to the target element.\r
+ */\r
+ copy->parent = target;\r
+ if (last == NULL) {\r
+ target->properties = copy;\r
+ last = copy;\r
+ } else {\r
+ last->next = copy;\r
+ copy->prev = last;\r
+ last = copy;\r
+ }\r
+ /*\r
+ * Set the namespace. Avoid lookups of same namespaces.\r
+ */\r
+ if (attr->ns != origNs) {\r
+ origNs = attr->ns;\r
+ if (attr->ns != NULL) {\r
+#ifdef XSLT_REFACTORED\r
+ copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,\r
+ attr->ns->href, attr->ns->prefix, target);\r
+#else\r
+ copyNs = xsltGetNamespace(ctxt, attr->parent,\r
+ attr->ns, target);\r
+#endif\r
+ if (copyNs == NULL)\r
+ goto error;\r
+ } else\r
+ copyNs = NULL;\r
+ }\r
+ copy->ns = copyNs;\r
+ \r
+ /*\r
+ * Set the value.\r
+ */ \r
+ text = xmlNewText(NULL);\r
+ if (text != NULL) {\r
+ copy->last = copy->children = text;\r
+ text->parent = (xmlNodePtr) copy;\r
+ text->doc = copy->doc;\r
+ \r
+ if (attr->psvi != NULL) {\r
+ /*\r
+ * Evaluate the Attribute Value Template.\r
+ */ \r
+ valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);\r
+ if (valueAVT == NULL) {\r
+ /*\r
+ * TODO: Damn, we need an easy mechanism to report\r
+ * qualified names!\r
+ */\r
+ if (attr->ns) {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to evaluate the AVT "\r
+ "of attribute '{%s}%s'.\n",\r
+ attr->ns->href, attr->name); \r
+ } else {\r
+ xsltTransformError(ctxt, NULL, attr->parent,\r
+ "Internal error: Failed to evaluate the AVT "\r
+ "of attribute '%s'.\n",\r
+ attr->name);\r
+ }\r
+ text->content = xmlStrdup(BAD_CAST "");\r
+ goto error;\r
+ } else {\r
+ text->content = valueAVT;\r
+ }\r
+ } else if ((ctxt->internalized) &&\r
+ (target->doc != NULL) &&\r
+ (target->doc->dict == ctxt->dict))\r
+ {\r
+ text->content = (xmlChar *) value;\r
+ } else {\r
+ text->content = xmlStrdup(value);\r
+ }\r
+ }\r
+\r
+next_attribute:\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+\r
+ /*\r
+ * Apply attribute-sets.\r
+ * The creation of such attributes will not overwrite any existing\r
+ * attribute.\r
+ */\r
+ attr = attrs;\r
+ do {\r
+#ifdef XSLT_REFACTORED\r
+ if ((attr->psvi == xsltXSLTAttrMarker) &&\r
+ xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))\r
+ {\r
+ xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);\r
+ }\r
+#else\r
+ if ((attr->ns != NULL) &&\r
+ xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&\r
+ xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))\r
+ {\r
+ xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);\r
+ }\r
+#endif\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+\r
+ ctxt->insert = oldInsert;\r
+ return(target->properties);\r
+\r
+error:\r
+ ctxt->insert = oldInsert;\r
+ return(NULL);\r
+}\r
+\r
+\r
+/**\r
+ * xsltTemplateProcess:\r
+ * @ctxt: the XSLT transformation context\r
+ * @node: the attribute template node\r
+ *\r
+ * Obsolete. Does always return NULL. Don't use it.\r
+ */\r
+xmlNodePtr *\r
+xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {\r
+ if (node == NULL)\r
+ return(NULL);\r
+ \r
+ return(0);\r
+}\r
+\r
+\r
-/*
- * Summary: interface for the template processing
- * Description: This set of routine encapsulates XPath calls
- * and Attribute Value Templates evaluation.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
-
-#ifndef __XML_XSLT_TEMPLATES_H__
-#define __XML_XSLT_TEMPLATES_H__
-
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include "xsltexports.h"
-#include "xsltInternals.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-XSLTPUBFUN int XSLTCALL
- xsltEvalXPathPredicate (xsltTransformContextPtr ctxt,
- xmlXPathCompExprPtr comp,
- xmlNsPtr *nsList,
- int nsNr);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltEvalTemplateString (xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- xmlNodePtr parent);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- const xmlChar *name,
- const xmlChar *ns);
-XSLTPUBFUN const xmlChar * XSLTCALL
- xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style,
- xmlNodePtr node,
- const xmlChar *name,
- const xmlChar *ns,
- int *found);
-
-/* TODO: this is obviously broken ... the namespaces should be passed too ! */
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltEvalXPathString (xsltTransformContextPtr ctxt,
- xmlXPathCompExprPtr comp);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltEvalXPathStringNs (xsltTransformContextPtr ctxt,
- xmlXPathCompExprPtr comp,
- int nsNr,
- xmlNsPtr *nsList);
-
-XSLTPUBFUN xmlNodePtr * XSLTCALL
- xsltTemplateProcess (xsltTransformContextPtr ctxt,
- xmlNodePtr node);
-XSLTPUBFUN xmlAttrPtr XSLTCALL
- xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt,
- xmlNodePtr target,
- xmlAttrPtr cur);
-XSLTPUBFUN xmlAttrPtr XSLTCALL
- xsltAttrTemplateProcess (xsltTransformContextPtr ctxt,
- xmlNodePtr target,
- xmlAttrPtr attr);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt,
- const xmlChar* attr);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
- const xmlChar* str,
- xmlNodePtr node);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XML_XSLT_TEMPLATES_H__ */
-
+/*\r
+ * Summary: interface for the template processing\r
+ * Description: This set of routine encapsulates XPath calls\r
+ * and Attribute Value Templates evaluation.\r
+ *\r
+ * Copy: See Copyright for the status of this software.\r
+ *\r
+ * Author: Daniel Veillard\r
+ */\r
+\r
+#ifndef __XML_XSLT_TEMPLATES_H__\r
+#define __XML_XSLT_TEMPLATES_H__\r
+\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+#include "xsltexports.h"\r
+#include "xsltInternals.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltEvalXPathPredicate (xsltTransformContextPtr ctxt,\r
+ xmlXPathCompExprPtr comp,\r
+ xmlNsPtr *nsList,\r
+ int nsNr);\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltEvalTemplateString (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr inst);\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node,\r
+ const xmlChar *name,\r
+ const xmlChar *ns);\r
+XSLTPUBFUN const xmlChar * XSLTCALL \r
+ xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style,\r
+ xmlNodePtr node,\r
+ const xmlChar *name,\r
+ const xmlChar *ns,\r
+ int *found);\r
+\r
+/* TODO: this is obviously broken ... the namespaces should be passed too ! */\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltEvalXPathString (xsltTransformContextPtr ctxt,\r
+ xmlXPathCompExprPtr comp);\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltEvalXPathStringNs (xsltTransformContextPtr ctxt,\r
+ xmlXPathCompExprPtr comp,\r
+ int nsNr,\r
+ xmlNsPtr *nsList);\r
+\r
+XSLTPUBFUN xmlNodePtr * XSLTCALL \r
+ xsltTemplateProcess (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node);\r
+XSLTPUBFUN xmlAttrPtr XSLTCALL \r
+ xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr target,\r
+ xmlAttrPtr cur);\r
+XSLTPUBFUN xmlAttrPtr XSLTCALL \r
+ xsltAttrTemplateProcess (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr target,\r
+ xmlAttrPtr attr);\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt,\r
+ const xmlChar* attr);\r
+XSLTPUBFUN xmlChar * XSLTCALL \r
+ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,\r
+ const xmlChar* str,\r
+ xmlNodePtr node);\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __XML_XSLT_TEMPLATES_H__ */\r
+\r
-/*
- * 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 <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
-#endif
-
-#define XSLT_GENERATE_HTML_DOCTYPE
-#ifdef XSLT_GENERATE_HTML_DOCTYPE
-static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
- const xmlChar **systemID);
-#endif
-
-static void
-xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr list, xsltTemplatePtr templ,
- xsltStackElemPtr params, int notcur);
-
-int xsltMaxDepth = 5000;
-
-/*
- * 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
-xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
- xmlNodePtr invocNode,
- xmlNodePtr node,
- xmlNodePtr insert, int isLRE, int topElemVisited);
-
-/**
- * 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);
- }
- }
- 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);
-}
-/**
- * varsPush:
- * @ctxt: the transformation context
- * @value: the variable to push on the stack
- *
- * Push a variable on the stack
- *
- * Returns the new index in the stack or 0 in case of error
- */
-static int
-varsPush(xsltTransformContextPtr ctxt, xsltStackElemPtr value)
-{
- if (ctxt->varsMax == 0) {
- ctxt->varsMax = 4;
- ctxt->varsTab =
- (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
- sizeof(ctxt->varsTab[0]));
- if (ctxt->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (0);
- }
- }
- 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 (0);
- }
- }
- ctxt->varsTab[ctxt->varsNr] = value;
- ctxt->vars = value;
- return (ctxt->varsNr++);
-}
-/**
- * varsPop:
- * @ctxt: the transformation context
- *
- * Pop a variable value from the stack
- *
- * Returns the stored variable value
- */
-static xsltStackElemPtr
-varsPop(xsltTransformContextPtr ctxt)
-{
- xsltStackElemPtr ret;
-
- if (ctxt->varsNr <= 0)
- return (0);
- ctxt->varsNr--;
- if (ctxt->varsNr > 0)
- ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
- else
- ctxt->vars = (xsltStackElemPtr) 0;
- ret = ctxt->varsTab[ctxt->varsNr];
- ctxt->varsTab[ctxt->varsNr] = 0;
- return (ret);
-}
-/**
- * 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);
- }
- }
- 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);
-}
-
-/************************************************************************
- * *
- * 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);
-}
-
-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 *
- * *
- ************************************************************************/
-
-/**
- * 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;
-
- cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
- "xsltNewTransformContext : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltTransformContext));
-
- /*
- * setup of the dictionnary 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;
-
- /*
- * 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 = 5;
- cur->vars = NULL;
- cur->varsBase = 0;
-
- /*
- * 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;
- }
- cur->xpathCtxt->proximityPosition = 0;
- cur->xpathCtxt->contextSize = 0;
- /*
- * 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();
-
- 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);
- xmlDictFree(ctxt->dict);
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "freeing transformation dictionnary\n");
-#endif
- memset(ctxt, -1, sizeof(xsltTransformContext));
- xmlFree(ctxt);
-}
-
-/************************************************************************
- * *
- * Copy of Nodes in an XSLT fashion *
- * *
- ************************************************************************/
-
-xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt,
- xmlNodePtr node, xmlNodePtr insert, int literal);
-
-/**
- * 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) {
-
- if (ctxt->lasttuse + len >= ctxt->lasttsize) {
- xmlChar *newbuf;
- int size;
-
- size = ctxt->lasttsize + len + 100;
- size *= 2;
- 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.
- *
- * Create a text node
- *
- * Returns: a new xmlNodePtr, or NULL in case of error.
- */
-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
-
- /* 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))))
- {
- if ((target != NULL) && (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) {
- 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 {
- 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) {
- if (target != NULL)
- xmlAddChild(target, copy);
- 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 dictionnary
- *
- * Do a copy of a text node
- *
- * Returns: a new xmlNodePtr, or NULL in case of error.
- */
-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
-
- 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)))) {
- /*
- * 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.
- */
- copy = xmlNewCDataBlock(ctxt->output, cur->content,
- xmlStrlen(cur->content));
- ctxt->lasttext = NULL;
- } 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
- */
- return(xsltAddTextString(ctxt, target->last, cur->content,
- xmlStrlen(cur->content)));
- } 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)
- return NULL;
- if (cur->name == xmlStringTextNoenc)
- copy->name = xmlStringTextNoenc;
-
- /* OPTIMIZE TODO: get rid of xmlDictOwns() in safe cases;
- * e.g. attribute values don't need the lookup.
- *
- * Must confirm that content is in dict (bug 302821)
- * TODO: Check if bug 302821 still applies here.
- */
- 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)
- return NULL;
- 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.
- */
- xmlAddChild(target, copy);
- }
- } else {
- xsltTransformError(ctxt, NULL, target,
- "xsltCopyText: text copy failed\n");
- }
- 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:
- * - xsltCopyTreeInternal()
- * - 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:
- * - xsltCopyTreeInternal()
- *
- * Returns 0 on success and -1 on errors and internal errors.
- */
-static int
-xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
- xmlNodePtr invocNode,
- xmlNodePtr target, xmlAttrPtr attr)
-{
- xmlAttrPtr last = NULL, copy;
- xmlNsPtr origNs = NULL, copyNs = NULL;
- xmlChar *value = NULL;
-
- /*
- * 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 (attr->children)
- value = xmlNodeListGetString(attr->doc, attr->children, 1);
- /*
- * REVISIT: I think xmlNewDocProp() is the only attr function
- * which does not eval if the attr is of type ID. This is good,
- * since we don't need this.
- */
- copy = xmlNewDocProp(target->doc, attr->name, BAD_CAST value);
- if (copy == NULL)
- return(-1);
- copy->parent = target;
- copy->ns = copyNs;
-
- if (last == NULL) {
- target->properties = copy;
- last = copy;
- } else {
- last->next = copy;
- copy->prev = last;
- last = copy;
- }
- /*
- * OPTIMIZE TODO: How to avoid this intermediate string?
- */
- if (value != NULL) {
- xmlFree(value);
- value = NULL;
- }
- 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:
- * xsltApplyOneTemplateInt() (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;
- xmlAddChild(insert, 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 xsltCopyTreeInternal(), 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.
- * @literal: is this a literal result element list
- *
- * 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 = xsltCopyTreeInternal(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:
- * xsltCopyTreeInternal()
- *
- * 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 int
-xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
- xmlNodePtr invocNode,
- xmlNodePtr insert,
- xmlNsPtr ns)
-{
- xmlNsPtr tmpns;
-
- if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
- return(-1);
-
- if (insert->children != NULL) {
- xsltTransformError(ctxt, NULL, invocNode,
- "Namespace nodes must be added before "
- "any child nodes are added to an element.\n");
- return(1);
- }
- /*
- *
- * 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"))
- {
- return(0);
- }
-
- 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(0);
- goto occupied;
- }
- }
- tmpns = tmpns->next;
- } while (tmpns != NULL);
- }
- tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
- if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
- return(0);
- /*
- * 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 :-/
- */
- xmlNewNs(insert, ns->href, ns->prefix);
- return(0);
-
-occupied:
- /*
- * TODO: We could as well raise an error here (like Saxon does),
- * or at least generate a warning.
- */
- return(0);
-}
-
-/**
- * xsltCopyTreeInternal:
- * @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
-xsltCopyTreeInternal(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;
- xmlAddChild(insert, 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,
- "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);
- }
- return(copy);
-}
-
-/**
- * xsltCopyTree:
- * @ctxt: the XSLT transformation context
- * @node: the element node in the source tree
- * @insert: the parent in the result tree
- * @literal: indicates if @node is a Literal Result Element
- *
- * Make a copy of the full tree under the element node @node
- * and insert it as last child of @insert
- * For literal result element, some of the namespaces may not be copied
- * over according to section 7.1.
- * TODO: Why is this a public function?
- *
- * Returns a pointer to the new tree, or NULL in case of error
- */
-xmlNodePtr
-xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr insert, int literal)
-{
- return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));
-
-}
-
-/************************************************************************
- * *
- * 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++;
- xsltApplyOneTemplateInt(ctxt, node, child->children, NULL, NULL, 0);
- }
- child = child->next;
- }
- return(ret);
-}
-
-/************************************************************************
- * *
- * Default processing *
- * *
- ************************************************************************/
-
-void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStackElemPtr params);
-/**
- * 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"));
- } 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
- */
- 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
- xsltApplyOneTemplateInt(ctxt, cur, template->content,
- template, params, 0);
- } 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;
- xsltApplyOneTemplateInt(ctxt, cur, template->content,
- template, params, 0);
- } 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;
- xsltApplyOneTemplateInt(ctxt, cur, template->content,
- template, params, 0);
- }
- break;
- default:
- break;
- }
- cur = cur->next;
- }
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
-}
-
-/**
- * xsltProcessOneNode:
- * @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.
- */
-void
-xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xsltStackElemPtr params) {
- xsltTemplatePtr template;
- xmlNodePtr oldNode;
-
- template = xsltGetTemplate(ctxt, node, NULL);
- /*
- * If no template is found, apply the default rule.
- */
- if (template == NULL) {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- if (node->type == XML_DOCUMENT_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for /\n"));
- } else if (node->type == XML_CDATA_SECTION_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for CDATA\n"));
- } else if (node->type == XML_ATTRIBUTE_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for attribute %s\n",
- ((xmlAttrPtr) node)->name));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: no template found for %s\n", node->name));
- }
-#endif
- oldNode = ctxt->node;
- ctxt->node = node;
- xsltDefaultProcessOneNode(ctxt, node, params);
- ctxt->node = oldNode;
- return;
- }
-
- if (node->type == XML_ATTRIBUTE_NODE) {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for attribute %s\n",
- template->match, node->name));
-#endif
- xsltApplyOneTemplateInt(ctxt, node, template->content, template, params, 0);
- } else {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- if (node->type == XML_DOCUMENT_NODE) {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for /\n",
- template->match));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltProcessOneNode: applying template '%s' for %s\n",
- template->match, node->name));
- }
-#endif
- xsltApplyOneTemplateInt(ctxt, node, template->content, template, params, 0);
- }
-}
-
-/**
- * xsltApplyOneTemplate:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @list: the template replacement nodelist
- * @templ: if is this a real template processing, the template processed
- * @params: a set of parameters for the template or NULL
- *
- * Process the apply-templates node on the source node, if params are passed
- * they are pushed on the variable stack but not popped, it's left to the
- * caller to handle them after return (they may be reused).
- */
-void
-xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr list, xsltTemplatePtr templ,
- xsltStackElemPtr params)
-{
- xsltApplyOneTemplateInt(ctxt, node, list, templ, params, 0);
-}
-
-/**
- * xsltApplyOneTemplateInt:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @list: the template replacement nodelist
- * @templ: if is this a real template processing, the template processed
- * @params: a set of parameters for the template or NULL
- * @notcur: flag to show current template rule doesn't change
- *
- * See above description for xsltApplyOneTemplate. Internally there is
- * an additional parameter 'notcur'. When this parameter is non-zero,
- * ctxt->templ is not changed (i.e. templPush and tempPop are not called).
- * This is used by xsltCallTemplate in order to meet the XSLT spec (5.6)
- * requirement that the "current template rule" should not be changed
- * (bug 157859).
- */
-static void
-xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr list, xsltTemplatePtr templ,
- xsltStackElemPtr params, int notcur)
-{
- xmlNodePtr cur = NULL, insert, copy = NULL;
- xmlNodePtr oldInsert;
- xmlNodePtr oldCurrent = NULL;
- xmlNodePtr oldInst = NULL;
- int oldBase;
- xmlDocPtr tmpRVT = NULL;
-#ifdef XSLT_REFACTORED
- xsltStylePreCompPtr info;
-#endif
-
- int level = 0;
-
-#ifdef WITH_DEBUGGER
- int addCallResult = 0;
- xmlNodePtr debugedNode = NULL;
-#endif
- long start = 0;
-
- if (ctxt == NULL) return;
-
-#ifdef WITH_DEBUGGER
- 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;
- }
-
- if (templ) {
- xslHandleDebugger(templ->elem, node, templ, ctxt);
- debugedNode = templ->elem;
- } else if (list) {
- xslHandleDebugger(list, node, templ, ctxt);
- debugedNode = list;
- } else if (ctxt->inst) {
- xslHandleDebugger(ctxt->inst, node, templ, ctxt);
- debugedNode = ctxt->inst;
- }
- }
-#endif
-
- if (list == NULL)
- return;
- CHECK_STOPPED;
-
- if ((ctxt->templNr >= xsltMaxDepth) ||
- (ctxt->varsNr >= 5 * xsltMaxDepth)) {
- xsltTransformError(ctxt, NULL, list,
- "xsltApplyOneTemplate: loop found ???\n");
- xsltGenericError(xsltGenericErrorContext,
- "try increasing xsltMaxDepth (--maxdepth)\n");
- xsltDebug(ctxt, node, list, NULL);
- return;
- }
-
- /*
- * stack saves, beware ordering of operations counts
- */
- oldInsert = insert = ctxt->insert;
- oldInst = ctxt->inst;
- oldCurrent = ctxt->node;
- varsPush(ctxt, params);
- oldBase = ctxt->varsBase; /* only needed if templ != NULL */
- if (templ != NULL) {
- ctxt->varsBase = ctxt->varsNr - 1;
- ctxt->node = node;
- if (ctxt->profile) {
- templ->nbCalls++;
- start = xsltTimestamp();
- profPush(ctxt, 0);
- }
- tmpRVT = ctxt->tmpRVT;
- ctxt->tmpRVT = NULL;
- if (!notcur)
- templPush(ctxt, templ);
-#ifdef WITH_XSLT_DEBUG_PROCESS
- if (templ->name != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "applying template '%s'\n", templ->name));
-#endif
- }
-
- /*
- * Insert all non-XSLT nodes found in the template
- */
- 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,
- "xsltApplyOneTemplateInt: insert == NULL !\n"));
-#endif
- goto error;
- }
-#ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debugedNode != cur))
- xslHandleDebugger(cur, node, 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, node, cur);
- goto skip_children;
- }
- /*
- * Something really went wrong:
- */
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltApplyOneTemplateInt(): "
- "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,
- "xsltApplyOneTemplateInt: 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 xsltApplyOneTemplateInt(): "
- "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;
- xmlAddChild(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 xsltApplyOneTemplateInt(): "
- "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."
- * TODO: Refactor this, since it still uses ns-aliasing.
- * 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, node, cur)) {
- xsltTransformError(ctxt, NULL, cur,
- "The is no fallback behaviour defined for "
- "the unknown XSLT element '%s'.\n",
- cur->name);
- }
- ctxt->insert = oldInsert;
- goto skip_children;
- }
- /*
- * Execute the XSLT instruction.
- */
- if (info->func != NULL) {
- ctxt->insert = insert;
- info->func(ctxt, node, cur, (xsltElemPreCompPtr) info);
- ctxt->insert = oldInsert;
- goto skip_children;
- }
- /*
- * Some XSLT instructions need custom execution.
- */
- if (info->type == XSLT_FUNC_VARIABLE) {
- if (level != 0) {
- /*
- * Build a new subframe and skip all the nodes
- * at that level.
- */
- ctxt->insert = insert;
- xsltApplyOneTemplateInt(ctxt, node, cur, NULL, NULL, 0);
- while (cur->next != NULL)
- cur = cur->next;
- ctxt->insert = oldInsert;
- } else {
- xsltParseStylesheetVariable(ctxt, cur);
- }
- } else if (info->type == XSLT_FUNC_PARAM) {
- xsltParseStylesheetParam(ctxt, cur);
- } else if (info->type == XSLT_FUNC_MESSAGE) {
- /*
- * TODO: Won't be hit, since we don't compile xsl:message.
- */
- xsltMessage(ctxt, node, cur);
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "Internal error in xsltApplyOneTemplateInt(): "
- "Don't know how to process the 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,
- "xsltApplyOneTemplate: unknown extension %s\n",
- cur->name));
-#endif
- ctxt->insert = insert;
- if (!xsltApplyFallbacks(ctxt, node, 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,
- "xsltApplyOneTemplate: extension construct %s\n",
- cur->name));
-#endif
- ctxt->insert = insert;
- func(ctxt, node, cur, cur->psvi);
- 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,
- "xsltApplyOneTemplateInt: copy unescaped text '%s'\n",
- cur->content));
- } else {
- XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplateInt: 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, node, cur);
- } else {
- /*
- * That's an error try to apply one of the fallback cases
- */
- ctxt->insert = insert;
- if (!xsltApplyFallbacks(ctxt, node, cur)) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltApplyOneTemplate: %s was not compiled\n",
- cur->name);
- }
- ctxt->insert = oldInsert;
- }
- goto skip_children;
- }
-
- if (info->func != NULL) {
- ctxt->insert = insert;
- info->func(ctxt, node, cur, (xsltElemPreCompPtr) info);
- ctxt->insert = oldInsert;
- goto skip_children;
- }
-
- if (IS_XSLT_NAME(cur, "variable")) {
- if (level != 0) {
- /*
- * Build a new subframe and skip all the nodes
- * at that level.
- */
- ctxt->insert = insert;
- xsltApplyOneTemplateInt(ctxt, node, cur, NULL, NULL, 0);
- while (cur->next != NULL)
- cur = cur->next;
- ctxt->insert = oldInsert;
- } else {
- xsltParseStylesheetVariable(ctxt, cur);
- }
- } else if (IS_XSLT_NAME(cur, "param")) {
- xsltParseStylesheetParam(ctxt, cur);
- } else if (IS_XSLT_NAME(cur, "message")) {
- xsltMessage(ctxt, node, cur);
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsltApplyOneTemplate: problem with xsl:%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,
- "xsltApplyOneTemplate: copy CDATA text %s\n",
- cur->content));
- } else if (cur->name == xmlStringTextNoenc) {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplate: copy unescaped text %s\n",
- cur->content));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplate: 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;
-
- /*
- * 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,
- "xsltApplyOneTemplate: 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;
- xsltApplyOneTemplateInt(ctxt, node, child->children,
- NULL, NULL, 0);
- }
- child = child->next;
- }
-
- if (!found) {
- xsltTransformError(ctxt, NULL, cur,
- "xsltApplyOneTemplate: failed to find extension %s\n",
- cur->name);
- }
- } else {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplate: extension construct %s\n",
- cur->name));
-#endif
-
- ctxt->insert = insert;
- function(ctxt, node, cur, cur->psvi);
- ctxt->insert = oldInsert;
- }
- goto skip_children;
- } else if (cur->type == XML_ELEMENT_NODE) {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplate: copy node %s\n",
- cur->name));
-#endif
- 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);
- }
- }
-#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--;
- 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:
- ctxt->node = oldCurrent;
- ctxt->inst = oldInst;
- ctxt->insert = oldInsert;
- if (params == NULL)
- xsltFreeStackElemList(varsPop(ctxt));
- else {
- xsltStackElemPtr p, tmp = varsPop(ctxt);
-
- if (tmp != params) {
- p = tmp;
- while ((p != NULL) && (p->next != params))
- p = p->next;
- if (p == NULL) {
- xsltFreeStackElemList(tmp);
- } else {
- p->next = NULL;
- xsltFreeStackElemList(tmp);
- }
- }
- }
- if (templ != NULL) {
- ctxt->varsBase = oldBase;
- if (!notcur)
- templPop(ctxt);
- /*
- * Free up all the unreferenced RVT
- * Also set any global variables instantiated
- * using them, to be "not yet computed".
- */
- if (ctxt->tmpRVT != NULL) {
- xsltStackElemPtr elem;
- xmlDocPtr tmp = ctxt->tmpRVT, next;
- while (tmp != NULL) {
- elem = (xsltStackElemPtr)tmp->psvi;
- if (elem != NULL) {
- elem->computed = 0;
- xmlXPathFreeObject(elem->value);
- }
- next = (xmlDocPtr) tmp->next;
- if (tmp->_private != NULL) {
- xsltFreeDocumentKeys(tmp->_private);
- xmlFree(tmp->_private);
- }
- xmlFreeDoc(tmp);
- tmp = next;
- }
- }
- ctxt->tmpRVT = tmpRVT;
- 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
-}
-
-/************************************************************************
- * *
- * XSLT-1.1 extensions *
- * *
- ************************************************************************/
-
-/**
- * xsltDocumentElem:
- * @ctxt: an XSLT processing context
- * @node: The current node
- * @inst: the instruction in the stylesheet
- * @comp: 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;
-
- 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)
-
- 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",
- style->method);
- 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",
- style->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 (style->encoding != NULL)
- res->encoding = xmlStrdup(style->encoding);
- ctxt->output = res;
- ctxt->insert = (xmlNodePtr) res;
- xsltApplyOneTemplateInt(ctxt, node, inst->children, NULL, NULL, 0);
-
- /*
- * 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);
- }
- }
-
- /*
- * Save the result
- */
- ret = xsltSaveResultToFilename((const char *) filename,
- res, style, 0);
- if (ret < 0) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltDocumentElem: unable to save to %s\n",
- filename);
- ctxt->state = XSLT_STATE_ERROR;
-#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
- * @comp: 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);
- xmlAddChild(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);
- xmlAddChild(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:
- xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children,
- NULL, NULL, 0);
- 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;
- }
- xmlAddChild(ctxt->insert, copy);
- text = text->next;
- }
- }
-}
-
-/**
- * xsltElement:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt element node
- * @comp: 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);
- if ((prefix != NULL) &&
- (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
- {
- /*
- * TODO: Should we really disallow an "xml" prefix?
- */
- goto error;
- }
- } 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;
- }
- xmlAddChild(ctxt->insert, copy);
-
- /*
- * 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);
- };
- } 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) {
- 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)
- xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children,
- NULL, NULL, 0);
-
-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);
- xmlAddChild(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
- * @comp: 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);
- xmlAddChild(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
- * @comp: 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;
- int oldProximityPosition, oldContextSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- 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
-
- /*
- * Set up the XPath evaluation context.
- */
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- /*
- * Evaluate the "select" expression.
- */
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- /*
- * Revert the XPath evaluation context to previous state.
- */
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
-
- 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 {
- xsltCopyTreeInternal(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>)
- * --------------------
- */
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: result is a result tree fragment\n"));
-#endif
- /*
- * TODO: Is list->nodeTab[0] is an xmlDocPtr?
- */
- 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 {
- /* Convert to a string. */
- res = xmlXPathConvertString(res);
- if ((res != NULL) && (res->type == XPATH_STRING)) {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltCopyOf: result %s\n", res->stringval));
-#endif
- /* Append content as text node. */
- xsltCopyTextString(ctxt, ctxt->insert, res->stringval, 0);
- }
- }
- } 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
- * @comp: 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;
- xmlNodePtr copy = NULL;
- int oldProximityPosition, oldContextSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:value-of : compilation failed\n");
- return;
- }
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltValueOf: select %s\n", comp->select));
-#endif
-
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- if (res != NULL) {
- if (res->type != XPATH_STRING)
- res = xmlXPathConvertString(res);
- if (res->type == XPATH_STRING) {
- copy = xsltCopyTextString(ctxt, ctxt->insert, res->stringval,
- comp->noescape);
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
- if (copy == NULL) {
- if ((res == NULL) || (res->stringval != NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltValueOf: text copy failed\n");
- }
- }
-#ifdef WITH_XSLT_DEBUG_PROCESS
- else
- XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltValueOf: result %s\n", res->stringval));
-#endif
- if (res != NULL)
- xmlXPathFreeObject(res);
-}
-
-/**
- * xsltNumber:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt number node
- * @comp: 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
- 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;
-
- xsltNumberFormat(ctxt, &comp->numdata, node);
-}
-
-/**
- * xsltApplyImports:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt apply-imports node
- * @comp: precomputed information
- *
- * Process the xslt apply-imports node on the source node
- */
-void
-xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst,
- xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
- xsltTemplatePtr template;
-
- if ((ctxt->templ == NULL) || (ctxt->templ->style == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:apply-imports : internal error no current template\n");
- return;
- }
- template = xsltGetTemplate(ctxt, node, ctxt->templ->style);
- if (template != NULL) {
- xsltApplyOneTemplateInt(ctxt, node, template->content, template, NULL, 0);
- }
-}
-
-/**
- * xsltCallTemplate:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt call-template node
- * @comp: precomputed information
- *
- * Process the xslt call-template node 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
- xmlNodePtr cur = NULL;
- xsltStackElemPtr params = NULL, param;
-
- if (ctxt->insert == NULL)
- return;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:call-template : compilation failed\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,
- "xsl:call-template : template %s:%s not found\n",
- comp->ns, comp->name);
- } else {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:call-template : template %s 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
-
- 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.
- */
-#ifdef XSLT_REFACTORED
- if (IS_XSLT_ELEM_FAST(cur)) {
-#else
- if (IS_XSLT_ELEM(cur)) {
-#endif
- if (IS_XSLT_NAME(cur, "with-param")) {
- param = xsltParseStylesheetCallerParam(ctxt, cur);
- if (param != NULL) {
- param->next = params;
- params = 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
- * Set the "notcur" flag to abide by Section 5.6 of the spec
- */
- xsltApplyOneTemplateInt(ctxt, node, comp->templ->content, comp->templ, params, 1);
- if (params != NULL)
- xsltFreeStackElemList(params);
-
-#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 process context
- * @node: the node in the source tree.
- * @inst: the apply-templates node
- * @comp: precomputed information
- *
- * Process the apply-templates node on the source node
- */
-void
-xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr castedComp)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemApplyTemplatesPtr comp =
- (xsltStyleItemApplyTemplatesPtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xmlNodePtr cur, delete = NULL, oldNode;
- xmlXPathObjectPtr res = NULL;
- xmlNodeSetPtr list = NULL, oldList;
- int i, oldProximityPosition, oldContextSize;
- const xmlChar *oldMode, *oldModeURI;
- xsltStackElemPtr params = NULL, param;
- int nbsorts = 0;
- xmlNodePtr sorts[XSLT_MAX_SORT];
- xmlDocPtr oldXDocPtr;
- xsltDocumentPtr oldCDocPtr;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- 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
-
- /*
- * Get mode if any
- */
- oldNode = ctxt->node;
- oldMode = ctxt->mode;
- oldModeURI = ctxt->modeURI;
- ctxt->mode = comp->mode;
- ctxt->modeURI = comp->modeURI;
-
- /*
- * 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
- */
- oldXDocPtr = ctxt->xpathCtxt->doc;
- oldCDocPtr = ctxt->document;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- oldList = ctxt->nodeList;
-
- if (comp->select != 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
-
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- if (res != NULL) {
- if (res->type == XPATH_NODESET) {
- list = res->nodesetval;
- res->nodesetval = NULL;
- /*
- In order to take care of potential keys we need to
- do some extra work in the case of an RVT converted
- into a nodeset (e.g. exslt:node-set())
- We create a "pseudo-doc" (if not already created) and
- store it's pointer into _private. This doc, together
- with the keyset, will be freed when the RVT is freed.
- */
- if ((list != NULL) && (ctxt->document->keys != NULL)) {
- if ((list->nodeNr != 0) &&
- (list->nodeTab[0]->doc != NULL) &&
-
- XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc) &&
-
- (list->nodeTab[0]->doc->_private == NULL)) {
- list->nodeTab[0]->doc->_private = xsltNewDocument(
- ctxt, list->nodeTab[0]->doc);
- if (list->nodeTab[0]->doc->_private == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltApplyTemplates : failed to allocate subdoc\n");
- }
-
- ctxt->document = list->nodeTab[0]->doc->_private;
- }
-
- }
- } else {
- list = NULL;
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
- 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 error;
- }
- } else {
- /*
- * Build an XPath nodelist with the children
- */
- list = xmlXPathNodeSetCreate(NULL);
- cur = node->children;
- 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"))) {
- delete = 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;
- default:
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: skipping cur type %d\n",
- cur->type));
-#endif
- delete = cur;
- }
- cur = cur->next;
- if (delete != NULL) {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: removing ignorable blank cur\n"));
-#endif
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = 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
-
- ctxt->nodeList = list;
- ctxt->xpathCtxt->contextSize = list->nodeNr;
-
- /*
- * handle (or skip) the xsl:sort and xsl:with-param
- */
- cur = inst->children;
- while (cur!=NULL) {
-#ifdef WITH_DEBUGGER
- if (ctxt->debugStatus != XSLT_DEBUG_NONE)
-#ifdef XSLT_REFACTORED
- xslHandleDebugger(cur, node, NULL, ctxt);
-#else
- /* TODO: Isn't comp->templ always NULL for apply-template? */
- xslHandleDebugger(cur, node, comp->templ, ctxt);
-#endif
-#endif
- if (ctxt->state == XSLT_STATE_STOPPED) break;
-#ifdef XSLT_REFACTORED
- if (IS_XSLT_ELEM_FAST(cur)) {
-#else
- if (IS_XSLT_ELEM(cur)) {
-#endif
- if (IS_XSLT_NAME(cur, "with-param")) {
- param = xsltParseStylesheetCallerParam(ctxt, cur);
- if (param != NULL) {
- param->next = params;
- params = param;
- }
- } else if (IS_XSLT_NAME(cur, "sort")) {
- if (nbsorts >= XSLT_MAX_SORT) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:apply-template: %s too many sort\n", node->name);
- } else {
- sorts[nbsorts++] = cur;
- }
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:apply-template: misplaced xsl:%s\n", cur->name);
- }
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:apply-template: misplaced %s element\n", cur->name);
- }
- cur = cur->next;
- }
-
- if (nbsorts > 0) {
- xsltDoSortFunction(ctxt, sorts, nbsorts);
- }
-
- for (i = 0;i < list->nodeNr;i++) {
- ctxt->node = list->nodeTab[i];
- ctxt->xpathCtxt->proximityPosition = i + 1;
- /* For a 'select' nodeset, need to check if document has changed */
- if ((IS_XSLT_REAL_NODE(list->nodeTab[i])) &&
- (list->nodeTab[i]->doc!=NULL) &&
- (list->nodeTab[i]->doc->doc!=NULL) &&
- (list->nodeTab[i]->doc->doc)!=ctxt->xpathCtxt->doc) {
- /* The nodeset is from another document, so must change */
- ctxt->xpathCtxt->doc=list->nodeTab[i]->doc->doc;
- if ((list->nodeTab[i]->doc->name != NULL) ||
- (list->nodeTab[i]->doc->URL != NULL)) {
- ctxt->document = xsltFindDocument(ctxt,
- list->nodeTab[i]->doc->doc);
- if (ctxt->document == NULL) {
- /* restore the previous context */
- ctxt->document = oldCDocPtr;
- }
- ctxt->xpathCtxt->node = list->nodeTab[i];
-#ifdef WITH_XSLT_DEBUG_PROCESS
- if ((ctxt->document != NULL) &&
- (ctxt->document->doc != NULL)) {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: Changing document - context doc %s, xpathdoc %s\n",
- ctxt->document->doc->URL, ctxt->xpathCtxt->doc->URL));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyTemplates: Changing document - Return tree fragment\n"));
- }
-#endif
- }
- }
- xsltProcessOneNode(ctxt, list->nodeTab[i], params);
- }
-error:
- if (params != NULL)
- xsltFreeStackElemList(params); /* free the parameter list */
- if (list != NULL)
- xmlXPathFreeNodeSet(list);
- /*
- * res must be deallocated after list
- */
- if (res != NULL)
- xmlXPathFreeObject(res);
-
- ctxt->nodeList = oldList;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->doc = oldXDocPtr;
- ctxt->document = oldCDocPtr;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
-
- ctxt->node = oldNode;
- ctxt->mode = oldMode;
- ctxt->modeURI = oldModeURI;
-}
-
-
-/**
- * xsltChoose:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt choose node
- * @comp: precomputed information
- *
- * Process the xslt choose node on the source node
- */
-void
-xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
-{
- xmlXPathObjectPtr res = NULL;
- xmlNodePtr replacement, when;
- int doit = 1;
- int oldProximityPosition, oldContextSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
-
- /*
- * Check the when's
- */
- replacement = inst->children;
- if (replacement == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: empty content not allowed\n");
- goto error;
- }
-#ifdef XSLT_REFACTORED
- if (((!IS_XSLT_ELEM_FAST(replacement)) ||
-#else
- if (((!IS_XSLT_ELEM(replacement)) ||
-#endif
- (!IS_XSLT_NAME(replacement, "when")))
- && (!xmlIsBlankNode(replacement))) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: xsl:when expected first\n");
- goto error;
- }
-#ifdef XSLT_REFACTORED
- while ((IS_XSLT_ELEM_FAST(replacement) &&
-#else
- while ((IS_XSLT_ELEM(replacement) &&
-#endif
- (IS_XSLT_NAME(replacement, "when")))
- || xmlIsBlankNode(replacement)) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemWhenPtr wcomp =
- (xsltStyleItemWhenPtr) replacement->psvi;
-#else
- xsltStylePreCompPtr wcomp = replacement->psvi;
-#endif
-
- if (xmlIsBlankNode(replacement)) {
- replacement = replacement->next;
- continue;
- }
-
- if ((wcomp == NULL) || (wcomp->test == NULL) || (wcomp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: compilation failed !\n");
- goto error;
- }
- when = replacement;
-
-
-#ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
-#ifdef XSLT_REFACTORED
- xslHandleDebugger(when, node, NULL, ctxt);
-#else
- /* TODO: Isn't comp->templ always NULL for xsl:choose? */
- xslHandleDebugger(when, node, comp->templ, ctxt);
-#endif
-#endif
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltChoose: test %s\n", wcomp->test));
-#endif
-
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (wcomp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = wcomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = wcomp->nsList;
- ctxt->xpathCtxt->nsNr = wcomp->nsNr;
-#endif
- res = xmlXPathCompiledEval(wcomp->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- if (res != NULL) {
- if (res->type != XPATH_BOOLEAN)
- res = xmlXPathConvertBoolean(res);
- if (res->type == XPATH_BOOLEAN)
- doit = 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;
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltChoose: test evaluate to %d\n", doit));
-#endif
- if (doit) {
- xsltApplyOneTemplateInt(ctxt, ctxt->node, when->children,
- NULL, NULL, 0);
- goto done;
- }
- if (res != NULL)
- xmlXPathFreeObject(res);
- res = NULL;
- replacement = replacement->next;
- }
-#ifdef XSLT_REFACTORED
- if (IS_XSLT_ELEM_FAST(replacement) &&
-#else
- if (IS_XSLT_ELEM(replacement) &&
-#endif
- (IS_XSLT_NAME(replacement, "otherwise"))) {
-#ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
-#ifdef XSLT_REFACTORED
- xslHandleDebugger(replacement, node, NULL, ctxt);
-#else
- /* TODO: Isn't comp->templ always NULL for xsl:otherwise? */
- xslHandleDebugger(replacement, node, comp->templ, ctxt);
-#endif
-#endif
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
- "evaluating xsl:otherwise\n"));
-#endif
- xsltApplyOneTemplateInt(ctxt, ctxt->node, replacement->children,
- NULL, NULL, 0);
- replacement = replacement->next;
- }
- while (xmlIsBlankNode(replacement)) {
- replacement = replacement->next;
- }
- if (replacement != NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:choose: unexpected content %s\n", replacement->name);
- goto error;
- }
-
-done:
-error:
- if (res != NULL)
- xmlXPathFreeObject(res);
-}
-
-/**
- * xsltIf:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt if node
- * @comp: precomputed information
- *
- * Process the xslt if node on the source node
- */
-void
-xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr castedComp){
-#ifdef XSLT_REFACTORED
- xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xmlXPathObjectPtr res = NULL;
- int doit = 1;
- int oldContextSize, oldProximityPosition;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:if : compilation failed\n");
- return;
- }
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test %s\n", comp->test));
-#endif
-
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- /*
- * OPTIMIZE TODO: Use a specialized function, which returns only
- * true/false.
- */
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- if (res != NULL) {
- if (res->type != XPATH_BOOLEAN)
- res = xmlXPathConvertBoolean(res);
- if (res->type == XPATH_BOOLEAN)
- doit = res->boolval;
- else {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test didn't evaluate to a boolean\n"));
-#endif
- goto error;
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
- "xsltIf: test evaluate to %d\n", doit));
-#endif
- if (doit) {
- xsltApplyOneTemplateInt(ctxt, node, inst->children, NULL, NULL, 0);
- }
-
-error:
- if (res != NULL)
- xmlXPathFreeObject(res);
-}
-
-/**
- * xsltForEach:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt for-each node
- * @comp: precomputed information
- *
- * Process the xslt for-each node on the source node
- */
-void
-xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr castedComp)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xmlXPathObjectPtr res = NULL;
- xmlNodePtr replacement;
- xmlNodeSetPtr list = NULL, oldList;
- int i, oldProximityPosition, oldContextSize;
- xmlNodePtr oldNode;
- int nbsorts = 0;
- xmlNodePtr sorts[XSLT_MAX_SORT];
- xmlDocPtr oldXDocPtr;
- xsltDocumentPtr oldCDocPtr;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return;
- if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:for-each : compilation failed\n");
- return;
- }
- oldNode = ctxt->node;
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: select %s\n", comp->select));
-#endif
-
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->node = node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- oldCDocPtr = ctxt->document;
- oldXDocPtr = ctxt->xpathCtxt->doc;
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- if (res != NULL) {
- if (res->type == XPATH_NODESET)
- list = res->nodesetval;
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- }
- if (list == NULL) {
-#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;
- }
-
-#ifdef WITH_XSLT_DEBUG_PROCESS
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
-#endif
-
- oldList = ctxt->nodeList;
- ctxt->nodeList = list;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- ctxt->xpathCtxt->contextSize = list->nodeNr;
-
- /*
- * handle and skip the xsl:sort
- */
- replacement = inst->children;
-#ifdef XSLT_REFACTORED
- while (IS_XSLT_ELEM_FAST(replacement) &&
-#else
- while (IS_XSLT_ELEM(replacement) &&
-#endif
- (IS_XSLT_NAME(replacement, "sort"))) {
- if (nbsorts >= XSLT_MAX_SORT) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:for-each: too many sorts\n");
- } else {
- sorts[nbsorts++] = replacement;
- }
-#ifdef WITH_DEBUGGER
- if (xslDebugStatus != XSLT_DEBUG_NONE)
- xslHandleDebugger(replacement, node, NULL, ctxt);
-#endif
- replacement = replacement->next;
- }
-
- if (nbsorts > 0) {
- xsltDoSortFunction(ctxt, sorts, nbsorts);
- }
-
-
- for (i = 0;i < list->nodeNr;i++) {
- ctxt->node = list->nodeTab[i];
- ctxt->xpathCtxt->proximityPosition = i + 1;
- /* For a 'select' nodeset, need to check if document has changed */
- if ((IS_XSLT_REAL_NODE(list->nodeTab[i])) &&
- (list->nodeTab[i]->doc!=NULL) &&
- (list->nodeTab[i]->doc->doc!=NULL) &&
- (list->nodeTab[i]->doc->doc)!=ctxt->xpathCtxt->doc) {
- /* The nodeset is from another document, so must change */
- ctxt->xpathCtxt->doc=list->nodeTab[i]->doc->doc;
- if ((list->nodeTab[i]->doc->name != NULL) ||
- (list->nodeTab[i]->doc->URL != NULL)) {
- ctxt->document = xsltFindDocument(ctxt,
- list->nodeTab[i]->doc->doc);
- if (ctxt->document == NULL) {
- /* restore the previous context */
- ctxt->document = oldCDocPtr;
- }
- ctxt->xpathCtxt->node = list->nodeTab[i];
-#ifdef WITH_XSLT_DEBUG_PROCESS
- if ((ctxt->document != NULL) &&
- (ctxt->document->doc != NULL)) {
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: Changing document - context doc %s, xpathdoc %s\n",
- ctxt->document->doc->URL, ctxt->xpathCtxt->doc->URL));
- } else {
- XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
- "xsltForEach: Changing document - Return tree fragment\n"));
- }
-#endif
- }
- }
- xsltApplyOneTemplateInt(ctxt, list->nodeTab[i], replacement, NULL, NULL, 0);
- }
- ctxt->document = oldCDocPtr;
- ctxt->nodeList = oldList;
- ctxt->node = oldNode;
- ctxt->xpathCtxt->doc = oldXDocPtr;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
-
-error:
- if (res != NULL)
- xmlXPathFreeObject(res);
-}
-
-/************************************************************************
- * *
- * Generic interface *
- * *
- ************************************************************************/
-
-#ifdef XSLT_GENERATE_HTML_DOCTYPE
-typedef struct xsltHTMLVersion {
- const char *version;
- const char *public;
- const char *system;
-} xsltHTMLVersion;
-
-static xsltHTMLVersion xsltHTMLVersions[] = {
- { "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;
-}
-
-#ifdef XSLT_REFACTORED_KEYCOMP
-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);
-}
-#endif /* XSLT_REFACTORED_KEYCOMP */
-
-/**
- * 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;
- xsltStackElemPtr variables;
- xsltStackElemPtr vptr;
-
- 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);
-
- 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)
-
- 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",
- style->method);
- 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",
- style->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 (style->encoding != NULL)
- res->encoding = xmlStrdup(style->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));
- ctxt->output = res;
- ctxt->insert = (xmlNodePtr) res;
- if (ctxt->globalVars == NULL)
- ctxt->globalVars = xmlHashCreate(20);
- if (params != NULL)
- xsltEvalUserParams(ctxt, params);
- xsltEvalGlobalVariables(ctxt);
-#ifdef XSLT_REFACTORED_KEYCOMP
- xsltCountKeys(ctxt);
-#endif
- ctxt->node = (xmlNodePtr) doc;
- varsPush(ctxt, NULL);
- ctxt->varsBase = ctxt->varsNr - 1;
- xsltProcessOneNode(ctxt, ctxt->node, NULL);
- xsltFreeStackElemList(varsPop(ctxt));
- 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;
- }
-
-
- /*
- * 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_ERROR)) {
- 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);
- }
- }
-
- if ((ctxt != NULL) && (userCtxt == NULL))
- xsltFreeTransformContext(ctxt);
-
- return (res);
-
-error:
- if (res != NULL)
- xmlFreeDoc(res);
- 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);
-
-}
+/*\r
+ * transform.c: Implementation of the XSL Transformation 1.0 engine\r
+ * transform part, i.e. applying a Stylesheet to a document\r
+ *\r
+ * References:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * Michael Kay "XSLT Programmer's Reference" pp 637-643\r
+ * Writing Multiple Output Files\r
+ *\r
+ * XSLT-1.1 Working Draft\r
+ * http://www.w3.org/TR/xslt11#multiple-output\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/encoding.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/parserInternals.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/HTMLtree.h>\r
+#include <libxml/debugXML.h>\r
+#include <libxml/uri.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "pattern.h"\r
+#include "transform.h"\r
+#include "variables.h"\r
+#include "numbersInternals.h"\r
+#include "namespaces.h"\r
+#include "attributes.h"\r
+#include "templates.h"\r
+#include "imports.h"\r
+#include "keys.h"\r
+#include "documents.h"\r
+#include "extensions.h"\r
+#include "extra.h"\r
+#include "preproc.h"\r
+#include "security.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_EXTRA\r
+#define WITH_XSLT_DEBUG_PROCESS\r
+#endif\r
+\r
+#define XSLT_GENERATE_HTML_DOCTYPE\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,\r
+ const xmlChar **systemID);\r
+#endif\r
+\r
+int xsltMaxDepth = 3000;\r
+\r
+/*\r
+ * Useful macros\r
+ */\r
+\r
+#ifndef FALSE\r
+# define FALSE (0 == 1)\r
+# define TRUE (!FALSE)\r
+#endif\r
+\r
+#define IS_BLANK_NODE(n) \\r
+ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))\r
+\r
+\r
+/*\r
+* Forward declarations\r
+*/\r
+\r
+static xmlNsPtr\r
+xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);\r
+\r
+static xmlNodePtr\r
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr invocNode,\r
+ xmlNodePtr node,\r
+ xmlNodePtr insert, int isLRE, int topElemVisited);\r
+\r
+static void\r
+xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode, xmlNodePtr list,\r
+ xsltTemplatePtr templ);\r
+\r
+static void\r
+xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr list,\r
+ xsltTemplatePtr templ,\r
+ xsltStackElemPtr withParams);\r
+\r
+/**\r
+ * templPush:\r
+ * @ctxt: the transformation context\r
+ * @value: the template to push on the stack\r
+ *\r
+ * Push a template on the stack\r
+ *\r
+ * Returns the new index in the stack or 0 in case of error\r
+ */\r
+static int\r
+templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)\r
+{\r
+ if (ctxt->templMax == 0) {\r
+ ctxt->templMax = 4;\r
+ ctxt->templTab =\r
+ (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *\r
+ sizeof(ctxt->templTab[0]));\r
+ if (ctxt->templTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ if (ctxt->templNr >= ctxt->templMax) {\r
+ ctxt->templMax *= 2;\r
+ ctxt->templTab =\r
+ (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,\r
+ ctxt->templMax *\r
+ sizeof(ctxt->templTab[0]));\r
+ if (ctxt->templTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ ctxt->templTab[ctxt->templNr] = value;\r
+ ctxt->templ = value;\r
+ return (ctxt->templNr++);\r
+}\r
+/**\r
+ * templPop:\r
+ * @ctxt: the transformation context\r
+ *\r
+ * Pop a template value from the stack\r
+ *\r
+ * Returns the stored template value\r
+ */\r
+static xsltTemplatePtr\r
+templPop(xsltTransformContextPtr ctxt)\r
+{\r
+ xsltTemplatePtr ret;\r
+\r
+ if (ctxt->templNr <= 0)\r
+ return (0);\r
+ ctxt->templNr--;\r
+ if (ctxt->templNr > 0)\r
+ ctxt->templ = ctxt->templTab[ctxt->templNr - 1];\r
+ else\r
+ ctxt->templ = (xsltTemplatePtr) 0;\r
+ ret = ctxt->templTab[ctxt->templNr];\r
+ ctxt->templTab[ctxt->templNr] = 0;\r
+ return (ret);\r
+}\r
+\r
+/**\r
+ * xsltVariablePop:\r
+ * @ctxt: the transformation context\r
+ * @depth: the depth in the xsl:template's tree\r
+ *\r
+ * Pops all variable values at the given @depth from the stack.\r
+ *\r
+ * Returns the stored variable value\r
+ */\r
+static void\r
+xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)\r
+{\r
+ xsltStackElemPtr variable;\r
+\r
+ if (ctxt->varsNr <= 0)\r
+ return;\r
+\r
+ do {\r
+ if (ctxt->varsNr <= limitNr)\r
+ break;\r
+ variable = ctxt->varsTab[ctxt->varsNr - 1];\r
+ if (variable->level <= level)\r
+ break; \r
+ if (variable->level >= 0)\r
+ xsltFreeStackElemList(variable);\r
+ ctxt->varsNr--;\r
+ } while (ctxt->varsNr != 0);\r
+ if (ctxt->varsNr > 0)\r
+ ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];\r
+ else\r
+ ctxt->vars = NULL;\r
+}\r
+\r
+/**\r
+ * xsltTemplateParamsCleanup:\r
+ *\r
+ * Removes xsl:param and xsl:with-param items from the\r
+ * variable-stack. Only xsl:with-param items are not freed. \r
+ */\r
+static void\r
+xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)\r
+{\r
+ xsltStackElemPtr param; \r
+\r
+ for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {\r
+ param = ctxt->varsTab[ctxt->varsNr -1];\r
+ /*\r
+ * Free xsl:param items.\r
+ * xsl:with-param items will have a level of -1 or -2.\r
+ */\r
+ if (param->level >= 0) { \r
+ xsltFreeStackElemList(param);\r
+ } \r
+ } \r
+ if (ctxt->varsNr > 0)\r
+ ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];\r
+ else\r
+ ctxt->vars = NULL;\r
+}\r
+\r
+/**\r
+ * profPush:\r
+ * @ctxt: the transformation context\r
+ * @value: the profiling value to push on the stack\r
+ *\r
+ * Push a profiling value on the stack\r
+ *\r
+ * Returns the new index in the stack or 0 in case of error\r
+ */\r
+static int\r
+profPush(xsltTransformContextPtr ctxt, long value)\r
+{\r
+ if (ctxt->profMax == 0) {\r
+ ctxt->profMax = 4;\r
+ ctxt->profTab =\r
+ (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));\r
+ if (ctxt->profTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ if (ctxt->profNr >= ctxt->profMax) {\r
+ ctxt->profMax *= 2;\r
+ ctxt->profTab =\r
+ (long *) xmlRealloc(ctxt->profTab,\r
+ ctxt->profMax * sizeof(ctxt->profTab[0]));\r
+ if (ctxt->profTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ ctxt->profTab[ctxt->profNr] = value;\r
+ ctxt->prof = value;\r
+ return (ctxt->profNr++);\r
+}\r
+/**\r
+ * profPop:\r
+ * @ctxt: the transformation context\r
+ *\r
+ * Pop a profiling value from the stack\r
+ *\r
+ * Returns the stored profiling value\r
+ */\r
+static long\r
+profPop(xsltTransformContextPtr ctxt)\r
+{\r
+ long ret;\r
+\r
+ if (ctxt->profNr <= 0)\r
+ return (0);\r
+ ctxt->profNr--;\r
+ if (ctxt->profNr > 0)\r
+ ctxt->prof = ctxt->profTab[ctxt->profNr - 1];\r
+ else\r
+ ctxt->prof = (long) 0;\r
+ ret = ctxt->profTab[ctxt->profNr];\r
+ ctxt->profTab[ctxt->profNr] = 0;\r
+ return (ret);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * XInclude default settings *\r
+ * *\r
+ ************************************************************************/\r
+\r
+static int xsltDoXIncludeDefault = 0;\r
+\r
+/**\r
+ * xsltSetXIncludeDefault:\r
+ * @xinclude: whether to do XInclude processing\r
+ *\r
+ * Set whether XInclude should be processed on document being loaded by default\r
+ */\r
+void\r
+xsltSetXIncludeDefault(int xinclude) {\r
+ xsltDoXIncludeDefault = (xinclude != 0);\r
+}\r
+\r
+/**\r
+ * xsltGetXIncludeDefault:\r
+ *\r
+ * Provides the default state for XInclude processing\r
+ *\r
+ * Returns 0 if there is no processing 1 otherwise\r
+ */\r
+int\r
+xsltGetXIncludeDefault(void) {\r
+ return(xsltDoXIncludeDefault);\r
+}\r
+\r
+unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;\r
+\r
+/**\r
+ * xsltDebugSetDefaultTrace:\r
+ * @val: tracing level mask\r
+ *\r
+ * Set the default debug tracing level mask\r
+ */\r
+void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {\r
+ xsltDefaultTrace = val;\r
+}\r
+\r
+/**\r
+ * xsltDebugGetDefaultTrace:\r
+ *\r
+ * Get the current default debug tracing level mask\r
+ *\r
+ * Returns the current default debug tracing level mask\r
+ */\r
+xsltDebugTraceCodes xsltDebugGetDefaultTrace() {\r
+ return xsltDefaultTrace;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Handling of Transformation Contexts *\r
+ * *\r
+ ************************************************************************/\r
+\r
+static xsltTransformCachePtr\r
+xsltTransformCacheCreate(void)\r
+{\r
+ xsltTransformCachePtr ret;\r
+ \r
+ ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltTransformCacheCreate : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltTransformCache));\r
+ return(ret);\r
+}\r
+\r
+static void\r
+xsltTransformCacheFree(xsltTransformCachePtr cache)\r
+{ \r
+ if (cache == NULL)\r
+ return; \r
+ /*\r
+ * Free tree fragments.\r
+ */\r
+ if (cache->RVT) {\r
+ xmlDocPtr tmp, cur = cache->RVT;\r
+ while (cur) {\r
+ tmp = cur;\r
+ cur = (xmlDocPtr) cur->next;\r
+ if (tmp->_private != NULL) {\r
+ /*\r
+ * Tree the document info.\r
+ */\r
+ xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);\r
+ xmlFree(tmp->_private);\r
+ }\r
+ xmlFreeDoc(tmp);\r
+ }\r
+ }\r
+ /*\r
+ * Free vars/params.\r
+ */\r
+ if (cache->stackItems) {\r
+ xsltStackElemPtr tmp, cur = cache->stackItems;\r
+ while (cur) {\r
+ tmp = cur;\r
+ cur = cur->next;\r
+ /*\r
+ * REVISIT TODO: Should be call a destruction-function\r
+ * instead?\r
+ */\r
+ xmlFree(tmp);\r
+ }\r
+ }\r
+ xmlFree(cache);\r
+}\r
+\r
+/**\r
+ * xsltNewTransformContext:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: the input document\r
+ *\r
+ * Create a new XSLT TransformContext\r
+ *\r
+ * Returns the newly allocated xsltTransformContextPtr or NULL in case of error\r
+ */\r
+xsltTransformContextPtr\r
+xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {\r
+ xsltTransformContextPtr cur;\r
+ xsltDocumentPtr docu;\r
+ int i;\r
+\r
+ cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, (xmlNodePtr)doc,\r
+ "xsltNewTransformContext : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltTransformContext));\r
+\r
+ cur->cache = xsltTransformCacheCreate();\r
+ if (cur->cache == NULL)\r
+ goto internal_err;\r
+ /*\r
+ * setup of the dictionnary must be done early as some of the\r
+ * processing later like key handling may need it.\r
+ */\r
+ cur->dict = xmlDictCreateSub(style->dict);\r
+ cur->internalized = ((style->internalized) && (cur->dict != NULL));\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Creating sub-dictionary from stylesheet for transformation\n");\r
+#endif\r
+\r
+ /*\r
+ * initialize the template stack\r
+ */\r
+ cur->templTab = (xsltTemplatePtr *)\r
+ xmlMalloc(10 * sizeof(xsltTemplatePtr));\r
+ if (cur->templTab == NULL) {\r
+ xsltTransformError(NULL, NULL, (xmlNodePtr) doc,\r
+ "xsltNewTransformContext: out of memory\n");\r
+ goto internal_err;\r
+ }\r
+ cur->templNr = 0;\r
+ cur->templMax = 5;\r
+ cur->templ = NULL;\r
+\r
+ /*\r
+ * initialize the variables stack\r
+ */\r
+ cur->varsTab = (xsltStackElemPtr *)\r
+ xmlMalloc(10 * sizeof(xsltStackElemPtr));\r
+ if (cur->varsTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltNewTransformContext: out of memory\n");\r
+ goto internal_err;\r
+ }\r
+ cur->varsNr = 0;\r
+ cur->varsMax = 10;\r
+ cur->vars = NULL;\r
+ cur->varsBase = 0;\r
+\r
+ /*\r
+ * the profiling stack is not initialized by default\r
+ */\r
+ cur->profTab = NULL;\r
+ cur->profNr = 0;\r
+ cur->profMax = 0;\r
+ cur->prof = 0;\r
+\r
+ cur->style = style;\r
+ xmlXPathInit();\r
+ cur->xpathCtxt = xmlXPathNewContext(doc);\r
+ if (cur->xpathCtxt == NULL) {\r
+ xsltTransformError(NULL, NULL, (xmlNodePtr) doc,\r
+ "xsltNewTransformContext : xmlXPathNewContext failed\n");\r
+ goto internal_err;\r
+ }\r
+ /*\r
+ * Create an XPath cache.\r
+ */\r
+ if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)\r
+ goto internal_err;\r
+ /*\r
+ * Initialize the extras array\r
+ */\r
+ if (style->extrasNr != 0) {\r
+ cur->extrasMax = style->extrasNr + 20;\r
+ cur->extras = (xsltRuntimeExtraPtr) \r
+ xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));\r
+ if (cur->extras == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltNewTransformContext: out of memory\n");\r
+ goto internal_err;\r
+ }\r
+ cur->extrasNr = style->extrasNr;\r
+ for (i = 0;i < cur->extrasMax;i++) {\r
+ cur->extras[i].info = NULL;\r
+ cur->extras[i].deallocate = NULL;\r
+ cur->extras[i].val.ptr = NULL;\r
+ }\r
+ } else {\r
+ cur->extras = NULL;\r
+ cur->extrasNr = 0;\r
+ cur->extrasMax = 0;\r
+ }\r
+\r
+ XSLT_REGISTER_VARIABLE_LOOKUP(cur);\r
+ XSLT_REGISTER_FUNCTION_LOOKUP(cur);\r
+ cur->xpathCtxt->nsHash = style->nsHash;\r
+ /*\r
+ * Initialize the registered external modules\r
+ */\r
+ xsltInitCtxtExts(cur);\r
+ /*\r
+ * Setup document element ordering for later efficiencies\r
+ * (bug 133289)\r
+ */\r
+ if (xslDebugStatus == XSLT_DEBUG_NONE)\r
+ xmlXPathOrderDocElems(doc);\r
+ /*\r
+ * Must set parserOptions before calling xsltNewDocument\r
+ * (bug 164530)\r
+ */\r
+ cur->parserOptions = XSLT_PARSE_OPTIONS;\r
+ docu = xsltNewDocument(cur, doc);\r
+ if (docu == NULL) {\r
+ xsltTransformError(cur, NULL, (xmlNodePtr)doc,\r
+ "xsltNewTransformContext : xsltNewDocument failed\n");\r
+ goto internal_err;\r
+ }\r
+ docu->main = 1;\r
+ cur->document = docu; \r
+ cur->inst = NULL;\r
+ cur->outputFile = NULL;\r
+ cur->sec = xsltGetDefaultSecurityPrefs();\r
+ cur->debugStatus = xslDebugStatus;\r
+ cur->traceCode = (unsigned long*) &xsltDefaultTrace;\r
+ cur->xinclude = xsltGetXIncludeDefault();\r
+\r
+ return(cur);\r
+\r
+internal_err:\r
+ if (cur != NULL)\r
+ xsltFreeTransformContext(cur);\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltFreeTransformContext:\r
+ * @ctxt: an XSLT parser context\r
+ *\r
+ * Free up the memory allocated by @ctxt\r
+ */\r
+void\r
+xsltFreeTransformContext(xsltTransformContextPtr ctxt) {\r
+ if (ctxt == NULL)\r
+ return;\r
+\r
+ /*\r
+ * Shutdown the extension modules associated to the stylesheet\r
+ * used if needed.\r
+ */\r
+ xsltShutdownCtxtExts(ctxt);\r
+\r
+ if (ctxt->xpathCtxt != NULL) {\r
+ ctxt->xpathCtxt->nsHash = NULL;\r
+ xmlXPathFreeContext(ctxt->xpathCtxt);\r
+ }\r
+ if (ctxt->templTab != NULL)\r
+ xmlFree(ctxt->templTab);\r
+ if (ctxt->varsTab != NULL)\r
+ xmlFree(ctxt->varsTab);\r
+ if (ctxt->profTab != NULL)\r
+ xmlFree(ctxt->profTab);\r
+ if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {\r
+ int i;\r
+\r
+ for (i = 0;i < ctxt->extrasNr;i++) {\r
+ if ((ctxt->extras[i].deallocate != NULL) &&\r
+ (ctxt->extras[i].info != NULL))\r
+ ctxt->extras[i].deallocate(ctxt->extras[i].info);\r
+ }\r
+ xmlFree(ctxt->extras);\r
+ }\r
+ xsltFreeGlobalVariables(ctxt);\r
+ xsltFreeDocuments(ctxt);\r
+ xsltFreeCtxtExts(ctxt);\r
+ xsltFreeRVTs(ctxt);\r
+ xsltTransformCacheFree(ctxt->cache);\r
+ xmlDictFree(ctxt->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "freeing transformation dictionnary\n");\r
+#endif\r
+ memset(ctxt, -1, sizeof(xsltTransformContext));\r
+ xmlFree(ctxt);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Copy of Nodes in an XSLT fashion *\r
+ * *\r
+ ************************************************************************/\r
+\r
+xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node, xmlNodePtr insert, int literal);\r
+\r
+/**\r
+ * xsltAddTextString:\r
+ * @ctxt: a XSLT process context\r
+ * @target: the text node where the text will be attached\r
+ * @string: the text string\r
+ * @len: the string length in byte\r
+ *\r
+ * Extend the current text node with the new string, it handles coalescing\r
+ *\r
+ * Returns: the text node\r
+ */\r
+static xmlNodePtr\r
+xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,\r
+ const xmlChar *string, int len) {\r
+ /*\r
+ * optimization\r
+ */\r
+ if ((len <= 0) || (string == NULL) || (target == NULL))\r
+ return(target);\r
+\r
+ if (ctxt->lasttext == target->content) {\r
+\r
+ if (ctxt->lasttuse + len >= ctxt->lasttsize) {\r
+ xmlChar *newbuf;\r
+ int size;\r
+\r
+ size = ctxt->lasttsize + len + 100;\r
+ size *= 2;\r
+ newbuf = (xmlChar *) xmlRealloc(target->content,size);\r
+ if (newbuf == NULL) {\r
+ xsltTransformError(ctxt, NULL, target,\r
+ "xsltCopyText: text allocation failed\n");\r
+ return(NULL);\r
+ }\r
+ ctxt->lasttsize = size;\r
+ ctxt->lasttext = newbuf;\r
+ target->content = newbuf;\r
+ }\r
+ memcpy(&(target->content[ctxt->lasttuse]), string, len);\r
+ ctxt->lasttuse += len;\r
+ target->content[ctxt->lasttuse] = 0;\r
+ } else {\r
+ xmlNodeAddContent(target, string);\r
+ ctxt->lasttext = target->content;\r
+ len = xmlStrlen(target->content);\r
+ ctxt->lasttsize = len;\r
+ ctxt->lasttuse = len;\r
+ }\r
+ return(target);\r
+}\r
+\r
+/**\r
+ * xsltCopyTextString:\r
+ * @ctxt: a XSLT process context\r
+ * @target: the element where the text will be attached\r
+ * @string: the text string\r
+ * @noescape: should disable-escaping be activated for this text node.\r
+ *\r
+ * Adds @string to a newly created or an existent text node child of\r
+ * @target.\r
+ *\r
+ * Returns: the text node, where the text content of @cur is copied to.\r
+ * NULL in case of API or internal errors.\r
+ */\r
+xmlNodePtr\r
+xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,\r
+ const xmlChar *string, int noescape)\r
+{\r
+ xmlNodePtr copy;\r
+ int len;\r
+\r
+ if (string == NULL)\r
+ return(NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyTextString: copy text %s\n",\r
+ string));\r
+#endif\r
+\r
+ /*\r
+ * Play save and reset the merging mechanism for every new\r
+ * target node.\r
+ */\r
+ if ((target == NULL) || (target->children == NULL)) {\r
+ ctxt->lasttext = NULL;\r
+ }\r
+\r
+ /* handle coalescing of text nodes here */\r
+ len = xmlStrlen(string);\r
+ if ((ctxt->type == XSLT_OUTPUT_XML) &&\r
+ (ctxt->style->cdataSection != NULL) &&\r
+ (target != NULL) && \r
+ (target->type == XML_ELEMENT_NODE) &&\r
+ (((target->ns == NULL) && \r
+ (xmlHashLookup2(ctxt->style->cdataSection,\r
+ target->name, NULL) != NULL)) ||\r
+ ((target->ns != NULL) &&\r
+ (xmlHashLookup2(ctxt->style->cdataSection,\r
+ target->name, target->ns->href) != NULL))))\r
+ {\r
+ /*\r
+ * Process "cdata-section-elements".\r
+ */\r
+ if ((target->last != NULL) &&\r
+ (target->last->type == XML_CDATA_SECTION_NODE))\r
+ {\r
+ return(xsltAddTextString(ctxt, target->last, string, len));\r
+ }\r
+ copy = xmlNewCDataBlock(ctxt->output, string, len);\r
+ } else if (noescape) {\r
+ /*\r
+ * Process "disable-output-escaping".\r
+ */\r
+ if ((target != NULL) && (target->last != NULL) &&\r
+ (target->last->type == XML_TEXT_NODE) &&\r
+ (target->last->name == xmlStringTextNoenc))\r
+ {\r
+ return(xsltAddTextString(ctxt, target->last, string, len));\r
+ }\r
+ copy = xmlNewTextLen(string, len);\r
+ if (copy != NULL)\r
+ copy->name = xmlStringTextNoenc;\r
+ } else {\r
+ /*\r
+ * Default processing.\r
+ */\r
+ if ((target != NULL) && (target->last != NULL) &&\r
+ (target->last->type == XML_TEXT_NODE) &&\r
+ (target->last->name == xmlStringText)) {\r
+ return(xsltAddTextString(ctxt, target->last, string, len));\r
+ }\r
+ copy = xmlNewTextLen(string, len);\r
+ }\r
+ if (copy != NULL) {\r
+ if (target != NULL)\r
+ xmlAddChild(target, copy);\r
+ ctxt->lasttext = copy->content;\r
+ ctxt->lasttsize = len;\r
+ ctxt->lasttuse = len;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, target,\r
+ "xsltCopyTextString: text copy failed\n");\r
+ ctxt->lasttext = NULL;\r
+ }\r
+ return(copy);\r
+}\r
+\r
+/**\r
+ * xsltCopyText:\r
+ * @ctxt: a XSLT process context\r
+ * @target: the element where the text will be attached\r
+ * @cur: the text or CDATA node\r
+ * @interned: the string is in the target doc dictionnary\r
+ *\r
+ * Copy the text content of @cur and append it to @target's children.\r
+ *\r
+ * Returns: the text node, where the text content of @cur is copied to.\r
+ * NULL in case of API or internal errors.\r
+ */\r
+static xmlNodePtr\r
+xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,\r
+ xmlNodePtr cur, int interned)\r
+{\r
+ xmlNodePtr copy;\r
+\r
+ if ((cur->type != XML_TEXT_NODE) &&\r
+ (cur->type != XML_CDATA_SECTION_NODE))\r
+ return(NULL);\r
+ if (cur->content == NULL) \r
+ return(NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->type == XML_CDATA_SECTION_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyText: copy CDATA text %s\n",\r
+ cur->content));\r
+ } else if (cur->name == xmlStringTextNoenc) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyText: copy unescaped text %s\n",\r
+ cur->content));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyText: copy text %s\n",\r
+ cur->content));\r
+ }\r
+#endif\r
+\r
+ /*\r
+ * Play save and reset the merging mechanism for every new\r
+ * target node.\r
+ */\r
+ if ((target == NULL) || (target->children == NULL)) {\r
+ ctxt->lasttext = NULL;\r
+ }\r
+\r
+ if ((ctxt->style->cdataSection != NULL) &&\r
+ (ctxt->type == XSLT_OUTPUT_XML) && \r
+ (target != NULL) &&\r
+ (target->type == XML_ELEMENT_NODE) &&\r
+ (((target->ns == NULL) && \r
+ (xmlHashLookup2(ctxt->style->cdataSection,\r
+ target->name, NULL) != NULL)) ||\r
+ ((target->ns != NULL) &&\r
+ (xmlHashLookup2(ctxt->style->cdataSection,\r
+ target->name, target->ns->href) != NULL))))\r
+ {\r
+ /*\r
+ * Process "cdata-section-elements".\r
+ */\r
+ /* \r
+ * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. \r
+ */\r
+ /*\r
+ * TODO: Since this doesn't merge adjacent CDATA-section nodes,\r
+ * we'll get: <![CDATA[x]]><!CDATA[y]]>.\r
+ * TODO: Reported in #321505.\r
+ */\r
+ if ((target->last != NULL) &&\r
+ (target->last->type == XML_CDATA_SECTION_NODE))\r
+ {\r
+ /*\r
+ * Append to existing CDATA-section node.\r
+ */\r
+ copy = xsltAddTextString(ctxt, target->last, cur->content,\r
+ xmlStrlen(cur->content));\r
+ goto exit;\r
+ } else {\r
+ unsigned int len;\r
+\r
+ len = xmlStrlen(cur->content); \r
+ copy = xmlNewCDataBlock(ctxt->output, cur->content, len);\r
+ if (copy == NULL)\r
+ goto exit;\r
+ ctxt->lasttext = copy->content;\r
+ ctxt->lasttsize = len;\r
+ ctxt->lasttuse = len;\r
+ }\r
+ } else if ((target != NULL) &&\r
+ (target->last != NULL) &&\r
+ /* both escaped or both non-escaped text-nodes */\r
+ (((target->last->type == XML_TEXT_NODE) &&\r
+ (target->last->name == cur->name)) ||\r
+ /* non-escaped text nodes and CDATA-section nodes */\r
+ (((target->last->type == XML_CDATA_SECTION_NODE) &&\r
+ (cur->name == xmlStringTextNoenc)))))\r
+ {\r
+ /*\r
+ * we are appending to an existing text node\r
+ */\r
+ copy = xsltAddTextString(ctxt, target->last, cur->content,\r
+ xmlStrlen(cur->content));\r
+ goto exit;\r
+ } else if ((interned) && (target != NULL) &&\r
+ (target->doc != NULL) &&\r
+ (target->doc->dict == ctxt->dict))\r
+ { \r
+ /*\r
+ * TODO: DO we want to use this also for "text" output?\r
+ */\r
+ copy = xmlNewTextLen(NULL, 0);\r
+ if (copy == NULL)\r
+ goto exit; \r
+ if (cur->name == xmlStringTextNoenc)\r
+ copy->name = xmlStringTextNoenc;\r
+ \r
+ /*\r
+ * Must confirm that content is in dict (bug 302821)\r
+ * TODO: This check should be not needed for text coming\r
+ * from the stylesheets \r
+ */\r
+ if (xmlDictOwns(ctxt->dict, cur->content))\r
+ copy->content = cur->content;\r
+ else {\r
+ if ((copy->content = xmlStrdup(cur->content)) == NULL)\r
+ return NULL;\r
+ }\r
+ } else {\r
+ /*\r
+ * normal processing. keep counters to extend the text node\r
+ * in xsltAddTextString if needed.\r
+ */\r
+ unsigned int len;\r
+\r
+ len = xmlStrlen(cur->content);\r
+ copy = xmlNewTextLen(cur->content, len);\r
+ if (copy == NULL)\r
+ goto exit;\r
+ if (cur->name == xmlStringTextNoenc)\r
+ copy->name = xmlStringTextNoenc;\r
+ ctxt->lasttext = copy->content;\r
+ ctxt->lasttsize = len;\r
+ ctxt->lasttuse = len;\r
+ }\r
+ if (copy != NULL) {\r
+ if (target != NULL) {\r
+ copy->doc = target->doc;\r
+ /*\r
+ * MAYBE TODO: Maybe we should reset the ctxt->lasttext here\r
+ * to ensure that the optimized text-merging mechanism\r
+ * won't interfere with normal node-merging in any case.\r
+ */\r
+ xmlAddChild(target, copy);\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, target,\r
+ "xsltCopyText: text copy failed\n");\r
+ }\r
+\r
+exit:\r
+ if ((copy == NULL) || (copy->content == NULL)) {\r
+ xsltTransformError(ctxt, NULL, target,\r
+ "Internal error in xsltCopyText(): "\r
+ "Failed to copy the string.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+ return(copy);\r
+}\r
+\r
+/**\r
+ * xsltShallowCopyAttr:\r
+ * @ctxt: a XSLT process context\r
+ * @invocNode: responsible node in the stylesheet; used for error reports\r
+ * @target: the element where the attribute will be grafted\r
+ * @attr: the attribute to be copied\r
+ *\r
+ * Do a copy of an attribute.\r
+ * Called by:\r
+ * - xsltCopyTreeInternal()\r
+ * - xsltCopyOf()\r
+ * - xsltCopy()\r
+ *\r
+ * Returns: a new xmlAttrPtr, or NULL in case of error.\r
+ */\r
+static xmlAttrPtr\r
+xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,\r
+ xmlNodePtr target, xmlAttrPtr attr)\r
+{\r
+ xmlAttrPtr copy;\r
+ xmlChar *value;\r
+\r
+ if (attr == NULL)\r
+ return(NULL);\r
+\r
+ if (target->type != XML_ELEMENT_NODE) {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Cannot add an attribute node to a non-element node.\n");\r
+ return(NULL);\r
+ }\r
+ \r
+ if (target->children != NULL) {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Attribute nodes must be added before "\r
+ "any child nodes to an element.\n");\r
+ return(NULL);\r
+ }\r
+\r
+ value = xmlNodeListGetString(attr->doc, attr->children, 1);\r
+ if (attr->ns != NULL) {\r
+ xmlNsPtr ns; \r
+\r
+ ns = xsltGetSpecialNamespace(ctxt, invocNode,\r
+ attr->ns->href, attr->ns->prefix, target);\r
+ if (ns == NULL) {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Namespace fixup error: Failed to acquire an in-scope "\r
+ "namespace binding of the copied attribute '{%s}%s'.\n",\r
+ attr->ns->href, attr->name);\r
+ /*\r
+ * TODO: Should we just stop here?\r
+ */\r
+ }\r
+ /*\r
+ * Note that xmlSetNsProp() will take care of duplicates\r
+ * and assigns the new namespace even to a duplicate.\r
+ */\r
+ copy = xmlSetNsProp(target, ns, attr->name, value);\r
+ } else {\r
+ copy = xmlSetNsProp(target, NULL, attr->name, value);\r
+ }\r
+ if (value != NULL)\r
+ xmlFree(value);\r
+\r
+ if (copy == NULL)\r
+ return(NULL);\r
+\r
+#if 0\r
+ /*\r
+ * NOTE: This was optimized according to bug #342695.\r
+ * TODO: Can this further be optimized, if source and target\r
+ * share the same dict and attr->children is just 1 text node\r
+ * which is in the dict? How probable is such a case?\r
+ */\r
+ /*\r
+ * TODO: Do we need to create an empty text node if the value\r
+ * is the empty string?\r
+ */\r
+ value = xmlNodeListGetString(attr->doc, attr->children, 1);\r
+ if (value != NULL) {\r
+ txtNode = xmlNewDocText(target->doc, NULL);\r
+ if (txtNode == NULL)\r
+ return(NULL);\r
+ if ((target->doc != NULL) &&\r
+ (target->doc->dict != NULL))\r
+ {\r
+ txtNode->content =\r
+ (xmlChar *) xmlDictLookup(target->doc->dict,\r
+ BAD_CAST value, -1);\r
+ xmlFree(value);\r
+ } else\r
+ txtNode->content = value;\r
+ copy->children = txtNode;\r
+ }\r
+#endif\r
+\r
+ return(copy);\r
+}\r
+\r
+/**\r
+ * xsltCopyAttrListNoOverwrite:\r
+ * @ctxt: a XSLT process context\r
+ * @invocNode: responsible node in the stylesheet; used for error reports\r
+ * @target: the element where the new attributes will be grafted\r
+ * @attr: the first attribute in the list to be copied\r
+ *\r
+ * Copies a list of attribute nodes, starting with @attr, over to the\r
+ * @target element node.\r
+ *\r
+ * Called by:\r
+ * - xsltCopyTreeInternal()\r
+ *\r
+ * Returns 0 on success and -1 on errors and internal errors.\r
+ */\r
+static int\r
+xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr invocNode,\r
+ xmlNodePtr target, xmlAttrPtr attr)\r
+{\r
+ xmlAttrPtr last = NULL, copy;\r
+ xmlNsPtr origNs = NULL, copyNs = NULL;\r
+ xmlChar *value = NULL;\r
+\r
+ /*\r
+ * Don't use xmlCopyProp() here, since it will try to\r
+ * reconciliate namespaces.\r
+ */\r
+ while (attr != NULL) {\r
+ /*\r
+ * Find a namespace node in the tree of @target.\r
+ * Avoid searching for the same ns.\r
+ */\r
+ if (attr->ns != origNs) {\r
+ origNs = attr->ns;\r
+ if (attr->ns != NULL) {\r
+ copyNs = xsltGetSpecialNamespace(ctxt, invocNode,\r
+ attr->ns->href, attr->ns->prefix, target);\r
+ if (copyNs == NULL)\r
+ return(-1);\r
+ } else\r
+ copyNs = NULL;\r
+ }\r
+ if (attr->children)\r
+ value = xmlNodeListGetString(attr->doc, attr->children, 1);\r
+ /*\r
+ * REVISIT: I think xmlNewDocProp() is the only attr function\r
+ * which does not eval if the attr is of type ID. This is good,\r
+ * since we don't need this.\r
+ */\r
+ copy = xmlNewDocProp(target->doc, attr->name, BAD_CAST value);\r
+ if (copy == NULL)\r
+ return(-1);\r
+ copy->parent = target;\r
+ copy->ns = copyNs;\r
+ \r
+ if (last == NULL) {\r
+ target->properties = copy;\r
+ last = copy;\r
+ } else {\r
+ last->next = copy;\r
+ copy->prev = last;\r
+ last = copy;\r
+ }\r
+ /*\r
+ * OPTIMIZE TODO: How to avoid this intermediate string?\r
+ */\r
+ if (value != NULL) {\r
+ xmlFree(value);\r
+ value = NULL;\r
+ }\r
+ attr = attr->next;\r
+ } \r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltShallowCopyElem:\r
+ * @ctxt: the XSLT process context\r
+ * @node: the element node in the source tree\r
+ * or the Literal Result Element\r
+ * @insert: the parent in the result tree\r
+ * @isLRE: if @node is a Literal Result Element\r
+ *\r
+ * Make a copy of the element node @node\r
+ * and insert it as last child of @insert.\r
+ *\r
+ * URGENT TODO: The problem with this one (for the non-refactored code)\r
+ * is that it is used for both, Literal Result Elements *and*\r
+ * copying input nodes.\r
+ *\r
+ * BIG NOTE: This is only called for XML_ELEMENT_NODEs.\r
+ *\r
+ * Called from:\r
+ * xsltApplySequenceConstructor()\r
+ * (for Literal Result Elements - which is a problem)\r
+ * xsltCopy() (for shallow-copying elements via xsl:copy)\r
+ *\r
+ * Returns a pointer to the new node, or NULL in case of error\r
+ */\r
+static xmlNodePtr\r
+xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr insert, int isLRE)\r
+{\r
+ xmlNodePtr copy;\r
+\r
+ if ((node->type == XML_DTD_NODE) || (insert == NULL))\r
+ return(NULL);\r
+ if ((node->type == XML_TEXT_NODE) ||\r
+ (node->type == XML_CDATA_SECTION_NODE))\r
+ return(xsltCopyText(ctxt, insert, node, 0));\r
+\r
+ copy = xmlDocCopyNode(node, insert->doc, 0);\r
+ if (copy != NULL) {\r
+ copy->doc = ctxt->output;\r
+ xmlAddChild(insert, copy);\r
+\r
+ if (node->type == XML_ELEMENT_NODE) {\r
+ /*\r
+ * Add namespaces as they are needed\r
+ */\r
+ if (node->nsDef != NULL) {\r
+ /*\r
+ * TODO: Remove the LRE case in the refactored code\r
+ * gets enabled.\r
+ */\r
+ if (isLRE)\r
+ xsltCopyNamespaceList(ctxt, copy, node->nsDef);\r
+ else\r
+ xsltCopyNamespaceListInternal(copy, node->nsDef);\r
+ }\r
+\r
+ /*\r
+ * URGENT TODO: The problem with this is that it does not\r
+ * copy over all namespace nodes in scope.\r
+ * The damn thing about this is, that we would need to\r
+ * use the xmlGetNsList(), for every single node; this is\r
+ * also done in xsltCopyTreeInternal(), but only for the top node.\r
+ */\r
+ if (node->ns != NULL) {\r
+ if (isLRE) {\r
+ /*\r
+ * REVISIT TODO: Since the non-refactored code still does\r
+ * ns-aliasing, we need to call xsltGetNamespace() here.\r
+ * Remove this when ready.\r
+ */\r
+ copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);\r
+ } else {\r
+ copy->ns = xsltGetSpecialNamespace(ctxt,\r
+ node, node->ns->href, node->ns->prefix, copy);\r
+ \r
+ }\r
+ } else if ((insert->type == XML_ELEMENT_NODE) &&\r
+ (insert->ns != NULL))\r
+ {\r
+ /*\r
+ * "Undeclare" the default namespace.\r
+ */\r
+ xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);\r
+ }\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltShallowCopyElem: copy %s failed\n", node->name);\r
+ }\r
+ return(copy);\r
+}\r
+\r
+/**\r
+ * xsltCopyTreeList:\r
+ * @ctxt: a XSLT process context\r
+ * @invocNode: responsible node in the stylesheet; used for error reports\r
+ * @list: the list of element nodes in the source tree.\r
+ * @insert: the parent in the result tree.\r
+ * @literal: is this a literal result element list\r
+ *\r
+ * Make a copy of the full list of tree @list\r
+ * and insert it as last children of @insert\r
+ *\r
+ * NOTE: Not to be used for Literal Result Elements.\r
+ *\r
+ * Used by:\r
+ * - xsltCopyOf()\r
+ *\r
+ * Returns a pointer to the new list, or NULL in case of error\r
+ */\r
+static xmlNodePtr\r
+xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,\r
+ xmlNodePtr list,\r
+ xmlNodePtr insert, int isLRE, int topElemVisited)\r
+{\r
+ xmlNodePtr copy, ret = NULL;\r
+\r
+ while (list != NULL) {\r
+ copy = xsltCopyTreeInternal(ctxt, invocNode,\r
+ list, insert, isLRE, topElemVisited);\r
+ if (copy != NULL) {\r
+ if (ret == NULL) {\r
+ ret = copy;\r
+ }\r
+ }\r
+ list = list->next;\r
+ }\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltCopyNamespaceListInternal:\r
+ * @node: the target node\r
+ * @cur: the first namespace\r
+ *\r
+ * Do a copy of a namespace list. If @node is non-NULL the\r
+ * new namespaces are added automatically.\r
+ * Called by:\r
+ * xsltCopyTreeInternal()\r
+ *\r
+ * QUESTION: What is the exact difference between this function\r
+ * and xsltCopyNamespaceList() in "namespaces.c"?\r
+ * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.\r
+ *\r
+ * Returns: a new xmlNsPtr, or NULL in case of error.\r
+ */\r
+static xmlNsPtr\r
+xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {\r
+ xmlNsPtr ret = NULL;\r
+ xmlNsPtr p = NULL, q, luNs;\r
+\r
+ if (ns == NULL)\r
+ return(NULL);\r
+ /*\r
+ * One can add namespaces only on element nodes\r
+ */\r
+ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))\r
+ elem = NULL;\r
+\r
+ do {\r
+ if (ns->type != XML_NAMESPACE_DECL)\r
+ break;\r
+ /*\r
+ * Avoid duplicating namespace declarations on the tree.\r
+ */\r
+ if (elem != NULL) { \r
+ if ((elem->ns != NULL) &&\r
+ xmlStrEqual(elem->ns->prefix, ns->prefix) &&\r
+ xmlStrEqual(elem->ns->href, ns->href))\r
+ {\r
+ ns = ns->next;\r
+ continue;\r
+ }\r
+ luNs = xmlSearchNs(elem->doc, elem, ns->prefix);\r
+ if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))\r
+ {\r
+ ns = ns->next;\r
+ continue;\r
+ }\r
+ } \r
+ q = xmlNewNs(elem, ns->href, ns->prefix);\r
+ if (p == NULL) {\r
+ ret = p = q;\r
+ } else if (q != NULL) {\r
+ p->next = q;\r
+ p = q;\r
+ }\r
+ ns = ns->next; \r
+ } while (ns != NULL);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltShallowCopyNsNode:\r
+ * @ctxt: the XSLT transformation context\r
+ * @invocNode: responsible node in the stylesheet; used for error reports\r
+ * @insert: the target element node in the result tree\r
+ * @ns: the namespace node\r
+ *\r
+ * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.\r
+ *\r
+ * Returns a new/existing ns-node, or NULL.\r
+ */\r
+static int\r
+xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr invocNode,\r
+ xmlNodePtr insert,\r
+ xmlNsPtr ns)\r
+{\r
+ xmlNsPtr tmpns;\r
+\r
+ if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))\r
+ return(-1);\r
+ \r
+ if (insert->children != NULL) {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "Namespace nodes must be added before "\r
+ "any child nodes are added to an element.\n");\r
+ return(1);\r
+ }\r
+ /* \r
+ *\r
+ * BIG NOTE: Xalan-J simply overwrites any ns-decls with\r
+ * an equal prefix. We definitively won't do that.\r
+ *\r
+ * MSXML 4.0 and the .NET ignores ns-decls for which an\r
+ * equal prefix is already in use.\r
+ *\r
+ * Saxon raises an error like:\r
+ * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace\r
+ * nodes with the same name".\r
+ *\r
+ * NOTE: We'll currently follow MSXML here.\r
+ * REVISIT TODO: Check if it's better to follow Saxon here.\r
+ */\r
+ if (ns->prefix == NULL) {\r
+ /*\r
+ * If we are adding ns-nodes to an element using e.g.\r
+ * <xsl:copy-of select="/foo/namespace::*">, then we need\r
+ * to ensure that we don't incorrectly declare a default\r
+ * namespace on an element in no namespace, which otherwise\r
+ * would move the element incorrectly into a namespace, if\r
+ * the node tree is serialized.\r
+ */\r
+ if (insert->ns == NULL)\r
+ goto occupied;\r
+ } else if ((ns->prefix[0] == 'x') &&\r
+ xmlStrEqual(ns->prefix, BAD_CAST "xml"))\r
+ {\r
+ return(0);\r
+ }\r
+\r
+ if (insert->nsDef != NULL) {\r
+ tmpns = insert->nsDef;\r
+ do {\r
+ if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { \r
+ if ((tmpns->prefix == ns->prefix) ||\r
+ xmlStrEqual(tmpns->prefix, ns->prefix))\r
+ {\r
+ /*\r
+ * Same prefix.\r
+ */\r
+ if (xmlStrEqual(tmpns->href, ns->href))\r
+ return(0);\r
+ goto occupied;\r
+ }\r
+ }\r
+ tmpns = tmpns->next;\r
+ } while (tmpns != NULL);\r
+ }\r
+ tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);\r
+ if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))\r
+ return(0);\r
+ /*\r
+ * Declare a new namespace.\r
+ * TODO: The problem (wrt efficiency) with this xmlNewNs() is\r
+ * that it will again search the already declared namespaces\r
+ * for a duplicate :-/\r
+ */\r
+ xmlNewNs(insert, ns->href, ns->prefix);\r
+ return(0); \r
+\r
+occupied:\r
+ /*\r
+ * TODO: We could as well raise an error here (like Saxon does),\r
+ * or at least generate a warning.\r
+ */\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltCopyTreeInternal:\r
+ * @ctxt: the XSLT transformation context\r
+ * @invocNode: responsible node in the stylesheet; used for error reports\r
+ * @node: the element node in the source tree\r
+ * @insert: the parent in the result tree\r
+ * @isLRE: indicates if @node is a Literal Result Element\r
+ * @topElemVisited: indicates if a top-most element was already processed\r
+ *\r
+ * Make a copy of the full tree under the element node @node\r
+ * and insert it as last child of @insert\r
+ *\r
+ * NOTE: Not to be used for Literal Result Elements.\r
+ *\r
+ * Used by:\r
+ * - xsltCopyOf()\r
+ *\r
+ * Returns a pointer to the new tree, or NULL in case of error\r
+ */\r
+static xmlNodePtr\r
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr invocNode,\r
+ xmlNodePtr node,\r
+ xmlNodePtr insert, int isLRE, int topElemVisited)\r
+{\r
+ xmlNodePtr copy;\r
+\r
+ if (node == NULL)\r
+ return(NULL);\r
+ switch (node->type) {\r
+ case XML_ELEMENT_NODE:\r
+ case XML_ENTITY_REF_NODE:\r
+ case XML_ENTITY_NODE:\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+#ifdef LIBXML_DOCB_ENABLED\r
+ case XML_DOCB_DOCUMENT_NODE:\r
+#endif\r
+ break;\r
+ case XML_TEXT_NODE: {\r
+ int noenc = (node->name == xmlStringTextNoenc);\r
+ return(xsltCopyTextString(ctxt, insert, node->content, noenc));\r
+ }\r
+ case XML_CDATA_SECTION_NODE:\r
+ return(xsltCopyTextString(ctxt, insert, node->content, 0));\r
+ case XML_ATTRIBUTE_NODE:\r
+ return((xmlNodePtr)\r
+ xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));\r
+ case XML_NAMESPACE_DECL:\r
+ return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,\r
+ insert, (xmlNsPtr) node));\r
+ \r
+ case XML_DOCUMENT_TYPE_NODE:\r
+ case XML_DOCUMENT_FRAG_NODE:\r
+ case XML_NOTATION_NODE:\r
+ case XML_DTD_NODE:\r
+ case XML_ELEMENT_DECL:\r
+ case XML_ATTRIBUTE_DECL:\r
+ case XML_ENTITY_DECL:\r
+ case XML_XINCLUDE_START:\r
+ case XML_XINCLUDE_END:\r
+ return(NULL);\r
+ } \r
+ if (XSLT_IS_RES_TREE_FRAG(node)) {\r
+ if (node->children != NULL)\r
+ copy = xsltCopyTreeList(ctxt, invocNode,\r
+ node->children, insert, 0, 0);\r
+ else\r
+ copy = NULL;\r
+ return(copy);\r
+ }\r
+ copy = xmlDocCopyNode(node, insert->doc, 0);\r
+ if (copy != NULL) {\r
+ copy->doc = ctxt->output;\r
+ xmlAddChild(insert, copy);\r
+ /*\r
+ * The node may have been coalesced into another text node.\r
+ */\r
+ if (insert->last != copy)\r
+ return(insert->last);\r
+ copy->next = NULL;\r
+\r
+ if (node->type == XML_ELEMENT_NODE) { \r
+ /*\r
+ * Copy in-scope namespace nodes.\r
+ *\r
+ * REVISIT: Since we try to reuse existing in-scope ns-decls by\r
+ * using xmlSearchNsByHref(), this will eventually change\r
+ * the prefix of an original ns-binding; thus it might\r
+ * break QNames in element/attribute content.\r
+ * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation\r
+ * context, plus a ns-lookup function, which writes directly\r
+ * to a given list, then we wouldn't need to create/free the\r
+ * nsList every time.\r
+ */\r
+ if ((topElemVisited == 0) &&\r
+ (node->parent != NULL) &&\r
+ (node->parent->type != XML_DOCUMENT_NODE) &&\r
+ (node->parent->type != XML_HTML_DOCUMENT_NODE))\r
+ {\r
+ xmlNsPtr *nsList, *curns, ns;\r
+ \r
+ /*\r
+ * If this is a top-most element in a tree to be\r
+ * copied, then we need to ensure that all in-scope\r
+ * namespaces are copied over. For nodes deeper in the\r
+ * tree, it is sufficient to reconcile only the ns-decls\r
+ * (node->nsDef entries).\r
+ */\r
+ \r
+ nsList = xmlGetNsList(node->doc, node);\r
+ if (nsList != NULL) {\r
+ curns = nsList;\r
+ do {\r
+ /*\r
+ * Search by prefix first in order to break as less\r
+ * QNames in element/attribute content as possible.\r
+ */\r
+ ns = xmlSearchNs(insert->doc, insert,\r
+ (*curns)->prefix);\r
+ \r
+ if ((ns == NULL) ||\r
+ (! xmlStrEqual(ns->href, (*curns)->href)))\r
+ {\r
+ ns = NULL;\r
+ /*\r
+ * Search by namespace name.\r
+ * REVISIT TODO: Currently disabled.\r
+ */\r
+#if 0\r
+ ns = xmlSearchNsByHref(insert->doc,\r
+ insert, (*curns)->href);\r
+#endif\r
+ }\r
+ if (ns == NULL) {\r
+ /*\r
+ * Declare a new namespace on the copied element.\r
+ */\r
+ ns = xmlNewNs(copy, (*curns)->href,\r
+ (*curns)->prefix);\r
+ /* TODO: Handle errors */\r
+ }\r
+ if (node->ns == *curns) {\r
+ /*\r
+ * If this was the original's namespace then set\r
+ * the generated counterpart on the copy.\r
+ */\r
+ copy->ns = ns;\r
+ }\r
+ curns++;\r
+ } while (*curns != NULL);\r
+ xmlFree(nsList);\r
+ }\r
+ } else if (node->nsDef != NULL) { \r
+ /*\r
+ * Copy over all namespace declaration attributes. \r
+ */\r
+ if (node->nsDef != NULL) {\r
+ if (isLRE)\r
+ xsltCopyNamespaceList(ctxt, copy, node->nsDef);\r
+ else\r
+ xsltCopyNamespaceListInternal(copy, node->nsDef);\r
+ }\r
+ }\r
+ /*\r
+ * Set the namespace.\r
+ */\r
+ if (node->ns != NULL) {\r
+ if (copy->ns == NULL) {\r
+ /*\r
+ * This will map copy->ns to one of the newly created\r
+ * in-scope ns-decls, OR create a new ns-decl on @copy.\r
+ */\r
+ copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,\r
+ node->ns->href, node->ns->prefix, copy);\r
+ }\r
+ } else if ((insert->type == XML_ELEMENT_NODE) &&\r
+ (insert->ns != NULL))\r
+ {\r
+ /*\r
+ * "Undeclare" the default namespace on @copy with xmlns="".\r
+ */\r
+ xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);\r
+ }\r
+ /*\r
+ * Copy attribute nodes.\r
+ */\r
+ if (node->properties != NULL) {\r
+ xsltCopyAttrListNoOverwrite(ctxt, invocNode,\r
+ copy, node->properties);\r
+ }\r
+ if (topElemVisited == 0)\r
+ topElemVisited = 1;\r
+ }\r
+ /*\r
+ * Copy the subtree.\r
+ */\r
+ if (node->children != NULL) {\r
+ xsltCopyTreeList(ctxt, invocNode,\r
+ node->children, copy, isLRE, topElemVisited);\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, invocNode,\r
+ "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);\r
+ }\r
+ return(copy);\r
+}\r
+\r
+/**\r
+ * xsltCopyTree:\r
+ * @ctxt: the XSLT transformation context\r
+ * @node: the element node in the source tree\r
+ * @insert: the parent in the result tree\r
+ * @literal: indicates if @node is a Literal Result Element\r
+ *\r
+ * Make a copy of the full tree under the element node @node\r
+ * and insert it as last child of @insert\r
+ * For literal result element, some of the namespaces may not be copied\r
+ * over according to section 7.1.\r
+ * TODO: Why is this a public function?\r
+ *\r
+ * Returns a pointer to the new tree, or NULL in case of error\r
+ */\r
+xmlNodePtr\r
+xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr insert, int literal)\r
+{\r
+ return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));\r
+ \r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Error/fallback processing *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltApplyFallbacks:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the node generating the error\r
+ *\r
+ * Process possible xsl:fallback nodes present under @inst\r
+ *\r
+ * Returns the number of xsl:fallback element found and processed\r
+ */\r
+static int\r
+xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst) {\r
+\r
+ xmlNodePtr child;\r
+ int ret = 0;\r
+ \r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||\r
+ (inst->children == NULL))\r
+ return(0);\r
+\r
+ child = inst->children;\r
+ while (child != NULL) {\r
+ if ((IS_XSLT_ELEM(child)) &&\r
+ (xmlStrEqual(child->name, BAD_CAST "fallback"))) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "applying xsl:fallback\n");\r
+#endif\r
+ ret++;\r
+ xsltApplySequenceConstructor(ctxt, node, child->children,\r
+ NULL);\r
+ }\r
+ child = child->next;\r
+ }\r
+ return(ret);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Default processing *\r
+ * *\r
+ ************************************************************************/\r
+\r
+void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xsltStackElemPtr params);\r
+/**\r
+ * xsltDefaultProcessOneNode:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @params: extra parameters passed to the template if any\r
+ *\r
+ * Process the source node with the default built-in template rule:\r
+ * <xsl:template match="*|/">\r
+ * <xsl:apply-templates/>\r
+ * </xsl:template>\r
+ *\r
+ * and\r
+ *\r
+ * <xsl:template match="text()|@*">\r
+ * <xsl:value-of select="."/>\r
+ * </xsl:template>\r
+ *\r
+ * Note also that namespace declarations are copied directly:\r
+ *\r
+ * the built-in template rule is the only template rule that is applied\r
+ * for namespace nodes.\r
+ */\r
+static void\r
+xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xsltStackElemPtr params) {\r
+ xmlNodePtr copy;\r
+ xmlNodePtr delete = NULL, cur;\r
+ int nbchild = 0, oldSize;\r
+ int childno = 0, oldPos;\r
+ xsltTemplatePtr template;\r
+\r
+ CHECK_STOPPED;\r
+ /*\r
+ * Handling of leaves\r
+ */\r
+ switch (node->type) {\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_ELEMENT_NODE:\r
+ break;\r
+ case XML_CDATA_SECTION_NODE:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy CDATA %s\n",\r
+ node->content));\r
+#endif\r
+ copy = xsltCopyText(ctxt, ctxt->insert, node, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltDefaultProcessOneNode: cdata copy failed\n");\r
+ }\r
+ return;\r
+ case XML_TEXT_NODE:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (node->content == NULL) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy empty text\n"));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy text %s\n",\r
+ node->content));\r
+ }\r
+#endif\r
+ copy = xsltCopyText(ctxt, ctxt->insert, node, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltDefaultProcessOneNode: text copy failed\n");\r
+ }\r
+ return;\r
+ case XML_ATTRIBUTE_NODE:\r
+ cur = node->children;\r
+ while ((cur != NULL) && (cur->type != XML_TEXT_NODE))\r
+ cur = cur->next;\r
+ if (cur == NULL) {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltDefaultProcessOneNode: no text for attribute\n");\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->content == NULL) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy empty text\n"));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy text %s\n",\r
+ cur->content));\r
+ }\r
+#endif\r
+ copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, node,\r
+ "xsltDefaultProcessOneNode: text copy failed\n");\r
+ }\r
+ }\r
+ return;\r
+ default:\r
+ return;\r
+ }\r
+ /*\r
+ * Handling of Elements: first pass, cleanup and counting\r
+ */\r
+ cur = node->children;\r
+ while (cur != NULL) {\r
+ switch (cur->type) {\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_ELEMENT_NODE:\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ nbchild++;\r
+ break;\r
+ case XML_DTD_NODE:\r
+ /* Unlink the DTD, it's still reachable using doc->intSubset */\r
+ if (cur->next != NULL)\r
+ cur->next->prev = cur->prev;\r
+ if (cur->prev != NULL)\r
+ cur->prev->next = cur->next;\r
+ break;\r
+ default:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: skipping node type %d\n",\r
+ cur->type));\r
+#endif\r
+ delete = cur;\r
+ }\r
+ cur = cur->next;\r
+ if (delete != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: removing ignorable blank node\n"));\r
+#endif\r
+ xmlUnlinkNode(delete);\r
+ xmlFreeNode(delete);\r
+ delete = NULL;\r
+ }\r
+ }\r
+ if (delete != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: removing ignorable blank node\n"));\r
+#endif\r
+ xmlUnlinkNode(delete);\r
+ xmlFreeNode(delete);\r
+ delete = NULL;\r
+ }\r
+\r
+ /*\r
+ * Handling of Elements: second pass, actual processing\r
+ */\r
+ oldSize = ctxt->xpathCtxt->contextSize;\r
+ oldPos = ctxt->xpathCtxt->proximityPosition;\r
+ cur = node->children;\r
+ while (cur != NULL) {\r
+ childno++;\r
+ switch (cur->type) {\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_ELEMENT_NODE:\r
+ ctxt->xpathCtxt->contextSize = nbchild;\r
+ ctxt->xpathCtxt->proximityPosition = childno;\r
+ xsltProcessOneNode(ctxt, cur, params);\r
+ break;\r
+ case XML_CDATA_SECTION_NODE:\r
+ template = xsltGetTemplate(ctxt, cur, NULL);\r
+ if (template) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: applying template for CDATA %s\n",\r
+ cur->content));\r
+#endif\r
+ /*\r
+ * Instantiate the xsl:template.\r
+ */\r
+ xsltApplyXSLTTemplate(ctxt, cur, template->content,\r
+ template, params);\r
+ } else /* if (ctxt->mode == NULL) */ {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy CDATA %s\n",\r
+ cur->content));\r
+#endif\r
+ copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "xsltDefaultProcessOneNode: cdata copy failed\n");\r
+ }\r
+ }\r
+ break;\r
+ case XML_TEXT_NODE:\r
+ template = xsltGetTemplate(ctxt, cur, NULL);\r
+ if (template) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: applying template for text %s\n",\r
+ cur->content));\r
+#endif\r
+ ctxt->xpathCtxt->contextSize = nbchild;\r
+ ctxt->xpathCtxt->proximityPosition = childno;\r
+ /*\r
+ * Instantiate the xsl:template.\r
+ */\r
+ xsltApplyXSLTTemplate(ctxt, cur, template->content,\r
+ template, params);\r
+ } else /* if (ctxt->mode == NULL) */ {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->content == NULL) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy empty text\n"));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: copy text %s\n",\r
+ cur->content));\r
+ }\r
+#endif\r
+ copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "xsltDefaultProcessOneNode: text copy failed\n");\r
+ }\r
+ }\r
+ break;\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ template = xsltGetTemplate(ctxt, cur, NULL);\r
+ if (template) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->type == XML_PI_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: template found for PI %s\n",\r
+ cur->name));\r
+ } else if (cur->type == XML_COMMENT_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltDefaultProcessOneNode: template found for comment\n"));\r
+ }\r
+#endif\r
+ ctxt->xpathCtxt->contextSize = nbchild;\r
+ ctxt->xpathCtxt->proximityPosition = childno;\r
+ /*\r
+ * Instantiate the xsl:template.\r
+ */\r
+ xsltApplyXSLTTemplate(ctxt, cur, template->content,\r
+ template, params);\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ ctxt->xpathCtxt->contextSize = oldSize;\r
+ ctxt->xpathCtxt->proximityPosition = oldPos;\r
+}\r
+\r
+/**\r
+ * xsltProcessOneNode:\r
+ * @ctxt: a XSLT process context\r
+ * @contextNode: the "current node" in the source tree\r
+ * @withParams: extra parameters (e.g. xsl:with-param) passed to the\r
+ * template if any\r
+ *\r
+ * Process the source node.\r
+ */\r
+void\r
+xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,\r
+ xsltStackElemPtr withParams)\r
+{\r
+ xsltTemplatePtr templ;\r
+ xmlNodePtr oldNode;\r
+ \r
+ templ = xsltGetTemplate(ctxt, contextNode, NULL);\r
+ /*\r
+ * If no template is found, apply the default rule.\r
+ */\r
+ if (templ == NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (contextNode->type == XML_DOCUMENT_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: no template found for /\n"));\r
+ } else if (contextNode->type == XML_CDATA_SECTION_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: no template found for CDATA\n"));\r
+ } else if (contextNode->type == XML_ATTRIBUTE_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: no template found for attribute %s\n",\r
+ ((xmlAttrPtr) contextNode)->name));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: no template found for %s\n", contextNode->name));\r
+ }\r
+#endif\r
+ oldNode = ctxt->node;\r
+ ctxt->node = contextNode;\r
+ xsltDefaultProcessOneNode(ctxt, contextNode, withParams);\r
+ ctxt->node = oldNode;\r
+ return;\r
+ }\r
+\r
+ if (contextNode->type == XML_ATTRIBUTE_NODE) {\r
+ xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; \r
+ /*\r
+ * Set the "current template rule".\r
+ */\r
+ ctxt->currentTemplateRule = templ;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: applying template '%s' for attribute %s\n",\r
+ templ->match, contextNode->name));\r
+#endif\r
+ xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);\r
+\r
+ ctxt->currentTemplateRule = oldCurTempRule;\r
+ } else {\r
+ xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; \r
+ /*\r
+ * Set the "current template rule".\r
+ */\r
+ ctxt->currentTemplateRule = templ;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (contextNode->type == XML_DOCUMENT_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: applying template '%s' for /\n",\r
+ templ->match));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessOneNode: applying template '%s' for %s\n",\r
+ templ->match, contextNode->name));\r
+ }\r
+#endif\r
+ xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);\r
+\r
+ ctxt->currentTemplateRule = oldCurTempRule;\r
+ }\r
+}\r
+\r
+static xmlNodePtr\r
+xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr list,\r
+ xsltTemplatePtr templ,\r
+ int *addCallResult)\r
+{\r
+ xmlNodePtr debugedNode = NULL; \r
+\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE) {\r
+ if (templ) {\r
+ *addCallResult = xslAddCall(templ, templ->elem);\r
+ } else {\r
+ *addCallResult = xslAddCall(NULL, list);\r
+ }\r
+ switch (ctxt->debugStatus) {\r
+ case XSLT_DEBUG_RUN_RESTART:\r
+ case XSLT_DEBUG_QUIT:\r
+ if (*addCallResult)\r
+ xslDropCall();\r
+ return(NULL);\r
+ }\r
+ if (templ) {\r
+ xslHandleDebugger(templ->elem, contextNode, templ, ctxt);\r
+ debugedNode = templ->elem;\r
+ } else if (list) {\r
+ xslHandleDebugger(list, contextNode, templ, ctxt);\r
+ debugedNode = list;\r
+ } else if (ctxt->inst) {\r
+ xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);\r
+ debugedNode = ctxt->inst;\r
+ }\r
+ }\r
+ return(debugedNode);\r
+}\r
+\r
+static int\r
+xsltLocalVariablePush(xsltTransformContextPtr ctxt,\r
+ xsltStackElemPtr variable,\r
+ int level)\r
+{\r
+ if (ctxt->varsMax == 0) {\r
+ ctxt->varsMax = 10;\r
+ ctxt->varsTab =\r
+ (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *\r
+ sizeof(ctxt->varsTab[0]));\r
+ if (ctxt->varsTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");\r
+ return (-1);\r
+ }\r
+ }\r
+ if (ctxt->varsNr >= ctxt->varsMax) {\r
+ ctxt->varsMax *= 2;\r
+ ctxt->varsTab =\r
+ (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,\r
+ ctxt->varsMax *\r
+ sizeof(ctxt->varsTab[0]));\r
+ if (ctxt->varsTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");\r
+ return (-1);\r
+ }\r
+ }\r
+ ctxt->varsTab[ctxt->varsNr++] = variable;\r
+ ctxt->vars = variable;\r
+ variable->level = level;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltReleaseLocalRVTs:\r
+ *\r
+ * Fragments which are results of extension instructions\r
+ * are preserved; all other fragments are freed/cached.\r
+ */\r
+static void\r
+xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)\r
+{\r
+ xmlDocPtr cur = ctxt->localRVT, tmp;\r
+ \r
+ while ((cur != NULL) && (cur != base)) {\r
+ if (cur->psvi == (void *) ((long) 1)) {\r
+ cur = (xmlDocPtr) cur->next;\r
+ } else {\r
+ tmp = cur;\r
+ cur = (xmlDocPtr) cur->next;\r
+\r
+ if (tmp == ctxt->localRVT)\r
+ ctxt->localRVT = (xmlDocPtr) tmp->next;\r
+\r
+ /*\r
+ * We need ctxt->localRVTBase for extension instructions\r
+ * which return values (like EXSLT's function).\r
+ */\r
+ if (tmp == ctxt->localRVTBase)\r
+ ctxt->localRVTBase = (xmlDocPtr) tmp->next;\r
+\r
+ if (tmp->prev)\r
+ tmp->prev->next = (xmlNodePtr) cur;\r
+ if (cur)\r
+ cur->prev = tmp->prev;\r
+ xsltReleaseRVT(ctxt, tmp);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltApplySequenceConstructor:\r
+ * @ctxt: a XSLT process context\r
+ * @contextNode: the "current node" in the source tree\r
+ * @list: the nodes of a sequence constructor;\r
+ * (plus leading xsl:param elements)\r
+ * @templ: the compiled xsl:template (optional)\r
+ *\r
+ * Processes a sequence constructor.\r
+ * \r
+ * NOTE: ctxt->currentTemplateRule was introduced to reflect the\r
+ * semantics of "current template rule". I.e. the field ctxt->templ\r
+ * is not intended to reflect this, thus always pushed onto the\r
+ * template stack.\r
+ */\r
+static void\r
+xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode, xmlNodePtr list,\r
+ xsltTemplatePtr templ)\r
+{\r
+ xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;\r
+ xmlNodePtr cur, insert, copy = NULL;\r
+ int level = 0, oldVarsNr;\r
+ xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ xsltStylePreCompPtr info;\r
+#endif\r
+\r
+#ifdef WITH_DEBUGGER\r
+ int addCallResult = 0;\r
+ xmlNodePtr debuggedNode = NULL;\r
+#endif\r
+\r
+ if (ctxt == NULL)\r
+ return;\r
+\r
+#ifdef WITH_DEBUGGER \r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE) {\r
+ debuggedNode =\r
+ xsltDebuggerStartSequenceConstructor(ctxt, contextNode,\r
+ list, templ, &addCallResult);\r
+ if (debuggedNode == NULL)\r
+ return;\r
+ }\r
+#endif\r
+\r
+ if (list == NULL)\r
+ return;\r
+ CHECK_STOPPED;\r
+\r
+ oldLocalFragmentTop = ctxt->localRVT;\r
+ oldInsert = insert = ctxt->insert;\r
+ oldInst = oldCurInst = ctxt->inst;\r
+ oldContextNode = ctxt->node;\r
+ /*\r
+ * Save current number of variables on the stack; new vars are popped when\r
+ * exiting.\r
+ */\r
+ oldVarsNr = ctxt->varsNr;\r
+ /*\r
+ * Process the sequence constructor.\r
+ */\r
+ cur = list;\r
+ while (cur != NULL) {\r
+ ctxt->inst = cur;\r
+\r
+#ifdef WITH_DEBUGGER\r
+ switch (ctxt->debugStatus) {\r
+ case XSLT_DEBUG_RUN_RESTART:\r
+ case XSLT_DEBUG_QUIT:\r
+ break;\r
+\r
+ }\r
+#endif\r
+ /*\r
+ * Test; we must have a valid insertion point.\r
+ */\r
+ if (insert == NULL) {\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: insert == NULL !\n"));\r
+#endif\r
+ goto error;\r
+ }\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))\r
+ xslHandleDebugger(cur, contextNode, templ, ctxt);\r
+#endif\r
+\r
+#ifdef XSLT_REFACTORED\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ info = (xsltStylePreCompPtr) cur->psvi;\r
+ /*\r
+ * We expect a compiled representation on:\r
+ * 1) XSLT instructions of this XSLT version (1.0)\r
+ * (with a few exceptions)\r
+ * 2) Literal result elements\r
+ * 3) Extension instructions\r
+ * 4) XSLT instructions of future XSLT versions\r
+ * (forwards-compatible mode).\r
+ */\r
+ if (info == NULL) {\r
+ /*\r
+ * Handle the rare cases where we don't expect a compiled\r
+ * representation on an XSLT element.\r
+ */\r
+ if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {\r
+ xsltMessage(ctxt, contextNode, cur);\r
+ goto skip_children;\r
+ } \r
+ /*\r
+ * Something really went wrong:\r
+ */\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Internal error in xsltApplySequenceConstructor(): "\r
+ "The element '%s' in the stylesheet has no compiled "\r
+ "representation.\n",\r
+ cur->name);\r
+ goto skip_children;\r
+ }\r
+\r
+ if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {\r
+ xsltStyleItemLRElementInfoPtr lrInfo =\r
+ (xsltStyleItemLRElementInfoPtr) info;\r
+ /*\r
+ * Literal result elements\r
+ * --------------------------------------------------------\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy literal result "\r
+ "element '%s'\n", cur->name));\r
+#endif\r
+ /*\r
+ * Copy the raw element-node.\r
+ * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))\r
+ * == NULL)\r
+ * goto error;\r
+ */ \r
+ copy = xmlDocCopyNode(cur, insert->doc, 0);\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Internal error in xsltApplySequenceConstructor(): "\r
+ "Failed to copy literal result element '%s'.\n",\r
+ cur->name);\r
+ goto error;\r
+ } else {\r
+ /*\r
+ * Add the element-node to the result tree.\r
+ */\r
+ copy->doc = ctxt->output;\r
+ xmlAddChild(insert, copy);\r
+ /*\r
+ * Create effective namespaces declarations.\r
+ * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);\r
+ */\r
+ if (lrInfo->effectiveNs != NULL) {\r
+ xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;\r
+ xmlNsPtr ns, lastns = NULL;\r
+\r
+ while (effNs != NULL) {\r
+ /*\r
+ * Avoid generating redundant namespace\r
+ * declarations; thus lookup if there is already\r
+ * such a ns-decl in the result.\r
+ */ \r
+ ns = xmlSearchNs(copy->doc, copy, effNs->prefix);\r
+ if ((ns != NULL) &&\r
+ (xmlStrEqual(ns->href, effNs->nsName)))\r
+ {\r
+ effNs = effNs->next;\r
+ continue; \r
+ }\r
+ ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Internal error in "\r
+ "xsltApplySequenceConstructor(): "\r
+ "Failed to copy a namespace "\r
+ "declaration.\n");\r
+ goto error;\r
+ }\r
+ \r
+ if (lastns == NULL)\r
+ copy->nsDef = ns;\r
+ else\r
+ lastns->next =ns;\r
+ lastns = ns;\r
+\r
+ effNs = effNs->next;\r
+ }\r
+ \r
+ }\r
+ /*\r
+ * NOTE that we don't need to apply ns-alising: this was\r
+ * already done at compile-time.\r
+ */\r
+ if (cur->ns != NULL) {\r
+ /*\r
+ * If there's no such ns-decl in the result tree,\r
+ * then xsltGetSpecialNamespace() will\r
+ * create a ns-decl on the copied node.\r
+ */ \r
+ copy->ns = xsltGetSpecialNamespace(ctxt, cur,\r
+ cur->ns->href, cur->ns->prefix, copy); \r
+ } else {\r
+ /*\r
+ * Undeclare the default namespace if needed.\r
+ * This can be skipped, if the result element has\r
+ * no ns-decls, in which case the result element\r
+ * obviously does not declare a default namespace;\r
+ * AND there's either no parent, or the parent\r
+ * element is in no namespace; this means there's no\r
+ * default namespace is scope to care about.\r
+ *\r
+ * REVISIT: This might result in massive\r
+ * generation of ns-decls if nodes in a default\r
+ * namespaces are mixed with nodes in no namespace.\r
+ * \r
+ */\r
+ if (copy->nsDef ||\r
+ ((insert != NULL) &&\r
+ (insert->type == XML_ELEMENT_NODE) &&\r
+ (insert->ns != NULL)))\r
+ {\r
+ xsltGetSpecialNamespace(ctxt, cur,\r
+ NULL, NULL, copy);\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * SPEC XSLT 2.0 "Each attribute of the literal result\r
+ * element, other than an attribute in the XSLT namespace,\r
+ * is processed to produce an attribute for the element in\r
+ * the result tree."\r
+ * NOTE: See bug #341325.\r
+ */\r
+ if (cur->properties != NULL) {\r
+ xsltAttrListTemplateProcess(ctxt, copy, cur->properties);\r
+ }\r
+ } else if (IS_XSLT_ELEM_FAST(cur)) {\r
+ /*\r
+ * XSLT instructions\r
+ * --------------------------------------------------------\r
+ */\r
+ if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {\r
+ /*\r
+ * We hit an unknown XSLT element.\r
+ * Try to apply one of the fallback cases.\r
+ */ \r
+ ctxt->insert = insert;\r
+ if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "The is no fallback behaviour defined for "\r
+ "the unknown XSLT element '%s'.\n",\r
+ cur->name);\r
+ } \r
+ ctxt->insert = oldInsert;\r
+ } else if (info->func != NULL) {\r
+ /*\r
+ * Execute the XSLT instruction.\r
+ */\r
+ ctxt->insert = insert;\r
+\r
+ info->func(ctxt, contextNode, cur,\r
+ (xsltElemPreCompPtr) info);\r
+\r
+ /*\r
+ * Cleanup temporary tree fragments.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT)\r
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);\r
+\r
+ ctxt->insert = oldInsert;\r
+ } else if (info->type == XSLT_FUNC_VARIABLE) { \r
+ xsltStackElemPtr tmpvar = ctxt->vars;\r
+ \r
+ xsltParseStylesheetVariable(ctxt, cur);\r
+ \r
+ if (tmpvar != ctxt->vars) {\r
+ /*\r
+ * TODO: Using a @tmpvar is an annoying workaround, but\r
+ * the current mechanisms do not provide any other way\r
+ * of knowing if the var was really pushed onto the\r
+ * stack.\r
+ */\r
+ ctxt->vars->level = level;\r
+ }\r
+ } else if (info->type == XSLT_FUNC_MESSAGE) {\r
+ /*\r
+ * TODO: Won't be hit, since we don't compile xsl:message.\r
+ */\r
+ xsltMessage(ctxt, contextNode, cur);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Unexpected XSLT element '%s'.\n", cur->name); \r
+ }\r
+ goto skip_children;\r
+\r
+ } else {\r
+ xsltTransformFunction func;\r
+ /*\r
+ * Extension intructions (elements)\r
+ * --------------------------------------------------------\r
+ */ \r
+ if (cur->psvi == xsltExtMarker) {\r
+ /*\r
+ * The xsltExtMarker was set during the compilation\r
+ * of extension instructions if there was no registered\r
+ * handler for this specific extension function at\r
+ * compile-time.\r
+ * Libxslt will now lookup if a handler is\r
+ * registered in the context of this transformation.\r
+ */\r
+ func = (xsltTransformFunction)\r
+ xsltExtElementLookup(ctxt, cur->name, cur->ns->href);\r
+ } else\r
+ func = ((xsltElemPreCompPtr) cur->psvi)->func;\r
+ \r
+ if (func == NULL) {\r
+ /*\r
+ * No handler available.\r
+ * Try to execute fallback behaviour via xsl:fallback.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: unknown extension %s\n",\r
+ cur->name));\r
+#endif\r
+ ctxt->insert = insert;\r
+ if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Unknown extension instruction '{%s}%s'.\n",\r
+ cur->ns->href, cur->name);\r
+ } \r
+ ctxt->insert = oldInsert; \r
+ } else {\r
+ /*\r
+ * Execute the handler-callback.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: extension construct %s\n",\r
+ cur->name));\r
+#endif \r
+ ctxt->insert = insert;\r
+ /*\r
+ * We need the fragment base for extension instructions\r
+ * which return values (like EXSLT's function).\r
+ */\r
+ oldLocalFragmentBase = ctxt->localRVTBase;\r
+ ctxt->localRVTBase = NULL;\r
+\r
+ func(ctxt, contextNode, cur, cur->psvi);\r
+\r
+ ctxt->localRVTBase = oldLocalFragmentBase;\r
+ /*\r
+ * Cleanup temporary tree fragments.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT)\r
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);\r
+\r
+ ctxt->insert = oldInsert;\r
+ }\r
+ goto skip_children;\r
+ }\r
+\r
+ } else if (XSLT_IS_TEXT_NODE(cur)) {\r
+ /*\r
+ * Text\r
+ * ------------------------------------------------------------\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->name == xmlStringTextNoenc) {\r
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy unescaped text '%s'\n",\r
+ cur->content));\r
+ } else {\r
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy text '%s'\n",\r
+ cur->content));\r
+ }\r
+#endif\r
+ if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)\r
+ goto error; \r
+ }\r
+\r
+#else /* XSLT_REFACTORED */\r
+\r
+ if (IS_XSLT_ELEM(cur)) {\r
+ /*\r
+ * This is an XSLT node\r
+ */\r
+ xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;\r
+\r
+ if (info == NULL) {\r
+ if (IS_XSLT_NAME(cur, "message")) {\r
+ xsltMessage(ctxt, contextNode, cur);\r
+ } else { \r
+ /*\r
+ * That's an error try to apply one of the fallback cases\r
+ */\r
+ ctxt->insert = insert;\r
+ if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltApplySequenceConstructor: %s was not compiled\n",\r
+ cur->name);\r
+ }\r
+ ctxt->insert = oldInsert;\r
+ }\r
+ goto skip_children;\r
+ } \r
+\r
+ if (info->func != NULL) {\r
+ oldCurInst = ctxt->inst;\r
+ ctxt->inst = cur;\r
+ ctxt->insert = insert;\r
+\r
+ info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);\r
+\r
+ /*\r
+ * Cleanup temporary tree fragments.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT)\r
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);\r
+\r
+ ctxt->insert = oldInsert;\r
+ ctxt->inst = oldCurInst;\r
+ goto skip_children;\r
+ }\r
+\r
+ if (IS_XSLT_NAME(cur, "variable")) {\r
+ xsltStackElemPtr tmpvar = ctxt->vars;\r
+ \r
+ oldCurInst = ctxt->inst;\r
+ ctxt->inst = cur;\r
+\r
+ xsltParseStylesheetVariable(ctxt, cur);\r
+\r
+ ctxt->inst = oldCurInst;\r
+ \r
+ if (tmpvar != ctxt->vars) {\r
+ /*\r
+ * TODO: Using a @tmpvar is an annoying workaround, but\r
+ * the current mechanisms do not provide any other way\r
+ * of knowing if the var was really pushed onto the\r
+ * stack.\r
+ */\r
+ ctxt->vars->level = level;\r
+ }\r
+ } else if (IS_XSLT_NAME(cur, "message")) {\r
+ xsltMessage(ctxt, contextNode, cur);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Unexpected XSLT element '%s'.\n", cur->name);\r
+ }\r
+ goto skip_children;\r
+ } else if ((cur->type == XML_TEXT_NODE) ||\r
+ (cur->type == XML_CDATA_SECTION_NODE)) {\r
+\r
+ /*\r
+ * This text comes from the stylesheet\r
+ * For stylesheets, the set of whitespace-preserving\r
+ * element names consists of just xsl:text.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (cur->type == XML_CDATA_SECTION_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy CDATA text %s\n",\r
+ cur->content));\r
+ } else if (cur->name == xmlStringTextNoenc) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy unescaped text %s\n",\r
+ cur->content));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy text %s\n",\r
+ cur->content));\r
+ }\r
+#endif\r
+ if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)\r
+ goto error;\r
+ } else if ((cur->type == XML_ELEMENT_NODE) &&\r
+ (cur->ns != NULL) && (cur->psvi != NULL)) {\r
+ xsltTransformFunction function;\r
+\r
+ oldCurInst = ctxt->inst;\r
+ ctxt->inst = cur;\r
+ /*\r
+ * Flagged as an extension element\r
+ */\r
+ if (cur->psvi == xsltExtMarker)\r
+ function = (xsltTransformFunction)\r
+ xsltExtElementLookup(ctxt, cur->name, cur->ns->href);\r
+ else\r
+ function = ((xsltElemPreCompPtr) cur->psvi)->func;\r
+\r
+ if (function == NULL) {\r
+ xmlNodePtr child;\r
+ int found = 0;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: unknown extension %s\n",\r
+ cur->name));\r
+#endif\r
+ /*\r
+ * Search if there are fallbacks\r
+ */\r
+ child = cur->children;\r
+ while (child != NULL) {\r
+ if ((IS_XSLT_ELEM(child)) &&\r
+ (IS_XSLT_NAME(child, "fallback")))\r
+ {\r
+ found = 1;\r
+ xsltApplySequenceConstructor(ctxt, contextNode,\r
+ child->children, NULL);\r
+ }\r
+ child = child->next;\r
+ }\r
+\r
+ if (!found) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "xsltApplySequenceConstructor: failed to find extension %s\n",\r
+ cur->name);\r
+ }\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: extension construct %s\n",\r
+ cur->name));\r
+#endif\r
+\r
+ ctxt->insert = insert;\r
+ /*\r
+ * We need the fragment base for extension instructions\r
+ * which return values (like EXSLT's function).\r
+ */\r
+ oldLocalFragmentBase = ctxt->localRVTBase;\r
+ ctxt->localRVTBase = NULL;\r
+\r
+ function(ctxt, contextNode, cur, cur->psvi);\r
+ /*\r
+ * Cleanup temporary tree fragments.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT)\r
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);\r
+\r
+ ctxt->localRVTBase = oldLocalFragmentBase;\r
+ ctxt->insert = oldInsert;\r
+\r
+ }\r
+ ctxt->inst = oldCurInst;\r
+ goto skip_children;\r
+ } else if (cur->type == XML_ELEMENT_NODE) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplySequenceConstructor: copy node %s\n",\r
+ cur->name));\r
+#endif\r
+ oldCurInst = ctxt->inst;\r
+ ctxt->inst = cur;\r
+\r
+ if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)\r
+ goto error; \r
+ /*\r
+ * Add extra namespaces inherited from the current template\r
+ * if we are in the first level children and this is a\r
+ * "real" template. \r
+ */\r
+ if ((templ != NULL) && (oldInsert == insert) &&\r
+ (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {\r
+ int i;\r
+ xmlNsPtr ns, ret;\r
+\r
+ for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {\r
+ const xmlChar *URI = NULL;\r
+ xsltStylesheetPtr style;\r
+ ns = ctxt->templ->inheritedNs[i]; \r
+ \r
+ /* Note that the XSLT namespace was already excluded\r
+ * in xsltGetInheritedNsList().\r
+ */\r
+#if 0\r
+ if (xmlStrEqual(ns->href, XSLT_NAMESPACE))\r
+ continue;\r
+#endif\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ if (style->nsAliases != NULL)\r
+ URI = (const xmlChar *) \r
+ xmlHashLookup(style->nsAliases, ns->href);\r
+ if (URI != NULL)\r
+ break;\r
+ \r
+ style = xsltNextImport(style);\r
+ }\r
+ if (URI == UNDEFINED_DEFAULT_NS)\r
+ continue;\r
+ if (URI == NULL)\r
+ URI = ns->href;\r
+ /*\r
+ * TODO: The following will still be buggy for the\r
+ * non-refactored code.\r
+ */\r
+ ret = xmlSearchNs(copy->doc, copy, ns->prefix);\r
+ if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))\r
+ {\r
+ xmlNewNs(copy, URI, ns->prefix);\r
+ }\r
+ }\r
+ if (copy->ns != NULL) {\r
+ /*\r
+ * Fix the node namespace if needed\r
+ */\r
+ copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);\r
+ }\r
+ }\r
+ /*\r
+ * all the attributes are directly inherited\r
+ */\r
+ if (cur->properties != NULL) {\r
+ xsltAttrListTemplateProcess(ctxt, copy, cur->properties);\r
+ }\r
+ ctxt->inst = oldCurInst;\r
+ }\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+ /*\r
+ * Descend into content in document order.\r
+ */\r
+ if (cur->children != NULL) {\r
+ if (cur->children->type != XML_ENTITY_DECL) {\r
+ cur = cur->children;\r
+ level++;\r
+ if (copy != NULL)\r
+ insert = copy;\r
+ continue;\r
+ }\r
+ }\r
+\r
+skip_children:\r
+ /*\r
+ * If xslt:message was just processed, we might have hit a\r
+ * terminate='yes'; if so, then break the loop and clean up.\r
+ * TODO: Do we need to check this also before trying to descend\r
+ * into the content?\r
+ */\r
+ if (ctxt->state == XSLT_STATE_STOPPED)\r
+ break;\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+\r
+ do {\r
+ cur = cur->parent;\r
+ level--;\r
+ /*\r
+ * Pop variables/params (xsl:variable and xsl:param).\r
+ */\r
+ if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {\r
+ xsltLocalVariablePop(ctxt, oldVarsNr, level); \r
+ }\r
+\r
+ insert = insert->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ if (cur == list->parent) {\r
+ cur = NULL;\r
+ break;\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ break;\r
+ }\r
+ } while (cur != NULL);\r
+ }\r
+\r
+error:\r
+ /*\r
+ * In case of errors: pop remaining variables.\r
+ */\r
+ if (ctxt->varsNr > oldVarsNr)\r
+ xsltLocalVariablePop(ctxt, oldVarsNr, -1); \r
+\r
+ ctxt->node = oldContextNode;\r
+ ctxt->inst = oldInst;\r
+ ctxt->insert = oldInsert;\r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {\r
+ xslDropCall();\r
+ }\r
+#endif\r
+}\r
+\r
+/*\r
+* xsltApplyXSLTTemplate:\r
+* @ctxt: a XSLT transformation context\r
+* @contextNode: the node in the source tree.\r
+* @list: the nodes of a sequence constructor;\r
+* (plus leading xsl:param elements)\r
+* @templ: the compiled xsl:template declaration;\r
+* NULL if a sequence constructor\r
+* @withParams: a set of caller-parameters (xsl:with-param) or NULL\r
+*\r
+* Called by:\r
+* - xsltApplyImports()\r
+* - xsltCallTemplate()\r
+* - xsltDefaultProcessOneNode()\r
+* - xsltProcessOneNode()\r
+*/\r
+static void\r
+xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr list,\r
+ xsltTemplatePtr templ,\r
+ xsltStackElemPtr withParams)\r
+{\r
+ int oldVarsBase = 0;\r
+ long start = 0;\r
+ xmlNodePtr cur;\r
+ xsltStackElemPtr tmpParam = NULL;\r
+ xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemParamPtr iparam;\r
+#else\r
+ xsltStylePreCompPtr iparam;\r
+#endif\r
+\r
+#ifdef WITH_DEBUGGER\r
+ int addCallResult = 0;\r
+#endif \r
+\r
+ if (ctxt == NULL)\r
+ return; \r
+ if (templ == NULL) {\r
+ xsltTransformError(ctxt, NULL, list,\r
+ "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE) {\r
+ if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,\r
+ list, templ, &addCallResult) == NULL)\r
+ return;\r
+ }\r
+#endif\r
+\r
+ if (list == NULL)\r
+ return;\r
+ CHECK_STOPPED;\r
+\r
+ /*\r
+ * Check for infinite recursion: stop if the maximum of nested templates\r
+ * is excceeded. Adjust xsltMaxDepth if you need more.\r
+ */\r
+ if (((ctxt->templNr >= xsltMaxDepth) ||\r
+ (ctxt->varsNr >= 5 * xsltMaxDepth)))\r
+ {\r
+ xsltTransformError(ctxt, NULL, list,\r
+ "xsltApplyXSLTTemplate: A potential infinite template recursion "\r
+ "was detected.\n"\r
+ "You can adjust xsltMaxDepth (--maxdepth) in order to "\r
+ "raise the maximum number of nested template calls and "\r
+ "variables/params (currently set to %d).\n",\r
+ xsltMaxDepth);\r
+ xsltDebug(ctxt, contextNode, list, NULL);\r
+ return;\r
+ }\r
+ \r
+ oldUserFragmentTop = ctxt->tmpRVT;\r
+ ctxt->tmpRVT = NULL;\r
+ oldLocalFragmentTop = ctxt->localRVT;\r
+ \r
+ /*\r
+ * Initiate a distinct scope of local params/variables.\r
+ */\r
+ oldVarsBase = ctxt->varsBase;\r
+ ctxt->varsBase = ctxt->varsNr;\r
+ \r
+ ctxt->node = contextNode;\r
+ if (ctxt->profile) {\r
+ templ->nbCalls++;\r
+ start = xsltTimestamp();\r
+ profPush(ctxt, 0);\r
+ }\r
+ /*\r
+ * Push the xsl:template declaration onto the stack.\r
+ */\r
+ templPush(ctxt, templ);\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (templ->name != NULL)\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "applying xsl:template '%s'\n", templ->name));\r
+#endif\r
+ /*\r
+ * Process xsl:param instructions and skip those elements for\r
+ * further processing.\r
+ */\r
+ cur = list;\r
+ do {\r
+ if (cur->type == XML_TEXT_NODE) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if ((cur->type != XML_ELEMENT_NODE) ||\r
+ (cur->name[0] != 'p') ||\r
+ (cur->psvi == NULL) ||\r
+ (! xmlStrEqual(cur->name, BAD_CAST "param")) ||\r
+ (! IS_XSLT_ELEM(cur)))\r
+ {\r
+ break;\r
+ }\r
+\r
+ list = cur->next;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ iparam = (xsltStyleItemParamPtr) cur->psvi;\r
+#else\r
+ iparam = (xsltStylePreCompPtr) cur->psvi;\r
+#endif\r
+ \r
+ /*\r
+ * Substitute xsl:param for a given xsl:with-param.\r
+ * Since the XPath expression will reference the params/vars\r
+ * by index, we need to slot the xsl:with-params in the\r
+ * order of encountered xsl:params to keep the sequence of\r
+ * params/variables in the stack exactly as it was at\r
+ * compile time,\r
+ */\r
+ tmpParam = NULL;\r
+ if (withParams) {\r
+ tmpParam = withParams;\r
+ do {\r
+ if ((tmpParam->name == (iparam->name)) &&\r
+ (tmpParam->nameURI == (iparam->ns)))\r
+ {\r
+ /*\r
+ * Push the caller-parameter.\r
+ */ \r
+ xsltLocalVariablePush(ctxt, tmpParam, -1);\r
+ break;\r
+ }\r
+ tmpParam = tmpParam->next;\r
+ } while (tmpParam != NULL);\r
+ }\r
+ /*\r
+ * Push the xsl:param.\r
+ */\r
+ if (tmpParam == NULL) {\r
+ /*\r
+ * Note that we must assume that the added parameter\r
+ * has a @depth of 0.\r
+ */\r
+ xsltParseStylesheetParam(ctxt, cur);\r
+ }\r
+ cur = cur->next;\r
+ } while (cur != NULL); \r
+ /*\r
+ * Process the sequence constructor.\r
+ */\r
+ xsltApplySequenceConstructor(ctxt, contextNode, list, templ);\r
+ \r
+ /*\r
+ * Remove remaining xsl:param and xsl:with-param items from\r
+ * the stack. Don't free xsl:with-param items.\r
+ */\r
+ if (ctxt->varsNr > ctxt->varsBase)\r
+ xsltTemplateParamsCleanup(ctxt); \r
+ ctxt->varsBase = oldVarsBase;\r
+ \r
+ /*\r
+ * Clean up remaining local tree fragments.\r
+ * This also frees fragments which are the result of\r
+ * extension instructions. Should normally not be hit; but\r
+ * just for the case xsltExtensionInstructionResultFinalize()\r
+ * was not called by the extension author.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT) {\r
+ xmlDocPtr cur = ctxt->localRVT, tmp;\r
+\r
+ do {\r
+ tmp = cur;\r
+ cur = (xmlDocPtr) cur->next;\r
+ xsltReleaseRVT(ctxt, tmp);\r
+ } while (cur != oldLocalFragmentTop);\r
+ }\r
+ ctxt->localRVT = oldLocalFragmentTop;\r
+\r
+ /*\r
+ * Release user-created fragments stored in the scope\r
+ * of xsl:template. Note that this mechanism is deprecated:\r
+ * user code should now use xsltRegisterLocalRVT() instead\r
+ * of the obsolete xsltRegisterTmpRVT(). \r
+ */\r
+ if (ctxt->tmpRVT) {\r
+ xmlDocPtr cur = ctxt->tmpRVT, tmp;\r
+\r
+ while (cur != NULL) {\r
+ tmp = cur;\r
+ cur = (xmlDocPtr) cur->next;\r
+ xsltReleaseRVT(ctxt, tmp);\r
+ } \r
+ }\r
+ ctxt->tmpRVT = oldUserFragmentTop; \r
+ \r
+ /*\r
+ * Pop the xsl:template declaration from the stack.\r
+ */\r
+ templPop(ctxt); \r
+ if (ctxt->profile) {\r
+ long spent, child, total, end;\r
+ \r
+ end = xsltTimestamp();\r
+ child = profPop(ctxt);\r
+ total = end - start;\r
+ spent = total - child;\r
+ if (spent <= 0) {\r
+ /*\r
+ * Not possible unless the original calibration failed\r
+ * we can try to correct it on the fly.\r
+ */\r
+ xsltCalibrateAdjust(spent);\r
+ spent = 0;\r
+ }\r
+ \r
+ templ->time += spent;\r
+ if (ctxt->profNr > 0)\r
+ ctxt->profTab[ctxt->profNr - 1] += total;\r
+ }\r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {\r
+ xslDropCall();\r
+ }\r
+#endif\r
+}\r
+\r
+\r
+/**\r
+ * xsltApplyOneTemplate:\r
+ * @ctxt: a XSLT process context\r
+ * @contextNode: the node in the source tree.\r
+ * @list: the nodes of a sequence constructor\r
+ * @templ: not used\r
+ * @params: a set of parameters (xsl:param) or NULL\r
+ *\r
+ * Processes a sequence constructor on the current node in the source tree.\r
+ *\r
+ * @params are the already computed variable stack items; this function\r
+ * pushes them on the variable stack, and pops them before exiting; it's\r
+ * left to the caller to free or reuse @params afterwards. The initial\r
+ * states of the variable stack will always be restored before this\r
+ * function exits.\r
+ * NOTE that this does *not* initiate a new distinct variable scope; i.e.\r
+ * variables already on the stack are visible to the process. The caller's\r
+ * side needs to start a new variable scope if needed (e.g. in exsl:function).\r
+ *\r
+ * @templ is obsolete and not used anymore (e.g. <exslt:function> does not\r
+ * provide a @templ); a non-NULL @templ might raise an error in the future.\r
+ *\r
+ * BIG NOTE: This function is not intended to process the content of an\r
+ * xsl:template; it does not expect xsl:param instructions in @list and\r
+ * will report errors if found.\r
+ *\r
+ * Called by:\r
+ * - xsltEvalVariable() (variables.c)\r
+ * - exsltFuncFunctionFunction() (libexsl/functions.c)\r
+ */\r
+void\r
+xsltApplyOneTemplate(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr contextNode,\r
+ xmlNodePtr list,\r
+ xsltTemplatePtr templ ATTRIBUTE_UNUSED,\r
+ xsltStackElemPtr params)\r
+{\r
+ if ((ctxt == NULL) || (list == NULL))\r
+ return;\r
+ CHECK_STOPPED;\r
+\r
+ if (params) {\r
+ int oldVarsNr = ctxt->varsNr;\r
+\r
+ /*\r
+ * Push the given xsl:param(s) onto the variable stack.\r
+ */\r
+ while (params != NULL) {\r
+ xsltLocalVariablePush(ctxt, params, -1);\r
+ params = params->next;\r
+ }\r
+ xsltApplySequenceConstructor(ctxt, contextNode, list, templ);\r
+ /*\r
+ * Pop the given xsl:param(s) from the stack but don't free them.\r
+ */\r
+ xsltLocalVariablePop(ctxt, oldVarsNr, -2);\r
+ } else\r
+ xsltApplySequenceConstructor(ctxt, contextNode, list, templ); \r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * XSLT-1.1 extensions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltDocumentElem:\r
+ * @ctxt: an XSLT processing context\r
+ * @node: The current node\r
+ * @inst: the instruction in the stylesheet\r
+ * @comp: precomputed information\r
+ *\r
+ * Process an EXSLT/XSLT-1.1 document element\r
+ */\r
+void\r
+xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xsltStylesheetPtr style = NULL;\r
+ int ret;\r
+ xmlChar *filename = NULL, *prop, *elements;\r
+ xmlChar *element, *end;\r
+ xmlDocPtr res = NULL;\r
+ xmlDocPtr oldOutput;\r
+ xmlNodePtr oldInsert, root;\r
+ const char *oldOutputFile;\r
+ xsltOutputType oldType;\r
+ xmlChar *URL = NULL;\r
+ const xmlChar *method;\r
+ const xmlChar *doctypePublic;\r
+ const xmlChar *doctypeSystem;\r
+ const xmlChar *version;\r
+\r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))\r
+ return;\r
+\r
+ if (comp->filename == NULL) {\r
+\r
+ if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {\r
+ /*\r
+ * The element "output" is in the namespace XSLT_SAXON_NAMESPACE\r
+ * (http://icl.com/saxon)\r
+ * The @file is in no namespace.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found saxon:output extension\n");\r
+#endif\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "file",\r
+ XSLT_SAXON_NAMESPACE);\r
+ \r
+ if (URL == NULL)\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "href",\r
+ XSLT_SAXON_NAMESPACE);\r
+ } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Found xalan:write extension\n");\r
+#endif\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "select",\r
+ XSLT_XALAN_NAMESPACE);\r
+ if (URL != NULL) {\r
+ xmlXPathCompExprPtr cmp;\r
+ xmlChar *val;\r
+\r
+ /*\r
+ * Trying to handle bug #59212\r
+ * The value of the "select" attribute is an\r
+ * XPath expression.\r
+ * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) \r
+ */\r
+ cmp = xmlXPathCompile(URL);\r
+ val = xsltEvalXPathString(ctxt, cmp);\r
+ xmlXPathFreeCompExpr(cmp);\r
+ xmlFree(URL);\r
+ URL = val;\r
+ }\r
+ if (URL == NULL)\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "file",\r
+ XSLT_XALAN_NAMESPACE);\r
+ if (URL == NULL)\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "href",\r
+ XSLT_XALAN_NAMESPACE);\r
+ } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {\r
+ URL = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "href",\r
+ NULL);\r
+ }\r
+\r
+ } else {\r
+ URL = xmlStrdup(comp->filename);\r
+ }\r
+\r
+ if (URL == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: href/URI-Reference not found\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * If the computation failed, it's likely that the URL wasn't escaped\r
+ */\r
+ filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);\r
+ if (filename == NULL) {\r
+ xmlChar *escURL;\r
+\r
+ escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");\r
+ if (escURL != NULL) {\r
+ filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);\r
+ xmlFree(escURL);\r
+ }\r
+ }\r
+\r
+ if (filename == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: URL computation failed for %s\n",\r
+ URL);\r
+ xmlFree(URL);\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Security checking: can we write to this resource\r
+ */\r
+ if (ctxt->sec != NULL) {\r
+ ret = xsltCheckWrite(ctxt->sec, ctxt, filename);\r
+ if (ret == 0) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: write rights for %s denied\n",\r
+ filename);\r
+ xmlFree(URL);\r
+ xmlFree(filename);\r
+ return;\r
+ }\r
+ }\r
+\r
+ oldOutputFile = ctxt->outputFile;\r
+ oldOutput = ctxt->output;\r
+ oldInsert = ctxt->insert;\r
+ oldType = ctxt->type;\r
+ ctxt->outputFile = (const char *) filename;\r
+\r
+ style = xsltNewStylesheet();\r
+ if (style == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: out of memory\n");\r
+ goto error;\r
+ }\r
+\r
+ /*\r
+ * Version described in 1.1 draft allows full parameterization\r
+ * of the output.\r
+ */\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "version",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ if (style->version != NULL)\r
+ xmlFree(style->version);\r
+ style->version = prop;\r
+ }\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "encoding",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ if (style->encoding != NULL)\r
+ xmlFree(style->encoding);\r
+ style->encoding = prop;\r
+ }\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "method",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+\r
+ if (style->method != NULL)\r
+ xmlFree(style->method);\r
+ style->method = NULL;\r
+ if (style->methodURI != NULL)\r
+ xmlFree(style->methodURI);\r
+ style->methodURI = NULL;\r
+\r
+ URI = xsltGetQNameURI(inst, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else if (URI == NULL) {\r
+ if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||\r
+ (xmlStrEqual(prop, (const xmlChar *) "html")) ||\r
+ (xmlStrEqual(prop, (const xmlChar *) "text"))) {\r
+ style->method = prop;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "invalid value for method: %s\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ } else {\r
+ style->method = prop;\r
+ style->methodURI = xmlStrdup(URI);\r
+ }\r
+ }\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "doctype-system", NULL);\r
+ if (prop != NULL) {\r
+ if (style->doctypeSystem != NULL)\r
+ xmlFree(style->doctypeSystem);\r
+ style->doctypeSystem = prop;\r
+ }\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "doctype-public", NULL);\r
+ if (prop != NULL) {\r
+ if (style->doctypePublic != NULL)\r
+ xmlFree(style->doctypePublic);\r
+ style->doctypePublic = prop;\r
+ }\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "standalone",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->standalone = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->standalone = 0;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "invalid value for standalone: %s\n",\r
+ prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "indent",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->indent = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->indent = 0;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "invalid value for indent: %s\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "omit-xml-declaration",\r
+ NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->omitXmlDeclaration = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->omitXmlDeclaration = 0;\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "invalid value for omit-xml-declaration: %s\n",\r
+ prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ elements = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)\r
+ "cdata-section-elements",\r
+ NULL);\r
+ if (elements != NULL) {\r
+ if (style->stripSpaces == NULL)\r
+ style->stripSpaces = xmlHashCreate(10);\r
+ if (style->stripSpaces == NULL)\r
+ return;\r
+\r
+ element = elements;\r
+ while (*element != 0) {\r
+ while (IS_BLANK_CH(*element))\r
+ element++;\r
+ if (*element == 0)\r
+ break;\r
+ end = element;\r
+ while ((*end != 0) && (!IS_BLANK_CH(*end)))\r
+ end++;\r
+ element = xmlStrndup(element, end - element);\r
+ if (element) {\r
+ const xmlChar *URI;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add cdata section output element %s\n",\r
+ element);\r
+#endif\r
+ URI = xsltGetQNameURI(inst, &element);\r
+\r
+ xmlHashAddEntry2(style->stripSpaces, element, URI,\r
+ (xmlChar *) "cdata");\r
+ xmlFree(element);\r
+ }\r
+ element = end;\r
+ }\r
+ xmlFree(elements);\r
+ }\r
+\r
+ /*\r
+ * Create a new document tree and process the element template\r
+ */\r
+ XSLT_GET_IMPORT_PTR(method, style, method)\r
+ XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)\r
+ XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)\r
+ XSLT_GET_IMPORT_PTR(version, style, version)\r
+\r
+ if ((method != NULL) &&\r
+ (!xmlStrEqual(method, (const xmlChar *) "xml"))) {\r
+ if (xmlStrEqual(method, (const xmlChar *) "html")) {\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL)))\r
+ res = htmlNewDoc(doctypeSystem, doctypePublic);\r
+ else {\r
+ if (version != NULL) {\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+ xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);\r
+#endif\r
+ }\r
+ res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);\r
+ }\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+ } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: unsupported method xhtml\n",\r
+ style->method);\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+ } else if (xmlStrEqual(method, (const xmlChar *) "text")) {\r
+ ctxt->type = XSLT_OUTPUT_TEXT;\r
+ res = xmlNewDoc(style->version);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: unsupported method %s\n",\r
+ style->method);\r
+ goto error;\r
+ }\r
+ } else {\r
+ ctxt->type = XSLT_OUTPUT_XML;\r
+ res = xmlNewDoc(style->version);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ }\r
+ res->charset = XML_CHAR_ENCODING_UTF8;\r
+ if (style->encoding != NULL)\r
+ res->encoding = xmlStrdup(style->encoding);\r
+ ctxt->output = res;\r
+ ctxt->insert = (xmlNodePtr) res;\r
+ xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);\r
+\r
+ /*\r
+ * Do some post processing work depending on the generated output\r
+ */\r
+ root = xmlDocGetRootElement(res);\r
+ if (root != NULL) {\r
+ const xmlChar *doctype = NULL;\r
+\r
+ if ((root->ns != NULL) && (root->ns->prefix != NULL))\r
+ doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);\r
+ if (doctype == NULL)\r
+ doctype = root->name;\r
+\r
+ /*\r
+ * Apply the default selection of the method\r
+ */\r
+ if ((method == NULL) &&\r
+ (root->ns == NULL) &&\r
+ (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {\r
+ xmlNodePtr tmp;\r
+\r
+ tmp = res->children;\r
+ while ((tmp != NULL) && (tmp != root)) {\r
+ if (tmp->type == XML_ELEMENT_NODE)\r
+ break;\r
+ if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))\r
+ break;\r
+ tmp = tmp->next;\r
+ }\r
+ if (tmp == root) {\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ res->type = XML_HTML_DOCUMENT_NODE;\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {\r
+ res->intSubset = xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+ } else if (version != NULL) {\r
+ xsltGetHTMLIDs(version, &doctypePublic,\r
+ &doctypeSystem);\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL)))\r
+ res->intSubset =\r
+ xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+#endif\r
+ }\r
+ }\r
+\r
+ }\r
+ if (ctxt->type == XSLT_OUTPUT_XML) {\r
+ XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)\r
+ XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL)))\r
+ res->intSubset = xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Save the result\r
+ */\r
+ ret = xsltSaveResultToFilename((const char *) filename,\r
+ res, style, 0);\r
+ if (ret < 0) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsltDocumentElem: unable to save to %s\n",\r
+ filename);\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+#ifdef WITH_XSLT_DEBUG_EXTRA\r
+ } else {\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Wrote %d bytes to %s\n", ret, filename);\r
+#endif\r
+ }\r
+\r
+ error:\r
+ ctxt->output = oldOutput;\r
+ ctxt->insert = oldInsert;\r
+ ctxt->type = oldType;\r
+ ctxt->outputFile = oldOutputFile;\r
+ if (URL != NULL)\r
+ xmlFree(URL);\r
+ if (filename != NULL)\r
+ xmlFree(filename);\r
+ if (style != NULL)\r
+ xsltFreeStylesheet(style);\r
+ if (res != NULL)\r
+ xmlFreeDoc(res);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Most of the XSLT-1.0 transformations *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltSort:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt sort node\r
+ * @comp: precomputed information\r
+ *\r
+ * function attached to xsl:sort nodes, but this should not be\r
+ * called directly\r
+ */\r
+void\r
+xsltSort(xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,\r
+ xsltStylePreCompPtr comp) {\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:sort : compilation failed\n");\r
+ return;\r
+ }\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:sort : improper use this should not be reached\n");\r
+}\r
+\r
+/**\r
+ * xsltCopy:\r
+ * @ctxt: an XSLT process context\r
+ * @node: the node in the source tree\r
+ * @inst: the element node of the XSLT-copy instruction\r
+ * @comp: computed information of the XSLT-copy instruction\r
+ *\r
+ * Execute the XSLT-copy instruction on the source node.\r
+ */\r
+void\r
+xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xmlNodePtr copy, oldInsert;\r
+ \r
+ oldInsert = ctxt->insert;\r
+ if (ctxt->insert != NULL) {\r
+ switch (node->type) {\r
+ case XML_TEXT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ /*\r
+ * This text comes from the stylesheet\r
+ * For stylesheets, the set of whitespace-preserving\r
+ * element names consists of just xsl:text.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (node->type == XML_CDATA_SECTION_NODE) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: CDATA text %s\n", node->content));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: text %s\n", node->content));\r
+ }\r
+#endif\r
+ xsltCopyText(ctxt, ctxt->insert, node, 0);\r
+ break;\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ break;\r
+ case XML_ELEMENT_NODE:\r
+ /*\r
+ * REVISIT NOTE: The "fake" is a doc-node, not an element node.\r
+ * REMOVED:\r
+ * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))\r
+ * return;\r
+ */ \r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: node %s\n", node->name));\r
+#endif\r
+ copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);\r
+ ctxt->insert = copy;\r
+ if (comp->use != NULL) {\r
+ xsltApplyAttributeSet(ctxt, node, inst, comp->use);\r
+ }\r
+ break;\r
+ case XML_ATTRIBUTE_NODE: {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: attribute %s\n", node->name));\r
+#endif\r
+ /*\r
+ * REVISIT: We could also raise an error if the parent is not\r
+ * an element node.\r
+ * OPTIMIZE TODO: Can we set the value/children of the\r
+ * attribute without an intermediate copy of the string value?\r
+ */\r
+ xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); \r
+ break;\r
+ }\r
+ case XML_PI_NODE:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: PI %s\n", node->name));\r
+#endif\r
+ copy = xmlNewDocPI(ctxt->insert->doc, node->name,\r
+ node->content);\r
+ xmlAddChild(ctxt->insert, copy);\r
+ break;\r
+ case XML_COMMENT_NODE:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: comment\n"));\r
+#endif\r
+ copy = xmlNewComment(node->content);\r
+ xmlAddChild(ctxt->insert, copy);\r
+ break;\r
+ case XML_NAMESPACE_DECL:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopy: namespace declaration\n"));\r
+#endif \r
+ xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); \r
+ break;\r
+ default:\r
+ break;\r
+\r
+ }\r
+ }\r
+\r
+ switch (node->type) {\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_ELEMENT_NODE:\r
+ xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,\r
+ NULL);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ ctxt->insert = oldInsert;\r
+}\r
+\r
+/**\r
+ * xsltText:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt text node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt text node on the source node\r
+ */\r
+void\r
+xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,\r
+ xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {\r
+ if ((inst->children != NULL) && (comp != NULL)) {\r
+ xmlNodePtr text = inst->children;\r
+ xmlNodePtr copy;\r
+\r
+ while (text != NULL) {\r
+ if ((text->type != XML_TEXT_NODE) &&\r
+ (text->type != XML_CDATA_SECTION_NODE)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:text content problem\n");\r
+ break;\r
+ }\r
+ copy = xmlNewDocText(ctxt->output, text->content);\r
+ if (text->type != XML_CDATA_SECTION_NODE) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Disable escaping: %s\n", text->content);\r
+#endif\r
+ copy->name = xmlStringTextNoenc;\r
+ }\r
+ xmlAddChild(ctxt->insert, copy);\r
+ text = text->next;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltElement:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt element node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt element node on the source node\r
+ */\r
+void\r
+xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xmlChar *prop = NULL;\r
+ const xmlChar *name, *prefix = NULL, *nsName = NULL; \r
+ xmlNodePtr copy;\r
+ xmlNodePtr oldInsert;\r
+\r
+ if (ctxt->insert == NULL)\r
+ return;\r
+\r
+ /* \r
+ * A comp->has_name == 0 indicates that we need to skip this instruction,\r
+ * since it was evaluated to be invalid already during compilation.\r
+ */\r
+ if (!comp->has_name)\r
+ return;\r
+\r
+ /*\r
+ * stack and saves\r
+ */\r
+ oldInsert = ctxt->insert;\r
+\r
+ if (comp->name == NULL) {\r
+ /* TODO: fix attr acquisition wrt to the XSLT namespace */\r
+ prop = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "name", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:element: The attribute 'name' is missing.\n");\r
+ goto error;\r
+ }\r
+ if (xmlValidateQName(prop, 0)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:element: The effective name '%s' is not a "\r
+ "valid QName.\n", prop);\r
+ /* we fall through to catch any further errors, if possible */\r
+ }\r
+ name = xsltSplitQName(ctxt->dict, prop, &prefix);\r
+ xmlFree(prop);\r
+ if ((prefix != NULL) &&\r
+ (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))\r
+ {\r
+ /*\r
+ * TODO: Should we really disallow an "xml" prefix?\r
+ */\r
+ goto error;\r
+ }\r
+ } else {\r
+ /*\r
+ * The "name" value was static.\r
+ */\r
+#ifdef XSLT_REFACTORED\r
+ prefix = comp->nsPrefix;\r
+ name = comp->name;\r
+#else \r
+ name = xsltSplitQName(ctxt->dict, comp->name, &prefix);\r
+#endif\r
+ }\r
+ \r
+ /*\r
+ * Create the new element\r
+ */\r
+ if (ctxt->output->dict == ctxt->dict) {\r
+ copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);\r
+ } else {\r
+ copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);\r
+ }\r
+ if (copy == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:element : creation of %s failed\n", name);\r
+ return;\r
+ }\r
+ xmlAddChild(ctxt->insert, copy); \r
+\r
+ /*\r
+ * Namespace\r
+ * ---------\r
+ */\r
+ if (comp->has_ns) { \r
+ if (comp->ns != NULL) {\r
+ /*\r
+ * No AVT; just plain text for the namespace name.\r
+ */\r
+ if (comp->ns[0] != 0)\r
+ nsName = comp->ns;\r
+ } else {\r
+ xmlChar *tmpNsName;\r
+ /*\r
+ * Eval the AVT.\r
+ */\r
+ /* TODO: check attr acquisition wrt to the XSLT namespace */\r
+ tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *) "namespace", XSLT_NAMESPACE); \r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If the string is empty, then the expanded-name of the\r
+ * attribute has a null namespace URI."\r
+ */\r
+ if ((tmpNsName != NULL) && (tmpNsName[0] != 0))\r
+ nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);\r
+ xmlFree(tmpNsName); \r
+ }; \r
+ } else {\r
+ xmlNsPtr ns;\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "If the namespace attribute is not present, then the QName is\r
+ * expanded into an expanded-name using the namespace declarations\r
+ * in effect for the xsl:element element, including any default\r
+ * namespace declaration.\r
+ */ \r
+ ns = xmlSearchNs(inst->doc, inst, prefix);\r
+ if (ns == NULL) {\r
+ /*\r
+ * TODO: Check this in the compilation layer in case it's a\r
+ * static value.\r
+ */\r
+ if (prefix != NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:element: The QName '%s:%s' has no "\r
+ "namespace binding in scope in the stylesheet; "\r
+ "this is an error, since the namespace was not "\r
+ "specified by the instruction itself.\n", prefix, name);\r
+ }\r
+ } else\r
+ nsName = ns->href; \r
+ }\r
+ /*\r
+ * Find/create a matching ns-decl in the result tree.\r
+ */\r
+ if (nsName != NULL) {\r
+ copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);\r
+ } else if ((copy->parent != NULL) &&\r
+ (copy->parent->type == XML_ELEMENT_NODE) &&\r
+ (copy->parent->ns != NULL))\r
+ {\r
+ /*\r
+ * "Undeclare" the default namespace.\r
+ */\r
+ xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);\r
+ }\r
+\r
+ ctxt->insert = copy;\r
+\r
+ if (comp->has_use) {\r
+ if (comp->use != NULL) {\r
+ xsltApplyAttributeSet(ctxt, node, inst, comp->use);\r
+ } else {\r
+ xmlChar *attrSets = NULL;\r
+ /*\r
+ * BUG TODO: use-attribute-sets is not a value template.\r
+ * use-attribute-sets = qnames\r
+ */\r
+ attrSets = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)"use-attribute-sets", NULL);\r
+ if (attrSets != NULL) {\r
+ xsltApplyAttributeSet(ctxt, node, inst, attrSets);\r
+ xmlFree(attrSets);\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * Instantiate the sequence constructor.\r
+ */\r
+ if (inst->children != NULL)\r
+ xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,\r
+ NULL);\r
+\r
+error:\r
+ ctxt->insert = oldInsert;\r
+ return; \r
+}\r
+\r
+\r
+/**\r
+ * xsltComment:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt comment node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt comment node on the source node\r
+ */\r
+void\r
+xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {\r
+ xmlChar *value = NULL;\r
+ xmlNodePtr commentNode;\r
+ int len;\r
+ \r
+ value = xsltEvalTemplateString(ctxt, node, inst);\r
+ /* TODO: use or generate the compiled form */\r
+ len = xmlStrlen(value);\r
+ if (len > 0) {\r
+ if ((value[len-1] == '-') || \r
+ (xmlStrstr(value, BAD_CAST "--"))) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:comment : '--' or ending '-' not allowed in comment\n");\r
+ /* fall through to try to catch further errors */\r
+ }\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (value == NULL) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltComment: empty\n"));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltComment: content %s\n", value));\r
+ }\r
+#endif\r
+\r
+ commentNode = xmlNewComment(value);\r
+ xmlAddChild(ctxt->insert, commentNode);\r
+\r
+ if (value != NULL)\r
+ xmlFree(value);\r
+}\r
+\r
+/**\r
+ * xsltProcessingInstruction:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt processing-instruction node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt processing-instruction node on the source node\r
+ */\r
+void\r
+xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ const xmlChar *name;\r
+ xmlChar *value = NULL;\r
+ xmlNodePtr pi;\r
+\r
+\r
+ if (ctxt->insert == NULL)\r
+ return;\r
+ if (comp->has_name == 0)\r
+ return;\r
+ if (comp->name == NULL) {\r
+ name = xsltEvalAttrValueTemplate(ctxt, inst,\r
+ (const xmlChar *)"name", NULL);\r
+ if (name == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:processing-instruction : name is missing\n");\r
+ goto error;\r
+ }\r
+ } else {\r
+ name = comp->name;\r
+ }\r
+ /* TODO: check that it's both an an NCName and a PITarget. */\r
+\r
+\r
+ value = xsltEvalTemplateString(ctxt, node, inst);\r
+ if (xmlStrstr(value, BAD_CAST "?>") != NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:processing-instruction: '?>' not allowed within PI content\n");\r
+ goto error;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (value == NULL) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessingInstruction: %s empty\n", name));\r
+ } else {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltProcessingInstruction: %s content %s\n", name, value));\r
+ }\r
+#endif\r
+\r
+ pi = xmlNewDocPI(ctxt->insert->doc, name, value);\r
+ xmlAddChild(ctxt->insert, pi);\r
+\r
+error:\r
+ if ((name != NULL) && (name != comp->name))\r
+ xmlFree((xmlChar *) name);\r
+ if (value != NULL)\r
+ xmlFree(value);\r
+}\r
+\r
+/**\r
+ * xsltCopyOf:\r
+ * @ctxt: an XSLT transformation context\r
+ * @node: the current node in the source tree\r
+ * @inst: the element node of the XSLT copy-of instruction \r
+ * @comp: precomputed information of the XSLT copy-of instruction\r
+ *\r
+ * Process the XSLT copy-of instruction.\r
+ */\r
+void\r
+xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xmlXPathObjectPtr res = NULL;\r
+ xmlNodeSetPtr list = NULL;\r
+ int i;\r
+ xmlDocPtr oldXPContextDoc;\r
+ xmlNsPtr *oldXPNamespaces;\r
+ xmlNodePtr oldXPContextNode;\r
+ int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;\r
+ xmlXPathContextPtr xpctxt;\r
+\r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL))\r
+ return;\r
+ if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:copy-of : compilation failed\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "The xsl:copy-of element can be used to insert a result tree\r
+ * fragment into the result tree, without first converting it to\r
+ * a string as xsl:value-of does (see [7.6.1 Generating Text with\r
+ * xsl:value-of]). The required select attribute contains an\r
+ * expression. When the result of evaluating the expression is a\r
+ * result tree fragment, the complete fragment is copied into the\r
+ * result tree. When the result is a node-set, all the nodes in the\r
+ * set are copied in document order into the result tree; copying\r
+ * an element node copies the attribute nodes, namespace nodes and\r
+ * children of the element node as well as the element node itself;\r
+ * a root node is copied by copying its children. When the result\r
+ * is neither a node-set nor a result tree fragment, the result is\r
+ * converted to a string and then inserted into the result tree,\r
+ * as with xsl:value-of.\r
+ */\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyOf: select %s\n", comp->select));\r
+#endif\r
+\r
+ /*\r
+ * Evaluate the "select" expression.\r
+ */\r
+ xpctxt = ctxt->xpathCtxt;\r
+ oldXPContextDoc = xpctxt->doc;\r
+ oldXPContextNode = xpctxt->node;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+ \r
+ xpctxt->node = node;\r
+ if (comp != NULL) {\r
+\r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+\r
+ res = xmlXPathCompiledEval(comp->comp, xpctxt);\r
+\r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition; \r
+ xpctxt->nsNr = oldXPNsNr;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+\r
+ if (res != NULL) {\r
+ if (res->type == XPATH_NODESET) {\r
+ /*\r
+ * Node-set\r
+ * --------\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyOf: result is a node set\n"));\r
+#endif\r
+ list = res->nodesetval;\r
+ if (list != NULL) {\r
+ xmlNodePtr cur;\r
+ /*\r
+ * The list is already sorted in document order by XPath.\r
+ * Append everything in this order under ctxt->insert.\r
+ */\r
+ for (i = 0;i < list->nodeNr;i++) {\r
+ cur = list->nodeTab[i];\r
+ if (cur == NULL)\r
+ continue;\r
+ if ((cur->type == XML_DOCUMENT_NODE) ||\r
+ (cur->type == XML_HTML_DOCUMENT_NODE))\r
+ {\r
+ xsltCopyTreeList(ctxt, inst,\r
+ cur->children, ctxt->insert, 0, 0);\r
+ } else if (cur->type == XML_ATTRIBUTE_NODE) {\r
+ xsltShallowCopyAttr(ctxt, inst,\r
+ ctxt->insert, (xmlAttrPtr) cur);\r
+ } else {\r
+ xsltCopyTreeInternal(ctxt, inst,\r
+ cur, ctxt->insert, 0, 0);\r
+ }\r
+ }\r
+ }\r
+ } else if (res->type == XPATH_XSLT_TREE) {\r
+ /*\r
+ * Result tree fragment\r
+ * --------------------\r
+ * E.g. via <xsl:variable ...><foo/></xsl:variable>\r
+ * Note that the root node of such trees is an xmlDocPtr in Libxslt.\r
+ */\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyOf: result is a result tree fragment\n"));\r
+#endif \r
+ list = res->nodesetval;\r
+ if ((list != NULL) && (list->nodeTab != NULL) &&\r
+ (list->nodeTab[0] != NULL) &&\r
+ (IS_XSLT_REAL_NODE(list->nodeTab[0])))\r
+ {\r
+ xsltCopyTreeList(ctxt, inst,\r
+ list->nodeTab[0]->children, ctxt->insert, 0, 0);\r
+ }\r
+ } else {\r
+ xmlChar *value = NULL;\r
+ /*\r
+ * Convert to a string.\r
+ */\r
+ value = xmlXPathCastToString(res);\r
+ if (value == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltCopyOf(): "\r
+ "failed to cast an XPath object to string.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ } else {\r
+ if (value[0] != 0) {\r
+ /*\r
+ * Append content as text node.\r
+ */\r
+ xsltCopyTextString(ctxt, ctxt->insert, value, 0);\r
+ }\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltCopyOf: result %s\n", res->stringval));\r
+#endif\r
+ }\r
+ }\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+\r
+ if (res != NULL)\r
+ xmlXPathFreeObject(res);\r
+}\r
+\r
+/**\r
+ * xsltValueOf:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt value-of node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt value-of node on the source node\r
+ */\r
+void\r
+xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xmlXPathObjectPtr res = NULL;\r
+ xmlNodePtr copy = NULL;\r
+ xmlChar *value = NULL;\r
+ xmlDocPtr oldXPContextDoc;\r
+ xmlNsPtr *oldXPNamespaces;\r
+ xmlNodePtr oldXPContextNode;\r
+ int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;\r
+ xmlXPathContextPtr xpctxt;\r
+\r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL))\r
+ return;\r
+\r
+ if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltValueOf(): "\r
+ "The XSLT 'value-of' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltValueOf: select %s\n", comp->select));\r
+#endif\r
+\r
+ xpctxt = ctxt->xpathCtxt;\r
+ oldXPContextDoc = xpctxt->doc;\r
+ oldXPContextNode = xpctxt->node;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+ \r
+ xpctxt->node = node;\r
+ if (comp != NULL) {\r
+\r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+\r
+ res = xmlXPathCompiledEval(comp->comp, xpctxt);\r
+\r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition; \r
+ xpctxt->nsNr = oldXPNsNr;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+\r
+ /*\r
+ * Cast the XPath object to string.\r
+ */\r
+ if (res != NULL) {\r
+ value = xmlXPathCastToString(res);\r
+ if (value == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltValueOf(): "\r
+ "failed to cast an XPath object to string.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ if (value[0] != 0) {\r
+ copy = xsltCopyTextString(ctxt,\r
+ ctxt->insert, value, comp->noescape);\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst, \r
+ "XPath evaluation returned no result.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error; \r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (value) { \r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltValueOf: result '%s'\n", value));\r
+ }\r
+#endif\r
+\r
+error:\r
+ if (value != NULL)\r
+ xmlFree(value);\r
+ if (res != NULL)\r
+ xmlXPathFreeObject(res);\r
+}\r
+\r
+/**\r
+ * xsltNumber:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the node in the source tree.\r
+ * @inst: the xslt number node\r
+ * @comp: precomputed information\r
+ *\r
+ * Process the xslt number node on the source node\r
+ */\r
+void\r
+xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:number : compilation failed\n");\r
+ return;\r
+ }\r
+\r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))\r
+ return;\r
+\r
+ comp->numdata.doc = inst->doc;\r
+ comp->numdata.node = inst;\r
+ \r
+ xsltNumberFormat(ctxt, &comp->numdata, node);\r
+}\r
+\r
+/**\r
+ * xsltApplyImports:\r
+ * @ctxt: an XSLT transformation context\r
+ * @contextNode: the current node in the source tree.\r
+ * @inst: the element node of the XSLT 'apply-imports' instruction\r
+ * @comp: the compiled instruction\r
+ *\r
+ * Process the XSLT apply-imports element.\r
+ */\r
+void\r
+xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,\r
+ xmlNodePtr inst,\r
+ xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)\r
+{\r
+ xsltTemplatePtr templ;\r
+\r
+ if ((ctxt == NULL) || (inst == NULL))\r
+ return;\r
+\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltApplyImports(): "\r
+ "The XSLT 'apply-imports' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+ /*\r
+ * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the\r
+ * same; the former is the "Current Template Rule" as defined by the\r
+ * XSLT spec, the latter is simply the template struct being\r
+ * currently processed.\r
+ */\r
+ if (ctxt->currentTemplateRule == NULL) {\r
+ /*\r
+ * SPEC XSLT 2.0:\r
+ * "[ERR XTDE0560] It is a non-recoverable dynamic error if\r
+ * xsl:apply-imports or xsl:next-match is evaluated when the\r
+ * current template rule is null."\r
+ */\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "It is an error to call 'apply-imports' "\r
+ "when there's no current template rule.\n");\r
+ return;\r
+ }\r
+ /*\r
+ * TODO: Check if this is correct.\r
+ */\r
+ templ = xsltGetTemplate(ctxt, contextNode,\r
+ ctxt->currentTemplateRule->style);\r
+\r
+ if (templ != NULL) {\r
+ xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;\r
+ /*\r
+ * Set the current template rule.\r
+ */\r
+ ctxt->currentTemplateRule = templ;\r
+ /*\r
+ * URGENT TODO: Need xsl:with-param be handled somehow here?\r
+ */\r
+ xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,\r
+ templ, NULL);\r
+\r
+ ctxt->currentTemplateRule = oldCurTemplRule;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltCallTemplate:\r
+ * @ctxt: a XSLT transformation context\r
+ * @node: the "current node" in the source tree\r
+ * @inst: the XSLT 'call-template' instruction\r
+ * @comp: the compiled information of the instruction\r
+ *\r
+ * Processes the XSLT call-template instruction on the source node.\r
+ */\r
+void\r
+xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemCallTemplatePtr comp =\r
+ (xsltStyleItemCallTemplatePtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ xsltStackElemPtr withParams = NULL;\r
+\r
+ if (ctxt->insert == NULL)\r
+ return;\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "The XSLT 'call-template' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * The template must have been precomputed\r
+ */\r
+ if (comp->templ == NULL) {\r
+ comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);\r
+ if (comp->templ == NULL) {\r
+ if (comp->ns != NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "The called template '{%s}%s' was not found.\n",\r
+ comp->ns, comp->name);\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "The called template '%s' was not found.\n",\r
+ comp->name);\r
+ }\r
+ return;\r
+ }\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if ((comp != NULL) && (comp->name != NULL))\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "call-template: name %s\n", comp->name));\r
+#endif\r
+\r
+ if (inst->children) {\r
+ xmlNodePtr cur;\r
+ xsltStackElemPtr param;\r
+\r
+ cur = inst->children;\r
+ while (cur != NULL) {\r
+#ifdef WITH_DEBUGGER\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(cur, node, comp->templ, ctxt);\r
+#endif\r
+ if (ctxt->state == XSLT_STATE_STOPPED) break;\r
+ /*\r
+ * TODO: The "with-param"s could be part of the "call-template"\r
+ * structure. Avoid to "search" for params dynamically\r
+ * in the XML tree every time.\r
+ */\r
+ if (IS_XSLT_ELEM(cur)) {\r
+ if (IS_XSLT_NAME(cur, "with-param")) {\r
+ param = xsltParseStylesheetCallerParam(ctxt, cur);\r
+ if (param != NULL) {\r
+ param->next = withParams;\r
+ withParams = param;\r
+ }\r
+ } else {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:call-template: misplaced xsl:%s\n", cur->name);\r
+ }\r
+ } else {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:call-template: misplaced %s element\n", cur->name);\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ }\r
+ /*\r
+ * Create a new frame using the params first \r
+ */\r
+ xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,\r
+ withParams);\r
+ if (withParams != NULL)\r
+ xsltFreeStackElemList(withParams);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if ((comp != NULL) && (comp->name != NULL))\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "call-template returned: name %s\n", comp->name));\r
+#endif\r
+}\r
+\r
+/**\r
+ * xsltApplyTemplates:\r
+ * @ctxt: a XSLT transformation context\r
+ * @node: the 'current node' in the source tree\r
+ * @inst: the element node of an XSLT 'apply-templates' instruction\r
+ * @comp: the compiled instruction\r
+ *\r
+ * Processes the XSLT 'apply-templates' instruction on the current node.\r
+ */\r
+void\r
+xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemApplyTemplatesPtr comp =\r
+ (xsltStyleItemApplyTemplatesPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ int i;\r
+ xmlNodePtr cur, delNode = NULL, oldContextNode; \r
+ xmlNodeSetPtr list = NULL, oldList;\r
+ xsltStackElemPtr withParams = NULL;\r
+ int oldXPProximityPosition, oldXPContextSize;\r
+ const xmlChar *oldMode, *oldModeURI;\r
+ xmlDocPtr oldDoc;\r
+ xsltDocumentPtr oldDocInfo;\r
+ xmlXPathContextPtr xpctxt;\r
+\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:apply-templates : compilation failed\n");\r
+ return;\r
+ }\r
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))\r
+ return;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if ((node != NULL) && (node->name != NULL))\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: node: '%s'\n", node->name));\r
+#endif\r
+\r
+ xpctxt = ctxt->xpathCtxt; \r
+ /*\r
+ * Save context states.\r
+ */\r
+ oldContextNode = ctxt->node;\r
+ oldMode = ctxt->mode;\r
+ oldModeURI = ctxt->modeURI; \r
+ oldDocInfo = ctxt->document;\r
+ oldDoc = ctxt->tmpDoc;\r
+ oldList = ctxt->nodeList; \r
+\r
+ /*\r
+ * The xpath context size and proximity position, as\r
+ * well as the xpath and context documents, may be changed\r
+ * so we save their initial state and will restore on exit\r
+ */ \r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+\r
+ /*\r
+ * Set up contexts.\r
+ */\r
+ ctxt->mode = comp->mode;\r
+ ctxt->modeURI = comp->modeURI;\r
+\r
+ if (comp->select != NULL) { \r
+ xmlXPathObjectPtr res = NULL;\r
+\r
+ if (comp->comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:apply-templates : compilation failed\n");\r
+ goto error;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: select %s\n", comp->select));\r
+#endif\r
+\r
+ /*\r
+ * Set up XPath.\r
+ */\r
+ xpctxt->node = node; /* Set the "context node" */\r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ res = xmlXPathCompiledEval(comp->comp, xpctxt);\r
+\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ if (res != NULL) {\r
+ if (res->type == XPATH_NODESET) {\r
+ list = res->nodesetval; /* consume the node set */\r
+ res->nodesetval = NULL; \r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "The 'select' expression did not evaluate to a "\r
+ "node set.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ xmlXPathFreeObject(res);\r
+ goto error;\r
+ }\r
+ xmlXPathFreeObject(res);\r
+ /*\r
+ * Note: An xsl:apply-templates with a 'select' attribute,\r
+ * can change the current source doc.\r
+ */ \r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Failed to evaluate the 'select' expression.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ } \r
+ if (list == NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: select didn't evaluate to a node list\n"));\r
+#endif\r
+ goto exit;\r
+ }\r
+ /*\r
+ * \r
+ * NOTE: Previously a document info (xsltDocument) was\r
+ * created and attached to the Result Tree Fragment.\r
+ * But such a document info is created on demand in\r
+ * xsltKeyFunction() (functions.c), so we need to create\r
+ * it here beforehand.\r
+ * In order to take care of potential keys we need to\r
+ * do some extra work for the case when a Result Tree Fragment\r
+ * is converted into a nodeset (e.g. exslt:node-set()) :\r
+ * We attach a "pseudo-doc" (xsltDocument) to _private. \r
+ * This xsltDocument, together with the keyset, will be freed\r
+ * when the Result Tree Fragment is freed.\r
+ * \r
+ */\r
+#if 0\r
+ if ((ctxt->nbKeys > 0) &&\r
+ (list->nodeNr != 0) && \r
+ (list->nodeTab[0]->doc != NULL) &&\r
+ XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))\r
+ {\r
+ /*\r
+ * NOTE that it's also OK if @effectiveDocInfo will be\r
+ * set to NULL.\r
+ */\r
+ isRTF = 1;\r
+ effectiveDocInfo = list->nodeTab[0]->doc->_private;\r
+ }\r
+#endif\r
+ } else {\r
+ /*\r
+ * Build an XPath node set with the children\r
+ */\r
+ list = xmlXPathNodeSetCreate(NULL);\r
+ if (list == NULL)\r
+ goto error;\r
+ cur = node->children;\r
+ while (cur != NULL) {\r
+ switch (cur->type) {\r
+ case XML_TEXT_NODE:\r
+ if ((IS_BLANK_NODE(cur)) &&\r
+ (cur->parent != NULL) &&\r
+ (cur->parent->type == XML_ELEMENT_NODE) &&\r
+ (ctxt->style->stripSpaces != NULL)) {\r
+ const xmlChar *val;\r
+\r
+ if (cur->parent->ns != NULL) {\r
+ val = (const xmlChar *)\r
+ xmlHashLookup2(ctxt->style->stripSpaces,\r
+ cur->parent->name,\r
+ cur->parent->ns->href);\r
+ if (val == NULL) {\r
+ val = (const xmlChar *)\r
+ xmlHashLookup2(ctxt->style->stripSpaces,\r
+ BAD_CAST "*",\r
+ cur->parent->ns->href);\r
+ }\r
+ } else {\r
+ val = (const xmlChar *)\r
+ xmlHashLookup2(ctxt->style->stripSpaces,\r
+ cur->parent->name, NULL);\r
+ }\r
+ if ((val != NULL) &&\r
+ (xmlStrEqual(val, (xmlChar *) "strip"))) {\r
+ delNode = cur;\r
+ break;\r
+ }\r
+ }\r
+ /* no break on purpose */\r
+ case XML_ELEMENT_NODE:\r
+ case XML_DOCUMENT_NODE:\r
+ case XML_HTML_DOCUMENT_NODE:\r
+ case XML_CDATA_SECTION_NODE:\r
+ case XML_PI_NODE:\r
+ case XML_COMMENT_NODE:\r
+ xmlXPathNodeSetAddUnique(list, cur);\r
+ break;\r
+ case XML_DTD_NODE:\r
+ /* Unlink the DTD, it's still reachable\r
+ * using doc->intSubset */\r
+ if (cur->next != NULL)\r
+ cur->next->prev = cur->prev;\r
+ if (cur->prev != NULL)\r
+ cur->prev->next = cur->next;\r
+ break;\r
+ default:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: skipping cur type %d\n",\r
+ cur->type));\r
+#endif\r
+ delNode = cur;\r
+ }\r
+ cur = cur->next;\r
+ if (delNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: removing ignorable blank cur\n"));\r
+#endif\r
+ xmlUnlinkNode(delNode);\r
+ xmlFreeNode(delNode);\r
+ delNode = NULL;\r
+ }\r
+ }\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ if (list != NULL)\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));\r
+#endif\r
+\r
+ if ((list == NULL) || (list->nodeNr == 0))\r
+ goto exit;\r
+\r
+ /*\r
+ * Set the context's node set and size; this is also needed for\r
+ * for xsltDoSortFunction().\r
+ */\r
+ ctxt->nodeList = list;\r
+ /* \r
+ * Process xsl:with-param and xsl:sort instructions.\r
+ * (The code became so verbose just to avoid the\r
+ * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)\r
+ * BUG TODO: We are not using namespaced potentially defined on the\r
+ * xsl:sort or xsl:with-param elements; XPath expression might fail.\r
+ */\r
+ if (inst->children) {\r
+ xsltStackElemPtr param;\r
+\r
+ cur = inst->children;\r
+ while (cur) {\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(cur, node, NULL, ctxt);\r
+#endif\r
+ if (ctxt->state == XSLT_STATE_STOPPED)\r
+ break;\r
+ if (cur->type == XML_TEXT_NODE) {\r
+ cur = cur->next;\r
+ continue;\r
+ } \r
+ if (! IS_XSLT_ELEM(cur))\r
+ break;\r
+ if (IS_XSLT_NAME(cur, "with-param")) {\r
+ param = xsltParseStylesheetCallerParam(ctxt, cur);\r
+ if (param != NULL) {\r
+ param->next = withParams;\r
+ withParams = param;\r
+ }\r
+ }\r
+ if (IS_XSLT_NAME(cur, "sort")) {\r
+ xsltTemplatePtr oldCurTempRule =\r
+ ctxt->currentTemplateRule;\r
+ int nbsorts = 0;\r
+ xmlNodePtr sorts[XSLT_MAX_SORT]; \r
+ \r
+ sorts[nbsorts++] = cur;\r
+ \r
+ while (cur) {\r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if (ctxt->debugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(cur, node, NULL, ctxt);\r
+#endif\r
+ if (ctxt->state == XSLT_STATE_STOPPED)\r
+ break;\r
+ \r
+ if (cur->type == XML_TEXT_NODE) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ \r
+ if (! IS_XSLT_ELEM(cur))\r
+ break;\r
+ if (IS_XSLT_NAME(cur, "with-param")) {\r
+ param = xsltParseStylesheetCallerParam(ctxt, cur);\r
+ if (param != NULL) {\r
+ param->next = withParams;\r
+ withParams = param;\r
+ }\r
+ } \r
+ if (IS_XSLT_NAME(cur, "sort")) {\r
+ if (nbsorts >= XSLT_MAX_SORT) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "The number (%d) of xsl:sort instructions exceeds the "\r
+ "maximum allowed by this processor's settings.\n",\r
+ nbsorts);\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ break;\r
+ } else {\r
+ sorts[nbsorts++] = cur;\r
+ }\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ /*\r
+ * The "current template rule" is cleared for xsl:sort.\r
+ */\r
+ ctxt->currentTemplateRule = NULL;\r
+ /*\r
+ * Sort.\r
+ */\r
+ xsltDoSortFunction(ctxt, sorts, nbsorts);\r
+ ctxt->currentTemplateRule = oldCurTempRule;\r
+ break;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ } \r
+ xpctxt->contextSize = list->nodeNr;\r
+ /*\r
+ * Apply templates for all selected source nodes.\r
+ */ \r
+ for (i = 0; i < list->nodeNr; i++) {\r
+ cur = list->nodeTab[i];\r
+ /*\r
+ * The node becomes the "current node".\r
+ */\r
+ ctxt->node = cur;\r
+ /*\r
+ * An xsl:apply-templates can change the current context doc.\r
+ * OPTIMIZE TODO: Get rid of the need to set the context doc.\r
+ */\r
+ if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))\r
+ xpctxt->doc = cur->doc;\r
+\r
+ xpctxt->proximityPosition = i + 1;\r
+ /*\r
+ * Find and apply a template for this node.\r
+ */\r
+ xsltProcessOneNode(ctxt, cur, withParams);\r
+ }\r
+\r
+exit:\r
+error:\r
+ /*\r
+ * Free the parameter list.\r
+ */\r
+ if (withParams != NULL)\r
+ xsltFreeStackElemList(withParams);\r
+ if (list != NULL)\r
+ xmlXPathFreeNodeSet(list); \r
+ /*\r
+ * Restore context states.\r
+ */\r
+ xpctxt->doc = oldDoc;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ \r
+ ctxt->tmpDoc = oldDoc;\r
+ ctxt->document = oldDocInfo;\r
+ ctxt->nodeList = oldList;\r
+ ctxt->node = oldContextNode;\r
+ ctxt->mode = oldMode;\r
+ ctxt->modeURI = oldModeURI;\r
+}\r
+\r
+\r
+/**\r
+ * xsltChoose:\r
+ * @ctxt: a XSLT process context\r
+ * @contextNode: the current node in the source tree\r
+ * @inst: the xsl:choose instruction\r
+ * @comp: compiled information of the instruction\r
+ *\r
+ * Processes the xsl:choose instruction on the source node.\r
+ */\r
+void\r
+xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,\r
+ xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)\r
+{\r
+ xmlNodePtr cur;\r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))\r
+ return;\r
+ \r
+ /* \r
+ * TODO: Content model checks should be done only at compilation\r
+ * time.\r
+ */\r
+ cur = inst->children;\r
+ if (cur == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:choose: The instruction has no content.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * We don't check the content model during transformation.\r
+ */\r
+#else\r
+ if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "xsl:choose: xsl:when expected first\n");\r
+ return;\r
+ }\r
+#endif\r
+\r
+ {\r
+ int testRes = 0, res = 0;\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; \r
+ xmlDocPtr oldXPContextDoc = xpctxt->doc;\r
+ int oldXPProximityPosition = xpctxt->proximityPosition;\r
+ int oldXPContextSize = xpctxt->contextSize;\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemWhenPtr wcomp = NULL;\r
+#else\r
+ xsltStylePreCompPtr wcomp = NULL;\r
+#endif\r
+\r
+ /*\r
+ * Process xsl:when ---------------------------------------------------\r
+ */\r
+ while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { \r
+ wcomp = cur->psvi;\r
+ \r
+ if ((wcomp == NULL) || (wcomp->test == NULL) ||\r
+ (wcomp->comp == NULL))\r
+ {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Internal error in xsltChoose(): "\r
+ "The XSLT 'when' instruction was not compiled.\n");\r
+ goto error;\r
+ }\r
+ \r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if (xslDebugStatus != XSLT_DEBUG_NONE) {\r
+ /* \r
+ * TODO: Isn't comp->templ always NULL for xsl:choose?\r
+ */\r
+ xslHandleDebugger(cur, contextNode, NULL, ctxt);\r
+ }\r
+#endif\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltChoose: test %s\n", wcomp->test));\r
+#endif\r
+\r
+ xpctxt->node = contextNode;\r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ if (wcomp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = wcomp->inScopeNs->list;\r
+ xpctxt->nsNr = wcomp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = wcomp->nsList;\r
+ xpctxt->nsNr = wcomp->nsNr;\r
+#endif\r
+ \r
+ \r
+#ifdef XSLT_FAST_IF\r
+ res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt);\r
+ \r
+ if (res == -1) {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ testRes = (res == 1) ? 1 : 0; \r
+ \r
+#else /* XSLT_FAST_IF */\r
+ \r
+ res = xmlXPathCompiledEval(wcomp->comp, xpctxt);\r
+ \r
+ if (res != NULL) {\r
+ if (res->type != XPATH_BOOLEAN)\r
+ res = xmlXPathConvertBoolean(res);\r
+ if (res->type == XPATH_BOOLEAN)\r
+ testRes = res->boolval;\r
+ else {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltChoose: test didn't evaluate to a boolean\n"));\r
+#endif\r
+ goto error;\r
+ }\r
+ xmlXPathFreeObject(res);\r
+ res = NULL;\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ \r
+#endif /* else of XSLT_FAST_IF */\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltChoose: test evaluate to %d\n", testRes));\r
+#endif\r
+ if (testRes) \r
+ goto test_is_true;\r
+ \r
+ cur = cur->next;\r
+ }\r
+ \r
+ /*\r
+ * Process xsl:otherwise ----------------------------------------------\r
+ */\r
+ if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {\r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if (xslDebugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(cur, contextNode, NULL, ctxt);\r
+#endif\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,\r
+ "evaluating xsl:otherwise\n"));\r
+#endif \r
+ goto test_is_true;\r
+ }\r
+ xpctxt->node = contextNode;\r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ goto exit;\r
+\r
+test_is_true:\r
+\r
+ xpctxt->node = contextNode;\r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ goto process_sequence;\r
+ }\r
+\r
+process_sequence:\r
+ \r
+ /*\r
+ * Instantiate the sequence constructor.\r
+ */\r
+ xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,\r
+ NULL);\r
+\r
+exit:\r
+error:\r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltIf:\r
+ * @ctxt: a XSLT process context\r
+ * @contextNode: the current node in the source tree\r
+ * @inst: the xsl:if instruction\r
+ * @comp: compiled information of the instruction\r
+ *\r
+ * Processes the xsl:if instruction on the source node.\r
+ */\r
+void\r
+xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+ int res = 0;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))\r
+ return;\r
+ if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltIf(): "\r
+ "The XSLT 'if' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltIf: test %s\n", comp->test));\r
+#endif\r
+\r
+#ifdef XSLT_FAST_IF \r
+ {\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;\r
+ xmlDocPtr oldXPContextDoc = xpctxt->doc;\r
+ xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;\r
+ xmlNodePtr oldXPContextNode = xpctxt->node;\r
+ int oldXPProximityPosition = xpctxt->proximityPosition;\r
+ int oldXPContextSize = xpctxt->contextSize;\r
+ int oldXPNsNr = xpctxt->nsNr;\r
+ xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; \r
+ \r
+ xpctxt->node = contextNode;\r
+ if (comp != NULL) {\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+ /*\r
+ * This XPath function is optimized for boolean results.\r
+ */ \r
+ res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);\r
+\r
+ /*\r
+ * Cleanup fragments created during evaluation of the\r
+ * "select" expression.\r
+ */\r
+ if (oldLocalFragmentTop != ctxt->localRVT)\r
+ xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);\r
+ \r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition; \r
+ xpctxt->nsNr = oldXPNsNr;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltIf: test evaluate to %d\n", res));\r
+#endif\r
+ \r
+ if (res == -1) {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+ if (res == 1) {\r
+ /*\r
+ * Instantiate the sequence constructor of xsl:if.\r
+ */\r
+ xsltApplySequenceConstructor(ctxt,\r
+ contextNode, inst->children, NULL);\r
+ }\r
+ \r
+#else /* XSLT_FAST_IF */\r
+ {\r
+ xmlXPathObjectPtr xpobj = NULL;\r
+ /*\r
+ * OLD CODE:\r
+ */\r
+ {\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;\r
+ xmlDocPtr oldXPContextDoc = xpctxt->doc;\r
+ xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;\r
+ xmlNodePtr oldXPContextNode = xpctxt->node;\r
+ int oldXPProximityPosition = xpctxt->proximityPosition;\r
+ int oldXPContextSize = xpctxt->contextSize;\r
+ int oldXPNsNr = xpctxt->nsNr; \r
+ \r
+ xpctxt->node = contextNode;\r
+ if (comp != NULL) {\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+ \r
+ /*\r
+ * This XPath function is optimized for boolean results.\r
+ */ \r
+ xpobj = xmlXPathCompiledEval(comp->comp, xpctxt);\r
+ \r
+ xpctxt->doc = oldXPContextDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition; \r
+ xpctxt->nsNr = oldXPNsNr;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ }\r
+ if (xpobj != NULL) {\r
+ if (xpobj->type != XPATH_BOOLEAN)\r
+ xpobj = xmlXPathConvertBoolean(xpobj);\r
+ if (xpobj->type == XPATH_BOOLEAN) {\r
+ res = xpobj->boolval;\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltIf: test evaluate to %d\n", res));\r
+#endif\r
+ if (res) {\r
+ xsltApplySequenceConstructor(ctxt,\r
+ contextNode, inst->children, NULL);\r
+ }\r
+ } else {\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt, XSLT_TRACE_IF,\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltIf: test didn't evaluate to a boolean\n"));\r
+#endif\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+ xmlXPathFreeObject(xpobj);\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ }\r
+ }\r
+#endif /* else of XSLT_FAST_IF */\r
+\r
+error:\r
+ return;\r
+}\r
+\r
+/**\r
+ * xsltForEach:\r
+ * @ctxt: an XSLT transformation context\r
+ * @node: the "current node" in the source tree \r
+ * @inst: the element node of the xsl:for-each instruction\r
+ * @comp: the compiled information of the instruction\r
+ *\r
+ * Process the xslt for-each node on the source node\r
+ */\r
+void\r
+xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,\r
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif\r
+ int i;\r
+ xmlXPathObjectPtr res = NULL;\r
+ xmlNodePtr cur, curInst;\r
+ xmlNodeSetPtr list = NULL;\r
+ xmlNodeSetPtr oldList; \r
+ int oldXPProximityPosition, oldXPContextSize;\r
+ xmlNodePtr oldContextNode;\r
+ xsltTemplatePtr oldCurTemplRule; \r
+ xmlDocPtr oldSourceDoc;\r
+ xsltDocumentPtr oldDocInfo;\r
+ xmlXPathContextPtr xpctxt;\r
+\r
+ if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {\r
+ xsltGenericError(xsltGenericErrorContext, \r
+ "xsltForEach(): Bad arguments.\n");\r
+ return;\r
+ }\r
+\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltForEach(): "\r
+ "The XSLT 'for-each' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+ if ((comp->select == NULL) || (comp->comp == NULL)) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltForEach(): "\r
+ "The selecting expression of the XSLT 'for-each' "\r
+ "instruction was not compiled correctly.\n");\r
+ return;\r
+ }\r
+ xpctxt = ctxt->xpathCtxt; \r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltForEach: select %s\n", comp->select));\r
+#endif\r
+\r
+ /*\r
+ * Save context states.\r
+ */\r
+ oldDocInfo = ctxt->document;\r
+ oldList = ctxt->nodeList;\r
+ oldSourceDoc = ctxt->tmpDoc;\r
+ oldContextNode = ctxt->node;\r
+ /*\r
+ * The "current template rule" is cleared for the instantiation of\r
+ * xsl:for-each.\r
+ */\r
+ oldCurTemplRule = ctxt->currentTemplateRule;\r
+ ctxt->currentTemplateRule = NULL;\r
+\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ /*\r
+ * Set up XPath.\r
+ */\r
+ xpctxt->node = contextNode;\r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif \r
+ \r
+ /*\r
+ * Evaluate the 'select' expression.\r
+ */\r
+ res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);\r
+\r
+ if (res != NULL) {\r
+ if (res->type == XPATH_NODESET)\r
+ list = res->nodesetval;\r
+ else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "The 'select' expression does not evaluate to a node set.\n");\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltForEach: select didn't evaluate to a node list\n"));\r
+#endif\r
+ goto error;\r
+ }\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Failed to evaluate the 'select' expression.\n");\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ goto error;\r
+ }\r
+\r
+ if ((list == NULL) || (list->nodeNr <= 0))\r
+ goto exit;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));\r
+#endif\r
+\r
+ /*\r
+ * Restore XPath states for the "current node".\r
+ */\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->node = contextNode;\r
+ \r
+ /*\r
+ * Set the list; this has to be done already here for xsltDoSortFunction().\r
+ */\r
+ ctxt->nodeList = list; \r
+ /* \r
+ * Handle xsl:sort instructions and skip them for further processing.\r
+ * BUG TODO: We are not using namespaced potentially defined on the\r
+ * xsl:sort element; XPath expression might fail.\r
+ */\r
+ curInst = inst->children;\r
+ if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {\r
+ int nbsorts = 0;\r
+ xmlNodePtr sorts[XSLT_MAX_SORT];\r
+\r
+ sorts[nbsorts++] = curInst;\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if (xslDebugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(curInst, contextNode, NULL, ctxt);\r
+#endif\r
+\r
+ curInst = curInst->next;\r
+ while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {\r
+ if (nbsorts >= XSLT_MAX_SORT) {\r
+ xsltTransformError(ctxt, NULL, curInst,\r
+ "The number of xsl:sort instructions exceeds the "\r
+ "maximum (%d) allowed by this processor.\n",\r
+ XSLT_MAX_SORT);\r
+ goto error;\r
+ } else {\r
+ sorts[nbsorts++] = curInst;\r
+ }\r
+ \r
+#ifdef WITH_DEBUGGER\r
+ if (xslDebugStatus != XSLT_DEBUG_NONE)\r
+ xslHandleDebugger(curInst, contextNode, NULL, ctxt);\r
+#endif\r
+ curInst = curInst->next;\r
+ }\r
+ xsltDoSortFunction(ctxt, sorts, nbsorts);\r
+ } \r
+ xpctxt->contextSize = list->nodeNr;\r
+ /*\r
+ * Instantiate the sequence constructor for each selected node.\r
+ */ \r
+ for (i = 0; i < list->nodeNr; i++) {\r
+ cur = list->nodeTab[i];\r
+ /*\r
+ * The selected node becomes the "current node".\r
+ */\r
+ ctxt->node = cur;\r
+ /*\r
+ * An xsl:for-each can change the current context doc.\r
+ * OPTIMIZE TODO: Get rid of the need to set the context doc.\r
+ */\r
+ if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))\r
+ xpctxt->doc = cur->doc;\r
+\r
+ xpctxt->proximityPosition = i + 1;\r
+\r
+ xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);\r
+ }\r
+\r
+exit:\r
+error:\r
+ if (res != NULL)\r
+ xmlXPathFreeObject(res);\r
+ /*\r
+ * Restore old states.\r
+ */\r
+ ctxt->tmpDoc = oldSourceDoc;\r
+ ctxt->document = oldDocInfo;\r
+ ctxt->nodeList = oldList;\r
+ ctxt->node = oldContextNode;\r
+ ctxt->currentTemplateRule = oldCurTemplRule;\r
+\r
+ xpctxt->doc = oldSourceDoc;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Generic interface *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+typedef struct xsltHTMLVersion {\r
+ const char *version;\r
+ const char *public;\r
+ const char *system;\r
+} xsltHTMLVersion;\r
+\r
+static xsltHTMLVersion xsltHTMLVersions[] = {\r
+ { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",\r
+ "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},\r
+ { "4.01strict", "-//W3C//DTD HTML 4.01//EN",\r
+ "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},\r
+ { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",\r
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},\r
+ { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",\r
+ "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},\r
+ { "4.0strict", "-//W3C//DTD HTML 4.01//EN",\r
+ "http://www.w3.org/TR/html4/strict.dtd"},\r
+ { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",\r
+ "http://www.w3.org/TR/html4/loose.dtd"},\r
+ { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",\r
+ "http://www.w3.org/TR/html4/frameset.dtd"},\r
+ { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",\r
+ "http://www.w3.org/TR/html4/loose.dtd"},\r
+ { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }\r
+};\r
+\r
+/**\r
+ * xsltGetHTMLIDs:\r
+ * @version: the version string\r
+ * @publicID: used to return the public ID\r
+ * @systemID: used to return the system ID\r
+ *\r
+ * Returns -1 if not found, 0 otherwise and the system and public\r
+ * Identifier for this given verion of HTML\r
+ */\r
+static int\r
+xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,\r
+ const xmlChar **systemID) {\r
+ unsigned int i;\r
+ if (version == NULL)\r
+ return(-1);\r
+ for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));\r
+ i++) {\r
+ if (!xmlStrcasecmp(version,\r
+ (const xmlChar *) xsltHTMLVersions[i].version)) {\r
+ if (publicID != NULL)\r
+ *publicID = (const xmlChar *) xsltHTMLVersions[i].public;\r
+ if (systemID != NULL)\r
+ *systemID = (const xmlChar *) xsltHTMLVersions[i].system;\r
+ return(0);\r
+ }\r
+ }\r
+ return(-1);\r
+}\r
+#endif\r
+\r
+/**\r
+ * xsltApplyStripSpaces:\r
+ * @ctxt: a XSLT process context\r
+ * @node: the root of the XML tree\r
+ *\r
+ * Strip the unwanted ignorable spaces from the input tree\r
+ */\r
+void\r
+xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {\r
+ xmlNodePtr current;\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ int nb = 0;\r
+#endif\r
+\r
+\r
+ current = node;\r
+ while (current != NULL) {\r
+ /*\r
+ * Cleanup children empty nodes if asked for\r
+ */\r
+ if ((IS_XSLT_REAL_NODE(current)) &&\r
+ (current->children != NULL) &&\r
+ (xsltFindElemSpaceHandling(ctxt, current))) {\r
+ xmlNodePtr delete = NULL, cur = current->children;\r
+\r
+ while (cur != NULL) {\r
+ if (IS_BLANK_NODE(cur))\r
+ delete = cur;\r
+ \r
+ cur = cur->next;\r
+ if (delete != NULL) {\r
+ xmlUnlinkNode(delete);\r
+ xmlFreeNode(delete);\r
+ delete = NULL;\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ nb++;\r
+#endif\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Skip to next node in document order.\r
+ */\r
+ if (node->type == XML_ENTITY_REF_NODE) {\r
+ /* process deep in entities */\r
+ xsltApplyStripSpaces(ctxt, node->children);\r
+ }\r
+ if ((current->children != NULL) &&\r
+ (current->type != XML_ENTITY_REF_NODE)) {\r
+ current = current->children;\r
+ } else if (current->next != NULL) {\r
+ current = current->next;\r
+ } else {\r
+ do {\r
+ current = current->parent;\r
+ if (current == NULL)\r
+ break;\r
+ if (current == node)\r
+ goto done;\r
+ if (current->next != NULL) {\r
+ current = current->next;\r
+ break;\r
+ }\r
+ } while (current != NULL);\r
+ }\r
+ }\r
+\r
+done:\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));\r
+#endif\r
+ return;\r
+}\r
+\r
+#ifdef XSLT_REFACTORED_KEYCOMP\r
+static int\r
+xsltCountKeys(xsltTransformContextPtr ctxt)\r
+{\r
+ xsltStylesheetPtr style;\r
+ xsltKeyDefPtr keyd;\r
+\r
+ if (ctxt == NULL)\r
+ return(-1); \r
+\r
+ /*\r
+ * Do we have those nastly templates with a key() in the match pattern?\r
+ */\r
+ ctxt->hasTemplKeyPatterns = 0;\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ if (style->keyMatch != NULL) {\r
+ ctxt->hasTemplKeyPatterns = 1;\r
+ break;\r
+ }\r
+ style = xsltNextImport(style);\r
+ }\r
+ /*\r
+ * Count number of key declarations.\r
+ */\r
+ ctxt->nbKeys = 0;\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ keyd = style->keys;\r
+ while (keyd) {\r
+ ctxt->nbKeys++;\r
+ keyd = keyd->next;\r
+ }\r
+ style = xsltNextImport(style);\r
+ } \r
+ return(ctxt->nbKeys);\r
+}\r
+#endif /* XSLT_REFACTORED_KEYCOMP */\r
+\r
+/**\r
+ * xsltApplyStylesheetInternal:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated array of parameters names/values tuples\r
+ * @output: the targetted output\r
+ * @profile: profile FILE * output or NULL\r
+ * @user: user provided parameter\r
+ *\r
+ * Apply the stylesheet to the document\r
+ * NOTE: This may lead to a non-wellformed output XML wise !\r
+ *\r
+ * Returns the result document or NULL in case of error\r
+ */\r
+static xmlDocPtr\r
+xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params, const char *output,\r
+ FILE * profile, xsltTransformContextPtr userCtxt)\r
+{\r
+ xmlDocPtr res = NULL;\r
+ xsltTransformContextPtr ctxt = NULL;\r
+ xmlNodePtr root, node;\r
+ const xmlChar *method;\r
+ const xmlChar *doctypePublic;\r
+ const xmlChar *doctypeSystem;\r
+ const xmlChar *version;\r
+ xsltStackElemPtr variables;\r
+ xsltStackElemPtr vptr;\r
+\r
+ if ((style == NULL) || (doc == NULL))\r
+ return (NULL);\r
+\r
+ if (style->internalized == 0) {\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Stylesheet was not fully internalized !\n");\r
+#endif\r
+ }\r
+ if (doc->intSubset != NULL) {\r
+ /*\r
+ * Avoid hitting the DTD when scanning nodes\r
+ * but keep it linked as doc->intSubset\r
+ */\r
+ xmlNodePtr cur = (xmlNodePtr) doc->intSubset;\r
+ if (cur->next != NULL)\r
+ cur->next->prev = cur->prev;\r
+ if (cur->prev != NULL)\r
+ cur->prev->next = cur->next;\r
+ if (doc->children == cur)\r
+ doc->children = cur->next;\r
+ if (doc->last == cur)\r
+ doc->last = cur->prev;\r
+ cur->prev = cur->next = NULL;\r
+ }\r
+\r
+ /*\r
+ * Check for XPath document order availability\r
+ */\r
+ root = xmlDocGetRootElement(doc);\r
+ if (root != NULL) {\r
+ if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE))\r
+ xmlXPathOrderDocElems(doc);\r
+ }\r
+\r
+ if (userCtxt != NULL)\r
+ ctxt = userCtxt;\r
+ else\r
+ ctxt = xsltNewTransformContext(style, doc);\r
+\r
+ if (ctxt == NULL)\r
+ return (NULL);\r
+\r
+ ctxt->initialContextDoc = doc;\r
+ ctxt->initialContextNode = (xmlNodePtr) doc;\r
+\r
+ if (profile != NULL)\r
+ ctxt->profile = 1;\r
+\r
+ if (output != NULL)\r
+ ctxt->outputFile = output;\r
+ else\r
+ ctxt->outputFile = NULL;\r
+\r
+ /*\r
+ * internalize the modes if needed\r
+ */\r
+ if (ctxt->dict != NULL) {\r
+ if (ctxt->mode != NULL)\r
+ ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);\r
+ if (ctxt->modeURI != NULL)\r
+ ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);\r
+ }\r
+\r
+ XSLT_GET_IMPORT_PTR(method, style, method)\r
+ XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)\r
+ XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)\r
+ XSLT_GET_IMPORT_PTR(version, style, version)\r
+\r
+ if ((method != NULL) &&\r
+ (!xmlStrEqual(method, (const xmlChar *) "xml")))\r
+ {\r
+ if (xmlStrEqual(method, (const xmlChar *) "html")) {\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {\r
+ res = htmlNewDoc(doctypeSystem, doctypePublic);\r
+ } else {\r
+ if (version == NULL) {\r
+ xmlDtdPtr dtd;\r
+ \r
+ res = htmlNewDoc(NULL, NULL);\r
+ /*\r
+ * Make sure no DTD node is generated in this case\r
+ */\r
+ if (res != NULL) {\r
+ dtd = xmlGetIntSubset(res);\r
+ if (dtd != NULL) {\r
+ xmlUnlinkNode((xmlNodePtr) dtd);\r
+ xmlFreeDtd(dtd);\r
+ }\r
+ res->intSubset = NULL;\r
+ res->extSubset = NULL;\r
+ }\r
+ } else {\r
+\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+ xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);\r
+#endif\r
+ res = htmlNewDoc(doctypeSystem, doctypePublic);\r
+ }\r
+ }\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {\r
+ xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,\r
+ "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",\r
+ style->method);\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ res = htmlNewDoc(doctypeSystem, doctypePublic);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ } else if (xmlStrEqual(method, (const xmlChar *) "text")) {\r
+ ctxt->type = XSLT_OUTPUT_TEXT;\r
+ res = xmlNewDoc(style->version);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(res->dict);\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ } else {\r
+ xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,\r
+ "xsltApplyStylesheetInternal: unsupported method %s\n",\r
+ style->method);\r
+ goto error;\r
+ }\r
+ } else {\r
+ ctxt->type = XSLT_OUTPUT_XML;\r
+ res = xmlNewDoc(style->version);\r
+ if (res == NULL)\r
+ goto error;\r
+ res->dict = ctxt->dict;\r
+ xmlDictReference(ctxt->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing transformation dict for output\n");\r
+#endif\r
+ }\r
+ res->charset = XML_CHAR_ENCODING_UTF8;\r
+ if (style->encoding != NULL)\r
+ res->encoding = xmlStrdup(style->encoding);\r
+ variables = style->variables;\r
+\r
+ /*\r
+ * Start the evaluation, evaluate the params, the stylesheets globals\r
+ * and start by processing the top node.\r
+ */\r
+ if (xsltNeedElemSpaceHandling(ctxt))\r
+ xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); \r
+ /*\r
+ * Evaluate global params and user-provided params.\r
+ */\r
+ ctxt->tmpDoc = doc;\r
+ ctxt->node = (xmlNodePtr) doc;\r
+ if (ctxt->globalVars == NULL)\r
+ ctxt->globalVars = xmlHashCreate(20);\r
+ if (params != NULL) { \r
+ xsltEvalUserParams(ctxt, params);\r
+ }\r
+ xsltEvalGlobalVariables(ctxt);\r
+\r
+#ifdef XSLT_REFACTORED_KEYCOMP \r
+ xsltCountKeys(ctxt);\r
+#endif\r
+\r
+ ctxt->tmpDoc = doc;\r
+ ctxt->node = (xmlNodePtr) doc;\r
+ ctxt->output = res;\r
+ ctxt->insert = (xmlNodePtr) res; \r
+ ctxt->varsBase = ctxt->varsNr - 1; \r
+ \r
+ ctxt->xpathCtxt->contextSize = 1;\r
+ ctxt->xpathCtxt->proximityPosition = 1;\r
+ ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */\r
+ /*\r
+ * Start processing the source tree -----------------------------------\r
+ */\r
+ xsltProcessOneNode(ctxt, ctxt->node, NULL);\r
+ /*\r
+ * Remove all remaining vars from the stack.\r
+ */\r
+ xsltLocalVariablePop(ctxt, 0, -2);\r
+ xsltShutdownCtxtExts(ctxt);\r
+\r
+ xsltCleanupTemplates(style); /* TODO: <- style should be read only */\r
+\r
+ /*\r
+ * Now cleanup our variables so stylesheet can be re-used\r
+ *\r
+ * TODO: this is not needed anymore global variables are copied\r
+ * and not evaluated directly anymore, keep this as a check\r
+ */\r
+ if (style->variables != variables) {\r
+ vptr = style->variables;\r
+ while (vptr->next != variables)\r
+ vptr = vptr->next;\r
+ vptr->next = NULL;\r
+ xsltFreeStackElemList(style->variables);\r
+ style->variables = variables;\r
+ }\r
+ vptr = style->variables;\r
+ while (vptr != NULL) {\r
+ if (vptr->computed) {\r
+ if (vptr->value != NULL) {\r
+ xmlXPathFreeObject(vptr->value);\r
+ vptr->value = NULL;\r
+ vptr->computed = 0;\r
+ }\r
+ }\r
+ vptr = vptr->next;\r
+ }\r
+ /*\r
+ * Free all remaining tree fragments.\r
+ */\r
+ xsltFreeRVTs(ctxt);\r
+ /*\r
+ * Do some post processing work depending on the generated output\r
+ */\r
+ root = xmlDocGetRootElement(res);\r
+ if (root != NULL) {\r
+ const xmlChar *doctype = NULL;\r
+\r
+ if ((root->ns != NULL) && (root->ns->prefix != NULL))\r
+ doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);\r
+ if (doctype == NULL)\r
+ doctype = root->name;\r
+\r
+ /*\r
+ * Apply the default selection of the method\r
+ */\r
+ if ((method == NULL) &&\r
+ (root->ns == NULL) &&\r
+ (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {\r
+ xmlNodePtr tmp;\r
+\r
+ tmp = res->children;\r
+ while ((tmp != NULL) && (tmp != root)) {\r
+ if (tmp->type == XML_ELEMENT_NODE)\r
+ break;\r
+ if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))\r
+ break;\r
+ tmp = tmp->next;\r
+ }\r
+ if (tmp == root) {\r
+ ctxt->type = XSLT_OUTPUT_HTML;\r
+ /*\r
+ * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the\r
+ * transformation on the doc, but functions like\r
+ */\r
+ res->type = XML_HTML_DOCUMENT_NODE;\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {\r
+ res->intSubset = xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+#ifdef XSLT_GENERATE_HTML_DOCTYPE\r
+ } else if (version != NULL) {\r
+ xsltGetHTMLIDs(version, &doctypePublic,\r
+ &doctypeSystem);\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL)))\r
+ res->intSubset =\r
+ xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+#endif\r
+ }\r
+ }\r
+\r
+ }\r
+ if (ctxt->type == XSLT_OUTPUT_XML) {\r
+ XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)\r
+ XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)\r
+ if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {\r
+ xmlNodePtr last;\r
+ /* Need a small "hack" here to assure DTD comes before\r
+ possible comment nodes */\r
+ node = res->children;\r
+ last = res->last;\r
+ res->children = NULL;\r
+ res->last = NULL;\r
+ res->intSubset = xmlCreateIntSubset(res, doctype,\r
+ doctypePublic,\r
+ doctypeSystem);\r
+ if (res->children != NULL) {\r
+ res->children->next = node;\r
+ node->prev = res->children;\r
+ res->last = last;\r
+ } else {\r
+ res->children = node;\r
+ res->last = last;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ xmlXPathFreeNodeSet(ctxt->nodeList);\r
+ if (profile != NULL) {\r
+ xsltSaveProfiling(ctxt, profile);\r
+ }\r
+\r
+ /*\r
+ * Be pedantic.\r
+ */\r
+ if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) {\r
+ xmlFreeDoc(res);\r
+ res = NULL;\r
+ }\r
+ if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {\r
+ int ret;\r
+\r
+ ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);\r
+ if (ret == 0) {\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xsltApplyStylesheet: forbidden to save to %s\n",\r
+ output);\r
+ } else if (ret < 0) {\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "xsltApplyStylesheet: saving to %s may not be possible\n",\r
+ output);\r
+ }\r
+ }\r
+\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ printf("# Cache:\n");\r
+ printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);\r
+ printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);\r
+#endif\r
+\r
+ if ((ctxt != NULL) && (userCtxt == NULL))\r
+ xsltFreeTransformContext(ctxt);\r
+\r
+ return (res);\r
+\r
+error:\r
+ if (res != NULL)\r
+ xmlFreeDoc(res);\r
+\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ printf("# Cache:\n");\r
+ printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);\r
+ printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars);\r
+#endif\r
+\r
+ if ((ctxt != NULL) && (userCtxt == NULL))\r
+ xsltFreeTransformContext(ctxt);\r
+ return (NULL);\r
+}\r
+\r
+/**\r
+ * xsltApplyStylesheet:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated arry of parameters names/values tuples\r
+ *\r
+ * Apply the stylesheet to the document\r
+ * NOTE: This may lead to a non-wellformed output XML wise !\r
+ *\r
+ * Returns the result document or NULL in case of error\r
+ */\r
+xmlDocPtr\r
+xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params)\r
+{\r
+ return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));\r
+}\r
+\r
+/**\r
+ * xsltProfileStylesheet:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated arry of parameters names/values tuples\r
+ * @output: a FILE * for the profiling output\r
+ *\r
+ * Apply the stylesheet to the document and dump the profiling to\r
+ * the given output.\r
+ *\r
+ * Returns the result document or NULL in case of error\r
+ */\r
+xmlDocPtr\r
+xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params, FILE * output)\r
+{\r
+ xmlDocPtr res;\r
+\r
+ res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);\r
+ return (res);\r
+}\r
+\r
+/**\r
+ * xsltApplyStylesheetUser:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated array of parameters names/values tuples\r
+ * @output: the targetted output\r
+ * @profile: profile FILE * output or NULL\r
+ * @userCtxt: user provided transform context\r
+ *\r
+ * Apply the stylesheet to the document and allow the user to provide\r
+ * its own transformation context.\r
+ *\r
+ * Returns the result document or NULL in case of error\r
+ */\r
+xmlDocPtr\r
+xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params, const char *output,\r
+ FILE * profile, xsltTransformContextPtr userCtxt)\r
+{\r
+ xmlDocPtr res;\r
+\r
+ res = xsltApplyStylesheetInternal(style, doc, params, output,\r
+ profile, userCtxt);\r
+ return (res);\r
+}\r
+\r
+/**\r
+ * xsltRunStylesheetUser:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated array of parameters names/values tuples\r
+ * @output: the URL/filename ot the generated resource if available\r
+ * @SAX: a SAX handler for progressive callback output (not implemented yet)\r
+ * @IObuf: an output buffer for progressive output (not implemented yet)\r
+ * @profile: profile FILE * output or NULL\r
+ * @userCtxt: user provided transform context\r
+ *\r
+ * Apply the stylesheet to the document and generate the output according\r
+ * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.\r
+ *\r
+ * NOTE: This may lead to a non-wellformed output XML wise !\r
+ * NOTE: This may also result in multiple files being generated\r
+ * NOTE: using IObuf, the result encoding used will be the one used for\r
+ * creating the output buffer, use the following macro to read it\r
+ * from the stylesheet\r
+ * XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ * NOTE: using SAX, any encoding specified in the stylesheet will be lost\r
+ * since the interface uses only UTF8\r
+ *\r
+ * Returns the number of by written to the main resource or -1 in case of\r
+ * error.\r
+ */\r
+int\r
+xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params, const char *output,\r
+ xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,\r
+ FILE * profile, xsltTransformContextPtr userCtxt)\r
+{\r
+ xmlDocPtr tmp;\r
+ int ret;\r
+\r
+ if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))\r
+ return (-1);\r
+ if ((SAX != NULL) && (IObuf != NULL))\r
+ return (-1);\r
+\r
+ /* unsupported yet */\r
+ if (SAX != NULL) {\r
+ XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */\r
+ return (-1);\r
+ }\r
+\r
+ tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,\r
+ userCtxt);\r
+ if (tmp == NULL) {\r
+ xsltTransformError(NULL, NULL, (xmlNodePtr) doc,\r
+ "xsltRunStylesheet : run failed\n");\r
+ return (-1);\r
+ }\r
+ if (IObuf != NULL) {\r
+ /* TODO: incomplete, IObuf output not progressive */\r
+ ret = xsltSaveResultTo(IObuf, tmp, style);\r
+ } else {\r
+ ret = xsltSaveResultToFilename(output, tmp, style, 0);\r
+ }\r
+ xmlFreeDoc(tmp);\r
+ return (ret);\r
+}\r
+\r
+/**\r
+ * xsltRunStylesheet:\r
+ * @style: a parsed XSLT stylesheet\r
+ * @doc: a parsed XML document\r
+ * @params: a NULL terminated array of parameters names/values tuples\r
+ * @output: the URL/filename ot the generated resource if available\r
+ * @SAX: a SAX handler for progressive callback output (not implemented yet)\r
+ * @IObuf: an output buffer for progressive output (not implemented yet)\r
+ *\r
+ * Apply the stylesheet to the document and generate the output according\r
+ * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.\r
+ *\r
+ * NOTE: This may lead to a non-wellformed output XML wise !\r
+ * NOTE: This may also result in multiple files being generated\r
+ * NOTE: using IObuf, the result encoding used will be the one used for\r
+ * creating the output buffer, use the following macro to read it\r
+ * from the stylesheet\r
+ * XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ * NOTE: using SAX, any encoding specified in the stylesheet will be lost\r
+ * since the interface uses only UTF8\r
+ *\r
+ * Returns the number of bytes written to the main resource or -1 in case of\r
+ * error.\r
+ */\r
+int\r
+xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,\r
+ const char **params, const char *output,\r
+ xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)\r
+{\r
+ return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,\r
+ NULL, NULL));\r
+}\r
+\r
+/**\r
+ * xsltRegisterAllElement:\r
+ * @ctxt: the XPath context\r
+ *\r
+ * Registers all default XSLT elements in this context\r
+ */\r
+void\r
+xsltRegisterAllElement(xsltTransformContextPtr ctxt)\r
+{\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltApplyTemplates);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltApplyImports);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltCallTemplate);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "element",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltElement);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltAttribute);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "text",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltText);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltProcessingInstruction);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltComment);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltCopy);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltValueOf);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "number",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltNumber);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltForEach);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "if",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltIf);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltChoose);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltSort);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltCopyOf);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "message",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltMessage);\r
+\r
+ /*\r
+ * Those don't have callable entry points but are registered anyway\r
+ */\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "param",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "when",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",\r
+ XSLT_NAMESPACE,\r
+ (xsltTransformFunction) xsltDebug);\r
+\r
+}\r
-/*
- * variables.c: Implementation of the variable storage and lookup
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/xmlerror.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/parserInternals.h>
-#include <libxml/dict.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "xsltutils.h"
-#include "variables.h"
-#include "transform.h"
-#include "imports.h"
-#include "preproc.h"
-#include "keys.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_VARIABLE
-#endif
-
-#ifdef XSLT_REFACTORED
-const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
-#endif
-
-/************************************************************************
- * *
- * Result Value Tree (Result Tree Fragment) interfaces *
- * *
- ************************************************************************/
-/**
- * xsltCreateRVT:
- * @ctxt: an XSLT transformation context
- *
- * Create a Result Value Tree
- * (the XSLT 1.0 term for this is "Result Tree Fragment")
- *
- * Returns the result value tree or NULL in case of error
- */
-xmlDocPtr
-xsltCreateRVT(xsltTransformContextPtr ctxt)
-{
- xmlDocPtr container;
-
- /*
- * Question: Why is this function public?
- * Answer: It is called by the EXSLT module.
- */
- if (ctxt == NULL) return(NULL);
-
- container = xmlNewDoc(NULL);
- if (container == NULL)
- return(NULL);
- container->dict = ctxt->dict;
- xmlDictReference(container->dict);
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing transformation dict for RVT\n");
-#endif
-
- XSLT_MARK_RES_TREE_FRAG(container);
- container->doc = container;
- container->parent = NULL;
- return(container);
-}
-
-/**
- * xsltRegisterTmpRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment)
- *
- * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
- * for destruction at the end of the context
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-int
-xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
-{
- if ((ctxt == NULL) || (RVT == NULL)) return(-1);
-
- RVT->next = (xmlNodePtr) ctxt->tmpRVT;
- if (ctxt->tmpRVT != NULL)
- ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
- ctxt->tmpRVT = RVT;
- return(0);
-}
-
-/**
- * xsltRegisterPersistRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment)
- *
- * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
- * for destruction at the end of the processing
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-int
-xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
-{
- if ((ctxt == NULL) || (RVT == NULL)) return(-1);
-
- RVT->next = (xmlNodePtr) ctxt->persistRVT;
- if (ctxt->persistRVT != NULL)
- ctxt->persistRVT->prev = (xmlNodePtr) RVT;
- ctxt->persistRVT = RVT;
- return(0);
-}
-
-/**
- * xsltFreeRVTs:
- * @ctxt: an XSLT transformation context
- *
- * Free all the registered result value tree (Result Tree Fragment)
- * of the transformation
- */
-void
-xsltFreeRVTs(xsltTransformContextPtr ctxt)
-{
- xmlDocPtr cur, next;
-
- if (ctxt == NULL) return;
-
- cur = ctxt->tmpRVT;
- while (cur != NULL) {
- next = (xmlDocPtr) cur->next;
- if (cur->_private != NULL) {
- xsltFreeDocumentKeys(cur->_private);
- xmlFree(cur->_private);
- }
- xmlFreeDoc(cur);
- cur = next;
- }
- cur = ctxt->persistRVT;
- while (cur != NULL) {
- next = (xmlDocPtr) cur->next;
- if (cur->_private != NULL) {
- xsltFreeDocumentKeys(cur->_private);
- xmlFree(cur->_private);
- }
- xmlFreeDoc(cur);
- cur = next;
- }
-}
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltNewStackElem:
- *
- * Create a new XSLT ParserContext
- *
- * Returns the newly allocated xsltParserStackElem or NULL in case of error
- */
-static xsltStackElemPtr
-xsltNewStackElem(void) {
- xsltStackElemPtr cur;
-
- cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewStackElem : malloc failed\n");
- return(NULL);
- }
- cur->computed = 0;
- cur->name = NULL;
- cur->nameURI = NULL;
- cur->select = NULL;
- cur->tree = NULL;
- cur->value = NULL;
- cur->comp = NULL;
- return(cur);
-}
-
-/**
- * xsltCopyStackElem:
- * @elem: an XSLT stack element
- *
- * Makes a copy of the stack element
- *
- * Returns the copy of NULL
- */
-static xsltStackElemPtr
-xsltCopyStackElem(xsltStackElemPtr elem) {
- xsltStackElemPtr cur;
-
- cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCopyStackElem : malloc failed\n");
- return(NULL);
- }
- cur->name = elem->name;
- cur->nameURI = elem->nameURI;
- cur->select = elem->select;
- cur->tree = elem->tree;
- cur->comp = elem->comp;
- cur->computed = 0;
- cur->value = NULL;
- return(cur);
-}
-
-/**
- * xsltFreeStackElem:
- * @elem: an XSLT stack element
- *
- * Free up the memory allocated by @elem
- */
-static void
-xsltFreeStackElem(xsltStackElemPtr elem) {
- if (elem == NULL)
- return;
- if (elem->value != NULL)
- xmlXPathFreeObject(elem->value);
-
- xmlFree(elem);
-}
-
-/**
- * xsltFreeStackElemList:
- * @elem: an XSLT stack element
- *
- * Free up the memory allocated by @elem
- */
-void
-xsltFreeStackElemList(xsltStackElemPtr elem) {
- xsltStackElemPtr next;
-
- while(elem != NULL) {
- next = elem->next;
- xsltFreeStackElem(elem);
- elem = next;
- }
-}
-
-/**
- * xsltStackLookup:
- * @ctxt: an XSLT transformation context
- * @name: the local part of the name
- * @nameURI: the URI part of the name
- *
- * Locate an element in the stack based on its name.
- */
-static int stack_addr = 0;
-static int stack_cmp = 0;
-static xsltStackElemPtr
-xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *nameURI) {
- int i;
- xsltStackElemPtr cur;
-
- if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
- return(NULL);
-
- /*
- * Do the lookup from the top of the stack, but
- * don't use params being computed in a call-param
- * First lookup expects the variable name and URI to
- * come from the disctionnary and hence get equality
- */
- for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
- cur = ctxt->varsTab[i-1];
- while (cur != NULL) {
- if (cur->name == name) {
- if (nameURI == NULL) {
- if (cur->nameURI == NULL) {
- stack_addr++;
- return(cur);
- }
- } else {
- if ((cur->nameURI != NULL) &&
- (cur->nameURI == nameURI)) {
- stack_addr++;
- return(cur);
- }
- }
-
- }
- cur = cur->next;
- }
- }
-
- /*
- * Redo the lookup with interned string compares
- * to avoid string compares.
- */
- name = xmlDictLookup(ctxt->dict, name, -1);
- if (nameURI != NULL)
- nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
- else
- nameURI = NULL;
- for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
- cur = ctxt->varsTab[i-1];
- while (cur != NULL) {
- if (cur->name == name) {
- if (nameURI == NULL) {
- if (cur->nameURI == NULL) {
- stack_cmp++;
- return(cur);
- }
- } else {
- if ((cur->nameURI != NULL) &&
- (cur->nameURI == nameURI)) {
- stack_cmp++;
- return(cur);
- }
- }
-
- }
- cur = cur->next;
- }
- }
-
- return(NULL);
-}
-
-/**
- * xsltCheckStackElem:
- * @ctxt: xn XSLT transformation context
- * @name: the variable name
- * @nameURI: the variable namespace URI
- *
- * check wether the variable or param is already defined
- *
- * Returns 1 if variable is present, 2 if param is present, 3 if this
- * is an inherited param, 0 if not found, -1 in case of failure.
- */
-static int
-xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *nameURI) {
- xsltStackElemPtr cur;
-
- if ((ctxt == NULL) || (name == NULL))
- return(-1);
-
- cur = xsltStackLookup(ctxt, name, nameURI);
- if (cur == NULL)
- return(0);
- if (cur->comp != NULL) {
- if (cur->comp->type == XSLT_FUNC_WITHPARAM)
- return(3);
- else if (cur->comp->type == XSLT_FUNC_PARAM)
- return(2);
- }
-
- return(1);
-}
-
-/**
- * xsltAddStackElem:
- * @ctxt: xn XSLT transformation context
- * @elem: a stack element
- *
- * add a new element at this level of the stack.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
- if ((ctxt == NULL) || (elem == NULL))
- return(-1);
-
- elem->next = ctxt->varsTab[ctxt->varsNr - 1];
- ctxt->varsTab[ctxt->varsNr - 1] = elem;
- ctxt->vars = elem;
- return(0);
-}
-
-/**
- * xsltAddStackElemList:
- * @ctxt: xn XSLT transformation context
- * @elems: a stack element list
- *
- * add the new element list at this level of the stack.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
- xsltStackElemPtr cur;
-
- if ((ctxt == NULL) || (elems == NULL))
- return(-1);
-
- /* TODO: check doublons */
- if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
- cur = ctxt->varsTab[ctxt->varsNr - 1];
- while (cur->next != NULL)
- cur = cur->next;
- cur->next = elems;
- } else {
- elems->next = ctxt->varsTab[ctxt->varsNr - 1];
- ctxt->varsTab[ctxt->varsNr - 1] = elems;
- ctxt->vars = elems;
- }
- return(0);
-}
-
-/************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
-
-/**
- * xsltEvalVariable:
- * @ctxt: the XSLT transformation context
- * @elem: the variable or parameter.
- * @precomp: pointer to precompiled data
- *
- * Evaluate a variable value.
- *
- * Returns the XPath Object value or NULL in case of error
- */
-static xmlXPathObjectPtr
-xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
- xsltStylePreCompPtr castedComp)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr precomp =
- (xsltStyleItemVariablePtr) castedComp;
-#else
- xsltStylePreCompPtr precomp = castedComp;
-#endif
- xmlXPathObjectPtr result = NULL;
- int oldProximityPosition, oldContextSize;
- xmlNodePtr oldInst, oldNode;
- xsltDocumentPtr oldDoc;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- if ((ctxt == NULL) || (elem == NULL))
- return(NULL);
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating variable %s\n", elem->name));
-#endif
- if (elem->select != NULL) {
- xmlXPathCompExprPtr comp = NULL;
-
- if ((precomp != NULL) && (precomp->comp != NULL)) {
- comp = precomp->comp;
- } else {
- comp = xmlXPathCompile(elem->select);
- }
- if (comp == NULL)
- return(NULL);
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
- oldDoc = ctxt->document;
- oldNode = ctxt->node;
- oldInst = ctxt->inst;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- if (precomp != NULL) {
- ctxt->inst = precomp->inst;
-#ifdef XSLT_REFACTORED
- if (precomp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = precomp->nsList;
- ctxt->xpathCtxt->nsNr = precomp->nsNr;
-#endif
- } else {
- ctxt->inst = NULL;
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
- result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- ctxt->inst = oldInst;
- ctxt->node = oldNode;
- ctxt->document = oldDoc;
- if ((precomp == NULL) || (precomp->comp == NULL))
- xmlXPathFreeCompExpr(comp);
- if (result == NULL) {
- if (precomp == NULL)
- xsltTransformError(ctxt, NULL, NULL,
- "Evaluating variable %s failed\n", elem->name);
- else
- xsltTransformError(ctxt, NULL, precomp->inst,
- "Evaluating variable %s failed\n", elem->name);
- ctxt->state = XSLT_STATE_STOPPED;
-#ifdef WITH_XSLT_DEBUG_VARIABLE
-#ifdef LIBXML_DEBUG_ENABLED
- } else {
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
-#endif
-#endif
- }
- } else {
- if (elem->tree == NULL) {
- result = xmlXPathNewCString("");
- } else {
- /*
- * This is a result tree fragment.
- */
- xmlDocPtr container;
- xmlNodePtr oldInsert;
- xmlDocPtr oldoutput;
-
- container = xsltCreateRVT(ctxt);
- if (container == NULL)
- return(NULL);
- /*
- * Tag the subtree for removal once consumed
- */
- xsltRegisterTmpRVT(ctxt, container);
- oldoutput = ctxt->output;
- ctxt->output = container;
- oldInsert = ctxt->insert;
- ctxt->insert = (xmlNodePtr) container;
- xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
- ctxt->insert = oldInsert;
- ctxt->output = oldoutput;
-
- result = xmlXPathNewValueTree((xmlNodePtr) container);
- if (result == NULL) {
- result = xmlXPathNewCString("");
- } else {
- result->boolval = 0; /* Freeing is not handled there anymore */
- }
-#ifdef WITH_XSLT_DEBUG_VARIABLE
-#ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
-#endif
-#endif
- }
- }
- return(result);
-}
-
-/**
- * xsltEvalGlobalVariable:
- * @elem: the variable or parameter.
- * @ctxt: the XSLT transformation context
- *
- * Evaluate a global variable value.
- *
- * Returns the XPath Object value or NULL in case of error
- */
-static xmlXPathObjectPtr
-xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
-{
- xmlXPathObjectPtr result = NULL;
-#ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr precomp;
-#else
- xsltStylePreCompPtr precomp;
-#endif
- int oldProximityPosition, oldContextSize;
- xmlDocPtr oldDoc;
- xmlNodePtr oldInst;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
- const xmlChar *name;
-
- if ((ctxt == NULL) || (elem == NULL))
- return(NULL);
- if (elem->computed)
- return(elem->value);
-
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating global variable %s\n", elem->name));
-#endif
-
-#ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
- elem->comp && elem->comp->inst)
- xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
-#endif
-
- name = elem->name;
- elem->name = BAD_CAST " being computed ... ";
-
-#ifdef XSLT_REFACTORED
- precomp = (xsltStyleBasicItemVariablePtr) elem->comp;
-#else
- precomp = elem->comp;
-#endif
-
- /*
- * OPTIMIZE TODO: We should consider if instantiating global vars/params
- * on a on-demand basis would be better. The vars/params don't
- * need to be evaluated if never called; and in the case of
- * global params, if values for such params are provided by the
- * user.
- */
- if (elem->select != NULL) {
- xmlXPathCompExprPtr comp = NULL;
-
- if ((precomp != NULL) && (precomp->comp != NULL)) {
- comp = precomp->comp;
- } else {
- comp = xmlXPathCompile(elem->select);
- }
- if (comp == NULL) {
- elem->name = name;
- return(NULL);
- }
- oldDoc = ctxt->xpathCtxt->doc;
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- oldInst = ctxt->inst;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
-
- if (precomp != NULL) {
- ctxt->inst = precomp->inst;
-#ifdef XSLT_REFACTORED
- if (precomp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = precomp->nsList;
- ctxt->xpathCtxt->nsNr = precomp->nsNr;
-#endif
- } else {
- ctxt->inst = NULL;
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
- ctxt->xpathCtxt->doc = ctxt->tmpDoc;
- ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->tmpDoc;
- result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
-
- ctxt->xpathCtxt->doc = oldDoc;
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->inst = oldInst;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- if ((precomp == NULL) || (precomp->comp == NULL))
- xmlXPathFreeCompExpr(comp);
- if (result == NULL) {
- if (precomp == NULL)
- xsltTransformError(ctxt, NULL, NULL,
- "Evaluating global variable %s failed\n", elem->name);
- else
- xsltTransformError(ctxt, NULL, precomp->inst,
- "Evaluating global variable %s failed\n", elem->name);
- ctxt->state = XSLT_STATE_STOPPED;
-#ifdef WITH_XSLT_DEBUG_VARIABLE
-#ifdef LIBXML_DEBUG_ENABLED
- } else {
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
-#endif
-#endif
- }
- } else {
- if (elem->tree == NULL) {
- result = xmlXPathNewCString("");
- } else {
- /*
- * This is a result tree fragment.
- */
- xmlDocPtr container;
- xmlNodePtr oldInsert;
- xmlDocPtr oldoutput;
-
- container = xsltCreateRVT(ctxt);
- if (container == NULL)
- return(NULL);
- /*
- * Tag the subtree for removal once consumed
- */
- xsltRegisterTmpRVT(ctxt, container);
- /*
- * Save a pointer to the global variable for later cleanup
- */
- container->psvi = elem;
- oldoutput = ctxt->output;
- ctxt->output = container;
- oldInsert = ctxt->insert;
- ctxt->insert = (xmlNodePtr) container;
- xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
- ctxt->insert = oldInsert;
- ctxt->output = oldoutput;
-
- result = xmlXPathNewValueTree((xmlNodePtr) container);
- if (result == NULL) {
- result = xmlXPathNewCString("");
- } else {
- result->boolval = 0; /* Freeing is not handled there anymore */
- }
-#ifdef WITH_XSLT_DEBUG_VARIABLE
-#ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
-#endif
-#endif
- }
- }
- if (result != NULL) {
- elem->value = result;
- elem->computed = 1;
- }
- elem->name = name;
- return(result);
-}
-
-/**
- * xsltEvalGlobalVariables:
- * @ctxt: the XSLT transformation context
- *
- * Evaluate the global variables of a stylesheet. This need to be
- * done on parsed stylesheets before starting to apply transformations
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
- xsltStackElemPtr elem;
- xsltStylesheetPtr style;
-
- if ((ctxt == NULL) || (ctxt->document == NULL))
- return(-1);
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variables\n"));
-#endif
-
- ctxt->tmpDoc = ctxt->document->doc;
- ctxt->node = (xmlNodePtr) ctxt->document->doc;
- ctxt->xpathCtxt->contextSize = 1;
- ctxt->xpathCtxt->proximityPosition = 1;
-
- /*
- * Walk the list from the stylesheets and populate the hash table
- */
- style = ctxt->style;
- while (style != NULL) {
- elem = style->variables;
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- if ((style->doc != NULL) && (style->doc->URL != NULL)) {
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variables from %s\n",
- style->doc->URL));
- }
-#endif
-
- while (elem != NULL) {
- xsltStackElemPtr def;
-
- /*
- * Global variables are stored in the variables pool.
- */
- def = (xsltStackElemPtr)
- xmlHashLookup2(ctxt->globalVars,
- elem->name, elem->nameURI);
- if (def == NULL) {
-
- def = xsltCopyStackElem(elem);
- xmlHashAddEntry2(ctxt->globalVars,
- elem->name, elem->nameURI, def);
- } else if ((elem->comp != NULL) &&
- (elem->comp->type == XSLT_FUNC_VARIABLE)) {
- /*
- * Redefinition of variables from a different stylesheet
- * should not generate a message.
- */
- if ((elem->comp->inst != NULL) &&
- (def->comp != NULL) && (def->comp->inst != NULL) &&
- (elem->comp->inst->doc == def->comp->inst->doc)) {
- xsltTransformError(ctxt, style, elem->comp->inst,
- "Global variable %s already defined\n", elem->name);
- if (style != NULL) style->errors++;
- }
- }
- elem = elem->next;
- }
-
- style = xsltNextImport(style);
- }
-
- /*
- * This part does the actual evaluation
- */
- ctxt->node = (xmlNodePtr) ctxt->document->doc;
- ctxt->xpathCtxt->contextSize = 1;
- ctxt->xpathCtxt->proximityPosition = 1;
- xmlHashScan(ctxt->globalVars,
- (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
-
- return(0);
-}
-
-/**
- * xsltRegisterGlobalVariable:
- * @style: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- * @sel: the expression which need to be evaluated to generate a value
- * @tree: the subtree if sel is NULL
- * @comp: the precompiled value
- * @value: the string value if available
- *
- * Register a new variable value. If @value is NULL it unregisters
- * the variable
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
- const xmlChar *ns_uri, const xmlChar *sel,
- xmlNodePtr tree, xsltStylePreCompPtr comp,
- const xmlChar *value) {
- xsltStackElemPtr elem, tmp;
- if (style == NULL)
- return(-1);
- if (name == NULL)
- return(-1);
- if (comp == NULL)
- return(-1);
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- if (comp->type == XSLT_FUNC_PARAM)
- xsltGenericDebug(xsltGenericDebugContext,
- "Defining global param %s\n", name);
- else
- xsltGenericDebug(xsltGenericDebugContext,
- "Defining global variable %s\n", name);
-#endif
-
- elem = xsltNewStackElem();
- if (elem == NULL)
- return(-1);
- elem->comp = comp;
- elem->name = xmlDictLookup(style->dict, name, -1);
- elem->select = xmlDictLookup(style->dict, sel, -1);
- if (ns_uri)
- elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
- elem->tree = tree;
- tmp = style->variables;
- if (tmp == NULL) {
- elem->next = NULL;
- style->variables = elem;
- } else {
- while (tmp != NULL) {
- if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
- (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
- (xmlStrEqual(elem->name, tmp->name)) &&
- ((elem->nameURI == tmp->nameURI) ||
- (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
- xsltTransformError(NULL, style, comp->inst,
- "redefinition of global variable %s\n", elem->name);
- if (style != NULL) style->errors++;
- }
- if (tmp->next == NULL)
- break;
- tmp = tmp->next;
- }
- elem->next = NULL;
- tmp->next = elem;
- }
- if (value != NULL) {
- elem->computed = 1;
- elem->value = xmlXPathNewString(value);
- }
- return(0);
-}
-
-/**
- * xsltProcessUserParamInternal
- *
- * @ctxt: the XSLT transformation context
- * @name: a null terminated parameter name
- * @value: a null terminated value (may be an XPath expression)
- * @eval: 0 to treat the value literally, else evaluate as XPath expression
- *
- * If @eval is 0 then @value is treated literally and is stored in the global
- * parameter/variable table without any change.
- *
- * Uf @eval is 1 then @value is treated as an XPath expression and is
- * evaluated. In this case, if you want to pass a string which will be
- * interpreted literally then it must be enclosed in single or double quotes.
- * If the string contains single quotes (double quotes) then it cannot be
- * enclosed single quotes (double quotes). If the string which you want to
- * be treated literally contains both single and double quotes (e.g. Meet
- * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
- * quoting character. You cannot use ' or " inside the string
- * because the replacement of character entities with their equivalents is
- * done at a different stage of processing. The solution is to call
- * xsltQuoteUserParams or xsltQuoteOneUserParam.
- *
- * This needs to be done on parsed stylesheets before starting to apply
- * transformations. Normally this will be called (directly or indirectly)
- * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
- * or xsltQuoteOneUserParam.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-
-static
-int
-xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value,
- int eval) {
-
- xsltStylesheetPtr style;
- const xmlChar *prefix;
- const xmlChar *href;
- xmlXPathCompExprPtr comp;
- xmlXPathObjectPtr result;
- int oldProximityPosition;
- int oldContextSize;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
- xsltStackElemPtr elem;
- int res;
- void *res_ptr;
-
- if (ctxt == NULL)
- return(-1);
- if (name == NULL)
- return(0);
- if (value == NULL)
- return(0);
-
- style = ctxt->style;
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating user parameter %s=%s\n", name, value));
-#endif
-
- /*
- * Name lookup
- */
-
- name = xsltSplitQName(ctxt->dict, name, &prefix);
- href = NULL;
- if (prefix != NULL) {
- xmlNsPtr ns;
-
- ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
- prefix);
- if (ns == NULL) {
- xsltTransformError(ctxt, style, NULL,
- "user param : no namespace bound to prefix %s\n", prefix);
- href = NULL;
- } else {
- href = ns->href;
- }
- }
-
- if (name == NULL)
- return (-1);
-
- res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
- if (res_ptr != 0) {
- xsltTransformError(ctxt, style, NULL,
- "Global parameter %s already defined\n", name);
- }
- if (ctxt->globalVars == NULL)
- ctxt->globalVars = xmlHashCreate(20);
-
- /*
- * do not overwrite variables with parameters from the command line
- */
- while (style != NULL) {
- elem = ctxt->style->variables;
- while (elem != NULL) {
- if ((elem->comp != NULL) &&
- (elem->comp->type == XSLT_FUNC_VARIABLE) &&
- (xmlStrEqual(elem->name, name)) &&
- (xmlStrEqual(elem->nameURI, href))) {
- return(0);
- }
- elem = elem->next;
- }
- style = xsltNextImport(style);
- }
- style = ctxt->style;
- elem = NULL;
-
- /*
- * Do the evaluation if @eval is non-zero.
- */
-
- result = NULL;
- if (eval != 0) {
- comp = xmlXPathCompile(value);
- if (comp != NULL) {
- oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
- oldContextSize = ctxt->xpathCtxt->contextSize;
- ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
-
- /*
- * There is really no in scope namespace for parameters on the
- * command line.
- */
-
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
- ctxt->xpathCtxt->contextSize = oldContextSize;
- ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
- xmlXPathFreeCompExpr(comp);
- }
- if (result == NULL) {
- xsltTransformError(ctxt, style, NULL,
- "Evaluating user parameter %s failed\n", name);
- ctxt->state = XSLT_STATE_STOPPED;
- return(-1);
- }
- }
-
- /*
- * If @eval is 0 then @value is to be taken literally and result is NULL
- *
- * If @eval is not 0, then @value is an XPath expression and has been
- * successfully evaluated and result contains the resulting value and
- * is not NULL.
- *
- * Now create an xsltStackElemPtr for insertion into the context's
- * global variable/parameter hash table.
- */
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
-#ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
-#endif
-#endif
-
- elem = xsltNewStackElem();
- if (elem != NULL) {
- elem->name = name;
- elem->select = xmlDictLookup(ctxt->dict, value, -1);
- if (href != NULL)
- elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
- elem->tree = NULL;
- elem->computed = 1;
- if (eval == 0) {
- elem->value = xmlXPathNewString(value);
- }
- else {
- elem->value = result;
- }
- }
-
- /*
- * Global parameters are stored in the XPath context variables pool.
- */
-
- res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
- if (res != 0) {
- xsltFreeStackElem(elem);
- xsltTransformError(ctxt, style, NULL,
- "Global parameter %s already defined\n", name);
- }
- return(0);
-}
-
-/**
- * xsltEvalUserParams:
- *
- * @ctxt: the XSLT transformation context
- * @params: a NULL terminated array of parameters name/value tuples
- *
- * Evaluate the global variables of a stylesheet. This needs to be
- * done on parsed stylesheets before starting to apply transformations.
- * Each of the parameters is evaluated as an XPath expression and stored
- * in the global variables/parameter hash table. If you want your
- * parameter used literally, use xsltQuoteUserParams.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-
-int
-xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
- int indx = 0;
- const xmlChar *name;
- const xmlChar *value;
-
- if (params == NULL)
- return(0);
- while (params[indx] != NULL) {
- name = (const xmlChar *) params[indx++];
- value = (const xmlChar *) params[indx++];
- if (xsltEvalOneUserParam(ctxt, name, value) != 0)
- return(-1);
- }
- return 0;
-}
-
-/**
- * xsltQuoteUserParams:
- *
- * @ctxt: the XSLT transformation context
- * @params: a NULL terminated arry of parameters names/values tuples
- *
- * Similar to xsltEvalUserParams, but the values are treated literally and
- * are * *not* evaluated as XPath expressions. This should be done on parsed
- * stylesheets before starting to apply transformations.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-
-int
-xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
- int indx = 0;
- const xmlChar *name;
- const xmlChar *value;
-
- if (params == NULL)
- return(0);
- while (params[indx] != NULL) {
- name = (const xmlChar *) params[indx++];
- value = (const xmlChar *) params[indx++];
- if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
- return(-1);
- }
- return 0;
-}
-
-/**
- * xsltEvalOneUserParam:
- * @ctxt: the XSLT transformation context
- * @name: a null terminated string giving the name of the parameter
- * @value: a null terminated string giving the XPath expression to be evaluated
- *
- * This is normally called from xsltEvalUserParams to process a single
- * parameter from a list of parameters. The @value is evaluated as an
- * XPath expression and the result is stored in the context's global
- * variable/parameter hash table.
- *
- * To have a parameter treated literally (not as an XPath expression)
- * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
- * details see description of xsltProcessOneUserParamInternal.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-
-int
-xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value) {
- return xsltProcessUserParamInternal(ctxt, name, value,
- 1 /* xpath eval ? */);
-}
-
-/**
- * xsltQuoteOneUserParam:
- * @ctxt: the XSLT transformation context
- * @name: a null terminated string giving the name of the parameter
- * @value: a null terminated string giving the parameter value
- *
- * This is normally called from xsltQuoteUserParams to process a single
- * parameter from a list of parameters. The @value is stored in the
- * context's global variable/parameter hash table.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-
-int
-xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value) {
- return xsltProcessUserParamInternal(ctxt, name, value,
- 0 /* xpath eval ? */);
-}
-
-/**
- * xsltBuildVariable:
- * @ctxt: the XSLT transformation context
- * @comp: the precompiled form
- * @tree: the tree if select is NULL
- *
- * Computes a new variable value.
- *
- * Returns the xsltStackElemPtr or NULL in case of error
- */
-static xsltStackElemPtr
-xsltBuildVariable(xsltTransformContextPtr ctxt,
- xsltStylePreCompPtr castedComp,
- xmlNodePtr tree)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp =
- (xsltStyleBasicItemVariablePtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xsltStackElemPtr elem;
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Building variable %s", comp->name));
- if (comp->select != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- " select %s", comp->select));
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
-#endif
-
- elem = xsltNewStackElem();
- if (elem == NULL)
- return(NULL);
- elem->comp = (xsltStylePreCompPtr) comp;
- elem->name = comp->name;
- if (comp->select != NULL)
- elem->select = comp->select;
- else
- elem->select = NULL;
- if (comp->ns)
- elem->nameURI = comp->ns;
- elem->tree = tree;
- if (elem->computed == 0) {
- elem->value = xsltEvalVariable(ctxt, elem,
- (xsltStylePreCompPtr) comp);
- if (elem->value != NULL)
- elem->computed = 1;
- }
- return(elem);
-}
-
-/**
- * xsltRegisterVariable:
- * @ctxt: the XSLT transformation context
- * @comp: pointer to precompiled data
- * @tree: the tree if select is NULL
- * @param: this is a parameter actually
- *
- * Computes and register a new variable value.
- * TODO: Is this intended for xsl:param as well?
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-xsltRegisterVariable(xsltTransformContextPtr ctxt,
- xsltStylePreCompPtr castedComp,
- xmlNodePtr tree, int param)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp =
- (xsltStyleBasicItemVariablePtr) castedComp;
-#else
- xsltStylePreCompPtr comp = castedComp;
-#endif
- xsltStackElemPtr elem;
- int present;
-
- present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
- if (param == 0) {
- if ((present != 0) && (present != 3)) {
- xsltTransformError(ctxt, NULL, comp->inst,
- "xsl:variable : redefining %s\n", comp->name);
- return(0);
- }
- } else if (present != 0) {
- if ((present == 1) || (present == 2)) {
- xsltTransformError(ctxt, NULL, comp->inst,
- "xsl:param : redefining %s\n", comp->name);
- return(0);
- }
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "param %s defined by caller\n", comp->name));
-#endif
- return(0);
- }
- elem = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
- xsltAddStackElem(ctxt, elem);
- return(0);
-}
-
-/**
- * xsltGlobalVariableLookup:
- * @ctxt: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * Search in the Variable array of the context for the given
- * variable value.
- *
- * Returns the value or NULL if not found
- */
-static xmlXPathObjectPtr
-xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltStackElemPtr elem;
- xmlXPathObjectPtr ret = NULL;
-
- /*
- * Lookup the global variables in XPath global variable hash table
- */
- if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
- return(NULL);
- elem = (xsltStackElemPtr)
- xmlHashLookup2(ctxt->globalVars, name, ns_uri);
- if (elem == NULL) {
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "global variable not found %s\n", name));
-#endif
- return(NULL);
- }
- if (elem->computed == 0) {
- if (xmlStrEqual(elem->name, BAD_CAST " being computed ... ")) {
- xsltTransformError(ctxt, NULL, elem->comp->inst,
- "Recursive definition of %s\n", name);
- return(NULL);
- }
- ret = xsltEvalGlobalVariable(elem, ctxt);
- } else
- ret = elem->value;
- return(xmlXPathObjectCopy(ret));
-}
-
-/**
- * xsltVariableLookup:
- * @ctxt: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * Search in the Variable array of the context for the given
- * variable value.
- *
- * Returns the value or NULL if not found
- */
-xmlXPathObjectPtr
-xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltStackElemPtr elem;
-
- if (ctxt == NULL)
- return(NULL);
-
- elem = xsltStackLookup(ctxt, name, ns_uri);
- if (elem == NULL) {
- return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
- }
- if (elem->computed == 0) {
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "uncomputed variable %s\n", name));
-#endif
- elem->value = xsltEvalVariable(ctxt, elem, NULL);
- elem->computed = 1;
- }
- if (elem->value != NULL)
- return(xmlXPathObjectCopy(elem->value));
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "variable not found %s\n", name));
-#endif
- return(NULL);
-}
-
-/**
- * xsltParseStylesheetCallerParam:
- * @ctxt: the XSLT transformation context
- * @cur: the "xsl:with-param" element
- *
- * parse an XSLT transformation param declaration, compute
- * its value but doesn't record it.
- * NOTE that this is also called with an *xsl:param* element
- * from exsltFuncFunctionFunction().
- *
- * Returns the new xsltStackElemPtr or NULL
- */
-
-xsltStackElemPtr
-xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- xmlNodePtr tree = NULL;
- xsltStackElemPtr elem = NULL;
-
- if ((cur == NULL) || (ctxt == NULL))
- return(NULL);
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleBasicItemVariablePtr) cur->psvi;
-#else
- comp = (xsltStylePreCompPtr) cur->psvi;
-#endif
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:with-param : compilation error\n");
- return(NULL);
- }
-
- if (comp->name == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:with-param : missing name attribute\n");
- return(NULL);
- }
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Handling xsl:with-param %s\n", comp->name));
-#endif
-
- if (comp->select == NULL) {
- tree = cur->children;
- } else {
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- " select %s\n", comp->select));
-#endif
- tree = cur;
- }
-
- elem = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
-
- return(elem);
-}
-
-/**
- * xsltParseGlobalVariable:
- * @style: the XSLT stylesheet
- * @cur: the "variable" element
- *
- * parse an XSLT transformation variable declaration and record
- * its value.
- */
-
-void
-xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((cur == NULL) || (style == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- /*
- * Note that xsltStylePreCompute() will be called from
- * xslt.c only.
- */
- comp = (xsltStyleItemVariablePtr) cur->psvi;
-#else
- xsltStylePreCompute(style, cur);
- comp = (xsltStylePreCompPtr) cur->psvi;
-#endif
- if (comp == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:variable : compilation failed\n");
- return;
- }
-
- if (comp->name == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:variable : missing name attribute\n");
- return;
- }
-
- /*
- * Parse the content (a sequence constructor) of xsl:variable.
- */
- if (cur->children != NULL) {
-#ifdef XSLT_REFACTORED
- xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
-#else
- xsltParseTemplateContent(style, cur);
-#endif
- }
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variable %s\n", comp->name);
-#endif
-
- xsltRegisterGlobalVariable(style, comp->name, comp->ns,
- comp->select, cur->children, (xsltStylePreCompPtr) comp,
- NULL);
-}
-
-/**
- * xsltParseGlobalParam:
- * @style: the XSLT stylesheet
- * @cur: the "param" element
- *
- * parse an XSLT transformation param declaration and record
- * its value.
- */
-
-void
-xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((cur == NULL) || (style == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- /*
- * Note that xsltStylePreCompute() will be called from
- * xslt.c only.
- */
- comp = (xsltStyleItemParamPtr) cur->psvi;
-#else
- xsltStylePreCompute(style, cur);
- comp = (xsltStylePreCompPtr) cur->psvi;
-#endif
- if (comp == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:param : compilation failed\n");
- return;
- }
-
- if (comp->name == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:param : missing name attribute\n");
- return;
- }
-
- /*
- * Parse the content (a sequence constructor) of xsl:param.
- */
- if (cur->children != NULL) {
-#ifdef XSLT_REFACTORED
- xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
-#else
- xsltParseTemplateContent(style, cur);
-#endif
- }
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- xsltGenericDebug(xsltGenericDebugContext,
- "Registering global param %s\n", comp->name);
-#endif
-
- xsltRegisterGlobalVariable(style, comp->name, comp->ns,
- comp->select, cur->children, (xsltStylePreCompPtr) comp,
- NULL);
-}
-
-/**
- * xsltParseStylesheetVariable:
- * @ctxt: the XSLT transformation context
- * @cur: the "variable" element
- *
- * parse an XSLT transformation variable declaration and record
- * its value.
- */
-
-void
-xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((cur == NULL) || (ctxt == NULL))
- return;
-
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemVariablePtr) cur->psvi;
-#else
- comp = (xsltStylePreCompPtr) cur->psvi;
-#endif
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:variable : compilation failed\n");
- return;
- }
-
- if (comp->name == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:variable : missing name attribute\n");
- return;
- }
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering variable %s\n", comp->name));
-#endif
-
- xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 0);
-}
-
-/**
- * xsltParseStylesheetParam:
- * @ctxt: the XSLT transformation context
- * @cur: the "param" element
- *
- * parse an XSLT transformation param declaration and record
- * its value.
- */
-
-void
-xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
-{
-#ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
-
- if ((cur == NULL) || (ctxt == NULL))
- return;
-#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemParamPtr) cur->psvi;
-#else
- comp = (xsltStylePreCompPtr) cur->psvi;
-#endif
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:param : compilation failed\n");
- return;
- }
-
- if (comp->name == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "xsl:param : missing name attribute\n");
- return;
- }
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering param %s\n", comp->name));
-#endif
-
- xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
-}
-
-/**
- * xsltFreeGlobalVariables:
- * @ctxt: the XSLT transformation context
- *
- * Free up the data associated to the global variables
- * its value.
- */
-
-void
-xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
- xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
-}
-
-/**
- * xsltXPathVariableLookup:
- * @ctxt: a void * but the the XSLT transformation context actually
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * This is the entry point when a varibale is needed by the XPath
- * interpretor.
- *
- * Returns the value or NULL if not found
- */
-xmlXPathObjectPtr
-xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltTransformContextPtr context;
- xmlXPathObjectPtr ret;
-
- if ((ctxt == NULL) || (name == NULL))
- return(NULL);
-
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Lookup variable %s\n", name));
-#endif
- context = (xsltTransformContextPtr) ctxt;
- ret = xsltVariableLookup(context, name, ns_uri);
- if (ret == NULL) {
- xsltTransformError(ctxt, NULL, NULL,
- "unregistered variable %s\n", name);
- }
-#ifdef WITH_XSLT_DEBUG_VARIABLE
- if (ret != NULL)
- XSLT_TRACE(context,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "found variable %s\n", name));
-#endif
- return(ret);
-}
-
-
+/*\r
+ * variables.c: Implementation of the variable storage and lookup\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/parserInternals.h>\r
+#include <libxml/dict.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "xsltutils.h"\r
+#include "variables.h"\r
+#include "transform.h"\r
+#include "imports.h"\r
+#include "preproc.h"\r
+#include "keys.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+ #define WITH_XSLT_DEBUG_VARIABLE\r
+#endif\r
+\r
+#ifdef XSLT_REFACTORED\r
+const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";\r
+#endif\r
+\r
+const xmlChar *xsltComputingGlobalVarMarker =\r
+ (const xmlChar *) " var/param being computed";\r
+\r
+/************************************************************************\r
+ * *\r
+ * Result Value Tree (Result Tree Fragment) interfaces *\r
+ * *\r
+ ************************************************************************/\r
+/**\r
+ * xsltCreateRVT:\r
+ * @ctxt: an XSLT transformation context\r
+ *\r
+ * Creates a Result Value Tree\r
+ * (the XSLT 1.0 term for this is "Result Tree Fragment") \r
+ *\r
+ * Returns the result value tree or NULL in case of API or internal errors.\r
+ */\r
+xmlDocPtr\r
+xsltCreateRVT(xsltTransformContextPtr ctxt)\r
+{\r
+ xmlDocPtr container;\r
+\r
+ /*\r
+ * Question: Why is this function public?\r
+ * Answer: It is called by the EXSLT module.\r
+ */ \r
+ if (ctxt == NULL)\r
+ return(NULL);\r
+\r
+ /*\r
+ * Reuse a RTF from the cache if available.\r
+ */\r
+ if (ctxt->cache->RVT) {\r
+ container = ctxt->cache->RVT;\r
+ ctxt->cache->RVT = (xmlDocPtr) container->next;\r
+ container->next = NULL;\r
+ if (ctxt->cache->nbRVT > 0)\r
+ ctxt->cache->nbRVT--;\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ ctxt->cache->dbgReusedRVTs++;\r
+#endif\r
+ return(container);\r
+ }\r
+\r
+ container = xmlNewDoc(NULL);\r
+ if (container == NULL)\r
+ return(NULL);\r
+ container->dict = ctxt->dict;\r
+ xmlDictReference(container->dict);\r
+ XSLT_MARK_RES_TREE_FRAG(container);\r
+ container->doc = container;\r
+ container->parent = NULL;\r
+ return(container);\r
+}\r
+\r
+/**\r
+ * xsltRegisterTmpRVT:\r
+ * @ctxt: an XSLT transformation context\r
+ * @RVT: a result value tree (Result Tree Fragment)\r
+ *\r
+ * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)\r
+ * in the garbage collector.\r
+ * The fragment will be freed at the exit of the currently\r
+ * instantiated xsl:template.\r
+ * Obsolete; this function might produce massive memory overhead,\r
+ * since the fragment is only freed when the current xsl:template\r
+ * exits. Use xsltRegisterLocalRVT() instead.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of API or internal errors.\r
+ */\r
+int\r
+xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)\r
+{\r
+ if ((ctxt == NULL) || (RVT == NULL))\r
+ return(-1);\r
+\r
+ /*\r
+ * We'll restrict the lifetime of user-created fragments\r
+ * insinde an xsl:variable and xsl:param to the lifetime of the\r
+ * var/param itself.\r
+ */\r
+ if (ctxt->contextVariable != NULL) {\r
+ RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;\r
+ XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;\r
+ return(0);\r
+ }\r
+\r
+ RVT->next = (xmlNodePtr) ctxt->tmpRVT;\r
+ if (ctxt->tmpRVT != NULL)\r
+ ctxt->tmpRVT->prev = (xmlNodePtr) RVT;\r
+ ctxt->tmpRVT = RVT;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltRegisterLocalRVT:\r
+ * @ctxt: an XSLT transformation context\r
+ * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)\r
+ *\r
+ * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)\r
+ * in the RVT garbage collector.\r
+ * The fragment will be freed when the instruction which created the\r
+ * fragment exits.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of API or internal errors.\r
+ */\r
+int\r
+xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,\r
+ xmlDocPtr RVT)\r
+{\r
+ if ((ctxt == NULL) || (RVT == NULL))\r
+ return(-1);\r
+ \r
+ /*\r
+ * When evaluating "select" expressions of xsl:variable\r
+ * and xsl:param, we need to bind newly created tree fragments\r
+ * to the variable itself; otherwise the tragment will be\r
+ * freed before we leave the scope of a var.\r
+ */\r
+ if ((ctxt->contextVariable != NULL) &&\r
+ (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))\r
+ {\r
+ RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;\r
+ XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;\r
+ return(0);\r
+ }\r
+ /*\r
+ * Store the fragment in the scope of the current instruction.\r
+ * If not reference by a returning instruction (like EXSLT's function),\r
+ * then this fragment will be freed, when the instruction exits.\r
+ */\r
+ RVT->next = (xmlNodePtr) ctxt->localRVT;\r
+ if (ctxt->localRVT != NULL)\r
+ ctxt->localRVT->prev = (xmlNodePtr) RVT;\r
+ ctxt->localRVT = RVT;\r
+ /*\r
+ * We need to keep track of the first registered fragment\r
+ * for extension instructions which return fragments\r
+ * (e.g. EXSLT'S function), in order to let\r
+ * xsltExtensionInstructionResultFinalize() clear the\r
+ * preserving flag on the fragments.\r
+ */\r
+ if (ctxt->localRVTBase == NULL)\r
+ ctxt->localRVTBase = RVT;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltExtensionInstructionResultFinalize:\r
+ * @ctxt: an XSLT transformation context\r
+ *\r
+ * Finalizes the data (e.g. result tree fragments) created\r
+ * within a value-returning process (e.g. EXSLT's function).\r
+ * Tree fragments marked as being returned by a function are\r
+ * set to normal state, which means that the fragment garbage\r
+ * collector will free them after the function-calling process exits.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of API or internal errors.\r
+ */\r
+int\r
+xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)\r
+{\r
+ xmlDocPtr cur;\r
+\r
+ if (ctxt == NULL)\r
+ return(-1);\r
+ if (ctxt->localRVTBase == NULL)\r
+ return(0);\r
+ /*\r
+ * Enable remaining local tree fragments to be freed\r
+ * by the fragment garbage collector.\r
+ */\r
+ cur = ctxt->localRVTBase;\r
+ do {\r
+ cur->psvi = NULL;\r
+ cur = (xmlDocPtr) cur->next;\r
+ } while (cur != NULL);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltExtensionInstructionResultRegister:\r
+ * @ctxt: an XSLT transformation context\r
+ * @nodeSet: a node set to be inspected for result tree fragments\r
+ *\r
+ * Marks the result of a value-returning extension instruction\r
+ * in order to avoid it being garbage collected before the\r
+ * extension instruction exits.\r
+ * Note that one still has to additionally register any newly created\r
+ * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().\r
+ *\r
+ * Returns 0 in case of success and -1 in case of error.\r
+ */\r
+int\r
+xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,\r
+ xmlXPathObjectPtr obj)\r
+{\r
+ int i;\r
+ xmlNodePtr cur;\r
+ xmlDocPtr doc;\r
+\r
+ if ((ctxt == NULL) || (obj == NULL))\r
+ return(-1);\r
+\r
+ /*\r
+ * OPTIMIZE TODO: If no local variables/params and no local tree\r
+ * fragments were created, then we don't need to analyse the XPath\r
+ * objects for tree fragments.\r
+ */\r
+\r
+ if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))\r
+ return(0);\r
+ if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))\r
+ return(0);\r
+\r
+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {\r
+ cur = obj->nodesetval->nodeTab[i];\r
+ if (cur->type == XML_NAMESPACE_DECL) {\r
+ /*\r
+ * The XPath module sets the owner element of a ns-node on\r
+ * the ns->next field.\r
+ */\r
+ if ((((xmlNsPtr) cur)->next != NULL) &&\r
+ (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))\r
+ {\r
+ cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;\r
+ doc = cur->doc; \r
+ } else {\r
+ xsltTransformError(ctxt, NULL, ctxt->inst,\r
+ "Internal error in "\r
+ "xsltExtensionInstructionResultRegister(): "\r
+ "Cannot retrieve the doc of a namespace node.\n");\r
+ goto error;\r
+ }\r
+ } else {\r
+ doc = cur->doc;\r
+ }\r
+ if (doc == NULL) {\r
+ xsltTransformError(ctxt, NULL, ctxt->inst,\r
+ "Internal error in "\r
+ "xsltExtensionInstructionResultRegister(): "\r
+ "Cannot retrieve the doc of a node.\n");\r
+ goto error;\r
+ }\r
+ if (doc->name && (doc->name[0] == ' ')) {\r
+ /*\r
+ * This is a result tree fragment.\r
+ * We'll use the @psvi field for reference counting.\r
+ * TODO: How do we know if this is a value of a\r
+ * global variable or a doc acquired via the\r
+ * document() function?\r
+ */\r
+ doc->psvi = (void *) ((long) 1);\r
+ }\r
+ }\r
+\r
+ return(0);\r
+error:\r
+ return(-1);\r
+}\r
+\r
+/**\r
+ * xsltReleaseRVT:\r
+ * @ctxt: an XSLT transformation context\r
+ * @RVT: a result value tree (Result Tree Fragment)\r
+ *\r
+ * Either frees the RVT (which is an xmlDoc) or stores\r
+ * it in the context's cache for later reuse.\r
+ */\r
+void\r
+xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)\r
+{\r
+ if (RVT == NULL)\r
+ return;\r
+\r
+ if (ctxt && (ctxt->cache->nbRVT < 40)) {\r
+ /*\r
+ * Store the Result Tree Fragment.\r
+ * Free the document info.\r
+ */\r
+ if (RVT->_private != NULL) {\r
+ xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);\r
+ xmlFree(RVT->_private);\r
+ RVT->_private = NULL;\r
+ }\r
+ /*\r
+ * Clear the document tree.\r
+ * REVISIT TODO: Do we expect ID/IDREF tables to be existent? \r
+ */\r
+ if (RVT->children != NULL) {\r
+ xmlFreeNodeList(RVT->children);\r
+ RVT->children = NULL;\r
+ RVT->last = NULL;\r
+ }\r
+ if (RVT->ids != NULL) {\r
+ xmlFreeIDTable((xmlIDTablePtr) RVT->ids);\r
+ RVT->ids = NULL;\r
+ }\r
+ if (RVT->refs != NULL) {\r
+ xmlFreeRefTable((xmlRefTablePtr) RVT->refs);\r
+ RVT->refs = NULL;\r
+ }\r
+\r
+ /*\r
+ * Reset the reference counter.\r
+ */\r
+ RVT->psvi = 0;\r
+\r
+ RVT->next = (xmlNodePtr) ctxt->cache->RVT;\r
+ ctxt->cache->RVT = RVT;\r
+\r
+ ctxt->cache->nbRVT++;\r
+\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ ctxt->cache->dbgCachedRVTs++;\r
+#endif\r
+ return;\r
+ }\r
+ /*\r
+ * Free it.\r
+ */\r
+ if (RVT->_private != NULL) {\r
+ xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);\r
+ xmlFree(RVT->_private);\r
+ }\r
+ xmlFreeDoc(RVT);\r
+}\r
+\r
+/**\r
+ * xsltRegisterPersistRVT:\r
+ * @ctxt: an XSLT transformation context\r
+ * @RVT: a result value tree (Result Tree Fragment)\r
+ *\r
+ * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)\r
+ * in the fragment garbage collector.\r
+ * The fragment will be freed when the transformation context is\r
+ * freed.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of error.\r
+ */\r
+int\r
+xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)\r
+{\r
+ if ((ctxt == NULL) || (RVT == NULL)) return(-1);\r
+\r
+ RVT->next = (xmlNodePtr) ctxt->persistRVT;\r
+ if (ctxt->persistRVT != NULL)\r
+ ctxt->persistRVT->prev = (xmlNodePtr) RVT;\r
+ ctxt->persistRVT = RVT;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltFreeRVTs:\r
+ * @ctxt: an XSLT transformation context\r
+ *\r
+ * Frees all registered result value trees (Result Tree Fragments)\r
+ * of the transformation. Internal function; should not be called\r
+ * by user-code.\r
+ */\r
+void\r
+xsltFreeRVTs(xsltTransformContextPtr ctxt)\r
+{\r
+ xmlDocPtr cur, next;\r
+\r
+ if (ctxt == NULL)\r
+ return;\r
+ /*\r
+ * Local fragments.\r
+ */\r
+ cur = ctxt->localRVT;\r
+ while (cur != NULL) {\r
+ next = (xmlDocPtr) cur->next;\r
+ if (cur->_private != NULL) {\r
+ xsltFreeDocumentKeys(cur->_private);\r
+ xmlFree(cur->_private);\r
+ }\r
+ xmlFreeDoc(cur);\r
+ cur = next;\r
+ }\r
+ ctxt->localRVT = NULL;\r
+ /*\r
+ * User-created per-template fragments.\r
+ */\r
+ cur = ctxt->tmpRVT;\r
+ while (cur != NULL) {\r
+ next = (xmlDocPtr) cur->next;\r
+ if (cur->_private != NULL) {\r
+ xsltFreeDocumentKeys(cur->_private);\r
+ xmlFree(cur->_private);\r
+ }\r
+ xmlFreeDoc(cur);\r
+ cur = next;\r
+ }\r
+ ctxt->tmpRVT = NULL;\r
+ /*\r
+ * Global fragments.\r
+ */\r
+ cur = ctxt->persistRVT;\r
+ while (cur != NULL) {\r
+ next = (xmlDocPtr) cur->next;\r
+ if (cur->_private != NULL) {\r
+ xsltFreeDocumentKeys(cur->_private);\r
+ xmlFree(cur->_private);\r
+ }\r
+ xmlFreeDoc(cur);\r
+ cur = next;\r
+ }\r
+ ctxt->persistRVT = NULL;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltNewStackElem:\r
+ *\r
+ * Create a new XSLT ParserContext\r
+ *\r
+ * Returns the newly allocated xsltParserStackElem or NULL in case of error\r
+ */\r
+static xsltStackElemPtr\r
+xsltNewStackElem(xsltTransformContextPtr ctxt)\r
+{\r
+ xsltStackElemPtr ret;\r
+ /*\r
+ * Reuse a stack item from the cache if available.\r
+ */\r
+ if (ctxt && ctxt->cache->stackItems) {\r
+ ret = ctxt->cache->stackItems;\r
+ ctxt->cache->stackItems = ret->next;\r
+ ret->next = NULL;\r
+ ctxt->cache->nbStackItems--;\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ ctxt->cache->dbgReusedVars++;\r
+#endif\r
+ return(ret);\r
+ }\r
+ ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewStackElem : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltStackElem));\r
+ ret->context = ctxt;\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltCopyStackElem:\r
+ * @elem: an XSLT stack element\r
+ *\r
+ * Makes a copy of the stack element\r
+ *\r
+ * Returns the copy of NULL\r
+ */\r
+static xsltStackElemPtr\r
+xsltCopyStackElem(xsltStackElemPtr elem) {\r
+ xsltStackElemPtr cur;\r
+\r
+ cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltCopyStackElem : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltStackElem));\r
+ cur->context = elem->context;\r
+ cur->name = elem->name;\r
+ cur->nameURI = elem->nameURI;\r
+ cur->select = elem->select;\r
+ cur->tree = elem->tree;\r
+ cur->comp = elem->comp; \r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeStackElem:\r
+ * @elem: an XSLT stack element\r
+ *\r
+ * Free up the memory allocated by @elem\r
+ */\r
+static void\r
+xsltFreeStackElem(xsltStackElemPtr elem) {\r
+ if (elem == NULL)\r
+ return;\r
+ if (elem->value != NULL)\r
+ xmlXPathFreeObject(elem->value);\r
+ /*\r
+ * Release the list of temporary Result Tree Fragments.\r
+ */\r
+ if (elem->fragment) {\r
+ xmlDocPtr cur;\r
+\r
+ while (elem->fragment != NULL) {\r
+ cur = elem->fragment;\r
+ elem->fragment = (xmlDocPtr) cur->next;\r
+\r
+ if (elem->context &&\r
+ (cur->psvi == (void *) ((long) 1)))\r
+ {\r
+ /*\r
+ * This fragment is a result of an extension instruction\r
+ * (e.g. XSLT's function) and needs to be preserved until\r
+ * the instruction exits.\r
+ * Example: The fragment of the variable must not be freed\r
+ * since it is returned by the EXSLT function:\r
+ * <f:function name="foo">\r
+ * <xsl:variable name="bar">\r
+ * <bar/>\r
+ * </xsl:variable>\r
+ * <f:result select="$bar"/>\r
+ * </f:function>\r
+ * \r
+ */\r
+ xsltRegisterLocalRVT(elem->context, cur);\r
+ } else {\r
+ xsltReleaseRVT((xsltTransformContextPtr) elem->context,\r
+ cur);\r
+ } \r
+ }\r
+ }\r
+ /*\r
+ * Cache or free the variable structure.\r
+ */\r
+ if (elem->context && (elem->context->cache->nbStackItems < 50)) {\r
+ /*\r
+ * Store the item in the cache.\r
+ */\r
+ xsltTransformContextPtr ctxt = elem->context;\r
+ memset(elem, 0, sizeof(xsltStackElem));\r
+ elem->context = ctxt;\r
+ elem->next = ctxt->cache->stackItems;\r
+ ctxt->cache->stackItems = elem; \r
+ ctxt->cache->nbStackItems++;\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ ctxt->cache->dbgCachedVars++;\r
+#endif\r
+ return;\r
+ }\r
+ xmlFree(elem);\r
+}\r
+\r
+/**\r
+ * xsltFreeStackElemList:\r
+ * @elem: an XSLT stack element\r
+ *\r
+ * Free up the memory allocated by @elem\r
+ */\r
+void\r
+xsltFreeStackElemList(xsltStackElemPtr elem) {\r
+ xsltStackElemPtr next;\r
+ \r
+ while (elem != NULL) {\r
+ next = elem->next;\r
+ xsltFreeStackElem(elem);\r
+ elem = next;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltStackLookup:\r
+ * @ctxt: an XSLT transformation context\r
+ * @name: the local part of the name\r
+ * @nameURI: the URI part of the name\r
+ *\r
+ * Locate an element in the stack based on its name.\r
+ */\r
+#if 0 /* TODO: Those seem to have been used for debugging. */\r
+static int stack_addr = 0;\r
+static int stack_cmp = 0;\r
+#endif\r
+\r
+static xsltStackElemPtr\r
+xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,\r
+ const xmlChar *nameURI) {\r
+ int i;\r
+ xsltStackElemPtr cur;\r
+\r
+ if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))\r
+ return(NULL);\r
+\r
+ /*\r
+ * Do the lookup from the top of the stack, but\r
+ * don't use params being computed in a call-param\r
+ * First lookup expects the variable name and URI to\r
+ * come from the disctionnary and hence pointer comparison.\r
+ */\r
+ for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {\r
+ cur = ctxt->varsTab[i-1];\r
+ while (cur != NULL) {\r
+ if ((cur->name == name) && (cur->nameURI == nameURI)) {\r
+#if 0\r
+ stack_addr++;\r
+#endif\r
+ return(cur);\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Redo the lookup with interned string compares\r
+ * to avoid string compares.\r
+ */\r
+ name = xmlDictLookup(ctxt->dict, name, -1);\r
+ if (nameURI != NULL)\r
+ nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);\r
+\r
+ for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {\r
+ cur = ctxt->varsTab[i-1];\r
+ while (cur != NULL) {\r
+ if ((cur->name == name) && (cur->nameURI == nameURI)) {\r
+#if 0\r
+ stack_cmp++;\r
+#endif\r
+ return(cur);\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ }\r
+\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltCheckStackElem:\r
+ * @ctxt: xn XSLT transformation context\r
+ * @name: the variable name\r
+ * @nameURI: the variable namespace URI\r
+ *\r
+ * Checks whether a variable or param is already defined.\r
+ *\r
+ * URGENT TODO: Checks for redefinition of vars/params should be\r
+ * done only at compilation time.\r
+ *\r
+ * Returns 1 if variable is present, 2 if param is present, 3 if this\r
+ * is an inherited param, 0 if not found, -1 in case of failure.\r
+ */\r
+static int\r
+xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,\r
+ const xmlChar *nameURI) {\r
+ xsltStackElemPtr cur;\r
+\r
+ if ((ctxt == NULL) || (name == NULL))\r
+ return(-1);\r
+\r
+ cur = xsltStackLookup(ctxt, name, nameURI);\r
+ if (cur == NULL)\r
+ return(0);\r
+ if (cur->comp != NULL) {\r
+ if (cur->comp->type == XSLT_FUNC_WITHPARAM)\r
+ return(3);\r
+ else if (cur->comp->type == XSLT_FUNC_PARAM)\r
+ return(2);\r
+ }\r
+ \r
+ return(1);\r
+}\r
+\r
+/**\r
+ * xsltAddStackElem:\r
+ * @ctxt: xn XSLT transformation context\r
+ * @elem: a stack element\r
+ *\r
+ * Push an element (or list) onto the stack.\r
+ * In case of a list, each member will be pushed into\r
+ * a seperate slot; i.e. there's always 1 stack entry for\r
+ * 1 stack element.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of failure.\r
+ */\r
+static int\r
+xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)\r
+{\r
+ if ((ctxt == NULL) || (elem == NULL))\r
+ return(-1);\r
+\r
+ do {\r
+ if (ctxt->varsMax == 0) {\r
+ ctxt->varsMax = 10;\r
+ ctxt->varsTab =\r
+ (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *\r
+ sizeof(ctxt->varsTab[0]));\r
+ if (ctxt->varsTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");\r
+ return (-1);\r
+ }\r
+ }\r
+ if (ctxt->varsNr >= ctxt->varsMax) {\r
+ ctxt->varsMax *= 2;\r
+ ctxt->varsTab =\r
+ (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,\r
+ ctxt->varsMax *\r
+ sizeof(ctxt->varsTab[0]));\r
+ if (ctxt->varsTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");\r
+ return (-1);\r
+ }\r
+ }\r
+ ctxt->varsTab[ctxt->varsNr++] = elem;\r
+ ctxt->vars = elem;\r
+ \r
+ elem = elem->next;\r
+ } while (elem != NULL);\r
+ \r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltAddStackElemList:\r
+ * @ctxt: xn XSLT transformation context\r
+ * @elems: a stack element list\r
+ *\r
+ * Push an element list onto the stack.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of failure.\r
+ */\r
+int\r
+xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)\r
+{\r
+ return(xsltAddStackElem(ctxt, elems));\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Module interfaces *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltEvalVariable:\r
+ * @ctxt: the XSLT transformation context\r
+ * @variable: the variable or parameter item\r
+ * @comp: the compiled XSLT instruction\r
+ *\r
+ * Evaluate a variable value.\r
+ *\r
+ * Returns the XPath Object value or NULL in case of error\r
+ */\r
+static xmlXPathObjectPtr\r
+xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,\r
+ xsltStylePreCompPtr castedComp)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemVariablePtr comp =\r
+ (xsltStyleItemVariablePtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif \r
+ xmlXPathObjectPtr result = NULL;\r
+ xmlNodePtr oldInst;\r
+\r
+ if ((ctxt == NULL) || (variable == NULL))\r
+ return(NULL);\r
+\r
+ /*\r
+ * A variable or parameter are evaluated on demand; thus the\r
+ * context (of XSLT and XPath) need to be temporarily adjusted and\r
+ * restored on exit.\r
+ */\r
+ oldInst = ctxt->inst;\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Evaluating variable '%s'\n", variable->name));\r
+#endif\r
+ if (variable->select != NULL) {\r
+ xmlXPathCompExprPtr xpExpr = NULL;\r
+ xmlDocPtr oldXPDoc;\r
+ xmlNodePtr oldXPContextNode;\r
+ int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;\r
+ xmlNsPtr *oldXPNamespaces;\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;\r
+ xsltStackElemPtr oldVar = ctxt->contextVariable;\r
+\r
+ if ((comp != NULL) && (comp->comp != NULL)) {\r
+ xpExpr = comp->comp;\r
+ } else {\r
+ xpExpr = xmlXPathCompile(variable->select);\r
+ }\r
+ if (xpExpr == NULL)\r
+ return(NULL);\r
+ /*\r
+ * Save context states.\r
+ */\r
+ oldXPDoc = xpctxt->doc;\r
+ oldXPContextNode = xpctxt->node;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ \r
+ xpctxt->node = ctxt->node;\r
+ /*\r
+ * OPTIMIZE TODO: Lame try to set the context doc.\r
+ * Get rid of this somehow in xpath.c.\r
+ */\r
+ if ((ctxt->node->type != XML_NAMESPACE_DECL) &&\r
+ ctxt->node->doc)\r
+ xpctxt->doc = ctxt->node->doc;\r
+ /*\r
+ * BUG TODO: The proximity position and the context size will\r
+ * potentially be wrong.\r
+ * Example: \r
+ * <xsl:template select="foo">\r
+ * <xsl:variable name="pos" select="position()"/>\r
+ * <xsl:for-each select="bar">\r
+ * <xsl:value-of select="$pos"/>\r
+ * </xsl:for-each>\r
+ * </xsl:template>\r
+ * Here the proximity position and context size are changed\r
+ * to the context of <xsl:for-each select="bar">, but\r
+ * the variable needs to be evaluated in the context of\r
+ * <xsl:template select="foo">.\r
+ */ \r
+ if (comp != NULL) {\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+\r
+ /*\r
+ * We need to mark that we are "selecting" a var's value;\r
+ * if any tree fragments are created inside the expression,\r
+ * then those need to be stored inside the variable; otherwise\r
+ * we'll eventually free still referenced fragments, before\r
+ * we leave the scope of the variable.\r
+ */\r
+ ctxt->contextVariable = variable; \r
+ variable->flags |= XSLT_VAR_IN_SELECT; \r
+ \r
+ result = xmlXPathCompiledEval(xpExpr, xpctxt);\r
+\r
+ variable->flags ^= XSLT_VAR_IN_SELECT;\r
+ /*\r
+ * Restore Context states.\r
+ */\r
+ ctxt->contextVariable = oldVar;\r
+\r
+ xpctxt->doc = oldXPDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ xpctxt->nsNr = oldXPNsNr;\r
+\r
+ if ((comp == NULL) || (comp->comp == NULL))\r
+ xmlXPathFreeCompExpr(xpExpr);\r
+ if (result == NULL) {\r
+ xsltTransformError(ctxt, NULL,\r
+ (comp != NULL) ? comp->inst : NULL,\r
+ "Failed to evaluate the expression of variable '%s'.\n",\r
+ variable->name);\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+ } else {\r
+ if ((xsltGenericDebugContext == stdout) ||\r
+ (xsltGenericDebugContext == stderr))\r
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,\r
+ result, 0);\r
+#endif\r
+#endif\r
+ }\r
+ } else {\r
+ if (variable->tree == NULL) {\r
+ result = xmlXPathNewCString("");\r
+ } else { \r
+ if (variable->tree) {\r
+ xmlDocPtr container;\r
+ xmlNodePtr oldInsert;\r
+ xmlDocPtr oldOutput;\r
+ xsltStackElemPtr oldVar = ctxt->contextVariable;\r
+\r
+ /*\r
+ * Generate a result tree fragment.\r
+ */\r
+ container = xsltCreateRVT(ctxt);\r
+ if (container == NULL)\r
+ goto error;\r
+ /*\r
+ * NOTE: Local Result Tree Fragments of params/variables\r
+ * are not registered globally anymore; the life-time\r
+ * is not directly dependant of the param/variable itself.\r
+ *\r
+ * OLD: xsltRegisterTmpRVT(ctxt, container);\r
+ */\r
+ /*\r
+ * Attach the Result Tree Fragment to the variable;\r
+ * when the variable is freed, it will also free \r
+ * the Result Tree Fragment.\r
+ */\r
+ variable->fragment = container;\r
+ \r
+ oldOutput = ctxt->output;\r
+ oldInsert = ctxt->insert; \r
+ \r
+ ctxt->output = container;\r
+ ctxt->insert = (xmlNodePtr) container;\r
+ ctxt->contextVariable = variable;\r
+ /*\r
+ * Process the sequence constructor (variable->tree).\r
+ * The resulting tree will be held by @container.\r
+ */\r
+ xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,\r
+ NULL, NULL);\r
+\r
+ ctxt->contextVariable = oldVar; \r
+ ctxt->insert = oldInsert;\r
+ ctxt->output = oldOutput;\r
+ \r
+ result = xmlXPathNewValueTree((xmlNodePtr) container);\r
+ }\r
+ if (result == NULL) {\r
+ result = xmlXPathNewCString("");\r
+ } else {\r
+ /*\r
+ * Freeing is not handled there anymore.\r
+ * QUESTION TODO: What does the above comment mean?\r
+ */\r
+ result->boolval = 0; \r
+ }\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+\r
+ if ((xsltGenericDebugContext == stdout) ||\r
+ (xsltGenericDebugContext == stderr))\r
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,\r
+ result, 0);\r
+#endif\r
+#endif\r
+ }\r
+ }\r
+\r
+error:\r
+ ctxt->inst = oldInst;\r
+ return(result);\r
+}\r
+\r
+/**\r
+ * xsltEvalGlobalVariable:\r
+ * @elem: the variable or parameter\r
+ * @ctxt: the XSLT transformation context\r
+ *\r
+ * Evaluates a the value of a global xsl:variable or\r
+ * xsl:param declaration.\r
+ *\r
+ * Returns the XPath Object value or NULL in case of error\r
+ */\r
+static xmlXPathObjectPtr\r
+xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)\r
+{\r
+ xmlXPathObjectPtr result = NULL;\r
+ xmlNodePtr oldInst;\r
+ const xmlChar* oldVarName;\r
+\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleBasicItemVariablePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((ctxt == NULL) || (elem == NULL))\r
+ return(NULL);\r
+ if (elem->computed)\r
+ return(elem->value);\r
+\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Evaluating global variable %s\n", elem->name));\r
+#endif\r
+\r
+#ifdef WITH_DEBUGGER\r
+ if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&\r
+ elem->comp && elem->comp->inst)\r
+ xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);\r
+#endif\r
+\r
+ oldInst = ctxt->inst;\r
+ comp = elem->comp;\r
+ oldVarName = elem->name;\r
+ elem->name = xsltComputingGlobalVarMarker;\r
+ /*\r
+ * OPTIMIZE TODO: We should consider instantiating global vars/params\r
+ * on-demand. The vars/params don't need to be evaluated if never\r
+ * called; and in the case of global params, if values for such params\r
+ * are provided by the user.\r
+ */\r
+ if (elem->select != NULL) { \r
+ xmlXPathCompExprPtr xpExpr = NULL;\r
+ xmlDocPtr oldXPDoc;\r
+ xmlNodePtr oldXPContextNode;\r
+ int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;\r
+ xmlNsPtr *oldXPNamespaces;\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;\r
+\r
+ if ((comp != NULL) && (comp->comp != NULL)) {\r
+ xpExpr = comp->comp;\r
+ } else {\r
+ xpExpr = xmlXPathCompile(elem->select);\r
+ }\r
+ if (xpExpr == NULL)\r
+ goto error;\r
+ \r
+ \r
+ if (comp != NULL)\r
+ ctxt->inst = comp->inst;\r
+ else\r
+ ctxt->inst = NULL;\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "At top-level, the expression or template specifying the\r
+ * variable value is evaluated with the same context as that used\r
+ * to process the root node of the source document: the current\r
+ * node is the root node of the source document and the current\r
+ * node list is a list containing just the root node of the source\r
+ * document." \r
+ */\r
+ /*\r
+ * Save context states.\r
+ */\r
+ oldXPDoc = xpctxt->doc;\r
+ oldXPContextNode = xpctxt->node;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ \r
+ xpctxt->node = ctxt->initialContextNode;\r
+ xpctxt->doc = ctxt->initialContextDoc;\r
+ xpctxt->contextSize = 1;\r
+ xpctxt->proximityPosition = 1;\r
+ \r
+ if (comp != NULL) {\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ xpctxt->namespaces = comp->inScopeNs->list;\r
+ xpctxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+#else\r
+ xpctxt->namespaces = comp->nsList;\r
+ xpctxt->nsNr = comp->nsNr;\r
+#endif\r
+ } else {\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0;\r
+ }\r
+ \r
+ result = xmlXPathCompiledEval(xpExpr, xpctxt);\r
+\r
+ /*\r
+ * Restore Context states.\r
+ */\r
+ xpctxt->doc = oldXPDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ xpctxt->nsNr = oldXPNsNr;\r
+\r
+ if ((comp == NULL) || (comp->comp == NULL))\r
+ xmlXPathFreeCompExpr(xpExpr);\r
+ if (result == NULL) {\r
+ if (comp == NULL)\r
+ xsltTransformError(ctxt, NULL, NULL,\r
+ "Evaluating global variable %s failed\n", elem->name);\r
+ else\r
+ xsltTransformError(ctxt, NULL, comp->inst,\r
+ "Evaluating global variable %s failed\n", elem->name);\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+ } else {\r
+ if ((xsltGenericDebugContext == stdout) ||\r
+ (xsltGenericDebugContext == stderr))\r
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,\r
+ result, 0);\r
+#endif\r
+#endif\r
+ }\r
+ } else {\r
+ if (elem->tree == NULL) {\r
+ result = xmlXPathNewCString("");\r
+ } else {\r
+ xmlDocPtr container;\r
+ xmlNodePtr oldInsert;\r
+ xmlDocPtr oldOutput, oldXPDoc; \r
+ /*\r
+ * Generate a result tree fragment.\r
+ */\r
+ container = xsltCreateRVT(ctxt);\r
+ if (container == NULL)\r
+ goto error;\r
+ /*\r
+ * Let the lifetime of the tree fragment be handled by\r
+ * the Libxslt's garbage collector.\r
+ */\r
+ xsltRegisterPersistRVT(ctxt, container); \r
+\r
+ oldOutput = ctxt->output;\r
+ oldInsert = ctxt->insert;\r
+\r
+ oldXPDoc = ctxt->xpathCtxt->doc;\r
+ \r
+ ctxt->output = container; \r
+ ctxt->insert = (xmlNodePtr) container;\r
+\r
+ ctxt->xpathCtxt->doc = ctxt->initialContextDoc;\r
+ /*\r
+ * Process the sequence constructor.\r
+ */\r
+ xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);\r
+\r
+ ctxt->xpathCtxt->doc = oldXPDoc;\r
+\r
+ ctxt->insert = oldInsert;\r
+ ctxt->output = oldOutput;\r
+ \r
+ result = xmlXPathNewValueTree((xmlNodePtr) container);\r
+ if (result == NULL) {\r
+ result = xmlXPathNewCString("");\r
+ } else {\r
+ result->boolval = 0; /* Freeing is not handled there anymore */\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+ if ((xsltGenericDebugContext == stdout) ||\r
+ (xsltGenericDebugContext == stderr))\r
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,\r
+ result, 0);\r
+#endif\r
+#endif\r
+ }\r
+ }\r
+\r
+error:\r
+ elem->name = oldVarName;\r
+ ctxt->inst = oldInst;\r
+ if (result != NULL) {\r
+ elem->value = result;\r
+ elem->computed = 1;\r
+ }\r
+ return(result);\r
+}\r
+\r
+/**\r
+ * xsltEvalGlobalVariables:\r
+ * @ctxt: the XSLT transformation context\r
+ *\r
+ * Evaluates all global variables and parameters of a stylesheet.\r
+ * For internal use only. This is called at start of a transformation.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error\r
+ */\r
+int\r
+xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {\r
+ xsltStackElemPtr elem;\r
+ xsltStylesheetPtr style; \r
+\r
+ if ((ctxt == NULL) || (ctxt->document == NULL))\r
+ return(-1);\r
+ \r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering global variables\n"));\r
+#endif\r
+ /*\r
+ * Walk the list from the stylesheets and populate the hash table\r
+ */\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ elem = style->variables;\r
+ \r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ if ((style->doc != NULL) && (style->doc->URL != NULL)) {\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering global variables from %s\n",\r
+ style->doc->URL));\r
+ }\r
+#endif\r
+\r
+ while (elem != NULL) {\r
+ xsltStackElemPtr def;\r
+\r
+ /*\r
+ * Global variables are stored in the variables pool.\r
+ */\r
+ def = (xsltStackElemPtr) \r
+ xmlHashLookup2(ctxt->globalVars,\r
+ elem->name, elem->nameURI);\r
+ if (def == NULL) {\r
+\r
+ def = xsltCopyStackElem(elem);\r
+ xmlHashAddEntry2(ctxt->globalVars,\r
+ elem->name, elem->nameURI, def);\r
+ } else if ((elem->comp != NULL) &&\r
+ (elem->comp->type == XSLT_FUNC_VARIABLE)) {\r
+ /*\r
+ * Redefinition of variables from a different stylesheet\r
+ * should not generate a message.\r
+ */\r
+ if ((elem->comp->inst != NULL) &&\r
+ (def->comp != NULL) && (def->comp->inst != NULL) &&\r
+ (elem->comp->inst->doc == def->comp->inst->doc))\r
+ {\r
+ xsltTransformError(ctxt, style, elem->comp->inst,\r
+ "Global variable %s already defined\n", elem->name);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ }\r
+ elem = elem->next;\r
+ }\r
+\r
+ style = xsltNextImport(style);\r
+ }\r
+\r
+ /*\r
+ * This part does the actual evaluation\r
+ */ \r
+ xmlHashScan(ctxt->globalVars,\r
+ (xmlHashScanner) xsltEvalGlobalVariable, ctxt);\r
+\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltRegisterGlobalVariable:\r
+ * @style: the XSLT transformation context\r
+ * @name: the variable name\r
+ * @ns_uri: the variable namespace URI\r
+ * @sel: the expression which need to be evaluated to generate a value\r
+ * @tree: the subtree if sel is NULL\r
+ * @comp: the precompiled value\r
+ * @value: the string value if available\r
+ *\r
+ * Register a new variable value. If @value is NULL it unregisters\r
+ * the variable\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error\r
+ */\r
+static int\r
+xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,\r
+ const xmlChar *ns_uri, const xmlChar *sel,\r
+ xmlNodePtr tree, xsltStylePreCompPtr comp,\r
+ const xmlChar *value) {\r
+ xsltStackElemPtr elem, tmp;\r
+ if (style == NULL)\r
+ return(-1);\r
+ if (name == NULL)\r
+ return(-1);\r
+ if (comp == NULL)\r
+ return(-1);\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ if (comp->type == XSLT_FUNC_PARAM)\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Defining global param %s\n", name);\r
+ else\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Defining global variable %s\n", name);\r
+#endif\r
+\r
+ elem = xsltNewStackElem(NULL);\r
+ if (elem == NULL)\r
+ return(-1);\r
+ elem->comp = comp;\r
+ elem->name = xmlDictLookup(style->dict, name, -1);\r
+ elem->select = xmlDictLookup(style->dict, sel, -1);\r
+ if (ns_uri)\r
+ elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);\r
+ elem->tree = tree;\r
+ tmp = style->variables;\r
+ if (tmp == NULL) {\r
+ elem->next = NULL;\r
+ style->variables = elem;\r
+ } else {\r
+ while (tmp != NULL) {\r
+ if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&\r
+ (tmp->comp->type == XSLT_FUNC_VARIABLE) &&\r
+ (xmlStrEqual(elem->name, tmp->name)) &&\r
+ ((elem->nameURI == tmp->nameURI) ||\r
+ (xmlStrEqual(elem->nameURI, tmp->nameURI))))\r
+ {\r
+ xsltTransformError(NULL, style, comp->inst,\r
+ "redefinition of global variable %s\n", elem->name);\r
+ style->errors++;\r
+ }\r
+ if (tmp->next == NULL)\r
+ break;\r
+ tmp = tmp->next;\r
+ }\r
+ elem->next = NULL;\r
+ tmp->next = elem;\r
+ }\r
+ if (value != NULL) {\r
+ elem->computed = 1;\r
+ elem->value = xmlXPathNewString(value);\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltProcessUserParamInternal\r
+ *\r
+ * @ctxt: the XSLT transformation context\r
+ * @name: a null terminated parameter name\r
+ * @value: a null terminated value (may be an XPath expression)\r
+ * @eval: 0 to treat the value literally, else evaluate as XPath expression\r
+ *\r
+ * If @eval is 0 then @value is treated literally and is stored in the global\r
+ * parameter/variable table without any change.\r
+ *\r
+ * Uf @eval is 1 then @value is treated as an XPath expression and is\r
+ * evaluated. In this case, if you want to pass a string which will be\r
+ * interpreted literally then it must be enclosed in single or double quotes.\r
+ * If the string contains single quotes (double quotes) then it cannot be\r
+ * enclosed single quotes (double quotes). If the string which you want to\r
+ * be treated literally contains both single and double quotes (e.g. Meet\r
+ * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable\r
+ * quoting character. You cannot use ' or " inside the string\r
+ * because the replacement of character entities with their equivalents is\r
+ * done at a different stage of processing. The solution is to call\r
+ * xsltQuoteUserParams or xsltQuoteOneUserParam.\r
+ *\r
+ * This needs to be done on parsed stylesheets before starting to apply\r
+ * transformations. Normally this will be called (directly or indirectly)\r
+ * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,\r
+ * or xsltQuoteOneUserParam.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error\r
+ */\r
+\r
+static\r
+int\r
+xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,\r
+ const xmlChar * name,\r
+ const xmlChar * value,\r
+ int eval) {\r
+\r
+ xsltStylesheetPtr style;\r
+ const xmlChar *prefix;\r
+ const xmlChar *href;\r
+ xmlXPathCompExprPtr xpExpr;\r
+ xmlXPathObjectPtr result;\r
+ \r
+ xsltStackElemPtr elem;\r
+ int res;\r
+ void *res_ptr;\r
+\r
+ if (ctxt == NULL)\r
+ return(-1);\r
+ if (name == NULL)\r
+ return(0);\r
+ if (value == NULL)\r
+ return(0);\r
+\r
+ style = ctxt->style;\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Evaluating user parameter %s=%s\n", name, value));\r
+#endif\r
+\r
+ /*\r
+ * Name lookup\r
+ */\r
+\r
+ name = xsltSplitQName(ctxt->dict, name, &prefix);\r
+ href = NULL;\r
+ if (prefix != NULL) {\r
+ xmlNsPtr ns;\r
+\r
+ ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),\r
+ prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(ctxt, style, NULL,\r
+ "user param : no namespace bound to prefix %s\n", prefix);\r
+ href = NULL;\r
+ } else {\r
+ href = ns->href;\r
+ }\r
+ }\r
+\r
+ if (name == NULL)\r
+ return (-1);\r
+\r
+ res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);\r
+ if (res_ptr != 0) {\r
+ xsltTransformError(ctxt, style, NULL,\r
+ "Global parameter %s already defined\n", name);\r
+ }\r
+ if (ctxt->globalVars == NULL)\r
+ ctxt->globalVars = xmlHashCreate(20);\r
+\r
+ /*\r
+ * do not overwrite variables with parameters from the command line\r
+ */\r
+ while (style != NULL) {\r
+ elem = ctxt->style->variables;\r
+ while (elem != NULL) {\r
+ if ((elem->comp != NULL) &&\r
+ (elem->comp->type == XSLT_FUNC_VARIABLE) &&\r
+ (xmlStrEqual(elem->name, name)) &&\r
+ (xmlStrEqual(elem->nameURI, href))) {\r
+ return(0);\r
+ }\r
+ elem = elem->next;\r
+ }\r
+ style = xsltNextImport(style);\r
+ }\r
+ style = ctxt->style;\r
+ elem = NULL;\r
+\r
+ /*\r
+ * Do the evaluation if @eval is non-zero.\r
+ */\r
+\r
+ result = NULL;\r
+ if (eval != 0) {\r
+ xpExpr = xmlXPathCompile(value);\r
+ if (xpExpr != NULL) {\r
+ xmlDocPtr oldXPDoc;\r
+ xmlNodePtr oldXPContextNode;\r
+ int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;\r
+ xmlNsPtr *oldXPNamespaces;\r
+ xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;\r
+ /*\r
+ * SPEC XSLT 1.0:\r
+ * "At top-level, the expression or template specifying the\r
+ * variable value is evaluated with the same context as that used\r
+ * to process the root node of the source document: the current\r
+ * node is the root node of the source document and the current\r
+ * node list is a list containing just the root node of the source\r
+ * document."\r
+ */\r
+ xpctxt->doc = ctxt->tmpDoc;\r
+ /*\r
+ * Save context states.\r
+ */\r
+ oldXPDoc = xpctxt->doc;\r
+ oldXPContextNode = xpctxt->node;\r
+ oldXPProximityPosition = xpctxt->proximityPosition;\r
+ oldXPContextSize = xpctxt->contextSize;\r
+ oldXPNamespaces = xpctxt->namespaces;\r
+ oldXPNsNr = xpctxt->nsNr;\r
+ \r
+ xpctxt->node = ctxt->initialContextNode;\r
+ xpctxt->doc = ctxt->initialContextDoc;\r
+ xpctxt->contextSize = 1;\r
+ xpctxt->proximityPosition = 1;\r
+ /* \r
+ * There is really no in scope namespace for parameters on the\r
+ * command line.\r
+ */\r
+ xpctxt->namespaces = NULL;\r
+ xpctxt->nsNr = 0; \r
+ \r
+ result = xmlXPathCompiledEval(xpExpr, xpctxt);\r
+ \r
+ /*\r
+ * Restore Context states.\r
+ */\r
+ xpctxt->doc = oldXPDoc;\r
+ xpctxt->node = oldXPContextNode;\r
+ xpctxt->contextSize = oldXPContextSize;\r
+ xpctxt->proximityPosition = oldXPProximityPosition;\r
+ xpctxt->namespaces = oldXPNamespaces;\r
+ xpctxt->nsNr = oldXPNsNr;\r
+ \r
+ xmlXPathFreeCompExpr(xpExpr);\r
+ }\r
+ if (result == NULL) {\r
+ xsltTransformError(ctxt, style, NULL,\r
+ "Evaluating user parameter %s failed\n", name);\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ return(-1);\r
+ }\r
+ }\r
+\r
+ /* \r
+ * If @eval is 0 then @value is to be taken literally and result is NULL\r
+ * \r
+ * If @eval is not 0, then @value is an XPath expression and has been\r
+ * successfully evaluated and result contains the resulting value and\r
+ * is not NULL.\r
+ *\r
+ * Now create an xsltStackElemPtr for insertion into the context's\r
+ * global variable/parameter hash table.\r
+ */\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+#ifdef LIBXML_DEBUG_ENABLED\r
+ if ((xsltGenericDebugContext == stdout) ||\r
+ (xsltGenericDebugContext == stderr))\r
+ xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,\r
+ result, 0);\r
+#endif\r
+#endif\r
+\r
+ elem = xsltNewStackElem(NULL);\r
+ if (elem != NULL) {\r
+ elem->name = name;\r
+ elem->select = xmlDictLookup(ctxt->dict, value, -1);\r
+ if (href != NULL)\r
+ elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);\r
+ elem->tree = NULL;\r
+ elem->computed = 1;\r
+ if (eval == 0) {\r
+ elem->value = xmlXPathNewString(value);\r
+ } \r
+ else {\r
+ elem->value = result;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Global parameters are stored in the XPath context variables pool.\r
+ */\r
+\r
+ res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);\r
+ if (res != 0) {\r
+ xsltFreeStackElem(elem);\r
+ xsltTransformError(ctxt, style, NULL,\r
+ "Global parameter %s already defined\n", name);\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltEvalUserParams:\r
+ *\r
+ * @ctxt: the XSLT transformation context\r
+ * @params: a NULL terminated array of parameters name/value tuples\r
+ *\r
+ * Evaluate the global variables of a stylesheet. This needs to be\r
+ * done on parsed stylesheets before starting to apply transformations.\r
+ * Each of the parameters is evaluated as an XPath expression and stored\r
+ * in the global variables/parameter hash table. If you want your\r
+ * parameter used literally, use xsltQuoteUserParams.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error\r
+ */\r
+ \r
+int\r
+xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {\r
+ int indx = 0;\r
+ const xmlChar *name;\r
+ const xmlChar *value;\r
+\r
+ if (params == NULL)\r
+ return(0);\r
+ while (params[indx] != NULL) {\r
+ name = (const xmlChar *) params[indx++];\r
+ value = (const xmlChar *) params[indx++];\r
+ if (xsltEvalOneUserParam(ctxt, name, value) != 0) \r
+ return(-1);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * xsltQuoteUserParams:\r
+ *\r
+ * @ctxt: the XSLT transformation context\r
+ * @params: a NULL terminated arry of parameters names/values tuples\r
+ *\r
+ * Similar to xsltEvalUserParams, but the values are treated literally and\r
+ * are * *not* evaluated as XPath expressions. This should be done on parsed\r
+ * stylesheets before starting to apply transformations.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error.\r
+ */\r
+ \r
+int\r
+xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {\r
+ int indx = 0;\r
+ const xmlChar *name;\r
+ const xmlChar *value;\r
+\r
+ if (params == NULL)\r
+ return(0);\r
+ while (params[indx] != NULL) {\r
+ name = (const xmlChar *) params[indx++];\r
+ value = (const xmlChar *) params[indx++];\r
+ if (xsltQuoteOneUserParam(ctxt, name, value) != 0) \r
+ return(-1);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * xsltEvalOneUserParam:\r
+ * @ctxt: the XSLT transformation context\r
+ * @name: a null terminated string giving the name of the parameter\r
+ * @value: a null terminated string giving the XPath expression to be evaluated\r
+ *\r
+ * This is normally called from xsltEvalUserParams to process a single\r
+ * parameter from a list of parameters. The @value is evaluated as an\r
+ * XPath expression and the result is stored in the context's global\r
+ * variable/parameter hash table.\r
+ *\r
+ * To have a parameter treated literally (not as an XPath expression)\r
+ * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more\r
+ * details see description of xsltProcessOneUserParamInternal.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error.\r
+ */\r
+\r
+int\r
+xsltEvalOneUserParam(xsltTransformContextPtr ctxt,\r
+ const xmlChar * name,\r
+ const xmlChar * value) {\r
+ return xsltProcessUserParamInternal(ctxt, name, value,\r
+ 1 /* xpath eval ? */);\r
+}\r
+\r
+/**\r
+ * xsltQuoteOneUserParam:\r
+ * @ctxt: the XSLT transformation context\r
+ * @name: a null terminated string giving the name of the parameter\r
+ * @value: a null terminated string giving the parameter value\r
+ *\r
+ * This is normally called from xsltQuoteUserParams to process a single\r
+ * parameter from a list of parameters. The @value is stored in the\r
+ * context's global variable/parameter hash table.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error.\r
+ */\r
+\r
+int\r
+xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,\r
+ const xmlChar * name,\r
+ const xmlChar * value) {\r
+ return xsltProcessUserParamInternal(ctxt, name, value,\r
+ 0 /* xpath eval ? */);\r
+}\r
+\r
+/**\r
+ * xsltBuildVariable:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the precompiled form\r
+ * @tree: the tree if select is NULL\r
+ *\r
+ * Computes a new variable value.\r
+ *\r
+ * Returns the xsltStackElemPtr or NULL in case of error\r
+ */\r
+static xsltStackElemPtr\r
+xsltBuildVariable(xsltTransformContextPtr ctxt,\r
+ xsltStylePreCompPtr castedComp,\r
+ xmlNodePtr tree)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleBasicItemVariablePtr comp =\r
+ (xsltStyleBasicItemVariablePtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+#endif \r
+ xsltStackElemPtr elem;\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Building variable %s", comp->name));\r
+ if (comp->select != NULL)\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ " select %s", comp->select));\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));\r
+#endif\r
+\r
+ elem = xsltNewStackElem(ctxt);\r
+ if (elem == NULL)\r
+ return(NULL);\r
+ elem->comp = (xsltStylePreCompPtr) comp;\r
+ elem->name = comp->name;\r
+ elem->select = comp->select;\r
+ elem->nameURI = comp->ns;\r
+ elem->tree = tree;\r
+ elem->value = xsltEvalVariable(ctxt, elem,\r
+ (xsltStylePreCompPtr) comp);\r
+ if (elem->value != NULL)\r
+ elem->computed = 1;\r
+ return(elem);\r
+}\r
+\r
+/**\r
+ * xsltRegisterVariable:\r
+ * @ctxt: the XSLT transformation context\r
+ * @comp: the compiled XSLT-variable (or param) instruction\r
+ * @tree: the tree if select is NULL\r
+ * @isParam: indicates if this is a parameter\r
+ *\r
+ * Computes and registers a new variable.\r
+ *\r
+ * Returns 0 in case of success, -1 in case of error\r
+ */\r
+static int\r
+xsltRegisterVariable(xsltTransformContextPtr ctxt,\r
+ xsltStylePreCompPtr castedComp,\r
+ xmlNodePtr tree, int isParam)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleBasicItemVariablePtr comp =\r
+ (xsltStyleBasicItemVariablePtr) castedComp;\r
+#else\r
+ xsltStylePreCompPtr comp = castedComp;\r
+ int present;\r
+#endif\r
+ xsltStackElemPtr variable; \r
+ \r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * REFACTORED NOTE: Redefinitions of vars/params are checked\r
+ * at compilation time in the refactored code.\r
+ * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().\r
+ */\r
+#else\r
+ present = xsltCheckStackElem(ctxt, comp->name, comp->ns);\r
+ if (isParam == 0) { \r
+ if ((present != 0) && (present != 3)) {\r
+ /* TODO: report QName. */\r
+ xsltTransformError(ctxt, NULL, comp->inst,\r
+ "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);\r
+ return(0);\r
+ }\r
+ } else if (present != 0) {\r
+ if ((present == 1) || (present == 2)) {\r
+ /* TODO: report QName. */\r
+ xsltTransformError(ctxt, NULL, comp->inst,\r
+ "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);\r
+ return(0);\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "param %s defined by caller\n", comp->name));\r
+#endif\r
+ return(0);\r
+ }\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+ variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);\r
+ xsltAddStackElem(ctxt, variable);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltGlobalVariableLookup:\r
+ * @ctxt: the XSLT transformation context\r
+ * @name: the variable name\r
+ * @ns_uri: the variable namespace URI\r
+ *\r
+ * Search in the Variable array of the context for the given\r
+ * variable value.\r
+ *\r
+ * Returns the value or NULL if not found\r
+ */\r
+static xmlXPathObjectPtr\r
+xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,\r
+ const xmlChar *ns_uri) {\r
+ xsltStackElemPtr elem;\r
+ xmlXPathObjectPtr ret = NULL;\r
+\r
+ /*\r
+ * Lookup the global variables in XPath global variable hash table\r
+ */\r
+ if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))\r
+ return(NULL);\r
+ elem = (xsltStackElemPtr)\r
+ xmlHashLookup2(ctxt->globalVars, name, ns_uri);\r
+ if (elem == NULL) {\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "global variable not found %s\n", name));\r
+#endif\r
+ return(NULL);\r
+ }\r
+ /*\r
+ * URGENT TODO: Move the detection of recursive definitions\r
+ * to compile-time.\r
+ */\r
+ if (elem->computed == 0) {\r
+ if (elem->name == xsltComputingGlobalVarMarker) {\r
+ xsltTransformError(ctxt, NULL, elem->comp->inst,\r
+ "Recursive definition of %s\n", name);\r
+ return(NULL);\r
+ }\r
+ ret = xsltEvalGlobalVariable(elem, ctxt);\r
+ } else\r
+ ret = elem->value;\r
+ return(xmlXPathObjectCopy(ret));\r
+}\r
+\r
+/**\r
+ * xsltVariableLookup:\r
+ * @ctxt: the XSLT transformation context\r
+ * @name: the variable name\r
+ * @ns_uri: the variable namespace URI\r
+ *\r
+ * Search in the Variable array of the context for the given\r
+ * variable value.\r
+ *\r
+ * Returns the value or NULL if not found\r
+ */\r
+xmlXPathObjectPtr\r
+xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,\r
+ const xmlChar *ns_uri) {\r
+ xsltStackElemPtr elem;\r
+\r
+ if (ctxt == NULL)\r
+ return(NULL);\r
+\r
+ elem = xsltStackLookup(ctxt, name, ns_uri);\r
+ if (elem == NULL) {\r
+ return(xsltGlobalVariableLookup(ctxt, name, ns_uri));\r
+ }\r
+ if (elem->computed == 0) {\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "uncomputed variable %s\n", name));\r
+#endif\r
+ elem->value = xsltEvalVariable(ctxt, elem, NULL);\r
+ elem->computed = 1;\r
+ }\r
+ if (elem->value != NULL)\r
+ return(xmlXPathObjectCopy(elem->value));\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "variable not found %s\n", name));\r
+#endif\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetCallerParam:\r
+ * @ctxt: the XSLT transformation context \r
+ * @inst: the xsl:with-param instruction element\r
+ *\r
+ * Processes an xsl:with-param instruction at transformation time.\r
+ * The value is compute, but not recorded.\r
+ * NOTE that this is also called with an *xsl:param* element\r
+ * from exsltFuncFunctionFunction(). \r
+ *\r
+ * Returns the new xsltStackElemPtr or NULL\r
+ */\r
+\r
+xsltStackElemPtr\r
+xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleBasicItemVariablePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ xmlNodePtr tree = NULL; /* The first child node of the instruction or\r
+ the instruction itself. */\r
+ xsltStackElemPtr param = NULL;\r
+ \r
+ if ((ctxt == NULL) || (inst == NULL))\r
+ return(NULL);\r
+\r
+#ifdef XSLT_REFACTORED\r
+ comp = (xsltStyleBasicItemVariablePtr) inst->psvi;\r
+#else\r
+ comp = (xsltStylePreCompPtr) inst->psvi;\r
+#endif\r
+ \r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltParseStylesheetCallerParam(): "\r
+ "The XSLT 'with-param' instruction was not compiled.\n");\r
+ return(NULL);\r
+ }\r
+ if (comp->name == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltParseStylesheetCallerParam(): "\r
+ "XSLT 'with-param': The attribute 'name' was not compiled.\n");\r
+ return(NULL);\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Handling xsl:with-param %s\n", comp->name));\r
+#endif\r
+\r
+ if (comp->select == NULL) {\r
+ tree = inst->children;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ " select %s\n", comp->select));\r
+#endif\r
+ tree = inst;\r
+ }\r
+\r
+ param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);\r
+\r
+ return(param);\r
+}\r
+\r
+/**\r
+ * xsltParseGlobalVariable:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "variable" element\r
+ *\r
+ * Parses a global XSLT 'variable' declaration at compilation time\r
+ * and registers it\r
+ */\r
+void\r
+xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemVariablePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Note that xsltStylePreCompute() will be called from\r
+ * xslt.c only.\r
+ */\r
+ comp = (xsltStyleItemVariablePtr) cur->psvi;\r
+#else\r
+ xsltStylePreCompute(style, cur);\r
+ comp = (xsltStylePreCompPtr) cur->psvi;\r
+#endif\r
+ if (comp == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:variable : compilation failed\n");\r
+ return;\r
+ }\r
+\r
+ if (comp->name == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:variable : missing name attribute\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Parse the content (a sequence constructor) of xsl:variable.\r
+ */\r
+ if (cur->children != NULL) {\r
+#ifdef XSLT_REFACTORED \r
+ xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);\r
+#else\r
+ xsltParseTemplateContent(style, cur);\r
+#endif\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering global variable %s\n", comp->name);\r
+#endif\r
+\r
+ xsltRegisterGlobalVariable(style, comp->name, comp->ns,\r
+ comp->select, cur->children, (xsltStylePreCompPtr) comp,\r
+ NULL);\r
+}\r
+\r
+/**\r
+ * xsltParseGlobalParam:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "param" element\r
+ *\r
+ * parse an XSLT transformation param declaration and record\r
+ * its value.\r
+ */\r
+\r
+void\r
+xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemParamPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Note that xsltStylePreCompute() will be called from\r
+ * xslt.c only.\r
+ */\r
+ comp = (xsltStyleItemParamPtr) cur->psvi;\r
+#else\r
+ xsltStylePreCompute(style, cur);\r
+ comp = (xsltStylePreCompPtr) cur->psvi;\r
+#endif \r
+ if (comp == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:param : compilation failed\n");\r
+ return;\r
+ }\r
+\r
+ if (comp->name == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:param : missing name attribute\n");\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Parse the content (a sequence constructor) of xsl:param.\r
+ */\r
+ if (cur->children != NULL) {\r
+#ifdef XSLT_REFACTORED \r
+ xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);\r
+#else\r
+ xsltParseTemplateContent(style, cur);\r
+#endif\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering global param %s\n", comp->name);\r
+#endif\r
+\r
+ xsltRegisterGlobalVariable(style, comp->name, comp->ns,\r
+ comp->select, cur->children, (xsltStylePreCompPtr) comp,\r
+ NULL);\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetVariable:\r
+ * @ctxt: the XSLT transformation context\r
+ * @inst: the xsl:variable instruction element\r
+ *\r
+ * Registers a local XSLT 'variable' instruction at transformation time\r
+ * and evaluates its value.\r
+ */\r
+void\r
+xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemVariablePtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((inst == NULL) || (ctxt == NULL))\r
+ return;\r
+\r
+ comp = inst->psvi;\r
+ if (comp == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltParseStylesheetVariable(): "\r
+ "The XSLT 'variable' instruction was not compiled.\n");\r
+ return;\r
+ }\r
+ if (comp->name == NULL) {\r
+ xsltTransformError(ctxt, NULL, inst,\r
+ "Internal error in xsltParseStylesheetVariable(): "\r
+ "The attribute 'name' was not compiled.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering variable '%s'\n", comp->name));\r
+#endif\r
+\r
+ xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetParam:\r
+ * @ctxt: the XSLT transformation context\r
+ * @cur: the XSLT 'param' element\r
+ *\r
+ * Registers a local XSLT 'param' declaration at transformation time and\r
+ * evaluates its value.\r
+ */\r
+void\r
+xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)\r
+{\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemParamPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+\r
+ if ((cur == NULL) || (ctxt == NULL))\r
+ return;\r
+\r
+ comp = cur->psvi;\r
+ if ((comp == NULL) || (comp->name == NULL)) {\r
+ xsltTransformError(ctxt, NULL, cur,\r
+ "Internal error in xsltParseStylesheetParam(): "\r
+ "The XSLT 'param' declaration was not compiled correctly.\n");\r
+ return;\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Registering param %s\n", comp->name));\r
+#endif\r
+\r
+ xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);\r
+}\r
+\r
+/**\r
+ * xsltFreeGlobalVariables:\r
+ * @ctxt: the XSLT transformation context\r
+ *\r
+ * Free up the data associated to the global variables\r
+ * its value.\r
+ */\r
+\r
+void\r
+xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {\r
+ xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);\r
+}\r
+\r
+/**\r
+ * xsltXPathVariableLookup:\r
+ * @ctxt: a void * but the the XSLT transformation context actually\r
+ * @name: the variable name\r
+ * @ns_uri: the variable namespace URI\r
+ *\r
+ * This is the entry point when a varibale is needed by the XPath\r
+ * interpretor.\r
+ *\r
+ * Returns the value or NULL if not found\r
+ */\r
+xmlXPathObjectPtr\r
+xsltXPathVariableLookup(void *ctxt, const xmlChar *name,\r
+ const xmlChar *ns_uri) {\r
+ xsltTransformContextPtr tctxt;\r
+ xmlXPathObjectPtr valueObj = NULL;\r
+\r
+ if ((ctxt == NULL) || (name == NULL))\r
+ return(NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "Lookup variable '%s'\n", name));\r
+#endif\r
+ \r
+ tctxt = (xsltTransformContextPtr) ctxt;\r
+ /*\r
+ * Local variables/params ---------------------------------------------\r
+ *\r
+ * Do the lookup from the top of the stack, but\r
+ * don't use params being computed in a call-param\r
+ * First lookup expects the variable name and URI to\r
+ * come from the disctionnary and hence pointer comparison.\r
+ */\r
+ if (tctxt->varsNr != 0) {\r
+ int i;\r
+ xsltStackElemPtr variable = NULL, cur;\r
+\r
+ for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {\r
+ cur = tctxt->varsTab[i-1];\r
+ if ((cur->name == name) && (cur->nameURI == ns_uri)) {\r
+#if 0\r
+ stack_addr++;\r
+#endif\r
+ variable = cur;\r
+ goto local_variable_found;\r
+ }\r
+ cur = cur->next;\r
+ } \r
+ /*\r
+ * Redo the lookup with interned strings to avoid string comparison.\r
+ *\r
+ * OPTIMIZE TODO: The problem here is, that if we request a\r
+ * global variable, then this will be also executed.\r
+ */\r
+ {\r
+ const xmlChar *tmpName = name, *tmpNsName = ns_uri;\r
+\r
+ name = xmlDictLookup(tctxt->dict, name, -1);\r
+ if (ns_uri)\r
+ ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);\r
+ if ((tmpName != name) || (tmpNsName != ns_uri)) { \r
+ for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {\r
+ cur = tctxt->varsTab[i-1];\r
+ if ((cur->name == name) && (cur->nameURI == ns_uri)) {\r
+#if 0\r
+ stack_cmp++;\r
+#endif\r
+ variable = cur;\r
+ goto local_variable_found;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+local_variable_found:\r
+\r
+ if (variable) {\r
+ if (variable->computed == 0) {\r
+ \r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "uncomputed variable '%s'\n", name));\r
+#endif\r
+ variable->value = xsltEvalVariable(tctxt, variable, NULL);\r
+ variable->computed = 1;\r
+ }\r
+ if (variable->value != NULL) {\r
+ valueObj = xmlXPathObjectCopy(variable->value); \r
+ }\r
+ return(valueObj);\r
+ }\r
+ }\r
+ /*\r
+ * Global variables/params --------------------------------------------\r
+ */ \r
+ if (tctxt->globalVars) {\r
+ valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);\r
+ }\r
+\r
+ if (valueObj == NULL) {\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "variable not found '%s'\n", name));\r
+#endif\r
+\r
+ if (ns_uri) {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "Variable '{%s}%s' has not been declared.\n", ns_uri, name);\r
+ } else {\r
+ xsltTransformError(tctxt, NULL, tctxt->inst,\r
+ "Variable '%s' has not been declared.\n", name);\r
+ }\r
+ } else {\r
+\r
+#ifdef WITH_XSLT_DEBUG_VARIABLE\r
+ XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,\r
+ "found variable '%s'\n", name));\r
+#endif\r
+ }\r
+\r
+ return(valueObj);\r
+}\r
+\r
+\r
-/*
- * xslt.c: Implemetation of an XSL Transformation 1.0 engine
- *
- * Reference:
- * XSLT specification
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * Associating Style Sheets with XML documents
- * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <string.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/valid.h>
-#include <libxml/hash.h>
-#include <libxml/uri.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parserInternals.h>
-#include <libxml/xpathInternals.h>
-#include <libxml/xpath.h>
-#include "xslt.h"
-#include "xsltInternals.h"
-#include "pattern.h"
-#include "variables.h"
-#include "namespaces.h"
-#include "attributes.h"
-#include "xsltutils.h"
-#include "imports.h"
-#include "keys.h"
-#include "documents.h"
-#include "extensions.h"
-#include "preproc.h"
-#include "extra.h"
-#include "security.h"
-
-#ifdef WITH_XSLT_DEBUG
-#define WITH_XSLT_DEBUG_PARSING
-/* #define WITH_XSLT_DEBUG_BLANKS */
-#endif
-
-const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
-const int xsltLibxsltVersion = LIBXSLT_VERSION;
-const int xsltLibxmlVersion = LIBXML_VERSION;
-
-#ifdef XSLT_REFACTORED
-
-const xmlChar *xsltConstNamespaceNameXSLT= (const xmlChar *) XSLT_NAMESPACE;
-
-/*
-* xsltLiteralResultMarker:
-* Marker for Literal result elements, in order to avoid multiple attempts
-* to recognize such elements in the stylesheet's tree.
-* This marker is set on node->psvi during the initial traversal
-* of a stylesheet's node tree.
-*
-const xmlChar *xsltLiteralResultMarker =
- (const xmlChar *) "Literal Result Element";
-*/
-
-/*
-* xsltXSLTTextMarker:
-* Marker for xsl:text elements. Used to recognize xsl:text elements
-* for post-processing of the stylesheet's tree, where those
-* elements are removed from the tree.
-*/
-const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
-
-/*
-* xsltXSLTAttrMarker:
-* Marker for XSLT attribute on Literal Result Elements.
-*/
-const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
-
-#endif
-
-/*
- * Harmless but avoiding a problem when compiling against a
- * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
- */
-#ifndef LIBXML_DEBUG_ENABLED
-double xmlXPathStringEvalNumber(const xmlChar *str);
-#endif
-/*
- * Useful macros
- */
-
-#ifdef IS_BLANK
-#undef IS_BLANK
-#endif
-#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
- ((c) == 0x0D))
-
-#ifdef IS_BLANK_NODE
-#undef IS_BLANK_NODE
-#endif
-#define IS_BLANK_NODE(n) \
- (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
-
-/**
- * xsltParseContentError:
- *
- * @style: the stylesheet
- * @node: the node where the error occured
- *
- * Compile-time error function.
- */
-static void
-xsltParseContentError(xsltStylesheetPtr style,
- xmlNodePtr node)
-{
- if ((style == NULL) || (node == NULL))
- return;
-
- if (IS_XSLT_ELEM(node))
- xsltTransformError(NULL, style, node,
- "The XSLT-element '%s' is not allowed at this position.\n",
- node->name);
- else
- xsltTransformError(NULL, style, node,
- "The element '%s' is not allowed at this position.\n",
- node->name);
- style->errors++;
-}
-
-#ifdef XSLT_REFACTORED
-#else
-/**
- * exclPrefixPush:
- * @style: the transformation stylesheet
- * @value: the excluded namespace name to push on the stack
- *
- * Push an excluded namespace name on the stack
- *
- * Returns the new index in the stack or 0 in case of error
- */
-static int
-exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
-{
- if (style->exclPrefixMax == 0) {
- style->exclPrefixMax = 4;
- style->exclPrefixTab =
- (xmlChar * *)xmlMalloc(style->exclPrefixMax *
- sizeof(style->exclPrefixTab[0]));
- if (style->exclPrefixTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (0);
- }
- }
- if (style->exclPrefixNr >= style->exclPrefixMax) {
- style->exclPrefixMax *= 2;
- style->exclPrefixTab =
- (xmlChar * *)xmlRealloc(style->exclPrefixTab,
- style->exclPrefixMax *
- sizeof(style->exclPrefixTab[0]));
- if (style->exclPrefixTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (0);
- }
- }
- style->exclPrefixTab[style->exclPrefixNr] = value;
- style->exclPrefix = value;
- return (style->exclPrefixNr++);
-}
-/**
- * exclPrefixPop:
- * @style: the transformation stylesheet
- *
- * Pop an excluded prefix value from the stack
- *
- * Returns the stored excluded prefix value
- */
-static xmlChar *
-exclPrefixPop(xsltStylesheetPtr style)
-{
- xmlChar *ret;
-
- if (style->exclPrefixNr <= 0)
- return (0);
- style->exclPrefixNr--;
- if (style->exclPrefixNr > 0)
- style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
- else
- style->exclPrefix = NULL;
- ret = style->exclPrefixTab[style->exclPrefixNr];
- style->exclPrefixTab[style->exclPrefixNr] = 0;
- return (ret);
-}
-#endif
-
-/************************************************************************
- * *
- * Helper functions *
- * *
- ************************************************************************/
-
-/**
- * xsltInit:
- *
- * Initializes the processor (e.g. registers built-in extensions,
- * etc.)
- */
-
-static int initialized = 0;
-
-void
-xsltInit (void) {
- if (initialized == 0) {
- initialized = 1;
- xsltRegisterAllExtras();
- }
-}
-
-/**
- * xsltUninit
- *
- * Uninitializes the processor.
- */
-
-void
-xsltUninit (void) {
- initialized = 0;
-}
-
-/**
- * xsltIsBlank:
- * @str: a string
- *
- * Check if a string is ignorable
- *
- * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
- */
-int
-xsltIsBlank(xmlChar *str) {
- if (str == NULL)
- return(1);
- while (*str != 0) {
- if (!(IS_BLANK(*str))) return(0);
- str++;
- }
- return(1);
-}
-
-/************************************************************************
- * *
- * Routines to handle XSLT data structures *
- * *
- ************************************************************************/
-static xsltDecimalFormatPtr
-xsltNewDecimalFormat(xmlChar *name)
-{
- xsltDecimalFormatPtr self;
- /* UTF-8 for 0x2030 */
- static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
-
- self = xmlMalloc(sizeof(xsltDecimalFormat));
- if (self != NULL) {
- self->next = NULL;
- self->name = name;
-
- /* Default values */
- self->digit = xmlStrdup(BAD_CAST("#"));
- self->patternSeparator = xmlStrdup(BAD_CAST(";"));
- self->decimalPoint = xmlStrdup(BAD_CAST("."));
- self->grouping = xmlStrdup(BAD_CAST(","));
- self->percent = xmlStrdup(BAD_CAST("%"));
- self->permille = xmlStrdup(BAD_CAST(permille));
- self->zeroDigit = xmlStrdup(BAD_CAST("0"));
- self->minusSign = xmlStrdup(BAD_CAST("-"));
- self->infinity = xmlStrdup(BAD_CAST("Infinity"));
- self->noNumber = xmlStrdup(BAD_CAST("NaN"));
- }
- return self;
-}
-
-static void
-xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
-{
- if (self != NULL) {
- if (self->digit)
- xmlFree(self->digit);
- if (self->patternSeparator)
- xmlFree(self->patternSeparator);
- if (self->decimalPoint)
- xmlFree(self->decimalPoint);
- if (self->grouping)
- xmlFree(self->grouping);
- if (self->percent)
- xmlFree(self->percent);
- if (self->permille)
- xmlFree(self->permille);
- if (self->zeroDigit)
- xmlFree(self->zeroDigit);
- if (self->minusSign)
- xmlFree(self->minusSign);
- if (self->infinity)
- xmlFree(self->infinity);
- if (self->noNumber)
- xmlFree(self->noNumber);
- if (self->name)
- xmlFree(self->name);
- xmlFree(self);
- }
-}
-
-static void
-xsltFreeDecimalFormatList(xsltStylesheetPtr self)
-{
- xsltDecimalFormatPtr iter;
- xsltDecimalFormatPtr tmp;
-
- if (self == NULL)
- return;
-
- iter = self->decimalFormat;
- while (iter != NULL) {
- tmp = iter->next;
- xsltFreeDecimalFormat(iter);
- iter = tmp;
- }
-}
-
-/**
- * xsltDecimalFormatGetByName:
- * @style: the XSLT stylesheet
- * @name: the decimal-format name to find
- *
- * Find decimal-format by name
- *
- * Returns the xsltDecimalFormatPtr
- */
-xsltDecimalFormatPtr
-xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
-{
- xsltDecimalFormatPtr result = NULL;
-
- if (name == NULL)
- return style->decimalFormat;
-
- while (style != NULL) {
- for (result = style->decimalFormat->next;
- result != NULL;
- result = result->next) {
- if (xmlStrEqual(name, result->name))
- return result;
- }
- style = xsltNextImport(style);
- }
- return result;
-}
-
-
-/**
- * xsltNewTemplate:
- *
- * Create a new XSLT Template
- *
- * Returns the newly allocated xsltTemplatePtr or NULL in case of error
- */
-static xsltTemplatePtr
-xsltNewTemplate(void) {
- xsltTemplatePtr cur;
-
- cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewTemplate : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltTemplate));
- cur->priority = XSLT_PAT_NO_PRIORITY;
- return(cur);
-}
-
-/**
- * xsltFreeTemplate:
- * @template: an XSLT template
- *
- * Free up the memory allocated by @template
- */
-static void
-xsltFreeTemplate(xsltTemplatePtr template) {
- if (template == NULL)
- return;
- if (template->match) xmlFree(template->match);
-/*
-* NOTE: @name and @nameURI are put into the string dict now.
-* if (template->name) xmlFree(template->name);
-* if (template->nameURI) xmlFree(template->nameURI);
-*/
-/*
- if (template->mode) xmlFree(template->mode);
- if (template->modeURI) xmlFree(template->modeURI);
- */
- if (template->inheritedNs) xmlFree(template->inheritedNs);
- memset(template, -1, sizeof(xsltTemplate));
- xmlFree(template);
-}
-
-/**
- * xsltFreeTemplateList:
- * @template: an XSLT template list
- *
- * Free up the memory allocated by all the elements of @template
- */
-static void
-xsltFreeTemplateList(xsltTemplatePtr template) {
- xsltTemplatePtr cur;
-
- while (template != NULL) {
- cur = template;
- template = template->next;
- xsltFreeTemplate(cur);
- }
-}
-
-#ifdef XSLT_REFACTORED
-
-static void
-xsltFreeNsAliasList(xsltNsAliasPtr item)
-{
- xsltNsAliasPtr tmp;
-
- while (item) {
- tmp = item;
- item = item->next;
- xmlFree(tmp);
- }
- return;
-}
-
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
-static void
-xsltFreeNamespaceMap(xsltNsMapPtr item)
-{
- xsltNsMapPtr tmp;
-
- while (item) {
- tmp = item;
- item = item->next;
- xmlFree(tmp);
- }
- return;
-}
-
-static xsltNsMapPtr
-xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
- xmlDocPtr doc,
- xmlNsPtr ns,
- xmlNodePtr elem)
-{
- xsltNsMapPtr ret;
-
- if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
- return(NULL);
-
- ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
- if (ret == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error: (xsltNewNamespaceMapItem) "
- "memory allocation failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltNsMap));
- ret->doc = doc;
- ret->ns = ns;
- ret->origNsName = ns->href;
- /*
- * Store the item at current stylesheet-level.
- */
- if (cctxt->psData->nsMap != NULL)
- ret->next = cctxt->psData->nsMap;
- cctxt->psData->nsMap = ret;
-
- return(ret);
-}
-#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
-
-/**
- * xsltCompilerCtxtFree:
- *
- * Free an XSLT compiler context.
- */
-static void
-xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
-{
- if (cctxt == NULL)
- return;
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Freeing compilation context\n");
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max inodes: %d\n", cctxt->maxNodeInfos);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max LREs : %d\n", cctxt->maxLREs);
-#endif
- /*
- * Free node-infos.
- */
- if (cctxt->inodeList != NULL) {
- xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
- while (cur != NULL) {
- tmp = cur;
- cur = cur->next;
- xmlFree(tmp);
- }
- }
- if (cctxt->tmpList != NULL)
- xsltPointerListFree(cctxt->tmpList);
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if (cctxt->xpathCtxt != NULL)
- xmlXPathFreeContext(cctxt->xpathCtxt);
-#endif
- if (cctxt->nsAliases != NULL)
- xsltFreeNsAliasList(cctxt->nsAliases);
-
- xmlFree(cctxt);
-}
-
-/**
- * xsltCompilerCreate:
- *
- * Creates an XSLT compiler context.
- *
- * Returns the pointer to the created xsltCompilerCtxt or
- * NULL in case of an internal error.
- */
-static xsltCompilerCtxtPtr
-xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
- xsltCompilerCtxtPtr ret;
-
- ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
- if (ret == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltCompilerCreate: allocation of compiler "
- "context failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltCompilerCtxt));
-
- ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
- ret->tmpList = xsltPointerListCreate(20);
- if (ret->tmpList == NULL) {
- goto internal_err;
- }
-#ifdef XSLT_REFACTORED_XPATHCOMP
- /*
- * Create the XPath compilation context in order
- * to speed up precompilation of XPath expressions.
- */
- ret->xpathCtxt = xmlXPathNewContext(NULL);
- if (ret->xpathCtxt == NULL)
- goto internal_err;
-#endif
-
- return(ret);
-
-internal_err:
- xsltCompilationCtxtFree(ret);
- return(NULL);
-}
-
-static void
-xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
-{
- xsltEffectiveNsPtr tmp;
-
- while (first != NULL) {
- tmp = first;
- first = first->nextInStore;
- xmlFree(tmp);
- }
-}
-
-static void
-xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
-{
- if (data == NULL)
- return;
-
- if (data->inScopeNamespaces != NULL) {
- int i;
- xsltNsListContainerPtr nsi;
- xsltPointerListPtr list =
- (xsltPointerListPtr) data->inScopeNamespaces;
-
- for (i = 0; i < list->number; i++) {
- /*
- * REVISIT TODO: Free info of in-scope namespaces.
- */
- nsi = (xsltNsListContainerPtr) list->items[i];
- if (nsi->list != NULL)
- xmlFree(nsi->list);
- xmlFree(nsi);
- }
- xsltPointerListFree(list);
- data->inScopeNamespaces = NULL;
- }
-
- if (data->exclResultNamespaces != NULL) {
- int i;
- xsltPointerListPtr list = (xsltPointerListPtr)
- data->exclResultNamespaces;
-
- for (i = 0; i < list->number; i++)
- xsltPointerListFree((xsltPointerListPtr) list->items[i]);
-
- xsltPointerListFree(list);
- data->exclResultNamespaces = NULL;
- }
-
- if (data->extElemNamespaces != NULL) {
- xsltPointerListPtr list = (xsltPointerListPtr)
- data->extElemNamespaces;
- int i;
-
- for (i = 0; i < list->number; i++)
- xsltPointerListFree((xsltPointerListPtr) list->items[i]);
-
- xsltPointerListFree(list);
- data->extElemNamespaces = NULL;
- }
- if (data->effectiveNs) {
- xsltLREEffectiveNsNodesFree(data->effectiveNs);
- data->effectiveNs = NULL;
- }
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- xsltFreeNamespaceMap(data->nsMap);
-#endif
- xmlFree(data);
-}
-
-static xsltPrincipalStylesheetDataPtr
-xsltNewPrincipalStylesheetData(void)
-{
- xsltPrincipalStylesheetDataPtr ret;
-
- ret = (xsltPrincipalStylesheetDataPtr)
- xmlMalloc(sizeof(xsltPrincipalStylesheetData));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
-
- /*
- * Global list of in-scope namespaces.
- */
- ret->inScopeNamespaces = xsltPointerListCreate(-1);
- if (ret->inScopeNamespaces == NULL)
- goto internal_err;
- /*
- * Global list of excluded result ns-decls.
- */
- ret->exclResultNamespaces = xsltPointerListCreate(-1);
- if (ret->exclResultNamespaces == NULL)
- goto internal_err;
- /*
- * Global list of extension instruction namespace names.
- */
- ret->extElemNamespaces = xsltPointerListCreate(-1);
- if (ret->extElemNamespaces == NULL)
- goto internal_err;
-
- return(ret);
-
-internal_err:
-
- return(NULL);
-}
-
-#endif
-
-/**
- * xsltNewStylesheet:
- *
- * Create a new XSLT Stylesheet
- *
- * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
- */
-xsltStylesheetPtr
-xsltNewStylesheet(void) {
- xsltStylesheetPtr ret = NULL;
-
- ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewStylesheet : malloc failed\n");
- goto internal_err;
- }
- memset(ret, 0, sizeof(xsltStylesheet));
-
- ret->omitXmlDeclaration = -1;
- ret->standalone = -1;
- ret->decimalFormat = xsltNewDecimalFormat(NULL);
- ret->indent = -1;
- ret->errors = 0;
- ret->warnings = 0;
- ret->exclPrefixNr = 0;
- ret->exclPrefixMax = 0;
- ret->exclPrefixTab = NULL;
- ret->extInfos = NULL;
- ret->extrasNr = 0;
- ret->internalized = 1;
- ret->literal_result = 0;
- ret->dict = xmlDictCreate();
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "creating dictionary for stylesheet\n");
-#endif
-
- xsltInit();
-
- return(ret);
-
-internal_err:
- if (ret != NULL)
- xsltFreeStylesheet(ret);
- return(NULL);
-}
-
-/**
- * xsltAllocateExtra:
- * @style: an XSLT stylesheet
- *
- * Allocate an extra runtime information slot statically while compiling
- * the stylesheet and return its number
- *
- * Returns the number of the slot
- */
-int
-xsltAllocateExtra(xsltStylesheetPtr style)
-{
- return(style->extrasNr++);
-}
-
-/**
- * xsltAllocateExtraCtxt:
- * @ctxt: an XSLT transformation context
- *
- * Allocate an extra runtime information slot at run-time
- * and return its number
- * This make sure there is a slot ready in the transformation context
- *
- * Returns the number of the slot
- */
-int
-xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
-{
- if (ctxt->extrasNr >= ctxt->extrasMax) {
- int i;
- if (ctxt->extrasNr == 0) {
- ctxt->extrasMax = 20;
- ctxt->extras = (xsltRuntimeExtraPtr)
- xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
- if (ctxt->extras == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltAllocateExtraCtxt: out of memory\n");
- ctxt->state = XSLT_STATE_ERROR;
- return(0);
- }
- for (i = 0;i < ctxt->extrasMax;i++) {
- ctxt->extras[i].info = NULL;
- ctxt->extras[i].deallocate = NULL;
- ctxt->extras[i].val.ptr = NULL;
- }
-
- } else {
- xsltRuntimeExtraPtr tmp;
-
- ctxt->extrasMax += 100;
- tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
- ctxt->extrasMax * sizeof(xsltRuntimeExtra));
- if (tmp == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltAllocateExtraCtxt: out of memory\n");
- ctxt->state = XSLT_STATE_ERROR;
- return(0);
- }
- ctxt->extras = tmp;
- for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
- ctxt->extras[i].info = NULL;
- ctxt->extras[i].deallocate = NULL;
- ctxt->extras[i].val.ptr = NULL;
- }
- }
- }
- return(ctxt->extrasNr++);
-}
-
-/**
- * xsltFreeStylesheetList:
- * @style: an XSLT stylesheet list
- *
- * Free up the memory allocated by the list @style
- */
-static void
-xsltFreeStylesheetList(xsltStylesheetPtr style) {
- xsltStylesheetPtr next;
-
- while (style != NULL) {
- next = style->next;
- xsltFreeStylesheet(style);
- style = next;
- }
-}
-
-/**
- * xsltCleanupStylesheetTree:
- *
- * @doc: the document-node
- * @node: the element where the stylesheet is rooted at
- *
- * Actually @node need not be the document-element, but
- * currently Libxslt does not support embedeed stylesheets.
- *
- * Returns 0 if OK, -1 on API or internal errors.
- */
-static int
-xsltCleanupStylesheetTree(xmlDocPtr doc, xmlNodePtr rootElem)
-{
-#if 0 /* TODO: Currently disabled, since probably not needed. */
- xmlNodePtr cur;
-
- if ((doc == NULL) || (rootElem == NULL) ||
- (rootElem->type != XML_ELEMENT_NODE) ||
- (doc != rootElem->doc))
- return(-1);
-
- /*
- * Cleanup was suggested by Aleksey Sanin:
- * Clear the PSVI field to avoid problems if the
- * node-tree of the stylesheet is intended to be used for
- * further processing by the user (e.g. for compiling it
- * once again - although not recommended).
- */
-
- cur = rootElem;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- /*
- * Clear the PSVI field.
- */
- cur->psvi = NULL;
- if (cur->children) {
- cur = cur->children;
- continue;
- }
- }
-
-leave_node:
- if (cur == rootElem)
- break;
- if (cur->next != NULL)
- cur = cur->next;
- else {
- cur = cur->parent;
- if (cur == NULL)
- break;
- goto leave_node;
- }
- }
-#endif /* #if 0 */
- return(0);
-}
-
-/**
- * xsltFreeStylesheet:
- * @style: an XSLT stylesheet
- *
- * Free up the memory allocated by @style
- */
-void
-xsltFreeStylesheet(xsltStylesheetPtr style)
-{
- if (style == NULL)
- return;
-
-#ifdef XSLT_REFACTORED
- /*
- * Start with a cleanup of the main stylesheet's doc.
- */
- if ((style->principal == style) && (style->doc))
- xsltCleanupStylesheetTree(style->doc,
- xmlDocGetRootElement(style->doc));
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Restore changed ns-decls before freeing the document.
- */
- if ((style->doc != NULL) &&
- XSLT_HAS_INTERNAL_NSMAP(style))
- {
- xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
- style->doc);
- }
-#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
-#else
- /*
- * Start with a cleanup of the main stylesheet's doc.
- */
- if ((style->parent == NULL) && (style->doc))
- xsltCleanupStylesheetTree(style->doc,
- xmlDocGetRootElement(style->doc));
-#endif /* XSLT_REFACTORED */
-
- xsltFreeKeys(style);
- xsltFreeExts(style);
- xsltFreeTemplateHashes(style);
- xsltFreeDecimalFormatList(style);
- xsltFreeTemplateList(style->templates);
- xsltFreeAttributeSetsHashes(style);
- xsltFreeNamespaceAliasHashes(style);
- xsltFreeStylePreComps(style);
- /*
- * Free documents of all included stylsheet modules of this
- * stylesheet level.
- */
- xsltFreeStyleDocuments(style);
- /*
- * TODO: Best time to shutdown extension stuff?
- */
- xsltShutdownExts(style);
-
- if (style->variables != NULL)
- xsltFreeStackElemList(style->variables);
- if (style->cdataSection != NULL)
- xmlHashFree(style->cdataSection, NULL);
- if (style->stripSpaces != NULL)
- xmlHashFree(style->stripSpaces, NULL);
- if (style->nsHash != NULL)
- xmlHashFree(style->nsHash, NULL);
- if (style->exclPrefixTab != NULL)
- xmlFree(style->exclPrefixTab);
- if (style->method != NULL)
- xmlFree(style->method);
- if (style->methodURI != NULL)
- xmlFree(style->methodURI);
- if (style->version != NULL)
- xmlFree(style->version);
- if (style->encoding != NULL)
- xmlFree(style->encoding);
- if (style->doctypePublic != NULL)
- xmlFree(style->doctypePublic);
- if (style->doctypeSystem != NULL)
- xmlFree(style->doctypeSystem);
- if (style->mediaType != NULL)
- xmlFree(style->mediaType);
- if (style->attVTs)
- xsltFreeAVTList(style->attVTs);
- if (style->imports != NULL)
- xsltFreeStylesheetList(style->imports);
-
-#ifdef XSLT_REFACTORED
- /*
- * If this is the principal stylesheet, then
- * free its internal data.
- */
- if (style->principal == style) {
- if (style->principalData) {
- xsltFreePrincipalStylesheetData(style->principalData);
- style->principalData = NULL;
- }
- }
-#endif
- /*
- * Better to free the main document of this stylesheet level
- * at the end - so here.
- */
- if (style->doc != NULL) {
- xmlFreeDoc(style->doc);
- }
-
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "freeing dictionary from stylesheet\n");
-#endif
- xmlDictFree(style->dict);
-
- memset(style, -1, sizeof(xsltStylesheet));
- xmlFree(style);
-}
-
-/************************************************************************
- * *
- * Parsing of an XSLT Stylesheet *
- * *
- ************************************************************************/
-
-#ifdef XSLT_REFACTORED
- /*
- * This is now performed in an optimized way in xsltParseXSLTTemplate.
- */
-#else
-/**
- * xsltGetInheritedNsList:
- * @style: the stylesheet
- * @template: the template
- * @node: the current node
- *
- * Search all the namespace applying to a given element except the ones
- * from excluded output prefixes currently in scope. Initialize the
- * template inheritedNs list with it.
- *
- * Returns the number of entries found
- */
-static int
-xsltGetInheritedNsList(xsltStylesheetPtr style,
- xsltTemplatePtr template,
- xmlNodePtr node)
-{
- xmlNsPtr cur;
- xmlNsPtr *ret = NULL;
- int nbns = 0;
- int maxns = 10;
- int i;
-
- /*
- * TODO: This will gather the ns-decls of elements even if
- * outside xsl:stylesheet. Example:
- * <doc xmlns:foo="urn:test:foo">
- * <xsl:stylesheet ...
- * </doc>
- * Will have foo="urn:test:foo" in the list.
- * Is this OK?
- */
-
- if ((style == NULL) || (template == NULL) || (node == NULL) ||
- (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
- return(0);
- while (node != NULL) {
- if (node->type == XML_ELEMENT_NODE) {
- cur = node->nsDef;
- while (cur != NULL) {
- if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
- goto skip_ns;
-
- if ((cur->prefix != NULL) &&
- (xsltCheckExtPrefix(style, cur->prefix)))
- goto skip_ns;
- /*
- * Check if this namespace was excluded.
- * Note that at this point only the exclusions defined
- * on the topmost stylesheet element are in the exclusion-list.
- */
- for (i = 0;i < style->exclPrefixNr;i++) {
- if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
- goto skip_ns;
- }
- if (ret == NULL) {
- ret =
- (xmlNsPtr *) xmlMalloc((maxns + 1) *
- sizeof(xmlNsPtr));
- if (ret == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltGetInheritedNsList : out of memory!\n");
- return(0);
- }
- ret[nbns] = NULL;
- }
- /*
- * Skip shadowed namespace bindings.
- */
- for (i = 0; i < nbns; i++) {
- if ((cur->prefix == ret[i]->prefix) ||
- (xmlStrEqual(cur->prefix, ret[i]->prefix)))
- break;
- }
- if (i >= nbns) {
- if (nbns >= maxns) {
- maxns *= 2;
- ret = (xmlNsPtr *) xmlRealloc(ret,
- (maxns +
- 1) *
- sizeof(xmlNsPtr));
- if (ret == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltGetInheritedNsList : realloc failed!\n");
- return(0);
- }
- }
- ret[nbns++] = cur;
- ret[nbns] = NULL;
- }
-skip_ns:
- cur = cur->next;
- }
- }
- node = node->parent;
- }
- if (nbns != 0) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "template has %d inherited namespaces\n", nbns);
-#endif
- template->inheritedNsNr = nbns;
- template->inheritedNs = ret;
- }
- return (nbns);
-}
-#endif /* else of XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetOutput:
- * @style: the XSLT stylesheet
- * @cur: the "output" element
- *
- * parse an XSLT stylesheet output element and record
- * information related to the stylesheet output
- */
-
-void
-xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
-{
- xmlChar *elements,
- *prop;
- xmlChar *element,
- *end;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
- if (prop != NULL) {
- if (style->version != NULL)
- xmlFree(style->version);
- style->version = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
- if (prop != NULL) {
- if (style->encoding != NULL)
- xmlFree(style->encoding);
- style->encoding = prop;
- }
-
- /* relaxed to support xt:document
- * TODO KB: What does "relaxed to support xt:document" mean?
- */
- prop = xmlGetNsProp(cur, (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;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &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(NULL, style, cur,
- "invalid value for method: %s\n", prop);
- if (style != NULL) style->warnings++;
- }
- } else {
- style->method = prop;
- style->methodURI = xmlStrdup(URI);
- }
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
- if (prop != NULL) {
- if (style->doctypeSystem != NULL)
- xmlFree(style->doctypeSystem);
- style->doctypeSystem = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
- if (prop != NULL) {
- if (style->doctypePublic != NULL)
- xmlFree(style->doctypePublic);
- style->doctypePublic = prop;
- }
-
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for standalone: %s\n", prop);
- style->errors++;
- }
- xmlFree(prop);
- }
-
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for indent: %s\n", prop);
- style->errors++;
- }
- xmlFree(prop);
- }
-
- prop = xmlGetNsProp(cur, (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(NULL, style, cur,
- "invalid value for omit-xml-declaration: %s\n",
- prop);
- style->errors++;
- }
- xmlFree(prop);
- }
-
- elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
- NULL);
- if (elements != NULL) {
- if (style->cdataSection == NULL)
- style->cdataSection = xmlHashCreate(10);
- if (style->cdataSection == NULL)
- return;
-
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element))
- element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end)))
- end++;
- element = xmlStrndup(element, end - element);
- if (element) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add cdata section output element %s\n",
- element);
-#endif
- if (xmlValidateQName(BAD_CAST element, 0) != 0) {
- xsltTransformError(NULL, style, cur,
- "Attribute 'cdata-section-elements': The value "
- "'%s' is not a valid QName.\n", element);
- xmlFree(element);
- style->errors++;
- } else {
- const xmlChar *URI;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
- if (element == NULL) {
- /*
- * TODO: We'll report additionally an error
- * via the stylesheet's error handling.
- */
- xsltTransformError(NULL, style, cur,
- "Attribute 'cdata-section-elements': The value "
- "'%s' is not a valid QName.\n", element);
- style->errors++;
- } else {
- xmlNsPtr ns;
-
- /*
- * XSLT-1.0 "Each QName is expanded into an
- * expanded-name using the namespace declarations in
- * effect on the xsl:output element in which the QName
- * occurs; if there is a default namespace, it is used
- * for QNames that do not have a prefix"
- * NOTE: Fix of bug #339570.
- */
- if (URI == NULL) {
- ns = xmlSearchNs(style->doc, cur, NULL);
- if (ns != NULL)
- URI = ns->href;
- }
- xmlHashAddEntry2(style->cdataSection, element, URI,
- (void *) "cdata");
- xmlFree(element);
- }
- }
- }
- element = end;
- }
- xmlFree(elements);
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
- if (prop != NULL) {
- if (style->mediaType)
- xmlFree(style->mediaType);
- style->mediaType = prop;
- }
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
-}
-
-/**
- * xsltParseStylesheetDecimalFormat:
- * @style: the XSLT stylesheet
- * @cur: the "decimal-format" element
- *
- * <!-- Category: top-level-element -->
- * <xsl:decimal-format
- * name = qname, decimal-separator = char, grouping-separator = char,
- * infinity = string, minus-sign = char, NaN = string, percent = char
- * per-mille = char, zero-digit = char, digit = char,
- * pattern-separator = char />
- *
- * parse an XSLT stylesheet decimal-format element and
- * and record the formatting characteristics
- */
-static void
-xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
-{
- xmlChar *prop;
- xsltDecimalFormatPtr format;
- xsltDecimalFormatPtr iter;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- format = style->decimalFormat;
-
- prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
- if (prop != NULL) {
- format = xsltDecimalFormatGetByName(style, prop);
- if (format != NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
- if (style != NULL) style->warnings++;
- return;
- }
- format = xsltNewDecimalFormat(prop);
- if (format == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
- if (style != NULL) style->errors++;
- return;
- }
- /* Append new decimal-format structure */
- for (iter = style->decimalFormat; iter->next; iter = iter->next)
- ;
- if (iter)
- iter->next = format;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
- if (prop != NULL) {
- if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
- format->decimalPoint = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
- if (prop != NULL) {
- if (format->grouping != NULL) xmlFree(format->grouping);
- format->grouping = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
- if (prop != NULL) {
- if (format->infinity != NULL) xmlFree(format->infinity);
- format->infinity = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
- if (prop != NULL) {
- if (format->minusSign != NULL) xmlFree(format->minusSign);
- format->minusSign = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
- if (prop != NULL) {
- if (format->noNumber != NULL) xmlFree(format->noNumber);
- format->noNumber = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
- if (prop != NULL) {
- if (format->percent != NULL) xmlFree(format->percent);
- format->percent = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
- if (prop != NULL) {
- if (format->permille != NULL) xmlFree(format->permille);
- format->permille = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
- if (prop != NULL) {
- if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
- format->zeroDigit = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
- if (prop != NULL) {
- if (format->digit != NULL) xmlFree(format->digit);
- format->digit = prop;
- }
-
- prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
- if (prop != NULL) {
- if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
- format->patternSeparator = prop;
- }
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
-}
-
-/**
- * xsltParseStylesheetPreserveSpace:
- * @style: the XSLT stylesheet
- * @cur: the "preserve-space" element
- *
- * parse an XSLT stylesheet preserve-space element and record
- * elements needing preserving
- */
-
-static void
-xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
- xmlChar *elements;
- xmlChar *element, *end;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
- if (elements == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
- if (style != NULL) style->warnings++;
- return;
- }
-
- if (style->stripSpaces == NULL)
- style->stripSpaces = xmlHashCreate(10);
- if (style->stripSpaces == NULL)
- return;
-
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element)) element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- element = xmlStrndup(element, end - element);
- if (element) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add preserved space element %s\n", element);
-#endif
- if (xmlStrEqual(element, (const xmlChar *)"*")) {
- style->stripAll = -1;
- } else {
- const xmlChar *URI;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
-
- xmlHashAddEntry2(style->stripSpaces, element, URI,
- (xmlChar *) "preserve");
- }
- xmlFree(element);
- }
- element = end;
- }
- xmlFree(elements);
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
-}
-
-#ifdef XSLT_REFACTORED
-#else
-/**
- * xsltParseStylesheetExtPrefix:
- * @style: the XSLT stylesheet
- * @template: the "extension-element-prefixes" prefix
- *
- * parse an XSLT stylesheet's "extension-element-prefix" attribute value
- * and register the namespaces of extension instruction.
- * SPEC "A namespace is designated as an extension namespace by using
- * an extension-element-prefixes attribute on:
- * 1) an xsl:stylesheet element
- * 2) an xsl:extension-element-prefixes attribute on a
- * literal result element
- * 3) an extension instruction."
- */
-static void
-xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
- int isXsltElem) {
- xmlChar *prefixes;
- xmlChar *prefix, *end;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- if (isXsltElem) {
- /* For xsl:stylesheet/xsl:transform. */
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"extension-element-prefixes", NULL);
- } else {
- /* For literal result elements and extension instructions. */
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
- }
- if (prefixes == NULL) {
- return;
- }
-
- prefix = prefixes;
- while (*prefix != 0) {
- while (IS_BLANK(*prefix)) prefix++;
- if (*prefix == 0)
- break;
- end = prefix;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- prefix = xmlStrndup(prefix, end - prefix);
- if (prefix) {
- xmlNsPtr ns;
-
- if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
- ns = xmlSearchNs(style->doc, cur, NULL);
- else
- ns = xmlSearchNs(style->doc, cur, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:extension-element-prefix : undefined namespace %s\n",
- prefix);
- if (style != NULL) style->warnings++;
- } else {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add extension prefix %s\n", prefix);
-#endif
- xsltRegisterExtPrefix(style, prefix, ns->href);
- }
- xmlFree(prefix);
- }
- prefix = end;
- }
- xmlFree(prefixes);
-}
-#endif /* else of XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetStripSpace:
- * @style: the XSLT stylesheet
- * @cur: the "strip-space" element
- *
- * parse an XSLT stylesheet's strip-space element and record
- * the elements needing stripping
- */
-
-static void
-xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
- xmlChar *elements;
- xmlChar *element, *end;
-
- if ((cur == NULL) || (style == NULL))
- return;
-
- elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
- if (elements == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetStripSpace: missing elements attribute\n");
- if (style != NULL) style->warnings++;
- return;
- }
-
- if (style->stripSpaces == NULL)
- style->stripSpaces = xmlHashCreate(10);
- if (style->stripSpaces == NULL)
- return;
-
- element = elements;
- while (*element != 0) {
- while (IS_BLANK(*element)) element++;
- if (*element == 0)
- break;
- end = element;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- element = xmlStrndup(element, end - element);
- if (element) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "add stripped space element %s\n", element);
-#endif
- if (xmlStrEqual(element, (const xmlChar *)"*")) {
- style->stripAll = 1;
- } else {
- const xmlChar *URI;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(cur, &element);
-
- xmlHashAddEntry2(style->stripSpaces, element, URI,
- (xmlChar *) "strip");
- }
- xmlFree(element);
- }
- element = end;
- }
- xmlFree(elements);
- if (cur->children != NULL) {
- xsltParseContentError(style, cur->children);
- }
-}
-
-#ifdef XSLT_REFACTORED
-#else
-/**
- * xsltParseStylesheetExcludePrefix:
- * @style: the XSLT stylesheet
- * @cur: the current point in the stylesheet
- *
- * parse an XSLT stylesheet exclude prefix and record
- * namespaces needing stripping
- *
- * Returns the number of Excluded prefixes added at that level
- */
-
-static int
-xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
- int isXsltElem)
-{
- int nb = 0;
- xmlChar *prefixes;
- xmlChar *prefix, *end;
-
- if ((cur == NULL) || (style == NULL))
- return(0);
-
- if (isXsltElem)
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"exclude-result-prefixes", NULL);
- else
- prefixes = xmlGetNsProp(cur,
- (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
-
- if (prefixes == NULL) {
- return(0);
- }
-
- prefix = prefixes;
- while (*prefix != 0) {
- while (IS_BLANK(*prefix)) prefix++;
- if (*prefix == 0)
- break;
- end = prefix;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- prefix = xmlStrndup(prefix, end - prefix);
- if (prefix) {
- xmlNsPtr ns;
-
- if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
- ns = xmlSearchNs(style->doc, cur, NULL);
- else
- ns = xmlSearchNs(style->doc, cur, prefix);
- if (ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:exclude-result-prefixes : undefined namespace %s\n",
- prefix);
- if (style != NULL) style->warnings++;
- } else {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "exclude result prefix %s\n", prefix);
-#endif
- exclPrefixPush(style, (xmlChar *) ns->href);
- nb++;
- }
- xmlFree(prefix);
- }
- prefix = end;
- }
- xmlFree(prefixes);
- return(nb);
-}
-#endif /* else of XSLT_REFACTORED */
-
-#ifdef XSLT_REFACTORED
-
-/*
-* xsltTreeEnsureXMLDecl:
-* @doc: the doc
-*
-* BIG NOTE:
-* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
-* Ensures that there is an XML namespace declaration on the doc.
-*
-* Returns the XML ns-struct or NULL on API and internal errors.
-*/
-static xmlNsPtr
-xsltTreeEnsureXMLDecl(xmlDocPtr doc)
-{
- if (doc == NULL)
- return (NULL);
- if (doc->oldNs != NULL)
- return (doc->oldNs);
- {
- xmlNsPtr ns;
- ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
- if (ns == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltTreeEnsureXMLDecl: Failed to allocate "
- "the XML namespace.\n");
- return (NULL);
- }
- memset(ns, 0, sizeof(xmlNs));
- ns->type = XML_LOCAL_NAMESPACE;
- /*
- * URGENT TODO: revisit this.
- */
-#ifdef LIBXML_NAMESPACE_DICT
- if (doc->dict)
- ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
- else
- ns->href = xmlStrdup(XML_XML_NAMESPACE);
-#else
- ns->href = xmlStrdup(XML_XML_NAMESPACE);
-#endif
- ns->prefix = xmlStrdup((const xmlChar *)"xml");
- doc->oldNs = ns;
- return (ns);
- }
-}
-
-/*
-* xsltTreeAcquireStoredNs:
-* @doc: the doc
-* @nsName: the namespace name
-* @prefix: the prefix
-*
-* BIG NOTE:
-* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
-* Creates or reuses an xmlNs struct on doc->oldNs with
-* the given prefix and namespace name.
-*
-* Returns the aquired ns struct or NULL in case of an API
-* or internal error.
-*/
-static xmlNsPtr
-xsltTreeAcquireStoredNs(xmlDocPtr doc,
- const xmlChar *nsName,
- const xmlChar *prefix)
-{
- xmlNsPtr ns;
-
- if (doc == NULL)
- return (NULL);
- if (doc->oldNs != NULL)
- ns = doc->oldNs;
- else
- ns = xsltTreeEnsureXMLDecl(doc);
- if (ns == NULL)
- return (NULL);
- if (ns->next != NULL) {
- /* Reuse. */
- ns = ns->next;
- while (ns != NULL) {
- if ((ns->prefix == NULL) != (prefix == NULL)) {
- /* NOP */
- } else if (prefix == NULL) {
- if (xmlStrEqual(ns->href, nsName))
- return (ns);
- } else {
- if ((ns->prefix[0] == prefix[0]) &&
- xmlStrEqual(ns->prefix, prefix) &&
- xmlStrEqual(ns->href, nsName))
- return (ns);
-
- }
- if (ns->next == NULL)
- break;
- ns = ns->next;
- }
- }
- /* Create. */
- ns->next = xmlNewNs(NULL, nsName, prefix);
- return (ns->next);
-}
-
-/**
- * xsltLREBuildEffectiveNs:
- *
- * Apply ns-aliasing on the namespace of the given @elem and
- * its attributes.
- */
-static int
-xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem)
-{
- xmlNsPtr ns;
- xsltNsAliasPtr alias;
-
- if ((cctxt == NULL) || (elem == NULL))
- return(-1);
- if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
- return(0);
-
- alias = cctxt->nsAliases;
- while (alias != NULL) {
- if ( /* If both namespaces are NULL... */
- ( (elem->ns == NULL) &&
- ((alias->literalNs == NULL) ||
- (alias->literalNs->href == NULL)) ) ||
- /* ... or both namespace are equal */
- ( (elem->ns != NULL) &&
- (alias->literalNs != NULL) &&
- xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
- {
- if ((alias->targetNs != NULL) &&
- (alias->targetNs->href != NULL))
- {
- /*
- * Convert namespace.
- */
- if (elem->doc == alias->docOfTargetNs) {
- /*
- * This is the nice case: same docs.
- * This will eventually assign a ns-decl which
- * is shadowed, but this has no negative effect on
- * the generation of the result tree.
- */
- elem->ns = alias->targetNs;
- } else {
- /*
- * This target xmlNs originates from a different
- * stylesheet tree. Try to locate it in the
- * in-scope namespaces.
- * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
- */
- ns = xmlSearchNs(elem->doc, elem,
- alias->targetNs->prefix);
- /*
- * If no matching ns-decl found, then assign a
- * ns-decl stored in xmlDoc.
- */
- if ((ns == NULL) ||
- (! xmlStrEqual(ns->href, alias->targetNs->href)))
- {
- /*
- * BIG NOTE: The use of xsltTreeAcquireStoredNs()
- * is not very efficient, but currently I don't
- * see an other way of *safely* changing a node's
- * namespace, since the xmlNs struct in
- * alias->targetNs might come from an other
- * stylesheet tree. So we need to anchor it in the
- * current document, without adding it to the tree,
- * which would otherwise change the in-scope-ns
- * semantic of the tree.
- */
- ns = xsltTreeAcquireStoredNs(elem->doc,
- alias->targetNs->href,
- alias->targetNs->prefix);
-
- if (ns == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in "
- "xsltLREBuildEffectiveNs(): "
- "failed to acquire a stored "
- "ns-declaration.\n");
- cctxt->style->errors++;
- return(-1);
-
- }
- }
- elem->ns = ns;
- }
- } else {
- /*
- * Move into or leave in the NULL namespace.
- */
- elem->ns = NULL;
- }
- break;
- }
- alias = alias->next;
- }
- /*
- * Same with attributes of literal result elements.
- */
- if (elem->properties != NULL) {
- xmlAttrPtr attr = elem->properties;
-
- while (attr != NULL) {
- if (attr->ns == NULL) {
- attr = attr->next;
- continue;
- }
- alias = cctxt->nsAliases;
- while (alias != NULL) {
- if ( /* If both namespaces are NULL... */
- ( (elem->ns == NULL) &&
- ((alias->literalNs == NULL) ||
- (alias->literalNs->href == NULL)) ) ||
- /* ... or both namespace are equal */
- ( (elem->ns != NULL) &&
- (alias->literalNs != NULL) &&
- xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
- {
- if ((alias->targetNs != NULL) &&
- (alias->targetNs->href != NULL))
- {
- if (elem->doc == alias->docOfTargetNs) {
- elem->ns = alias->targetNs;
- } else {
- ns = xmlSearchNs(elem->doc, elem,
- alias->targetNs->prefix);
- if ((ns == NULL) ||
- (! xmlStrEqual(ns->href, alias->targetNs->href)))
- {
- ns = xsltTreeAcquireStoredNs(elem->doc,
- alias->targetNs->href,
- alias->targetNs->prefix);
-
- if (ns == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in "
- "xsltLREBuildEffectiveNs(): "
- "failed to acquire a stored "
- "ns-declaration.\n");
- cctxt->style->errors++;
- return(-1);
-
- }
- }
- elem->ns = ns;
- }
- } else {
- /*
- * Move into or leave in the NULL namespace.
- */
- elem->ns = NULL;
- }
- break;
- }
- alias = alias->next;
- }
-
- attr = attr->next;
- }
- }
- return(0);
-}
-
-/**
- * xsltLREBuildEffectiveNsNodes:
- *
- * Computes the effective namespaces nodes for a literal result
- * element.
- * @effectiveNs is the set of effective ns-nodes
- * on the literal result element, which will be added to the result
- * element if not already existing in the result tree.
- * This means that excluded namespaces (via exclude-result-prefixes,
- * extension-element-prefixes and the XSLT namespace) not added
- * to the set.
- * Namespace-aliasing was applied on the @effectiveNs.
- */
-static int
-xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
- xsltStyleItemLRElementInfoPtr item,
- xmlNodePtr elem,
- int isLRE)
-{
- xmlNsPtr ns, tmpns;
- xsltEffectiveNsPtr effNs, lastEffNs = NULL;
- int i, j, holdByElem;
- xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
- xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
-
- if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
- (item == NULL) || (item->effectiveNs != NULL))
- return(-1);
-
- if (item->inScopeNs == NULL)
- return(0);
-
- extElemNs = cctxt->inode->extElemNs;
- exclResultNs = cctxt->inode->exclResultNs;
-
- for (i = 0; i < item->inScopeNs->totalNumber; i++) {
- ns = item->inScopeNs->list[i];
- /*
- * Skip namespaces designated as excluded namespaces
- * -------------------------------------------------
- *
- * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
- * which are target namespaces of namespace-aliases
- * regardless if designated as excluded.
- *
- * Exclude the XSLT namespace.
- */
- if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
- goto skip_ns;
-
- /*
- * Exclude excluded result namespaces.
- */
- if (exclResultNs) {
- for (j = 0; j < exclResultNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
- goto skip_ns;
- }
- /*
- * Exclude extension-element namespaces.
- */
- if (extElemNs) {
- for (j = 0; j < extElemNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
- goto skip_ns;
- }
- /*
- * OPTIMIZE TODO: This information may not be needed.
- */
- if (isLRE && (elem->nsDef != NULL)) {
- holdByElem = 0;
- tmpns = elem->nsDef;
- do {
- if (tmpns == ns) {
- holdByElem = 1;
- break;
- }
- tmpns = tmpns->next;
- } while (tmpns != NULL);
- } else
- holdByElem = 0;
- /*
- * Apply namespace aliasing
- * ------------------------
- *
- * NOTE: The ns-aliasing machanism is non-cascading.
- * (checked with Saxon, Xalan and MSXML .NET).
- * URGENT TODO: is style->nsAliases the effective list of
- * ns-aliases, or do we need to lookup the whole
- * import-tree?
- * TODO: Get rid of import-tree lookup.
- */
- if (cctxt->hasNsAliases) {
- xsltNsAliasPtr alias = cctxt->nsAliases;
- do {
- /*
- * TODO: What to do with xmlns="" ?
- */
- if ((alias->literalNs != NULL) &&
- (xmlStrEqual(alias->literalNs->href, ns->href)))
- {
- /*
- * Recognized as an namespace alias; convert it to
- * the target namespace.
- */
- if (alias->targetNs != NULL)
- ns = alias->literalNs;
- else {
- /*
- * The target is the NULL namespace.
- */
- goto skip_ns;
- }
- break;
- }
- alias = alias->next;
- } while (alias != NULL);
- }
-
- /*
- * Add the effective namespace declaration.
- */
- effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
- if (effNs == NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "Internal error in xsltLREBuildEffectiveNs(): "
- "failed to allocate memory.\n");
- cctxt->style->errors++;
- return(-1);
- }
- if (cctxt->psData->effectiveNs == NULL) {
- cctxt->psData->effectiveNs = effNs;
- effNs->nextInStore = NULL;
- } else {
- effNs->nextInStore = cctxt->psData->effectiveNs;
- cctxt->psData->effectiveNs = effNs;
- }
-
- effNs->next = NULL;
- effNs->prefix = ns->prefix;
- effNs->nsName = ns->href;
- effNs->holdByElem = holdByElem;
-
- if (lastEffNs == NULL)
- item->effectiveNs = effNs;
- else
- lastEffNs->next = effNs;
- lastEffNs = effNs;
-
-skip_ns:
- {}
- }
- return(0);
-}
-
-
-/**
- * xsltLREInfoCreate:
- *
- * @isLRE: indicates if the given @elem is a literal result element
- *
- * Creates a new info for a literal result element.
- */
-static int
-xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem,
- int isLRE)
-{
- xsltStyleItemLRElementInfoPtr item;
-
- if ((cctxt == NULL) || (cctxt->inode == NULL))
- return(-1);
-
- item = (xsltStyleItemLRElementInfoPtr)
- xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "Internal error in xsltLREInfoCreate(): "
- "memory allocation failed.\n");
- cctxt->style->errors++;
- return(-1);
- }
- memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
- item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
- /*
- * Store it in the stylesheet.
- */
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
- /*
- * @inScopeNs are used for execution of XPath expressions
- * in AVTs.
- */
- item->inScopeNs = cctxt->inode->inScopeNs;
-
- if (elem)
- xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
-
- cctxt->inode->litResElemInfo = item;
- cctxt->inode->nsChanged = 0;
- cctxt->maxLREs++;
- return(0);
-}
-
-/*
-* xsltCompilerNodePush:
-*
-* @cctxt: the compilation context
-* @node: the node to be pushed (this can also be the doc-node)
-*
-* Returns the current node info structure or
-* NULL in case of an internal error.
-*/
-xsltCompilerNodeInfoPtr
-xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- xsltCompilerNodeInfoPtr inode, iprev;
-
- if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
- inode = cctxt->inode->next;
- } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
- inode = cctxt->inodeList;
- } else {
- /*
- * Create a new node-info.
- */
- inode = (xsltCompilerNodeInfoPtr)
- xmlMalloc(sizeof(xsltCompilerNodeInfo));
- if (inode == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerNodePush: malloc failed.\n");
- return(NULL);
- }
- memset(inode, 0, sizeof(xsltCompilerNodeInfo));
- if (cctxt->inodeList == NULL)
- cctxt->inodeList = inode;
- else {
- cctxt->inodeLast->next = inode;
- inode->prev = cctxt->inodeLast;
- }
- cctxt->inodeLast = inode;
- cctxt->maxNodeInfos++;
- if (cctxt->inode == NULL) {
- cctxt->inode = inode;
- /*
- * Create an initial literal result element info for
- * the root of the stylesheet.
- */
- xsltLREInfoCreate(cctxt, NULL, 0);
- }
- }
- cctxt->depth++;
- cctxt->inode = inode;
- /*
- * REVISIT TODO: Keep the reset always complete.
- * NOTE: Be carefull with the @node, since it might be
- * a doc-node.
- */
- inode->node = node;
- inode->depth = cctxt->depth;
- inode->templ = NULL;
- inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
- inode->type = 0;
- inode->item = NULL;
- inode->curChildType = 0;
- inode->extContentHandled = 0;
- inode->isRoot = 0;
-
- if (inode->prev != NULL) {
- iprev = inode->prev;
- /*
- * Inherit the following information:
- * ---------------------------------
- *
- * In-scope namespaces
- */
- inode->inScopeNs = iprev->inScopeNs;
- /*
- * Info for literal result elements
- */
- inode->litResElemInfo = iprev->litResElemInfo;
- inode->nsChanged = iprev->nsChanged;
- /*
- * Excluded result namespaces
- */
- inode->exclResultNs = iprev->exclResultNs;
- /*
- * Extension instruction namespaces
- */
- inode->extElemNs = iprev->extElemNs;
- /*
- * Whitespace preservation
- */
- inode->preserveWhitespace = iprev->preserveWhitespace;
- /*
- * Forwards-compatible mode
- */
- inode->forwardsCompat = iprev->forwardsCompat;
- } else {
- inode->inScopeNs = NULL;
- inode->exclResultNs = NULL;
- inode->extElemNs = NULL;
- inode->preserveWhitespace = 0;
- inode->forwardsCompat = 0;
- }
-
- return(inode);
-}
-
-/*
-* xsltCompilerNodePop:
-*
-* @cctxt: the compilation context
-* @node: the node to be pushed (this can also be the doc-node)
-*
-* Pops the current node info.
-*/
-static void
-xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- if (cctxt->inode == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Top-node mismatch.\n");
- return;
- }
- /*
- * NOTE: Be carefull with the @node, since it might be
- * a doc-node.
- */
- if (cctxt->inode->node != node) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Node mismatch.\n");
- goto mismatch;
- }
- if (cctxt->inode->depth != cctxt->depth) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Depth mismatch.\n");
- goto mismatch;
- }
- cctxt->depth--;
- cctxt->inode = cctxt->inode->prev;
- if (cctxt->inode != NULL)
- cctxt->inode->curChildType = 0;
- return;
-
-mismatch:
- {
- const xmlChar *nsName = NULL, *name = NULL;
- const xmlChar *infnsName = NULL, *infname = NULL;
-
- if (node) {
- if (node->type == XML_ELEMENT_NODE) {
- name = node->name;
- if (node->ns != NULL)
- nsName = node->ns->href;
- else
- nsName = BAD_CAST "";
- } else {
- name = BAD_CAST "#document";
- nsName = BAD_CAST "";
- }
- } else
- name = BAD_CAST "Not given";
-
- if (cctxt->inode->node) {
- if (node->type == XML_ELEMENT_NODE) {
- infname = cctxt->inode->node->name;
- if (cctxt->inode->node->ns != NULL)
- infnsName = cctxt->inode->node->ns->href;
- else
- infnsName = BAD_CAST "";
- } else {
- infname = BAD_CAST "#document";
- infnsName = BAD_CAST "";
- }
- } else
- infname = BAD_CAST "Not given";
-
-
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
- name, nsName);
- xmlGenericError(xmlGenericErrorContext,
- "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
- infname, infnsName);
- }
-}
-
-/*
-* xsltCompilerBuildInScopeNsList:
-*
-* Create and store the list of in-scope namespaces for the given
-* node in the stylesheet. If there are no changes in the in-scope
-* namespaces then the last ns-info of the ancestor axis will be returned.
-* Compilation-time only.
-*
-* Returns the ns-info or NULL if there are no namespaces in scope.
-*/
-static xsltNsListContainerPtr
-xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- xsltNsListContainerPtr nsi = NULL;
- xmlNsPtr *list = NULL, ns;
- int i, maxns = 5;
- /*
- * Create a new ns-list for this position in the node-tree.
- * xmlGetNsList() will return NULL, if there are no ns-decls in the
- * tree. Note that the ns-decl for the XML namespace is not added
- * to the resulting list; the XPath module handles the XML namespace
- * internally.
- */
- while (node != NULL) {
- if (node->type == XML_ELEMENT_NODE) {
- ns = node->nsDef;
- while (ns != NULL) {
- if (nsi == NULL) {
- nsi = (xsltNsListContainerPtr)
- xmlMalloc(sizeof(xsltNsListContainer));
- if (nsi == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "malloc failed!\n");
- goto internal_err;
- }
- memset(nsi, 0, sizeof(xsltNsListContainer));
- nsi->list =
- (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
- if (nsi->list == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "malloc failed!\n");
- goto internal_err;
- }
- nsi->list[0] = NULL;
- }
- /*
- * Skip shadowed namespace bindings.
- */
- for (i = 0; i < nsi->totalNumber; i++) {
- if ((ns->prefix == nsi->list[i]->prefix) ||
- (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
- break;
- }
- if (i >= nsi->totalNumber) {
- if (nsi->totalNumber >= maxns) {
- maxns *= 2;
- nsi->list =
- (xmlNsPtr *) xmlRealloc(nsi->list,
- maxns * sizeof(xmlNsPtr));
- if (nsi->list == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: "
- "realloc failed!\n");
- goto internal_err;
- }
- }
- nsi->list[nsi->totalNumber++] = ns;
- nsi->list[nsi->totalNumber] = NULL;
- }
-
- ns = ns->next;
- }
- }
- node = node->parent;
- }
- if (nsi == NULL)
- return(NULL);
- /*
- * Move the default namespace to last position.
- */
- nsi->xpathNumber = nsi->totalNumber;
- for (i = 0; i < nsi->totalNumber; i++) {
- if (nsi->list[i]->prefix == NULL) {
- ns = nsi->list[i];
- nsi->list[i] = nsi->list[nsi->totalNumber-1];
- nsi->list[nsi->totalNumber-1] = ns;
- nsi->xpathNumber--;
- break;
- }
- }
- /*
- * Store the ns-list in the stylesheet.
- */
- if (xsltPointerListAddSize(
- (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
- (void *) nsi, 5) == -1)
- {
- xmlFree(nsi);
- nsi = NULL;
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
- goto internal_err;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
-
- return(nsi);
-
-internal_err:
- if (list != NULL)
- xmlFree(list);
- cctxt->style->errors++;
- return(NULL);
-}
-
-static int
-xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
- xsltPointerListPtr list,
- xmlNodePtr node,
- const xmlChar *value)
-{
- xmlChar *cur, *end;
- xmlNsPtr ns;
-
- if ((cctxt == NULL) || (value == NULL) || (list == NULL))
- return(-1);
-
- list->number = 0;
-
- cur = (xmlChar *) value;
- while (*cur != 0) {
- while (IS_BLANK(*cur)) cur++;
- if (*cur == 0)
- break;
- end = cur;
- while ((*end != 0) && (!IS_BLANK(*end))) end++;
- cur = xmlStrndup(cur, end - cur);
- if (cur == NULL) {
- cur = end;
- continue;
- }
- /*
- * TODO: Export and use xmlSearchNsByPrefixStrict()
- * in Libxml2, tree.c, since xmlSearchNs() is in most
- * cases not efficient and in some cases not correct.
- *
- * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
- */
- if ((cur[0] == '#') &&
- xmlStrEqual(cur, (const xmlChar *)"#default"))
- ns = xmlSearchNs(cctxt->style->doc, node, NULL);
- else
- ns = xmlSearchNs(cctxt->style->doc, node, cur);
-
- if (ns == NULL) {
- /*
- * TODO: Better to report the attr-node, otherwise
- * the user won't know which attribute was invalid.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "No namespace binding in scope for prefix '%s'.\n", cur);
- /*
- * XSLT-1.0: "It is an error if there is no namespace
- * bound to the prefix on the element bearing the
- * exclude-result-prefixes or xsl:exclude-result-prefixes
- * attribute."
- */
- cctxt->style->errors++;
- } else {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "resolved prefix '%s'\n", cur);
-#endif
- /*
- * Note that we put the namespace name into the dict.
- */
- if (xsltPointerListAddSize(list,
- (void *) xmlDictLookup(cctxt->style->dict,
- ns->href, -1), 5) == -1)
- {
- xmlFree(cur);
- goto internal_err;
- }
- }
- xmlFree(cur);
-
- cur = end;
- }
- return(0);
-
-internal_err:
- cctxt->style->errors++;
- return(-1);
-}
-
-/**
- * xsltCompilerUtilsCreateMergedList:
- * @dest: the destination list (optional)
- * @first: the first list
- * @second: the second list (optional)
- *
- * Appends the content of @second to @first into @destination.
- * If @destination is NULL a new list will be created.
- *
- * Returns the merged list of items or NULL if there's nothing to merge.
- */
-static xsltPointerListPtr
-xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
- xsltPointerListPtr second)
-{
- xsltPointerListPtr ret;
- size_t num;
-
- if (first)
- num = first->number;
- else
- num = 0;
- if (second)
- num += second->number;
- if (num == 0)
- return(NULL);
- ret = xsltPointerListCreate(num);
- if (ret == NULL)
- return(NULL);
- /*
- * Copy contents.
- */
- if ((first != NULL) && (first->number != 0)) {
- memcpy(ret->items, first->items,
- first->number * sizeof(void *));
- if ((second != NULL) && (second->number != 0))
- memcpy(ret->items + first->number, second->items,
- second->number * sizeof(void *));
- } else if ((second != NULL) && (second->number != 0))
- memcpy(ret->items, (void *) second->items,
- second->number * sizeof(void *));
- ret->number = num;
- return(ret);
-}
-
-/*
-* xsltParseExclResultPrefixes:
-*
-* Create and store the list of in-scope namespaces for the given
-* node in the stylesheet. If there are no changes in the in-scope
-* namespaces then the last ns-info of the ancestor axis will be returned.
-* Compilation-time only.
-*
-* Returns the ns-info or NULL if there are no namespaces in scope.
-*/
-static xsltPointerListPtr
-xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- xsltPointerListPtr def,
- int instrCategory)
-{
- xsltPointerListPtr list = NULL;
- xmlChar *value;
- xmlAttrPtr attr;
-
- if ((cctxt == NULL) || (node == NULL))
- return(NULL);
-
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
- XSLT_NAMESPACE);
- if (attr == NULL)
- return(def);
-
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Mark the XSLT attr.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
-
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'exclude-result-prefixes': Invalid value.\n");
- cctxt->style->errors++;
- return(def);
- }
-
- if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
- BAD_CAST value) != 0)
- goto exit;
- if (cctxt->tmpList->number == 0)
- goto exit;
- /*
- * Merge the list with the inherited list.
- */
- list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
- if (list == NULL)
- goto exit;
- /*
- * Store the list in the stylesheet/compiler context.
- */
- if (xsltPointerListAddSize(
- cctxt->psData->exclResultNamespaces, list, 5) == -1)
- {
- xsltPointerListFree(list);
- list = NULL;
- goto exit;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
-
-exit:
- if (list != NULL)
- return(list);
- else
- return(def);
-}
-
-/*
-* xsltParseExtElemPrefixes:
-*
-* Create and store the list of in-scope namespaces for the given
-* node in the stylesheet. If there are no changes in the in-scope
-* namespaces then the last ns-info of the ancestor axis will be returned.
-* Compilation-time only.
-*
-* Returns the ns-info or NULL if there are no namespaces in scope.
-*/
-static xsltPointerListPtr
-xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- xsltPointerListPtr def,
- int instrCategory)
-{
- xsltPointerListPtr list = NULL;
- xmlAttrPtr attr;
- xmlChar *value;
- int i;
-
- if ((cctxt == NULL) || (node == NULL))
- return(NULL);
-
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
- XSLT_NAMESPACE);
- if (attr == NULL)
- return(def);
-
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Mark the XSLT attr.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
-
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'extension-element-prefixes': Invalid value.\n");
- cctxt->style->errors++;
- return(def);
- }
-
-
- if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
- BAD_CAST value) != 0)
- goto exit;
-
- if (cctxt->tmpList->number == 0)
- goto exit;
- /*
- * REVISIT: Register the extension namespaces.
- */
- for (i = 0; i < cctxt->tmpList->number; i++)
- xsltRegisterExtPrefix(cctxt->style, NULL,
- BAD_CAST cctxt->tmpList->items[i]);
- /*
- * Merge the list with the inherited list.
- */
- list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
- if (list == NULL)
- goto exit;
- /*
- * Store the list in the stylesheet.
- */
- if (xsltPointerListAddSize(
- cctxt->psData->extElemNamespaces, list, 5) == -1)
- {
- xsltPointerListFree(list);
- list = NULL;
- goto exit;
- }
- /*
- * Notify of change in status wrt namespaces.
- */
- if (cctxt->inode != NULL)
- cctxt->inode->nsChanged = 1;
-
-exit:
- if (list != NULL)
- return(list);
- else
- return(def);
-}
-
-/*
-* xsltParseAttrXSLTVersion:
-*
-* @cctxt: the compilation context
-* @node: the element-node
-* @isXsltElem: whether this is an XSLT element
-*
-* Parses the attribute xsl:version.
-*
-* Returns 1 if there was such an attribute, 0 if not and
-* -1 if an internal or API error occured.
-*/
-static int
-xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- int instrCategory)
-{
- xmlChar *value;
- xmlAttrPtr attr;
-
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
-
- if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
- else
- attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
-
- if (attr == NULL)
- return(0);
-
- attr->psvi = (void *) xsltXSLTAttrMarker;
-
- if ((attr->children != NULL) &&
- (attr->children->content != NULL))
- value = attr->children->content;
- else {
- xsltTransformError(NULL, cctxt->style, node,
- "Attribute 'version': Invalid value.\n");
- cctxt->style->errors++;
- return(1);
- }
-
- if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
- cctxt->inode->forwardsCompat = 1;
- /*
- * TODO: To what extent do we support the
- * forwards-compatible mode?
- */
- /*
- * Report this only once per compilation episode.
- */
- if (! cctxt->hasForwardsCompat) {
- cctxt->hasForwardsCompat = 1;
- cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
- xsltTransformError(NULL, cctxt->style, node,
- "Warning: the attribute xsl:version specifies a value "
- "different from '1.0'. Switching to forwards-compatible "
- "mode. Only features of XSLT 1.0 are supported by this "
- "processor.\n");
- cctxt->style->warnings++;
- cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
- }
- } else {
- cctxt->inode->forwardsCompat = 0;
- }
-
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Set a marker on XSLT attributes.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- return(1);
-}
-
-static int
-xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- xmlNodePtr deleteNode, cur, txt, textNode = NULL;
- xmlDocPtr doc;
- xsltStylesheetPtr style;
- int internalize = 0, findSpaceAttr;
- int xsltStylesheetElemDepth;
- xmlAttrPtr attr;
- xmlChar *value;
- const xmlChar *name, *nsNameXSLT = NULL;
- int strictWhitespace, inXSLText = 0;
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- xsltNsMapPtr nsMapItem;
-#endif
-
- if ((cctxt == NULL) || (cctxt->style == NULL) ||
- (node == NULL) || (node->type != XML_ELEMENT_NODE))
- return(-1);
-
- doc = node->doc;
- if (doc == NULL)
- goto internal_err;
-
- style = cctxt->style;
- if ((style->dict != NULL) && (doc->dict == style->dict))
- internalize = 1;
- else
- style->internalized = 0;
-
- /*
- * Init value of xml:space. Since this might be an embedded
- * stylesheet, this is needed to be performed on the element
- * where the stylesheet is rooted at, taking xml:space of
- * ancestors into account.
- */
- if (! cctxt->simplified)
- xsltStylesheetElemDepth = cctxt->depth +1;
- else
- xsltStylesheetElemDepth = 0;
-
- if (xmlNodeGetSpacePreserve(node) != 1)
- cctxt->inode->preserveWhitespace = 0;
- else
- cctxt->inode->preserveWhitespace = 1;
-
- /*
- * Eval if we should keep the old incorrect behaviour.
- */
- strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
-
- nsNameXSLT = xsltConstNamespaceNameXSLT;
-
- deleteNode = NULL;
- cur = node;
- while (cur != NULL) {
- if (deleteNode != NULL) {
-
-#ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParsePreprocessStylesheetTree: removing node\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
-
- /*
- * Clear the PSVI field.
- */
- cur->psvi = NULL;
-
- xsltCompilerNodePush(cctxt, cur);
-
- inXSLText = 0;
- textNode = NULL;
- findSpaceAttr = 1;
- cctxt->inode->stripWhitespace = 0;
- /*
- * TODO: I'd love to use a string pointer comparison here :-/
- */
- if (IS_XSLT_ELEM(cur)) {
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if (cur->ns->href != nsNameXSLT) {
- nsMapItem = xsltNewNamespaceMapItem(cctxt,
- doc, cur->ns, cur);
- if (nsMapItem == NULL)
- goto internal_err;
- cur->ns->href = nsNameXSLT;
- }
-#endif
-
- if (cur->name == NULL)
- goto process_attributes;
- /*
- * Mark the XSLT element for later recognition.
- * TODO: Using the marker is still too dangerous, since if
- * the parsing mechanism leaves out an XSLT element, then
- * this might hit the transformation-mechanism, which
- * will break if it doesn't expect such a marker.
- */
- /* cur->psvi = (void *) xsltXSLTElemMarker; */
-
- /*
- * XSLT 2.0: "Any whitespace text node whose parent is
- * one of the following elements is removed from the "
- * tree, regardless of any xml:space attributes:..."
- * xsl:apply-imports,
- * xsl:apply-templates,
- * xsl:attribute-set,
- * xsl:call-template,
- * xsl:choose,
- * xsl:stylesheet, xsl:transform.
- * XSLT 2.0: xsl:analyze-string,
- * xsl:character-map,
- * xsl:next-match
- *
- * TODO: I'd love to use a string pointer comparison here :-/
- */
- name = cur->name;
- switch (*name) {
- case 't':
- if ((name[0] == 't') && (name[1] == 'e') &&
- (name[2] == 'x') && (name[3] == 't') &&
- (name[4] == 0))
- {
- /*
- * Process the xsl:text element.
- * ----------------------------
- * Mark it for later recognition.
- */
- cur->psvi = (void *) xsltXSLTTextMarker;
- /*
- * For stylesheets, the set of
- * whitespace-preserving element names
- * consists of just xsl:text.
- */
- findSpaceAttr = 0;
- cctxt->inode->preserveWhitespace = 1;
- inXSLText = 1;
- }
- break;
- case 'c':
- if (xmlStrEqual(name, BAD_CAST "choose") ||
- xmlStrEqual(name, BAD_CAST "call-template"))
- cctxt->inode->stripWhitespace = 1;
- break;
- case 'a':
- if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
- xmlStrEqual(name, BAD_CAST "apply-imports") ||
- xmlStrEqual(name, BAD_CAST "attribute-set"))
-
- cctxt->inode->stripWhitespace = 1;
- break;
- default:
- if (xsltStylesheetElemDepth == cctxt->depth) {
- /*
- * This is a xsl:stylesheet/xsl:transform.
- */
- cctxt->inode->stripWhitespace = 1;
- break;
- }
-
- if ((cur->prev != NULL) &&
- (cur->prev->type == XML_TEXT_NODE))
- {
- /*
- * XSLT 2.0 : "Any whitespace text node whose
- * following-sibling node is an xsl:param or
- * xsl:sort element is removed from the tree,
- * regardless of any xml:space attributes."
- */
- if (((*name == 'p') || (*name == 's')) &&
- (xmlStrEqual(name, BAD_CAST "param") ||
- xmlStrEqual(name, BAD_CAST "sort")))
- {
- do {
- if (IS_BLANK_NODE(cur->prev)) {
- txt = cur->prev;
- xmlUnlinkNode(txt);
- xmlFreeNode(txt);
- } else {
- /*
- * This will result in a content
- * error, when hitting the parsing
- * functions.
- */
- break;
- }
- } while (cur->prev);
- }
- }
- break;
- }
- }
-
-process_attributes:
- /*
- * Process attributes.
- * ------------------
- */
- if (cur->properties != NULL) {
- if (cur->children == NULL)
- findSpaceAttr = 0;
- attr = cur->properties;
- do {
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
- xmlStrEqual(attr->ns->href, nsNameXSLT))
- {
- nsMapItem = xsltNewNamespaceMapItem(cctxt,
- doc, attr->ns, cur);
- if (nsMapItem == NULL)
- goto internal_err;
- attr->ns->href = nsNameXSLT;
- }
-#endif
- if (internalize) {
- /*
- * Internalize the attribute's value; the goal is to
- * speed up operations and minimize used space by
- * compiled stylesheets.
- */
- txt = attr->children;
- /*
- * NOTE that this assumes only one
- * text-node in the attribute's content.
- */
- if ((txt != NULL) && (txt->content != NULL) &&
- (!xmlDictOwns(style->dict, txt->content)))
- {
- value = (xmlChar *) xmlDictLookup(style->dict,
- txt->content, -1);
- xmlNodeSetContent(txt, NULL);
- txt->content = value;
- }
- }
- /*
- * Process xml:space attributes.
- * ----------------------------
- */
- if ((findSpaceAttr != 0) &&
- (attr->ns != NULL) &&
- (attr->name != NULL) &&
- (attr->name[0] == 's') &&
- (attr->ns->prefix != NULL) &&
- (attr->ns->prefix[0] == 'x') &&
- (attr->ns->prefix[1] == 'm') &&
- (attr->ns->prefix[2] == 'l') &&
- (attr->ns->prefix[3] == 0))
- {
- value = xmlGetNsProp(cur, BAD_CAST "space",
- XML_XML_NAMESPACE);
- if (value != NULL) {
- if (xmlStrEqual(value, BAD_CAST "preserve")) {
- cctxt->inode->preserveWhitespace = 1;
- } else if (xmlStrEqual(value, BAD_CAST "default")) {
- cctxt->inode->preserveWhitespace = 0;
- } else {
- /* Invalid value for xml:space. */
- xsltTransformError(NULL, style, cur,
- "Attribute xml:space: Invalid value.\n");
- cctxt->style->warnings++;
- }
- findSpaceAttr = 0;
- xmlFree(value);
- }
-
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- /*
- * We'll descend into the children of element nodes only.
- */
- if (cur->children != NULL) {
- cur = cur->children;
- continue;
- }
- } else if ((cur->type == XML_TEXT_NODE) ||
- (cur->type == XML_CDATA_SECTION_NODE))
- {
- /*
- * Merge adjacent text/CDATA-section-nodes
- * ---------------------------------------
- * In order to avoid breaking of existing stylesheets,
- * if the old behaviour is wanted (strictWhitespace == 0),
- * then we *won't* merge adjacent text-nodes
- * (except in xsl:text); this will ensure that whitespace-only
- * text nodes are (incorrectly) not stripped in some cases.
- *
- * Example: : <foo> <!-- bar -->zoo</foo>
- * Corrent (strict) result: <foo> zoo</foo>
- * Incorrect (old) result : <foo>zoo</foo>
- *
- * NOTE that we *will* merge adjacent text-nodes if
- * they are in xsl:text.
- * Example, the following:
- * <xsl:text> <!-- bar -->zoo<xsl:text>
- * will result in both cases in:
- * <xsl:text> zoo<xsl:text>
- */
- cur->type = XML_TEXT_NODE;
- if ((strictWhitespace != 0) || (inXSLText != 0)) {
- /*
- * New behaviour; merge nodes.
- */
- if (textNode == NULL)
- textNode = cur;
- else {
- if (cur->content != NULL)
- xmlNodeAddContent(textNode, cur->content);
- deleteNode = cur;
- }
- if ((cur->next == NULL) ||
- (cur->next->type == XML_ELEMENT_NODE))
- goto end_of_text;
- else
- goto next_sibling;
- } else {
- /*
- * Old behaviour.
- */
- if (textNode == NULL)
- textNode = cur;
- goto end_of_text;
- }
- } else if ((cur->type == XML_COMMENT_NODE) ||
- (cur->type == XML_PI_NODE))
- {
- /*
- * Remove processing instructions and comments.
- */
- deleteNode = cur;
- if ((cur->next == NULL) ||
- (cur->next->type == XML_ELEMENT_NODE))
- goto end_of_text;
- else
- goto next_sibling;
- } else {
- textNode = NULL;
- /*
- * Invalid node-type for this data-model.
- */
- xsltTransformError(NULL, style, cur,
- "Invalid type of node for the XSLT data model.\n");
- cctxt->style->errors++;
- goto next_sibling;
- }
-
-end_of_text:
- if (textNode) {
- value = textNode->content;
- /*
- * At this point all adjacent text/CDATA-section nodes
- * have been merged.
- *
- * Strip whitespace-only text-nodes.
- * (cctxt->inode->stripWhitespace)
- */
- if ((value == NULL) || (*value == 0) ||
- (((cctxt->inode->stripWhitespace) ||
- (! cctxt->inode->preserveWhitespace)) &&
- IS_BLANK(*value) &&
- xsltIsBlank(value)))
- {
- if (textNode != cur) {
- xmlUnlinkNode(textNode);
- xmlFreeNode(textNode);
- } else
- deleteNode = textNode;
- textNode = NULL;
- goto next_sibling;
- }
- /*
- * Convert CDATA-section nodes to text-nodes.
- * TODO: Can this produce problems?
- */
- if (textNode->type != XML_TEXT_NODE) {
- textNode->type = XML_TEXT_NODE;
- textNode->name = xmlStringText;
- }
- if (internalize &&
- (textNode->content != NULL) &&
- (!xmlDictOwns(style->dict, textNode->content)))
- {
- /*
- * Internalize the string.
- */
- value = (xmlChar *) xmlDictLookup(style->dict,
- textNode->content, -1);
- xmlNodeSetContent(textNode, NULL);
- textNode->content = value;
- }
- textNode = NULL;
- /*
- * Note that "disable-output-escaping" of the xsl:text
- * element will be applied at a later level, when
- * XSLT elements are processed.
- */
- }
-
-next_sibling:
- if (cur->type == XML_ELEMENT_NODE) {
- xsltCompilerNodePop(cctxt, cur);
- }
- if (cur == node)
- break;
- if (cur->next != NULL) {
- cur = cur->next;
- } else {
- cur = cur->parent;
- inXSLText = 0;
- goto next_sibling;
- };
- }
- if (deleteNode != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParsePreprocessStylesheetTree: removing node\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- }
- return(0);
-
-internal_err:
- return(-1);
-}
-
-#endif /* XSLT_REFACTORED */
-
-#ifdef XSLT_REFACTORED
-#else
-static void
-xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
-{
- xmlNodePtr deleteNode;
- int internalize = 0;
-
- if ((style == NULL) || (cur == NULL))
- return;
-
- if ((cur->doc != NULL) && (style->dict != NULL) &&
- (cur->doc->dict == style->dict))
- internalize = 1;
- else
- style->internalized = 0;
- /*
- * This content comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- deleteNode = NULL;
- while (cur != NULL) {
- if (deleteNode != NULL) {
-#ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltPrecomputeStylesheet: removing ignorable blank node\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
- int exclPrefixes;
- /*
- * Internalize attributes values.
- */
- if ((internalize) && (cur->properties != NULL)) {
- xmlAttrPtr attr = cur->properties;
- xmlNodePtr txt;
-
- while (attr != NULL) {
- txt = attr->children;
- if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
- (txt->content != NULL) &&
- (!xmlDictOwns(style->dict, txt->content)))
- {
- xmlChar *tmp;
-
- /*
- * internalize the text string, goal is to speed
- * up operations and minimize used space by compiled
- * stylesheets.
- */
- tmp = (xmlChar *) xmlDictLookup(style->dict,
- txt->content, -1);
- if (tmp != txt->content) {
- xmlNodeSetContent(txt, NULL);
- txt->content = tmp;
- }
- }
- attr = attr->next;
- }
- }
- if (IS_XSLT_ELEM(cur)) {
- exclPrefixes = 0;
- xsltStylePreCompute(style, cur);
- if (IS_XSLT_NAME(cur, "text")) {
- for (;exclPrefixes > 0;exclPrefixes--)
- exclPrefixPop(style);
- goto skip_children;
- }
- } else {
- exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
- }
-
- if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
- xmlNsPtr ns = cur->nsDef, prev = NULL, next;
- xmlNodePtr root = NULL;
- int i, moved;
-
- root = xmlDocGetRootElement(cur->doc);
- if ((root != NULL) && (root != cur)) {
- while (ns != NULL) {
- moved = 0;
- next = ns->next;
- for (i = 0;i < style->exclPrefixNr;i++) {
- if ((ns->prefix != NULL) &&
- (xmlStrEqual(ns->href,
- style->exclPrefixTab[i]))) {
- /*
- * Move the namespace definition on the root
- * element to avoid duplicating it without
- * loosing it.
- */
- if (prev == NULL) {
- cur->nsDef = ns->next;
- } else {
- prev->next = ns->next;
- }
- ns->next = root->nsDef;
- root->nsDef = ns;
- moved = 1;
- break;
- }
- }
- if (moved == 0)
- prev = ns;
- ns = next;
- }
- }
- }
- /*
- * If we have prefixes locally, recurse and pop them up when
- * going back
- */
- if (exclPrefixes > 0) {
- xsltPrecomputeStylesheet(style, cur->children);
- for (;exclPrefixes > 0;exclPrefixes--)
- exclPrefixPop(style);
- goto skip_children;
- }
- } else if (cur->type == XML_TEXT_NODE) {
- if (IS_BLANK_NODE(cur)) {
- if (xmlNodeGetSpacePreserve(cur) != 1) {
- deleteNode = cur;
- }
- } else if ((cur->content != NULL) && (internalize) &&
- (!xmlDictOwns(style->dict, cur->content))) {
- xmlChar *tmp;
-
- /*
- * internalize the text string, goal is to speed
- * up operations and minimize used space by compiled
- * stylesheets.
- */
- tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
- xmlNodeSetContent(cur, NULL);
- cur->content = tmp;
- }
- } else if ((cur->type != XML_ELEMENT_NODE) &&
- (cur->type != XML_CDATA_SECTION_NODE)) {
- deleteNode = cur;
- goto skip_children;
- }
-
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if ((cur->children->type != XML_ENTITY_DECL) &&
- (cur->children->type != XML_ENTITY_REF_NODE) &&
- (cur->children->type != XML_ENTITY_NODE)) {
- cur = cur->children;
- continue;
- }
- }
-
-skip_children:
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
- do {
-
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == (xmlNodePtr) style->doc) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- if (deleteNode != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltPrecomputeStylesheet: removing ignorable blank node\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- }
-}
-#endif /* end of else XSLT_REFACTORED */
-
-/**
- * xsltGatherNamespaces:
- * @style: the XSLT stylesheet
- *
- * Browse the stylesheet and build the namspace hash table which
- * will be used for XPath interpretation. If needed do a bit of normalization
- */
-
-static void
-xsltGatherNamespaces(xsltStylesheetPtr style) {
- xmlNodePtr cur;
- const xmlChar *URI;
-
- if (style == NULL)
- return;
- /*
- * TODO: basically if the stylesheet uses the same prefix for different
- * patterns, well they may be in problem, hopefully they will get
- * a warning first.
- */
- /*
- * TODO: Eliminate the use of the hash for XPath expressions.
- * An expression should be evaluated in the context of the in-scope
- * namespaces; eliminate the restriction of an XML document to contain
- * no duplicate prefixes for different namespace names.
- *
- */
- cur = xmlDocGetRootElement(style->doc);
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- xmlNsPtr ns = cur->nsDef;
- while (ns != NULL) {
- if (ns->prefix != NULL) {
- if (style->nsHash == NULL) {
- style->nsHash = xmlHashCreate(10);
- if (style->nsHash == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsltGatherNamespaces: failed to create hash table\n");
- style->errors++;
- return;
- }
- }
- URI = xmlHashLookup(style->nsHash, ns->prefix);
- if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
- xsltTransformError(NULL, style, cur,
- "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
- style->warnings++;
- } else if (URI == NULL) {
- xmlHashUpdateEntry(style->nsHash, ns->prefix,
- (void *) ns->href, (xmlHashDeallocator)xmlFree);
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
-#endif
- }
- }
- ns = ns->next;
- }
- }
-
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if (cur->children->type != XML_ENTITY_DECL) {
- cur = cur->children;
- continue;
- }
- }
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
-
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == (xmlNodePtr) style->doc) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
-}
-
-#ifdef XSLT_REFACTORED
-
-static xsltStyleType
-xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node)
-{
- if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
- (node->name == NULL))
- return(0);
-
- if (node->name[0] == 'a') {
- if (IS_XSLT_NAME(node, "apply-templates"))
- return(XSLT_FUNC_APPLYTEMPLATES);
- else if (IS_XSLT_NAME(node, "attribute"))
- return(XSLT_FUNC_ATTRIBUTE);
- else if (IS_XSLT_NAME(node, "apply-imports"))
- return(XSLT_FUNC_APPLYIMPORTS);
- else if (IS_XSLT_NAME(node, "attribute-set"))
- return(0);
-
- } else if (node->name[0] == 'c') {
- if (IS_XSLT_NAME(node, "choose"))
- return(XSLT_FUNC_CHOOSE);
- else if (IS_XSLT_NAME(node, "copy"))
- return(XSLT_FUNC_COPY);
- else if (IS_XSLT_NAME(node, "copy-of"))
- return(XSLT_FUNC_COPYOF);
- else if (IS_XSLT_NAME(node, "call-template"))
- return(XSLT_FUNC_CALLTEMPLATE);
- else if (IS_XSLT_NAME(node, "comment"))
- return(XSLT_FUNC_COMMENT);
-
- } else if (node->name[0] == 'd') {
- if (IS_XSLT_NAME(node, "document"))
- return(XSLT_FUNC_DOCUMENT);
- else if (IS_XSLT_NAME(node, "decimal-format"))
- return(0);
-
- } else if (node->name[0] == 'e') {
- if (IS_XSLT_NAME(node, "element"))
- return(XSLT_FUNC_ELEMENT);
-
- } else if (node->name[0] == 'f') {
- if (IS_XSLT_NAME(node, "for-each"))
- return(XSLT_FUNC_FOREACH);
- else if (IS_XSLT_NAME(node, "fallback"))
- return(XSLT_FUNC_FALLBACK);
-
- } else if (*(node->name) == 'i') {
- if (IS_XSLT_NAME(node, "if"))
- return(XSLT_FUNC_IF);
- else if (IS_XSLT_NAME(node, "include"))
- return(0);
- else if (IS_XSLT_NAME(node, "import"))
- return(0);
-
- } else if (*(node->name) == 'k') {
- if (IS_XSLT_NAME(node, "key"))
- return(0);
-
- } else if (*(node->name) == 'm') {
- if (IS_XSLT_NAME(node, "message"))
- return(XSLT_FUNC_MESSAGE);
-
- } else if (*(node->name) == 'n') {
- if (IS_XSLT_NAME(node, "number"))
- return(XSLT_FUNC_NUMBER);
- else if (IS_XSLT_NAME(node, "namespace-alias"))
- return(0);
-
- } else if (*(node->name) == 'o') {
- if (IS_XSLT_NAME(node, "otherwise"))
- return(XSLT_FUNC_OTHERWISE);
- else if (IS_XSLT_NAME(node, "output"))
- return(0);
-
- } else if (*(node->name) == 'p') {
- if (IS_XSLT_NAME(node, "param"))
- return(XSLT_FUNC_PARAM);
- else if (IS_XSLT_NAME(node, "processing-instruction"))
- return(XSLT_FUNC_PI);
- else if (IS_XSLT_NAME(node, "preserve-space"))
- return(0);
-
- } else if (*(node->name) == 's') {
- if (IS_XSLT_NAME(node, "sort"))
- return(XSLT_FUNC_SORT);
- else if (IS_XSLT_NAME(node, "strip-space"))
- return(0);
- else if (IS_XSLT_NAME(node, "stylesheet"))
- return(0);
-
- } else if (node->name[0] == 't') {
- if (IS_XSLT_NAME(node, "text"))
- return(XSLT_FUNC_TEXT);
- else if (IS_XSLT_NAME(node, "template"))
- return(0);
- else if (IS_XSLT_NAME(node, "transform"))
- return(0);
-
- } else if (*(node->name) == 'v') {
- if (IS_XSLT_NAME(node, "value-of"))
- return(XSLT_FUNC_VALUEOF);
- else if (IS_XSLT_NAME(node, "variable"))
- return(XSLT_FUNC_VARIABLE);
-
- } else if (*(node->name) == 'w') {
- if (IS_XSLT_NAME(node, "when"))
- return(XSLT_FUNC_WHEN);
- if (IS_XSLT_NAME(node, "with-param"))
- return(XSLT_FUNC_WITHPARAM);
- }
- return(0);
-}
-
-int
-xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
-{
- if ((cctxt == NULL) || (elem == NULL) ||
- (elem->type != XML_ELEMENT_NODE))
- return(-1);
-
- elem->psvi = NULL;
-
- if (! (IS_XSLT_ELEM_FAST(elem)))
- return(-1);
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
-
- xsltCompilerNodePush(cctxt, elem);
- /*
- * URGENT TODO: Find a way to speed up this annoying redundant
- * textual node-name and namespace comparison.
- */
- if (cctxt->inode->prev->curChildType != 0)
- cctxt->inode->type = cctxt->inode->prev->curChildType;
- else
- cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (elem->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, elem);
- /*
- * xsltStylePreCompute(): Precompute the XSLT-instruction.
- * This will compile the information found on the current
- * element's attributes. NOTE that this won't process the
- * children of the current element.
- */
- xsltStylePreCompute(cctxt->style, elem);
- /*
- * Validate the content model of the XSLT-element.
- */
- switch (cctxt->inode->type) {
- case XSLT_FUNC_APPLYIMPORTS:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_APPLYTEMPLATES:
- /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
- goto apply_templates;
- case XSLT_FUNC_ATTRIBUTE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_CALLTEMPLATE:
- /* <!-- Content: xsl:with-param* --> */
- goto call_template;
- case XSLT_FUNC_CHOOSE:
- /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
- goto choose;
- case XSLT_FUNC_COMMENT:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_COPY:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_COPYOF:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_DOCUMENT: /* Extra one */
- /* ?? template ?? */
- goto sequence_constructor;
- case XSLT_FUNC_ELEMENT:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_FALLBACK:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_FOREACH:
- /* <!-- Content: (xsl:sort*, template) --> */
- goto for_each;
- case XSLT_FUNC_IF:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_OTHERWISE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_MESSAGE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_NUMBER:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_PARAM:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_PI:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_SORT:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_TEXT:
- /* <!-- Content: #PCDATA --> */
- goto text;
- case XSLT_FUNC_VALUEOF:
- /* EMPTY */
- goto empty_content;
- case XSLT_FUNC_VARIABLE:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_WHEN:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- case XSLT_FUNC_WITHPARAM:
- /* <!-- Content: template --> */
- goto sequence_constructor;
- default:
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
- elem->name);
-#endif
- xsltTransformError(NULL, cctxt->style, elem,
- "xsltParseXSLTNode: Internal error; "
- "unhandled XSLT element '%s'.\n", elem->name);
- cctxt->style->errors++;
- goto internal_err;
- }
-
-apply_templates:
- /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
- cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
- xsltParseAnyXSLTElem(cctxt, child);
- } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
- cctxt->inode->curChildType = XSLT_FUNC_SORT;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- xsltParseContentError(cctxt->style, child);
- } else
- xsltParseContentError(cctxt->style, child);
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
-
-call_template:
- /* <!-- Content: xsl:with-param* --> */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- xsltStyleType type;
-
- type = xsltGetXSLTElementTypeByNode(cctxt, child);
- if (type == XSLT_FUNC_WITHPARAM) {
- cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
- xsltParseAnyXSLTElem(cctxt, child);
- } else {
- xsltParseContentError(cctxt->style, child);
- }
- } else
- xsltParseContentError(cctxt->style, child);
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
-
-text:
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- do {
- if ((child->type != XML_TEXT_NODE) &&
- (child->type != XML_CDATA_SECTION_NODE))
- {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT 'text' element must have only character "
- "data as content.\n");
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
-
-empty_content:
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- /*
- * Relaxed behaviour: we will allow whitespace-only text-nodes.
- */
- do {
- if (((child->type != XML_TEXT_NODE) &&
- (child->type != XML_CDATA_SECTION_NODE)) ||
- (! IS_BLANK_NODE(child)))
- {
- xsltTransformError(NULL, cctxt->style, elem,
- "This XSLT element must have no content.\n");
- cctxt->style->errors++;
- break;
- }
- child = child->next;
- } while (child != NULL);
- }
- goto exit;
-
-choose:
- /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
- /*
- * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
- * The old behaviour did not check this.
- * NOTE: In XSLT 2.0 they are stripped beforehand
- * if whitespace-only (regardless of xml:space).
- */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- int nbWhen = 0, nbOtherwise = 0, err = 0;
- do {
- if (child->type == XML_ELEMENT_NODE) {
- if (IS_XSLT_ELEM_FAST(child)) {
- xsltStyleType type;
-
- type = xsltGetXSLTElementTypeByNode(cctxt, child);
- if (type == XSLT_FUNC_WHEN) {
- nbWhen++;
- if (nbOtherwise) {
- xsltParseContentError(cctxt->style, child);
- err = 1;
- break;
- }
- cctxt->inode->curChildType = XSLT_FUNC_WHEN;
- xsltParseAnyXSLTElem(cctxt, child);
- } else if (type == XSLT_FUNC_OTHERWISE) {
- if (! nbWhen) {
- xsltParseContentError(cctxt->style, child);
- err = 1;
- break;
- }
- if (nbOtherwise) {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT 'choose' element must not contain "
- "more than one XSLT 'otherwise' element.\n");
- cctxt->style->errors++;
- err = 1;
- break;
- }
- nbOtherwise++;
- cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- xsltParseContentError(cctxt->style, child);
- } else
- xsltParseContentError(cctxt->style, child);
- }
- /*
- else
- xsltParseContentError(cctxt, child);
- */
- child = child->next;
- } while (child != NULL);
- if ((! err) && (! nbWhen)) {
- xsltTransformError(NULL, cctxt->style, elem,
- "The XSLT element 'choose' must contain at least one "
- "XSLT element 'when'.\n");
- cctxt->style->errors++;
- }
- }
- goto exit;
-
-for_each:
- /* <!-- Content: (xsl:sort*, template) --> */
- /*
- * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
- * The old behaviour did not allow this, but it catched this
- * only at transformation-time.
- * In XSLT 2.0 they are stripped beforehand if whitespace-only
- * (regardless of xml:space).
- */
- if (elem->children != NULL) {
- xmlNodePtr child = elem->children;
- /*
- * Parse xsl:sort first.
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child))
- {
- if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
- XSLT_FUNC_SORT)
- {
- cctxt->inode->curChildType = XSLT_FUNC_SORT;
- xsltParseAnyXSLTElem(cctxt, child);
- } else
- break;
- } else
- break;
- child = child->next;
- } while (child != NULL);
- /*
- * Parse the sequece constructor.
- */
- if (child != NULL)
- xsltParseSequenceConstructor(cctxt, child);
- }
- goto exit;
-
-sequence_constructor:
- if (elem->children != NULL)
- xsltParseSequenceConstructor(cctxt, elem->children);
-
-exit:
- xsltCompilerNodePop(cctxt, elem);
- return(0);
-
-internal_err:
- xsltCompilerNodePop(cctxt, elem);
- return(-1);
-}
-
-static xsltStyleItemUknownPtr
-xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
-{
- xsltStyleItemUknownPtr item;
-
- item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "Internal error in xsltForwardsCompatUnkownItemCreate(): "
- "Failed to allocate memory.\n");
- cctxt->style->errors++;
- return(NULL);
- }
- memset(item, 0, sizeof(xsltStyleItemUknown));
- item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
- /*
- * Store it in the stylesheet.
- */
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
- return(item);
-}
-
-static int
-xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node)
-{
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
-
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
- if (cctxt->inode->forwardsCompat == 0) {
- /*
- * We are not in forwards-compatible mode, so raise an error.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "Unknown XSLT element '%s'.\n", node->name);
- cctxt->style->errors++;
- return(0);
- }
- /*
- * Forwards-compatible mode.
- * ------------------------
- *
- * Parse/compile xsl:fallback elements.
- *
- * QUESTION: Do we have to raise an error if there's no xsl:fallback?
- * ANSWER: No, since in the stylesheet the fallback behaviour might
- * also be provided by using the XSLT function "element-available".
- */
- if (cctxt->unknownItem == NULL) {
- /*
- * Create a singleton for all unknown XSLT instructions.
- */
- cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
- if (cctxt->unknownItem == NULL) {
- node->psvi = NULL;
- return(-1);
- }
- }
- node->psvi = cctxt->unknownItem;
- if (node->children == NULL)
- return(0);
- else {
- xmlNodePtr child = node->children;
-
- xsltCompilerNodePush(cctxt, node);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (node->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- /*
- * Parse all xsl:fallback children.
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child) &&
- IS_XSLT_NAME(child, "fallback"))
- {
- cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
- xsltParseAnyXSLTElem(cctxt, child);
- }
- child = child->next;
- } while (child != NULL);
-
- xsltCompilerNodePop(cctxt, node);
- }
- return(0);
-}
-/**
- * xsltParseSequenceConstructor:
- *
- * @cctxt: the compilation context
- * @cur: the start-node of the content to be parsed
- *
- * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
- * This will additionally remove xsl:text elements from the tree.
- */
-void
-xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
-{
- xsltStyleType type;
- xmlNodePtr deleteNode = NULL;
-
- if (cctxt == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltParseSequenceConstructor: Bad arguments\n");
- cctxt->style->errors++;
- return;
- }
- /*
- * Detection of handled content of extension instructions.
- */
- if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- cctxt->inode->extContentHandled = 1;
- }
- if (cur == NULL)
- return;
- /*
- * This is the content reffered to as a "template".
- * E.g. an xsl:element has such content model:
- * <xsl:element
- * name = { qname }
- * namespace = { uri-reference }
- * use-attribute-sets = qnames>
- * <!-- Content: template -->
- *
- * NOTE that in XSLT-2 the term "template" was abandoned due to
- * confusion with xsl:template and the term "sequence constructor"
- * was introduced instead.
- *
- * The following XSLT-instructions are allowed to appear:
- * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
- * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
- * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
- * xsl:message, xsl:fallback,
- * xsl:processing-instruction, xsl:comment, xsl:element
- * xsl:attribute.
- * Additional allowed content:
- * 1) extension instructions
- * 2) literal result elements
- * 3) PCDATA
- *
- * NOTE that this content model does *not* allow xsl:param.
- */
- while (cur != NULL) {
- if (deleteNode != NULL) {
-#ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSequenceConstructor: removing xsl:text element\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
- if (cur->type == XML_ELEMENT_NODE) {
-
- if (cur->psvi == xsltXSLTTextMarker) {
- /*
- * xsl:text elements
- * --------------------------------------------------------
- */
- xmlNodePtr tmp;
-
- cur->psvi = NULL;
- /*
- * Mark the xsl:text element for later deletion.
- */
- deleteNode = cur;
- /*
- * Validate content.
- */
- tmp = cur->children;
- if (tmp) {
- /*
- * We don't expect more than one text-node in the
- * content, since we already merged adjacent
- * text/CDATA-nodes and eliminated PI/comment-nodes.
- */
- if ((tmp->type == XML_TEXT_NODE) ||
- (tmp->next == NULL))
- {
- /*
- * Leave the contained text-node in the tree.
- */
- xmlUnlinkNode(tmp);
- xmlAddPrevSibling(cur, tmp);
- } else {
- tmp = NULL;
- xsltTransformError(NULL, cctxt->style, cur,
- "Element 'xsl:text': Invalid type "
- "of node found in content.\n");
- cctxt->style->errors++;
- }
- }
- if (cur->properties) {
- xmlAttrPtr attr;
- /*
- * TODO: We need to report errors for
- * invalid attrs.
- */
- attr = cur->properties;
- do {
- if ((attr->ns == NULL) &&
- (attr->name != NULL) &&
- (attr->name[0] == 'd') &&
- xmlStrEqual(attr->name,
- BAD_CAST "disable-output-escaping"))
- {
- /*
- * Attr "disable-output-escaping".
- * XSLT-2: This attribute is deprecated.
- */
- if ((attr->children != NULL) &&
- xmlStrEqual(attr->children->content,
- BAD_CAST "yes"))
- {
- /*
- * Disable output escaping for this
- * text node.
- */
- if (tmp)
- tmp->name = xmlStringTextNoenc;
- } else if ((attr->children == NULL) ||
- (attr->children->content == NULL) ||
- (!xmlStrEqual(attr->children->content,
- BAD_CAST "no")))
- {
- xsltTransformError(NULL, cctxt->style,
- cur,
- "Attribute 'disable-output-escaping': "
- "Invalid value. Expected is "
- "'yes' or 'no'.\n");
- cctxt->style->errors++;
- }
- break;
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- } else if (IS_XSLT_ELEM_FAST(cur)) {
- /*
- * TODO: Using the XSLT-marker is still not stable yet.
- */
- /* if (cur->psvi == xsltXSLTElemMarker) { */
- /*
- * XSLT instructions
- * --------------------------------------------------------
- */
- cur->psvi = NULL;
- type = xsltGetXSLTElementTypeByNode(cctxt, cur);
- switch (type) {
- case XSLT_FUNC_APPLYIMPORTS:
- case XSLT_FUNC_APPLYTEMPLATES:
- case XSLT_FUNC_ATTRIBUTE:
- case XSLT_FUNC_CALLTEMPLATE:
- case XSLT_FUNC_CHOOSE:
- case XSLT_FUNC_COMMENT:
- case XSLT_FUNC_COPY:
- case XSLT_FUNC_COPYOF:
- case XSLT_FUNC_DOCUMENT: /* Extra one */
- case XSLT_FUNC_ELEMENT:
- case XSLT_FUNC_FALLBACK:
- case XSLT_FUNC_FOREACH:
- case XSLT_FUNC_IF:
- case XSLT_FUNC_MESSAGE:
- case XSLT_FUNC_NUMBER:
- case XSLT_FUNC_PI:
- case XSLT_FUNC_TEXT:
- case XSLT_FUNC_VALUEOF:
- case XSLT_FUNC_VARIABLE:
- /*
- * Parse the XSLT element.
- */
- cctxt->inode->curChildType = type;
- xsltParseAnyXSLTElem(cctxt, cur);
- break;
- default:
- xsltParseUnknownXSLTElem(cctxt, cur);
- cur = cur->next;
- continue;
- }
- } else {
- /*
- * Non-XSLT elements
- * -----------------
- */
- xsltCompilerNodePush(cctxt, cur);
- /*
- * Update the in-scope namespaces if needed.
- */
- if (cur->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, cur);
- /*
- * The current element is either a literal result element
- * or an extension instruction.
- *
- * Process attr "xsl:extension-element-prefixes".
- * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
- * processed by the implementor of the extension function;
- * i.e., it won't be handled by the XSLT processor.
- */
- /* SPEC 1.0:
- * "exclude-result-prefixes" is only allowed on literal
- * result elements and "xsl:exclude-result-prefixes"
- * on xsl:stylesheet/xsl:transform.
- * SPEC 2.0:
- * "There are a number of standard attributes
- * that may appear on any XSLT element: specifically
- * version, exclude-result-prefixes,
- * extension-element-prefixes, xpath-default-namespace,
- * default-collation, and use-when."
- *
- * SPEC 2.0:
- * For literal result elements:
- * "xsl:version, xsl:exclude-result-prefixes,
- * xsl:extension-element-prefixes,
- * xsl:xpath-default-namespace,
- * xsl:default-collation, or xsl:use-when."
- */
- if (cur->properties)
- cctxt->inode->extElemNs =
- xsltParseExtElemPrefixes(cctxt,
- cur, cctxt->inode->extElemNs,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Eval if we have an extension instruction here.
- */
- if ((cur->ns != NULL) &&
- (cctxt->inode->extElemNs != NULL) &&
- (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
- {
- /*
- * Extension instructions
- * ----------------------------------------------------
- * Mark the node information.
- */
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
- cctxt->inode->extContentHandled = 0;
- if (cur->psvi != NULL) {
- cur->psvi = NULL;
- /*
- * TODO: Temporary sanity check.
- */
- xsltTransformError(NULL, cctxt->style, cur,
- "Internal error in xsltParseSequenceConstructor(): "
- "Occupied PSVI field.\n");
- cctxt->style->errors++;
- cur = cur->next;
- continue;
- }
- cur->psvi = (void *)
- xsltPreComputeExtModuleElement(cctxt->style, cur);
-
- if (cur->psvi == NULL) {
- /*
- * OLD COMMENT: "Unknown element, maybe registered at the
- * context level. Mark it for later recognition."
- * QUESTION: What does the xsltExtMarker mean?
- * ANSWER: It is used in xsltApplyOneTemplateInt() at
- * transformation-time to look out for extension
- * registered in the transformation context.
- */
- cur->psvi = (void *) xsltExtMarker;
- }
- /*
- * BIG NOTE: Now the ugly part. In previous versions
- * of Libxslt (until 1.1.16), all the content of an
- * extension instruction was processed and compiled without
- * the need of the extension-author to explicitely call
- * such a processing;.We now need to mimic this old
- * behaviour in order to avoid breaking old code
- * on the extension-author's side.
- * The mechanism:
- * 1) If the author does *not* set the
- * compile-time-flag @extContentHandled, then we'll
- * parse the content assuming that it's a "template"
- * (or "sequence constructor in XSLT 2.0 terms).
- * NOTE: If the extension is registered at
- * transformation-time only, then there's no way of
- * knowing that content shall be valid, and we'll
- * process the content the same way.
- * 2) If author *does* set the flag, then we'll assume
- * that the author has handled the parsing him/herself
- * (e.g. called xsltParseSequenceConstructor(), etc.
- * explicitely in his/her code).
- */
- if ((cur->children != NULL) &&
- (cctxt->inode->extContentHandled == 0))
- {
- /*
- * Default parsing of the content using the
- * sequence-constructor model.
- */
- xsltParseSequenceConstructor(cctxt, cur->children);
- }
- } else {
- /*
- * Literal result element
- * ----------------------------------------------------
- * Allowed XSLT attributes:
- * xsl:extension-element-prefixes CDATA #IMPLIED
- * xsl:exclude-result-prefixes CDATA #IMPLIED
- * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
- * xsl:version NMTOKEN #IMPLIED
- */
- cur->psvi = NULL;
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
- if (cur->properties != NULL) {
- xmlAttrPtr attr = cur->properties;
- /*
- * Attribute "xsl:exclude-result-prefixes".
- */
- cctxt->inode->exclResultNs =
- xsltParseExclResultPrefixes(cctxt, cur,
- cctxt->inode->exclResultNs,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Attribute "xsl:version".
- */
- xsltParseAttrXSLTVersion(cctxt, cur,
- XSLT_ELEMENT_CATEGORY_LRE);
- /*
- * Report invalid XSLT attributes.
- * For XSLT 1.0 only xsl:use-attribute-sets is allowed
- * next to xsl:version, xsl:exclude-result-prefixes and
- * xsl:extension-element-prefixes.
- *
- * Mark all XSLT attributes, in order to skip such
- * attributes when instantiating the LRE.
- */
- do {
- if ((attr->psvi != xsltXSLTAttrMarker) &&
- IS_XSLT_ATTR_FAST(attr))
- {
- if (! xmlStrEqual(attr->name,
- BAD_CAST "use-attribute-sets"))
- {
- xsltTransformError(NULL, cctxt->style,
- cur,
- "Unknown XSLT attribute '%s'.\n",
- attr->name);
- cctxt->style->errors++;
- } else {
- /*
- * XSLT attr marker.
- */
- attr->psvi = (void *) xsltXSLTAttrMarker;
- }
- }
- attr = attr->next;
- } while (attr != NULL);
- }
- /*
- * Create/reuse info for the literal result element.
- */
- if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, cur, 1);
- cur->psvi = cctxt->inode->litResElemInfo;
- /*
- * Apply ns-aliasing on the element and on its attributes.
- */
- if (cctxt->hasNsAliases)
- xsltLREBuildEffectiveNs(cctxt, cur);
- /*
- * Compile attribute value templates (AVT).
- */
- if (cur->properties) {
- xmlAttrPtr attr = cur->properties;
-
- while (attr != NULL) {
- xsltCompileAttr(cctxt->style, attr);
- attr = attr->next;
- }
- }
- /*
- * Parse the content, which is defined to be a "template"
- * (or "sequence constructor" in XSLT 2.0 terms).
- */
- if (cur->children != NULL) {
- xsltParseSequenceConstructor(cctxt, cur->children);
- }
- }
- /*
- * Leave the non-XSLT element.
- */
- xsltCompilerNodePop(cctxt, cur);
- }
- }
- cur = cur->next;
- }
- if (deleteNode != NULL) {
-#ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSequenceConstructor: removing xsl:text element\n");
-#endif
- xmlUnlinkNode(deleteNode);
- xmlFreeNode(deleteNode);
- deleteNode = NULL;
- }
-}
-
-/**
- * xsltParseTemplateContent:
- * @style: the XSLT stylesheet
- * @templ: the node containing the content to be parsed
- *
- * Parses and compiles the content-model of an xsl:template element.
- * Note that this is *not* the "template" (or "sequence constructor"
- * in XSLT 2.0) content model. Since it allows addional xsl:param
- * elements as immediate children of @templ.
- *
- * Called by:
- * exsltFuncFunctionComp() (EXSLT, functions.c)
- * So this is intended to be called from extension functions.
- */
-void
-xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
- if ((style == NULL) || (templ == NULL))
- return;
-
- /*
- * Detection of handled content of extension instructions.
- */
- if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
- XSLT_CCTXT(style)->inode->extContentHandled = 1;
- }
-
- if (templ->children != NULL) {
- xmlNodePtr child = templ->children;
- /*
- * Process xsl:param elements, which can only occur as the
- * immediate children of xsl:template (well, and of any
- * user-defined extension instruction if needed).
- */
- do {
- if ((child->type == XML_ELEMENT_NODE) &&
- IS_XSLT_ELEM_FAST(child) &&
- IS_XSLT_NAME(child, "param"))
- {
- XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
- xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
- } else
- break;
- child = child->next;
- } while (child != NULL);
- /*
- * Parse the content and register the pattern.
- */
- xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
- }
-}
-
-#else /* XSLT_REFACTORED */
-
-/**
- * xsltParseTemplateContent:
- * @style: the XSLT stylesheet
- * @templ: the container node (can be a document for literal results)
- *
- * parse a template content-model
- * Clean-up the template content from unwanted ignorable blank nodes
- * and process xslt:text
- */
-void
-xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
- xmlNodePtr cur, delete;
- /*
- * This content comes from the stylesheet
- * For stylesheets, the set of whitespace-preserving
- * element names consists of just xsl:text.
- */
- cur = templ->children;
- delete = NULL;
- while (cur != NULL) {
- if (delete != NULL) {
-#ifdef WITH_XSLT_DEBUG_BLANKS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseTemplateContent: removing text\n");
-#endif
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = NULL;
- }
- if (IS_XSLT_ELEM(cur)) {
- if (IS_XSLT_NAME(cur, "text")) {
- /*
- * TODO: Processing of xsl:text should be moved to
- * xsltPrecomputeStylesheet(), since otherwise this
- * will be performed for every multiply included
- * stylesheet; i.e. this here is not skipped with
- * the use of the style->nopreproc flag.
- */
- if (cur->children != NULL) {
- xmlChar *prop;
- xmlNodePtr text = cur->children, next;
- int noesc = 0;
-
- prop = xmlGetNsProp(cur,
- (const xmlChar *)"disable-output-escaping",
- NULL);
- if (prop != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "Disable escaping: %s\n", text->content);
-#endif
- if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
- noesc = 1;
- } else if (!xmlStrEqual(prop,
- (const xmlChar *)"no")){
- xsltTransformError(NULL, style, cur,
- "xsl:text: disable-output-escaping allows only yes or no\n");
- style->warnings++;
-
- }
- xmlFree(prop);
- }
-
- while (text != NULL) {
- if (text->type == XML_COMMENT_NODE) {
- text = text->next;
- continue;
- }
- if ((text->type != XML_TEXT_NODE) &&
- (text->type != XML_CDATA_SECTION_NODE)) {
- xsltTransformError(NULL, style, cur,
- "xsltParseTemplateContent: xslt:text content problem\n");
- style->errors++;
- break;
- }
- if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
- text->name = xmlStringTextNoenc;
- text = text->next;
- }
-
- /*
- * replace xsl:text by the list of childs
- */
- if (text == NULL) {
- text = cur->children;
- while (text != NULL) {
- if ((style->internalized) &&
- (text->content != NULL) &&
- (!xmlDictOwns(style->dict, text->content))) {
-
- /*
- * internalize the text string
- */
- if (text->doc->dict != NULL) {
- const xmlChar *tmp;
-
- tmp = xmlDictLookup(text->doc->dict,
- text->content, -1);
- if (tmp != text->content) {
- xmlNodeSetContent(text, NULL);
- text->content = (xmlChar *) tmp;
- }
- }
- }
-
- next = text->next;
- xmlUnlinkNode(text);
- xmlAddPrevSibling(cur, text);
- text = next;
- }
- }
- }
- delete = cur;
- goto skip_children;
- }
- }
- else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
- (xsltCheckExtPrefix(style, cur->ns->prefix)))
- {
- /*
- * okay this is an extension element compile it too
- */
- xsltStylePreCompute(style, cur);
- } else {
- /*
- * This is an element which will be output as part of the
- * template exectution, precompile AVT if found.
- */
- if ((cur->ns == NULL) && (style->defaultAlias != NULL) &&
- (cur->type == XML_ELEMENT_NODE)) {
- cur->ns = xmlSearchNsByHref(cur->doc, cur,
- style->defaultAlias);
- }
- if (cur->properties != NULL) {
- xmlAttrPtr attr = cur->properties;
-
- while (attr != NULL) {
- xsltCompileAttr(style, attr);
- attr = attr->next;
- }
- }
- }
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if (cur->children->type != XML_ENTITY_DECL) {
- cur = cur->children;
- continue;
- }
- }
-skip_children:
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
-
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == templ) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- if (delete != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseTemplateContent: removing text\n");
-#endif
- xmlUnlinkNode(delete);
- xmlFreeNode(delete);
- delete = NULL;
- }
-
- /*
- * Skip the first params
- */
- cur = templ->children;
- while (cur != NULL) {
- if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
- break;
- cur = cur->next;
- }
-
- /*
- * Browse the remainder of the template
- */
- while (cur != NULL) {
- if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
- xmlNodePtr param = cur;
-
- xsltTransformError(NULL, style, cur,
- "xsltParseTemplateContent: ignoring misplaced param element\n");
- if (style != NULL) style->warnings++;
- cur = cur->next;
- xmlUnlinkNode(param);
- xmlFreeNode(param);
- } else
- break;
- }
-}
-
-#endif /* else XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetKey:
- * @style: the XSLT stylesheet
- * @key: the "key" element
- *
- * <!-- Category: top-level-element -->
- * <xsl:key name = qname, match = pattern, use = expression />
- *
- * parse an XSLT stylesheet key definition and register it
- */
-
-static void
-xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
- xmlChar *prop = NULL;
- xmlChar *use = NULL;
- xmlChar *match = NULL;
- xmlChar *name = NULL;
- xmlChar *nameURI = NULL;
-
- if ((style == NULL) || (key == NULL))
- return;
-
- /*
- * Get arguments
- */
- prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(key, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- name = prop;
- if (URI != NULL)
- nameURI = xmlStrdup(URI);
- }
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetKey: name %s\n", name);
-#endif
- } else {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing name\n");
- if (style != NULL) style->errors++;
- goto error;
- }
-
- match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
- if (match == NULL) {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing match\n");
- if (style != NULL) style->errors++;
- goto error;
- }
-
- use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
- if (use == NULL) {
- xsltTransformError(NULL, style, key,
- "xsl:key : error missing use\n");
- if (style != NULL) style->errors++;
- goto error;
- }
-
- /*
- * register the keys
- */
- xsltAddKey(style, name, nameURI, match, use, key);
-
-
-error:
- if (use != NULL)
- xmlFree(use);
- if (match != NULL)
- xmlFree(match);
- if (name != NULL)
- xmlFree(name);
- if (nameURI != NULL)
- xmlFree(nameURI);
-
- if (key->children != NULL) {
- xsltParseContentError(style, key->children);
- }
-}
-
-#ifdef XSLT_REFACTORED
-/**
- * xsltParseXSLTTemplate:
- * @style: the XSLT stylesheet
- * @template: the "template" element
- *
- * parse an XSLT stylesheet template building the associated structures
- * TODO: Is @style ever expected to be NULL?
- *
- * Called from:
- * xsltParseXSLTStylesheet()
- * xsltParseStylesheetTop()
- */
-
-static void
-xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
- xsltTemplatePtr templ;
- xmlChar *prop;
- double priority;
-
- if ((cctxt == NULL) || (templNode == NULL))
- return;
-
- /*
- * Create and link the structure
- */
- templ = xsltNewTemplate();
- if (templ == NULL)
- return;
-
- xsltCompilerNodePush(cctxt, templNode);
- if (templNode->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, templNode);
-
- templ->next = cctxt->style->templates;
- cctxt->style->templates = templ;
- templ->style = cctxt->style;
-
- /*
- * Attribute "mode".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
- if (prop != NULL) {
- const xmlChar *modeURI;
-
- /*
- * TODO: We need a standardized function for extraction
- * of namespace names and local names from QNames.
- * Don't use xsltGetQNameURI() as it cannot channeö
- * reports through the context.
- */
- modeURI = xsltGetQNameURI(templNode, &prop);
- if (prop == NULL) {
- cctxt->style->errors++;
- goto error;
- }
- templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (xmlValidateNCName(templ->mode, 0)) {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: Attribute 'mode': The local part '%s' "
- "of the value is not a valid NCName.\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- if (modeURI != NULL)
- templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTTemplate: mode %s\n", templ->mode);
-#endif
- }
- /*
- * Attribute "match".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
- if (prop != NULL) {
- templ->match = prop;
- prop = NULL;
- }
- /*
- * Attribute "priority".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
- if (prop != NULL) {
- priority = xmlXPathStringEvalNumber(prop);
- templ->priority = (float) priority;
- xmlFree(prop);
- prop = NULL;
- }
- /*
- * Attribute "name".
- */
- prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *nameURI;
- xsltTemplatePtr curTempl;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- nameURI = xsltGetQNameURI(templNode, &prop);
- if (prop == NULL) {
- cctxt->style->errors++;
- goto error;
- }
- templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (xmlValidateNCName(templ->name, 0)) {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: Attribute 'name': The local part '%s' of "
- "the value is not a valid NCName.\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- if (nameURI != NULL)
- templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
- curTempl = templ->next;
- while (curTempl != NULL) {
- if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
- xmlStrEqual(curTempl->nameURI, nameURI) ) ||
- (nameURI == NULL && curTempl->nameURI == NULL &&
- xmlStrEqual(curTempl->name, templ->name)))
- {
- xsltTransformError(NULL, cctxt->style, templNode,
- "xsl:template: error duplicate name '%s'\n", templ->name);
- cctxt->style->errors++;
- goto error;
- }
- curTempl = curTempl->next;
- }
- }
- if (templNode->children != NULL) {
- xsltParseTemplateContent(cctxt->style, templNode);
- /*
- * MAYBE TODO: Custom behaviour: In order to stay compatible with
- * Xalan and MSXML(.NET), we could allow whitespace
- * to appear before an xml:param element; this whitespace
- * will additionally become part of the "template".
- * NOTE that this is totally deviates from the spec, but
- * is the de facto behaviour of Xalan and MSXML(.NET).
- * Personally I wouldn't allow this, since if we have:
- * <xsl:template ...xml:space="preserve">
- * <xsl:param name="foo"/>
- * <xsl:param name="bar"/>
- * <xsl:param name="zoo"/>
- * ... the whitespace between every xsl:param would be
- * added to the result tree.
- */
- }
-
- templ->elem = templNode;
- templ->content = templNode->children;
- xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
-
-error:
- xsltCompilerNodePop(cctxt, templNode);
- return;
-}
-
-#else /* XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetTemplate:
- * @style: the XSLT stylesheet
- * @template: the "template" element
- *
- * parse an XSLT stylesheet template building the associated structures
- */
-
-static void
-xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
- xsltTemplatePtr ret;
- xmlChar *prop;
- xmlChar *mode = NULL;
- xmlChar *modeURI = NULL;
- double priority;
-
- if (template == NULL)
- return;
-
- /*
- * Create and link the structure
- */
- ret = xsltNewTemplate();
- if (ret == NULL)
- return;
- ret->next = style->templates;
- style->templates = ret;
- ret->style = style;
-
- /*
- * Get inherited namespaces
- */
- /*
- * TODO: Apply the optimized in-scope-namespace mechanism
- * as for the other XSLT instructions.
- */
- xsltGetInheritedNsList(style, ret, template);
-
- /*
- * Get arguments
- */
- prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(template, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- mode = prop;
- if (URI != NULL)
- modeURI = xmlStrdup(URI);
- }
- ret->mode = xmlDictLookup(style->dict, mode, -1);
- ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetTemplate: mode %s\n", mode);
-#endif
- if (mode != NULL) xmlFree(mode);
- if (modeURI != NULL) xmlFree(modeURI);
- }
- prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
- if (prop != NULL) {
- if (ret->match != NULL) xmlFree(ret->match);
- ret->match = prop;
- }
-
- prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
- if (prop != NULL) {
- priority = xmlXPathStringEvalNumber(prop);
- ret->priority = (float) priority;
- xmlFree(prop);
- }
-
- prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
- if (prop != NULL) {
- const xmlChar *URI;
- xsltTemplatePtr cur;
-
- /*
- * TODO: Don't use xsltGetQNameURI().
- */
- URI = xsltGetQNameURI(template, &prop);
- if (prop == NULL) {
- if (style != NULL) style->errors++;
- goto error;
- } else {
- if (xmlValidateNCName(prop,0)) {
- xsltTransformError(NULL, style, template,
- "xsl:template : error invalid name '%s'\n", prop);
- if (style != NULL) style->errors++;
- goto error;
- }
- ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
- xmlFree(prop);
- prop = NULL;
- if (URI != NULL)
- ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
- else
- ret->nameURI = NULL;
- cur = ret->next;
- while (cur != NULL) {
- if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
- xmlStrEqual(cur->nameURI, URI) ) ||
- (URI == NULL && cur->nameURI == NULL &&
- xmlStrEqual(cur->name, ret->name))) {
- xsltTransformError(NULL, style, template,
- "xsl:template: error duplicate name '%s'\n", ret->name);
- style->errors++;
- goto error;
- }
- cur = cur->next;
- }
- }
- }
-
- /*
- * parse the content and register the pattern
- */
- xsltParseTemplateContent(style, template);
- ret->elem = template;
- ret->content = template->children;
- xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
-
-error:
- return;
-}
-
-#endif /* else XSLT_REFACTORED */
-
-#ifdef XSLT_REFACTORED
-
-/**
- * xsltIncludeComp:
- * @cctxt: the compilation contenxt
- * @node: the xsl:include node
- *
- * Process the xslt include node on the source node
- */
-static xsltStyleItemIncludePtr
-xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
- xsltStyleItemIncludePtr item;
-
- if ((cctxt == NULL) || (node == NULL))
- return(NULL);
-
- node->psvi = NULL;
- item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
- if (item == NULL) {
- xsltTransformError(NULL, cctxt->style, node,
- "xsltIncludeComp : malloc failed\n");
- cctxt->style->errors++;
- return(NULL);
- }
- memset(item, 0, sizeof(xsltStyleItemInclude));
-
- node->psvi = item;
- item->inst = node;
- item->type = XSLT_FUNC_INCLUDE;
-
- item->next = cctxt->style->preComps;
- cctxt->style->preComps = (xsltElemPreCompPtr) item;
-
- return(item);
-}
-
-/**
- * xsltParseFindTopLevelElem:
- */
-static int
-xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr cur,
- const xmlChar *name,
- const xmlChar *namespaceURI,
- int breakOnOtherElem,
- xmlNodePtr *resultNode)
-{
- if (name == NULL)
- return(-1);
-
- *resultNode = NULL;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE) {
- if ((cur->ns != NULL) && (cur->name != NULL)) {
- if ((*(cur->name) == *name) &&
- xmlStrEqual(cur->name, name) &&
- xmlStrEqual(cur->ns->href, namespaceURI))
- {
- *resultNode = cur;
- return(1);
- }
- }
- if (breakOnOtherElem)
- break;
- }
- cur = cur->next;
- }
- *resultNode = cur;
- return(0);
-}
-
-static int
-xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node,
- xsltStyleType type)
-{
- int ret = 0;
-
- /*
- * TODO: The reason why this function exists:
- * due to historical reasons some of the
- * top-level declarations are processed by functions
- * in other files. Since we need still to set
- * up the node-info and generate information like
- * in-scope namespaces, this is a wrapper around
- * those old parsing functions.
- */
- xsltCompilerNodePush(cctxt, node);
- if (node->nsDef != NULL)
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- cctxt->inode->type = type;
-
- switch (type) {
- case XSLT_FUNC_INCLUDE:
- {
- int oldIsInclude;
-
- if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
- goto exit;
- /*
- * Mark this stylesheet tree as being currently included.
- */
- oldIsInclude = cctxt->isInclude;
- cctxt->isInclude = 1;
-
- if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
- cctxt->style->errors++;
- }
- cctxt->isInclude = oldIsInclude;
- }
- break;
- case XSLT_FUNC_PARAM:
- xsltStylePreCompute(cctxt->style, node);
- xsltParseGlobalParam(cctxt->style, node);
- break;
- case XSLT_FUNC_VARIABLE:
- xsltStylePreCompute(cctxt->style, node);
- xsltParseGlobalVariable(cctxt->style, node);
- break;
- case XSLT_FUNC_ATTRSET:
- xsltParseStylesheetAttributeSet(cctxt->style, node);
- break;
- default:
- xsltTransformError(NULL, cctxt->style, node,
- "Internal error: (xsltParseTopLevelXSLTElem) "
- "Cannot handle this top-level declaration.\n");
- cctxt->style->errors++;
- ret = -1;
- }
-
-exit:
- xsltCompilerNodePop(cctxt, node);
-
- return(ret);
-}
-
-#if 0
-static int
-xsltParseRemoveWhitespace(xmlNodePtr node)
-{
- if ((node == NULL) || (node->children == NULL))
- return(0);
- else {
- xmlNodePtr delNode = NULL, child = node->children;
-
- do {
- if (delNode) {
- xmlUnlinkNode(delNode);
- xmlFreeNode(delNode);
- delNode = NULL;
- }
- if (((child->type == XML_TEXT_NODE) ||
- (child->type == XML_CDATA_SECTION_NODE)) &&
- (IS_BLANK_NODE(child)))
- delNode = child;
- child = child->next;
- } while (child != NULL);
- if (delNode) {
- xmlUnlinkNode(delNode);
- xmlFreeNode(delNode);
- delNode = NULL;
- }
- }
- return(0);
-}
-#endif
-
-static int
-xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
-#ifdef WITH_XSLT_DEBUG_PARSING
- int templates = 0;
-#endif
- xmlNodePtr cur, start = NULL;
- xsltStylesheetPtr style;
-
- if ((cctxt == NULL) || (node == NULL) ||
- (node->type != XML_ELEMENT_NODE))
- return(-1);
-
- style = cctxt->style;
- /*
- * At this stage all import declarations of all stylesheet modules
- * with the same stylesheet level have been processed.
- * Now we can safely parse the rest of the declarations.
- */
- if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
- {
- xsltDocumentPtr include;
- /*
- * URGENT TODO: Make this work with simplified stylesheets!
- * I.e., when we won't find an xsl:stylesheet element.
- */
- /*
- * This is as include declaration.
- */
- include = ((xsltStyleItemIncludePtr) node->psvi)->include;
- if (include == NULL) {
- /* TODO: raise error? */
- return(-1);
- }
- /*
- * TODO: Actually an xsl:include should locate an embedded
- * stylesheet as well; so the document-element won't always
- * be the element where the actual stylesheet is rooted at.
- * But such embedded stylesheets are not supported by Libxslt yet.
- */
- node = xmlDocGetRootElement(include->doc);
- if (node == NULL) {
- return(-1);
- }
- }
-
- if (node->children == NULL)
- return(0);
- /*
- * Push the xsl:stylesheet/xsl:transform element.
- */
- xsltCompilerNodePush(cctxt, node);
- cctxt->inode->isRoot = 1;
- cctxt->inode->nsChanged = 0;
- /*
- * Start with the naked dummy info for literal result elements.
- */
- cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
-
- /*
- * In every case, we need to have
- * the in-scope namespaces of the element, where the
- * stylesheet is rooted at, regardless if it's an XSLT
- * instruction or a literal result instruction (or if
- * this is an embedded stylesheet).
- */
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
-
- /*
- * Process attributes of xsl:stylesheet/xsl:transform.
- * --------------------------------------------------
- * Allowed are:
- * id = id
- * extension-element-prefixes = tokens
- * exclude-result-prefixes = tokens
- * version = number (mandatory)
- */
- if (xsltParseAttrXSLTVersion(cctxt, node,
- XSLT_ELEMENT_CATEGORY_XSLT) == 0)
- {
- /*
- * Attribute "version".
- * XSLT 1.0: "An xsl:stylesheet element *must* have a version
- * attribute, indicating the version of XSLT that the
- * stylesheet requires".
- * The root element of a simplified stylesheet must also have
- * this attribute.
- */
-#ifdef XSLT_REFACTORED_MANDATORY_VERSION
- if (isXsltElem)
- xsltTransformError(NULL, cctxt->style, node,
- "The attribute 'version' is missing.\n");
- cctxt->style->errors++;
-#else
- /* OLD behaviour. */
- xsltTransformError(NULL, cctxt->style, node,
- "xsl:version is missing: document may not be a stylesheet\n");
- cctxt->style->warnings++;
-#endif
- }
- /*
- * The namespaces declared by the attributes
- * "extension-element-prefixes" and
- * "exclude-result-prefixes" are local to *this*
- * stylesheet tree; i.e., they are *not* visible to
- * other stylesheet-modules, whether imported or included.
- *
- * Attribute "extension-element-prefixes".
- */
- cctxt->inode->extElemNs =
- xsltParseExtElemPrefixes(cctxt, node, NULL,
- XSLT_ELEMENT_CATEGORY_XSLT);
- /*
- * Attribute "exclude-result-prefixes".
- */
- cctxt->inode->exclResultNs =
- xsltParseExclResultPrefixes(cctxt, node, NULL,
- XSLT_ELEMENT_CATEGORY_XSLT);
- /*
- * Create/reuse info for the literal result element.
- */
- if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, node, 0);
- /*
- * Processed top-level elements:
- * ----------------------------
- * xsl:variable, xsl:param (QName, in-scope ns,
- * expression (vars allowed))
- * xsl:attribute-set (QName, in-scope ns)
- * xsl:strip-space, xsl:preserve-space (XPath NameTests,
- * in-scope ns)
- * I *think* global scope, merge with includes
- * xsl:output (QName, in-scope ns)
- * xsl:key (QName, in-scope ns, pattern,
- * expression (vars *not* allowed))
- * xsl:decimal-format (QName, needs in-scope ns)
- * xsl:namespace-alias (in-scope ns)
- * global scope, merge with includes
- * xsl:template (last, QName, pattern)
- *
- * (whitespace-only text-nodes have *not* been removed
- * yet; this will be done in xsltParseSequenceConstructor)
- *
- * Report misplaced child-nodes first.
- */
- cur = node->children;
- while (cur != NULL) {
- if (cur->type == XML_TEXT_NODE) {
- xsltTransformError(NULL, style, cur,
- "Misplaced text node (content: '%s').\n",
- (cur->content != NULL) ? cur->content : BAD_CAST "");
- style->errors++;
- } else if (cur->type != XML_ELEMENT_NODE) {
- xsltTransformError(NULL, style, cur, "Misplaced node.\n");
- style->errors++;
- }
- cur = cur->next;
- }
- /*
- * Skip xsl:import elements; they have been processed
- * already.
- */
- cur = node->children;
- while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
- cur = cur->next;
- if (cur == NULL)
- goto exit;
-
- start = cur;
- /*
- * Process all top-level xsl:param elements.
- */
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
- cur = cur->next;
- }
- /*
- * Process all top-level xsl:variable elements.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
- cur = cur->next;
- }
- /*
- * Process all the rest of top-level elements.
- */
- cur = start;
- while (cur != NULL) {
- /*
- * Process element nodes.
- */
- if (cur->type == XML_ELEMENT_NODE) {
- if (cur->ns == NULL) {
- xsltTransformError(NULL, style, cur,
- "Unexpected top-level element in no namespace.\n");
- style->errors++;
- cur = cur->next;
- continue;
- }
- /*
- * Process all XSLT elements.
- */
- if (IS_XSLT_ELEM_FAST(cur)) {
- /*
- * xsl:import is only allowed at the beginning.
- */
- if (IS_XSLT_NAME(cur, "import")) {
- xsltTransformError(NULL, style, cur,
- "Misplaced xsl:import element.\n");
- style->errors++;
- cur = cur->next;
- continue;
- }
- /*
- * TODO: Change the return type of the parsing functions
- * to int.
- */
- if (IS_XSLT_NAME(cur, "template")) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- templates++;
-#endif
- /*
- * TODO: Is the position of xsl:template in the
- * tree significant? If not it would be easier to
- * parse them at a later stage.
- */
- xsltParseXSLTTemplate(cctxt, cur);
- } else if (IS_XSLT_NAME(cur, "variable")) {
- /* NOP; done already */
- } else if (IS_XSLT_NAME(cur, "param")) {
- /* NOP; done already */
- } else if (IS_XSLT_NAME(cur, "include")) {
- if (cur->psvi != NULL)
- xsltParseXSLTStylesheetElemCore(cctxt, cur);
- else {
- xsltTransformError(NULL, style, cur,
- "Internal error: "
- "(xsltParseXSLTStylesheetElemCore) "
- "The xsl:include element was not compiled.\n");
- style->errors++;
- }
- } else if (IS_XSLT_NAME(cur, "strip-space")) {
- /* No node info needed. */
- xsltParseStylesheetStripSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "preserve-space")) {
- /* No node info needed. */
- xsltParseStylesheetPreserveSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "output")) {
- /* No node-info needed. */
- xsltParseStylesheetOutput(style, cur);
- } else if (IS_XSLT_NAME(cur, "key")) {
- /* TODO: node-info needed for expressions ? */
- xsltParseStylesheetKey(style, cur);
- } else if (IS_XSLT_NAME(cur, "decimal-format")) {
- /* No node-info needed. */
- xsltParseStylesheetDecimalFormat(style, cur);
- } else if (IS_XSLT_NAME(cur, "attribute-set")) {
- xsltParseTopLevelXSLTElem(cctxt, cur,
- XSLT_FUNC_ATTRSET);
- } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
- /* NOP; done already */
- } else {
- if (cctxt->inode->forwardsCompat) {
- /*
- * Forwards-compatible mode:
- *
- * XSLT-1: "if it is a top-level element and
- * XSLT 1.0 does not allow such elements as top-level
- * elements, then the element must be ignored along
- * with its content;"
- */
- /*
- * TODO: I don't think we should generate a warning.
- */
- xsltTransformError(NULL, style, cur,
- "Forwards-compatible mode: Ignoring unknown XSLT "
- "element '%s'.\n", cur->name);
- style->warnings++;
- } else {
- xsltTransformError(NULL, style, cur,
- "Unknown XSLT element '%s'.\n", cur->name);
- style->errors++;
- }
- }
- } else {
- xsltTopLevelFunction function;
-
- /*
- * Process non-XSLT elements, which are in a
- * non-NULL namespace.
- */
- /*
- * QUESTION: What does xsltExtModuleTopLevelLookup()
- * do exactly?
- */
- function = xsltExtModuleTopLevelLookup(cur->name,
- cur->ns->href);
- if (function != NULL)
- function(style, cur);
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseXSLTStylesheetElemCore : User-defined "
- "data element '%s'.\n", cur->name);
-#endif
- }
- }
- cur = cur->next;
- }
-
-exit:
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "### END of parsing top-level elements of doc '%s'.\n",
- node->doc->URL);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Templates: %d\n", templates);
-#ifdef XSLT_REFACTORED
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max inodes: %d\n", cctxt->maxNodeInfos);
- xsltGenericDebug(xsltGenericDebugContext,
- "### Max LREs : %d\n", cctxt->maxLREs);
-#endif /* XSLT_REFACTORED */
-#endif /* WITH_XSLT_DEBUG_PARSING */
-
- xsltCompilerNodePop(cctxt, node);
- return(0);
-}
-
-/**
- * xsltParseXSLTStylesheet:
- * @cctxt: the compiler context
- * @node: the xsl:stylesheet/xsl:transform element-node
- *
- * Parses the xsl:stylesheet and xsl:transform element.
- *
- * <xsl:stylesheet
- * id = id
- * extension-element-prefixes = tokens
- * exclude-result-prefixes = tokens
- * version = number>
- * <!-- Content: (xsl:import*, top-level-elements) -->
- * </xsl:stylesheet>
- *
- * BIG TODO: The xsl:include stuff.
- *
- * Called by xsltParseStylesheetTree()
- *
- * Returns 0 on success, a positive result on errors and
- * -1 on API or internal errors.
- */
-static int
-xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- xmlNodePtr cur, start;
-
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
-
- if (node->children == NULL)
- goto exit;
-
- /*
- * Process top-level elements:
- * xsl:import (must be first)
- * xsl:include (this is just a pre-processing)
- */
- cur = node->children;
- /*
- * Process xsl:import elements.
- * XSLT 1.0: "The xsl:import element children must precede all
- * other element children of an xsl:stylesheet element,
- * including any xsl:include element children."
- */
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
- {
- if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
- cctxt->style->errors++;
- }
- cur = cur->next;
- }
- if (cur == NULL)
- goto exit;
- start = cur;
- /*
- * Pre-process all xsl:include elements.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
- cur = cur->next;
- }
- /*
- * Pre-process all xsl:namespace-alias elements.
- * URGENT TODO: This won't work correctly: the order of included
- * aliases and aliases defined here is significant.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
- {
- xsltNamespaceAlias(cctxt->style, cur);
- cur = cur->next;
- }
-
- if (cctxt->isInclude) {
- /*
- * If this stylesheet is intended for inclusion, then
- * we will process only imports and includes.
- */
- goto exit;
- }
- /*
- * Now parse the rest of the top-level elements.
- */
- xsltParseXSLTStylesheetElemCore(cctxt, node);
-exit:
-
- return(0);
-}
-
-#else /* XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetTop:
- * @style: the XSLT stylesheet
- * @top: the top level "stylesheet" or "transform" element
- *
- * scan the top level elements of an XSL stylesheet
- */
-static void
-xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
- xmlNodePtr cur;
- xmlChar *prop;
-#ifdef WITH_XSLT_DEBUG_PARSING
- int templates = 0;
-#endif
-
- if (top == NULL)
- return;
-
- prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
- if (prop == NULL) {
- xsltTransformError(NULL, style, top,
- "xsl:version is missing: document may not be a stylesheet\n");
- if (style != NULL) style->warnings++;
- } else {
- if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
- (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
- xsltTransformError(NULL, style, top,
- "xsl:version: only 1.0 features are supported\n");
- /* TODO set up compatibility when not XSLT 1.0 */
- if (style != NULL) style->warnings++;
- }
- xmlFree(prop);
- }
-
- cur = top->children;
-
- /*
- * process xsl:import elements
- */
- while (cur != NULL) {
- if (IS_BLANK_NODE(cur)) {
- cur = cur->next;
- continue;
- }
- if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
- if (xsltParseStylesheetImport(style, cur) != 0)
- if (style != NULL) style->errors++;
- } else
- break;
- cur = cur->next;
- }
-
- /*
- * process other top-level elements
- */
- while (cur != NULL) {
- if (IS_BLANK_NODE(cur)) {
- cur = cur->next;
- continue;
- }
- if (cur->type == XML_TEXT_NODE) {
- if (cur->content != NULL) {
- xsltTransformError(NULL, style, cur,
- "misplaced text node: '%s'\n", cur->content);
- }
- if (style != NULL) style->errors++;
- cur = cur->next;
- continue;
- }
- if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
- xsltGenericError(xsltGenericErrorContext,
- "Found a top-level element %s with null namespace URI\n",
- cur->name);
- if (style != NULL) style->errors++;
- cur = cur->next;
- continue;
- }
- if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
- xsltTopLevelFunction function;
-
- function = xsltExtModuleTopLevelLookup(cur->name,
- cur->ns->href);
- if (function != NULL)
- function(style, cur);
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetTop : found foreign element %s\n",
- cur->name);
-#endif
- cur = cur->next;
- continue;
- }
- if (IS_XSLT_NAME(cur, "import")) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetTop: ignoring misplaced import element\n");
- if (style != NULL) style->errors++;
- } else if (IS_XSLT_NAME(cur, "include")) {
- if (xsltParseStylesheetInclude(style, cur) != 0)
- if (style != NULL) style->errors++;
- } else if (IS_XSLT_NAME(cur, "strip-space")) {
- xsltParseStylesheetStripSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "preserve-space")) {
- xsltParseStylesheetPreserveSpace(style, cur);
- } else if (IS_XSLT_NAME(cur, "output")) {
- xsltParseStylesheetOutput(style, cur);
- } else if (IS_XSLT_NAME(cur, "key")) {
- xsltParseStylesheetKey(style, cur);
- } else if (IS_XSLT_NAME(cur, "decimal-format")) {
- xsltParseStylesheetDecimalFormat(style, cur);
- } else if (IS_XSLT_NAME(cur, "attribute-set")) {
- xsltParseStylesheetAttributeSet(style, cur);
- } else if (IS_XSLT_NAME(cur, "variable")) {
- xsltParseGlobalVariable(style, cur);
- } else if (IS_XSLT_NAME(cur, "param")) {
- xsltParseGlobalParam(style, cur);
- } else if (IS_XSLT_NAME(cur, "template")) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- templates++;
-#endif
- xsltParseStylesheetTemplate(style, cur);
- } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
- xsltNamespaceAlias(style, cur);
- } else {
- /*
- * BUG TODO: The version of the *doc* is irrelevant for
- * the forwards-compatible mode.
- */
- if ((style != NULL) && (style->doc->version != NULL) &&
- (!strncmp((const char *) style->doc->version, "1.0", 3))) {
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetTop: unknown %s element\n",
- cur->name);
- if (style != NULL) style->errors++;
- }
- else {
- /* do Forwards-Compatible Processing */
- xsltTransformError(NULL, style, cur,
- "xsltParseStylesheetTop: ignoring unknown %s element\n",
- cur->name);
- if (style != NULL) style->warnings++;
- }
- }
- cur = cur->next;
- }
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "parsed %d templates\n", templates);
-#endif
-}
-
-#endif /* else of XSLT_REFACTORED */
-
-#ifdef XSLT_REFACTORED
-/**
- * xsltParseSimplifiedStylesheetTree:
- *
- * @style: the stylesheet (TODO: Change this to the compiler context)
- * @doc: the document containing the stylesheet.
- * @node: the node where the stylesheet is rooted at
- *
- * Returns 0 in case of success, a positive result if an error occurred
- * and -1 on API and internal errors.
- */
-static int
-xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
- xmlDocPtr doc,
- xmlNodePtr node)
-{
- xsltTemplatePtr templ;
-
- if ((cctxt == NULL) || (node == NULL))
- return(-1);
-
- if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
- {
- /*
- * TODO: Adjust report, since this might be an
- * embedded stylesheet.
- */
- xsltTransformError(NULL, cctxt->style, node,
- "The attribute 'xsl:version' is missing; cannot identify "
- "this document as an XSLT stylesheet document.\n");
- cctxt->style->errors++;
- return(1);
- }
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
-#endif
-
- /*
- * Create and link the template
- */
- templ = xsltNewTemplate();
- if (templ == NULL) {
- return(-1);
- }
- templ->next = cctxt->style->templates;
- cctxt->style->templates = templ;
- templ->match = xmlStrdup(BAD_CAST "/");
-
- /*
- * Note that we push the document-node in this special case.
- */
- xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
- /*
- * In every case, we need to have
- * the in-scope namespaces of the element, where the
- * stylesheet is rooted at, regardless if it's an XSLT
- * instruction or a literal result instruction (or if
- * this is an embedded stylesheet).
- */
- cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
- /*
- * Parse the content and register the match-pattern.
- */
- xsltParseSequenceConstructor(cctxt, node);
- xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
-
- templ->elem = (xmlNodePtr) doc;
- templ->content = node;
- xsltAddTemplate(cctxt->style, templ, NULL, NULL);
- cctxt->style->literal_result = 1;
- return(0);
-}
-
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
-int
-xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
-{
- if (doc == NULL)
- return(-1);
- /*
- * Revert the changes we have applied to the namespace-URIs of
- * ns-decls.
- */
- while (ns != NULL) {
- if ((ns->doc == doc) && (ns->ns != NULL)) {
- ns->ns->href = ns->origNsName;
- ns->origNsName = NULL;
- ns->ns = NULL;
- }
- ns = ns->next;
- }
- return(0);
-}
-#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
-
-/**
- * xsltParseStylesheetProcess:
- * @style: the XSLT stylesheet (the current stylesheet-level)
- * @doc: and xmlDoc parsed XML
- *
- * Parses an XSLT stylesheet, adding the associated structures.
- * Called by:
- * xsltParseStylesheetImportedDoc() (xslt.c)
- * xsltParseStylesheetInclude() (imports.c)
- *
- * Returns the value of the @style parameter if everything
- * went right, NULL if something went amiss.
- */
-xsltStylesheetPtr
-xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
-{
- xsltCompilerCtxtPtr cctxt;
- xmlNodePtr cur;
- int oldIsSimplifiedStylesheet;
-
-
- if ((style == NULL) || (doc == NULL))
- return(NULL);
-
- cctxt = XSLT_CCTXT(style);
-
- cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
- xsltTransformError(NULL, style, (xmlNodePtr) doc,
- "xsltParseStylesheetProcess : empty stylesheet\n");
- return(NULL);
- }
- oldIsSimplifiedStylesheet = cctxt->simplified;
-
- if ((IS_XSLT_ELEM(cur)) &&
- ((IS_XSLT_NAME(cur, "stylesheet")) ||
- (IS_XSLT_NAME(cur, "transform")))) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : found stylesheet\n");
-#endif
- cctxt->simplified = 0;
- style->literal_result = 0;
- } else {
- cctxt->simplified = 1;
- style->literal_result = 1;
- }
- /*
- * Pre-process the stylesheet if not already done before.
- * This will remove PIs and comments, merge adjacent
- * text nodes, internalize strings, etc.
- */
- if (! style->nopreproc)
- xsltParsePreprocessStylesheetTree(cctxt, cur);
- /*
- * Parse and compile the stylesheet.
- */
- if (style->literal_result == 0) {
- if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
- return(NULL);
- } else {
- if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
- return(NULL);
- }
-
- cctxt->simplified = oldIsSimplifiedStylesheet;
-
- return(style);
-}
-
-#else /* XSLT_REFACTORED */
-
-xsltStylesheetPtr
-xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
- xmlNodePtr cur;
-
- if (doc == NULL)
- return(NULL);
- if (ret == NULL)
- return(ret);
-
- /*
- * First steps, remove blank nodes,
- * locate the xsl:stylesheet element and the
- * namespace declaration.
- */
- cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
- xsltTransformError(NULL, ret, (xmlNodePtr) doc,
- "xsltParseStylesheetProcess : empty stylesheet\n");
- return(NULL);
- }
-
- if ((IS_XSLT_ELEM(cur)) &&
- ((IS_XSLT_NAME(cur, "stylesheet")) ||
- (IS_XSLT_NAME(cur, "transform")))) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : found stylesheet\n");
-#endif
- ret->literal_result = 0;
- xsltParseStylesheetExcludePrefix(ret, cur, 1);
- xsltParseStylesheetExtPrefix(ret, cur, 1);
- } else {
- xsltParseStylesheetExcludePrefix(ret, cur, 0);
- xsltParseStylesheetExtPrefix(ret, cur, 0);
- ret->literal_result = 1;
- }
- if (!ret->nopreproc) {
- xsltPrecomputeStylesheet(ret, cur);
- }
- if (ret->literal_result == 0) {
- xsltParseStylesheetTop(ret, cur);
- } else {
- xmlChar *prop;
- xsltTemplatePtr template;
-
- /*
- * the document itself might be the template, check xsl:version
- */
- prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
- if (prop == NULL) {
- xsltTransformError(NULL, ret, cur,
- "xsltParseStylesheetProcess : document is not a stylesheet\n");
- return(NULL);
- }
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetProcess : document is stylesheet\n");
-#endif
-
- if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
- xsltTransformError(NULL, ret, cur,
- "xsl:version: only 1.0 features are supported\n");
- /* TODO set up compatibility when not XSLT 1.0 */
- ret->warnings++;
- }
- xmlFree(prop);
-
- /*
- * Create and link the template
- */
- template = xsltNewTemplate();
- if (template == NULL) {
- return(NULL);
- }
- template->next = ret->templates;
- ret->templates = template;
- template->match = xmlStrdup((const xmlChar *)"/");
-
- /*
- * parse the content and register the pattern
- */
- xsltParseTemplateContent(ret, (xmlNodePtr) doc);
- template->elem = (xmlNodePtr) doc;
- template->content = doc->children;
- xsltAddTemplate(ret, template, NULL, NULL);
- ret->literal_result = 1;
- }
-
- return(ret);
-}
-
-#endif /* else of XSLT_REFACTORED */
-
-/**
- * xsltParseStylesheetImportedDoc:
- * @doc: an xmlDoc parsed XML
- * @style: pointer to the parent stylesheet (if it exists)
- *
- * parse an XSLT stylesheet building the associated structures
- * except the processing not needed for imported documents.
- *
- * Returns a new XSLT stylesheet structure.
- */
-
-xsltStylesheetPtr
-xsltParseStylesheetImportedDoc(xmlDocPtr doc,
- xsltStylesheetPtr parentStyle) {
- xsltStylesheetPtr retStyle;
-
- if (doc == NULL)
- return(NULL);
-
- retStyle = xsltNewStylesheet();
- if (retStyle == NULL)
- return(NULL);
- /*
- * Set the importing stylesheet module; also used to detect recursion.
- */
- retStyle->parent = parentStyle;
- /*
- * Adjust the string dict.
- */
- if (doc->dict != NULL) {
- xmlDictFree(retStyle->dict);
- retStyle->dict = doc->dict;
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing dictionary from %s for stylesheet\n",
- doc->URL);
-#endif
- xmlDictReference(retStyle->dict);
- }
-
- /*
- * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
- * the stylesheet to containt distinct namespace prefixes.
- */
- xsltGatherNamespaces(retStyle);
-
-#ifdef XSLT_REFACTORED
- {
- xsltCompilerCtxtPtr cctxt;
- xsltStylesheetPtr oldCurSheet;
-
- if (parentStyle == NULL) {
- xsltPrincipalStylesheetDataPtr principalData;
- /*
- * Principal stylesheet
- * --------------------
- */
- retStyle->principal = retStyle;
- /*
- * Create extra data for the principal stylesheet.
- */
- principalData = xsltNewPrincipalStylesheetData();
- if (principalData == NULL) {
- xsltFreeStylesheet(retStyle);
- return(NULL);
- }
- retStyle->principalData = principalData;
- /*
- * Create the compilation context
- * ------------------------------
- * (only once; for the principal stylesheet).
- * This is currently the only function where the
- * compilation context is created.
- */
- cctxt = xsltCompilationCtxtCreate(retStyle);
- if (cctxt == NULL) {
- xsltFreeStylesheet(retStyle);
- return(NULL);
- }
- retStyle->compCtxt = (void *) cctxt;
- cctxt->style = retStyle;
- cctxt->dict = retStyle->dict;
- cctxt->psData = principalData;
- /*
- * Push initial dummy node info.
- */
- cctxt->depth = -1;
- xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
- } else {
- /*
- * Imported stylesheet.
- */
- retStyle->principal = parentStyle->principal;
- cctxt = parentStyle->compCtxt;
- retStyle->compCtxt = cctxt;
- }
- /*
- * Save the old and set the current stylesheet structure in the
- * compilation context.
- */
- oldCurSheet = cctxt->style;
- cctxt->style = retStyle;
-
- retStyle->doc = doc;
- xsltParseStylesheetProcess(retStyle, doc);
-
- cctxt->style = oldCurSheet;
- if (parentStyle == NULL) {
- /*
- * Pop the initial dummy node info.
- */
- xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
- } else {
- /*
- * Clear the compilation context of imported
- * stylesheets.
- * TODO: really?
- */
- /* retStyle->compCtxt = NULL; */
- }
- /*
- * Free the stylesheet if there were errors.
- */
- if (retStyle != NULL) {
- if (retStyle->errors != 0) {
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Restore all changes made to namespace URIs of ns-decls.
- */
- if (cctxt->psData->nsMap)
- xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
-#endif
- /*
- * Detach the doc from the stylesheet; otherwise the doc
- * will be freed in xsltFreeStylesheet().
- */
- retStyle->doc = NULL;
- /*
- * Cleanup the doc if its the main stylesheet.
- */
- if (parentStyle == NULL) {
- xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
- if (retStyle->compCtxt != NULL) {
- xsltCompilationCtxtFree(retStyle->compCtxt);
- retStyle->compCtxt = NULL;
- }
- }
-
- xsltFreeStylesheet(retStyle);
- retStyle = NULL;
- }
- }
- }
-
-#else /* XSLT_REFACTORED */
- /*
- * Old behaviour.
- */
- retStyle->doc = doc;
- xsltParseStylesheetProcess(retStyle, doc);
- if (retStyle != NULL) {
- if (retStyle->errors != 0) {
- retStyle->doc = NULL;
- if (parentStyle == NULL)
- xsltCleanupStylesheetTree(doc,
- xmlDocGetRootElement(doc));
- xsltFreeStylesheet(retStyle);
- retStyle = NULL;
- }
- }
-#endif /* else of XSLT_REFACTORED */
-
- return(retStyle);
-}
-
-/**
- * xsltParseStylesheetDoc:
- * @doc: and xmlDoc parsed XML
- *
- * parse an XSLT stylesheet building the associated structures
- *
- * Returns a new XSLT stylesheet structure.
- */
-
-xsltStylesheetPtr
-xsltParseStylesheetDoc(xmlDocPtr doc) {
- xsltStylesheetPtr ret;
-
- ret = xsltParseStylesheetImportedDoc(doc, NULL);
- if (ret == NULL)
- return(NULL);
-
- xsltResolveStylesheetAttributeSet(ret);
-#ifdef XSLT_REFACTORED
- /*
- * Free the compilation context.
- * TODO: Check if it's better to move this cleanup to
- * xsltParseStylesheetImportedDoc().
- */
- if (ret->compCtxt != NULL) {
- xsltCompilationCtxtFree(XSLT_CCTXT(ret));
- ret->compCtxt = NULL;
- }
-#endif
- return(ret);
-}
-
-/**
- * xsltParseStylesheetFile:
- * @filename: the filename/URL to the stylesheet
- *
- * Load and parse an XSLT stylesheet
- *
- * Returns a new XSLT stylesheet structure.
- */
-
-xsltStylesheetPtr
-xsltParseStylesheetFile(const xmlChar* filename) {
- xsltSecurityPrefsPtr sec;
- xsltStylesheetPtr ret;
- xmlDocPtr doc;
-
-
- if (filename == NULL)
- return(NULL);
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetFile : parse %s\n", filename);
-#endif
-
- /*
- * Security framework check
- */
- sec = xsltGetDefaultSecurityPrefs();
- if (sec != NULL) {
- int res;
-
- res = xsltCheckRead(sec, NULL, filename);
- if (res == 0) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltParseStylesheetFile: read rights for %s denied\n",
- filename);
- return(NULL);
- }
- }
-
- doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
- NULL, XSLT_LOAD_START);
- if (doc == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltParseStylesheetFile : cannot parse %s\n", filename);
- return(NULL);
- }
- ret = xsltParseStylesheetDoc(doc);
- if (ret == NULL) {
- xmlFreeDoc(doc);
- return(NULL);
- }
-
- return(ret);
-}
-
-/************************************************************************
- * *
- * Handling of Stylesheet PI *
- * *
- ************************************************************************/
-
-#define CUR (*cur)
-#define SKIP(val) cur += (val)
-#define NXT(val) cur[(val)]
-#define SKIP_BLANKS \
- while (IS_BLANK(CUR)) NEXT
-#define NEXT ((*cur) ? cur++ : cur)
-
-/**
- * xsltParseStylesheetPI:
- * @value: the value of the PI
- *
- * This function checks that the type is text/xml and extracts
- * the URI-Reference for the stylesheet
- *
- * Returns the URI-Reference for the stylesheet or NULL (it need to
- * be freed by the caller)
- */
-static xmlChar *
-xsltParseStylesheetPI(const xmlChar *value) {
- const xmlChar *cur;
- const xmlChar *start;
- xmlChar *val;
- xmlChar tmp;
- xmlChar *href = NULL;
- int isXml = 0;
-
- if (value == NULL)
- return(NULL);
-
- cur = value;
- while (CUR != 0) {
- SKIP_BLANKS;
- if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
- (NXT(3) == 'e')) {
- SKIP(4);
- SKIP_BLANKS;
- if (CUR != '=')
- continue;
- NEXT;
- if ((CUR != '\'') && (CUR != '"'))
- continue;
- tmp = CUR;
- NEXT;
- start = cur;
- while ((CUR != 0) && (CUR != tmp))
- NEXT;
- if (CUR != tmp)
- continue;
- val = xmlStrndup(start, cur - start);
- NEXT;
- if (val == NULL)
- return(NULL);
- if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
- (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
- xmlFree(val);
- break;
- }
- isXml = 1;
- xmlFree(val);
- } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
- (NXT(3) == 'f')) {
- SKIP(4);
- SKIP_BLANKS;
- if (CUR != '=')
- continue;
- NEXT;
- if ((CUR != '\'') && (CUR != '"'))
- continue;
- tmp = CUR;
- NEXT;
- start = cur;
- while ((CUR != 0) && (CUR != tmp))
- NEXT;
- if (CUR != tmp)
- continue;
- if (href == NULL)
- href = xmlStrndup(start, cur - start);
- NEXT;
- } else {
- while ((CUR != 0) && (!IS_BLANK(CUR)))
- NEXT;
- }
-
- }
-
- if (!isXml) {
- if (href != NULL)
- xmlFree(href);
- href = NULL;
- }
- return(href);
-}
-
-/**
- * xsltLoadStylesheetPI:
- * @doc: a document to process
- *
- * This function tries to locate the stylesheet PI in the given document
- * If found, and if contained within the document, it will extract
- * that subtree to build the stylesheet to process @doc (doc itself will
- * be modified). If found but referencing an external document it will
- * attempt to load it and generate a stylesheet from it. In both cases,
- * the resulting stylesheet and the document need to be freed once the
- * transformation is done.
- *
- * Returns a new XSLT stylesheet structure or NULL if not found.
- */
-xsltStylesheetPtr
-xsltLoadStylesheetPI(xmlDocPtr doc) {
- xmlNodePtr child;
- xsltStylesheetPtr ret = NULL;
- xmlChar *href = NULL;
- xmlURIPtr URI;
-
- if (doc == NULL)
- return(NULL);
-
- /*
- * Find the text/xml stylesheet PI id any before the root
- */
- child = doc->children;
- while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
- if ((child->type == XML_PI_NODE) &&
- (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
- href = xsltParseStylesheetPI(child->content);
- if (href != NULL)
- break;
- }
- child = child->next;
- }
-
- /*
- * If found check the href to select processing
- */
- if (href != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : found PI href=%s\n", href);
-#endif
- URI = xmlParseURI((const char *) href);
- if (URI == NULL) {
- xsltTransformError(NULL, NULL, child,
- "xml-stylesheet : href %s is not valid\n", href);
- xmlFree(href);
- return(NULL);
- }
- if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
- (URI->opaque == NULL) && (URI->authority == NULL) &&
- (URI->server == NULL) && (URI->user == NULL) &&
- (URI->path == NULL) && (URI->query == NULL)) {
- xmlAttrPtr ID;
-
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : Reference to ID %s\n", href);
-#endif
- if (URI->fragment[0] == '#')
- ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
- else
- ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
- if (ID == NULL) {
- xsltTransformError(NULL, NULL, child,
- "xml-stylesheet : no ID %s found\n", URI->fragment);
- } else {
- xmlDocPtr fake;
- xmlNodePtr subtree;
-
- /*
- * move the subtree in a new document passed to
- * the stylesheet analyzer
- */
- subtree = ID->parent;
- fake = xmlNewDoc(NULL);
- if (fake != NULL) {
- /*
- * the dictionnary should be shared since nodes are
- * moved over.
- */
- fake->dict = doc->dict;
- xmlDictReference(doc->dict);
-#ifdef WITH_XSLT_DEBUG
- xsltGenericDebug(xsltGenericDebugContext,
- "reusing dictionary from %s for stylesheet\n",
- doc->URL);
-#endif
-
- xmlUnlinkNode(subtree);
- xmlAddChild((xmlNodePtr) fake, subtree);
- ret = xsltParseStylesheetDoc(fake);
- if (ret == NULL)
- xmlFreeDoc(fake);
- }
- }
- } else {
- xmlChar *URL, *base;
-
- /*
- * Reference to an external stylesheet
- */
-
- base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
- URL = xmlBuildURI(href, base);
- if (URL != NULL) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : fetching %s\n", URL);
-#endif
- ret = xsltParseStylesheetFile(URL);
- xmlFree(URL);
- } else {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltLoadStylesheetPI : fetching %s\n", href);
-#endif
- ret = xsltParseStylesheetFile(href);
- }
- if (base != NULL)
- xmlFree(base);
- }
- xmlFreeURI(URI);
- xmlFree(href);
- }
- return(ret);
-}
+/*\r
+ * xslt.c: Implemetation of an XSL Transformation 1.0 engine\r
+ *\r
+ * Reference:\r
+ * XSLT specification\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * Associating Style Sheets with XML documents\r
+ * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <string.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/parser.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/valid.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/uri.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/parserInternals.h>\r
+#include <libxml/xpathInternals.h>\r
+#include <libxml/xpath.h>\r
+#include "xslt.h"\r
+#include "xsltInternals.h"\r
+#include "pattern.h"\r
+#include "variables.h"\r
+#include "namespaces.h"\r
+#include "attributes.h"\r
+#include "xsltutils.h"\r
+#include "imports.h"\r
+#include "keys.h"\r
+#include "documents.h"\r
+#include "extensions.h"\r
+#include "preproc.h"\r
+#include "extra.h"\r
+#include "security.h"\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+#define WITH_XSLT_DEBUG_PARSING\r
+/* #define WITH_XSLT_DEBUG_BLANKS */\r
+#endif\r
+\r
+const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;\r
+const int xsltLibxsltVersion = LIBXSLT_VERSION;\r
+const int xsltLibxmlVersion = LIBXML_VERSION;\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;\r
+\r
+/*\r
+* xsltLiteralResultMarker:\r
+* Marker for Literal result elements, in order to avoid multiple attempts\r
+* to recognize such elements in the stylesheet's tree.\r
+* This marker is set on node->psvi during the initial traversal\r
+* of a stylesheet's node tree.\r
+*\r
+const xmlChar *xsltLiteralResultMarker =\r
+ (const xmlChar *) "Literal Result Element";\r
+*/\r
+\r
+/*\r
+* xsltXSLTTextMarker:\r
+* Marker for xsl:text elements. Used to recognize xsl:text elements\r
+* for post-processing of the stylesheet's tree, where those\r
+* elements are removed from the tree.\r
+*/\r
+const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";\r
+\r
+/*\r
+* xsltXSLTAttrMarker:\r
+* Marker for XSLT attribute on Literal Result Elements.\r
+*/\r
+const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";\r
+\r
+#endif\r
+\r
+/*\r
+ * Harmless but avoiding a problem when compiling against a\r
+ * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED\r
+ */\r
+#ifndef LIBXML_DEBUG_ENABLED\r
+double xmlXPathStringEvalNumber(const xmlChar *str);\r
+#endif\r
+/*\r
+ * Useful macros\r
+ */\r
+\r
+#ifdef IS_BLANK\r
+#undef IS_BLANK\r
+#endif\r
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \\r
+ ((c) == 0x0D))\r
+\r
+#ifdef IS_BLANK_NODE\r
+#undef IS_BLANK_NODE\r
+#endif\r
+#define IS_BLANK_NODE(n) \\r
+ (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))\r
+\r
+/**\r
+ * xsltParseContentError:\r
+ *\r
+ * @style: the stylesheet\r
+ * @node: the node where the error occured\r
+ *\r
+ * Compile-time error function.\r
+ */\r
+static void\r
+xsltParseContentError(xsltStylesheetPtr style,\r
+ xmlNodePtr node)\r
+{\r
+ if ((style == NULL) || (node == NULL))\r
+ return;\r
+\r
+ if (IS_XSLT_ELEM(node))\r
+ xsltTransformError(NULL, style, node,\r
+ "The XSLT-element '%s' is not allowed at this position.\n",\r
+ node->name);\r
+ else\r
+ xsltTransformError(NULL, style, node,\r
+ "The element '%s' is not allowed at this position.\n",\r
+ node->name);\r
+ style->errors++;\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+#else\r
+/**\r
+ * exclPrefixPush:\r
+ * @style: the transformation stylesheet\r
+ * @value: the excluded namespace name to push on the stack\r
+ *\r
+ * Push an excluded namespace name on the stack\r
+ *\r
+ * Returns the new index in the stack or 0 in case of error\r
+ */\r
+static int\r
+exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)\r
+{\r
+ if (style->exclPrefixMax == 0) {\r
+ style->exclPrefixMax = 4;\r
+ style->exclPrefixTab =\r
+ (xmlChar * *)xmlMalloc(style->exclPrefixMax *\r
+ sizeof(style->exclPrefixTab[0]));\r
+ if (style->exclPrefixTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ if (style->exclPrefixNr >= style->exclPrefixMax) {\r
+ style->exclPrefixMax *= 2;\r
+ style->exclPrefixTab =\r
+ (xmlChar * *)xmlRealloc(style->exclPrefixTab,\r
+ style->exclPrefixMax *\r
+ sizeof(style->exclPrefixTab[0]));\r
+ if (style->exclPrefixTab == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");\r
+ return (0);\r
+ }\r
+ }\r
+ style->exclPrefixTab[style->exclPrefixNr] = value;\r
+ style->exclPrefix = value;\r
+ return (style->exclPrefixNr++);\r
+}\r
+/**\r
+ * exclPrefixPop:\r
+ * @style: the transformation stylesheet\r
+ *\r
+ * Pop an excluded prefix value from the stack\r
+ *\r
+ * Returns the stored excluded prefix value\r
+ */\r
+static xmlChar *\r
+exclPrefixPop(xsltStylesheetPtr style)\r
+{\r
+ xmlChar *ret;\r
+\r
+ if (style->exclPrefixNr <= 0)\r
+ return (0);\r
+ style->exclPrefixNr--;\r
+ if (style->exclPrefixNr > 0)\r
+ style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];\r
+ else\r
+ style->exclPrefix = NULL;\r
+ ret = style->exclPrefixTab[style->exclPrefixNr];\r
+ style->exclPrefixTab[style->exclPrefixNr] = 0;\r
+ return (ret);\r
+}\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * Helper functions *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltInit:\r
+ *\r
+ * Initializes the processor (e.g. registers built-in extensions,\r
+ * etc.)\r
+ */\r
+\r
+static int initialized = 0;\r
+\r
+void\r
+xsltInit (void) {\r
+ if (initialized == 0) {\r
+ initialized = 1;\r
+ xsltRegisterAllExtras();\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltUninit\r
+ *\r
+ * Uninitializes the processor.\r
+ */\r
+\r
+void\r
+xsltUninit (void) {\r
+ initialized = 0;\r
+}\r
+\r
+/**\r
+ * xsltIsBlank:\r
+ * @str: a string\r
+ *\r
+ * Check if a string is ignorable\r
+ *\r
+ * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise\r
+ */\r
+int\r
+xsltIsBlank(xmlChar *str) {\r
+ if (str == NULL)\r
+ return(1);\r
+ while (*str != 0) {\r
+ if (!(IS_BLANK(*str))) return(0);\r
+ str++;\r
+ }\r
+ return(1);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Routines to handle XSLT data structures *\r
+ * *\r
+ ************************************************************************/\r
+static xsltDecimalFormatPtr\r
+xsltNewDecimalFormat(xmlChar *name)\r
+{\r
+ xsltDecimalFormatPtr self;\r
+ /* UTF-8 for 0x2030 */\r
+ static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};\r
+\r
+ self = xmlMalloc(sizeof(xsltDecimalFormat));\r
+ if (self != NULL) {\r
+ self->next = NULL;\r
+ self->name = name;\r
+ \r
+ /* Default values */\r
+ self->digit = xmlStrdup(BAD_CAST("#"));\r
+ self->patternSeparator = xmlStrdup(BAD_CAST(";"));\r
+ self->decimalPoint = xmlStrdup(BAD_CAST("."));\r
+ self->grouping = xmlStrdup(BAD_CAST(","));\r
+ self->percent = xmlStrdup(BAD_CAST("%"));\r
+ self->permille = xmlStrdup(BAD_CAST(permille));\r
+ self->zeroDigit = xmlStrdup(BAD_CAST("0"));\r
+ self->minusSign = xmlStrdup(BAD_CAST("-"));\r
+ self->infinity = xmlStrdup(BAD_CAST("Infinity"));\r
+ self->noNumber = xmlStrdup(BAD_CAST("NaN"));\r
+ }\r
+ return self;\r
+}\r
+\r
+static void\r
+xsltFreeDecimalFormat(xsltDecimalFormatPtr self)\r
+{\r
+ if (self != NULL) {\r
+ if (self->digit)\r
+ xmlFree(self->digit);\r
+ if (self->patternSeparator)\r
+ xmlFree(self->patternSeparator);\r
+ if (self->decimalPoint)\r
+ xmlFree(self->decimalPoint);\r
+ if (self->grouping)\r
+ xmlFree(self->grouping);\r
+ if (self->percent)\r
+ xmlFree(self->percent);\r
+ if (self->permille)\r
+ xmlFree(self->permille);\r
+ if (self->zeroDigit)\r
+ xmlFree(self->zeroDigit);\r
+ if (self->minusSign)\r
+ xmlFree(self->minusSign);\r
+ if (self->infinity)\r
+ xmlFree(self->infinity);\r
+ if (self->noNumber)\r
+ xmlFree(self->noNumber);\r
+ if (self->name)\r
+ xmlFree(self->name);\r
+ xmlFree(self);\r
+ }\r
+}\r
+\r
+static void\r
+xsltFreeDecimalFormatList(xsltStylesheetPtr self)\r
+{\r
+ xsltDecimalFormatPtr iter;\r
+ xsltDecimalFormatPtr tmp;\r
+\r
+ if (self == NULL)\r
+ return;\r
+ \r
+ iter = self->decimalFormat;\r
+ while (iter != NULL) {\r
+ tmp = iter->next;\r
+ xsltFreeDecimalFormat(iter);\r
+ iter = tmp;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltDecimalFormatGetByName:\r
+ * @style: the XSLT stylesheet\r
+ * @name: the decimal-format name to find\r
+ *\r
+ * Find decimal-format by name\r
+ *\r
+ * Returns the xsltDecimalFormatPtr\r
+ */\r
+xsltDecimalFormatPtr\r
+xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)\r
+{\r
+ xsltDecimalFormatPtr result = NULL;\r
+\r
+ if (name == NULL)\r
+ return style->decimalFormat;\r
+\r
+ while (style != NULL) {\r
+ for (result = style->decimalFormat->next;\r
+ result != NULL;\r
+ result = result->next) {\r
+ if (xmlStrEqual(name, result->name))\r
+ return result;\r
+ }\r
+ style = xsltNextImport(style);\r
+ }\r
+ return result;\r
+}\r
+\r
+\r
+/**\r
+ * xsltNewTemplate:\r
+ *\r
+ * Create a new XSLT Template\r
+ *\r
+ * Returns the newly allocated xsltTemplatePtr or NULL in case of error\r
+ */\r
+static xsltTemplatePtr\r
+xsltNewTemplate(void) {\r
+ xsltTemplatePtr cur;\r
+\r
+ cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewTemplate : malloc failed\n");\r
+ return(NULL);\r
+ }\r
+ memset(cur, 0, sizeof(xsltTemplate));\r
+ cur->priority = XSLT_PAT_NO_PRIORITY;\r
+ return(cur);\r
+}\r
+\r
+/**\r
+ * xsltFreeTemplate:\r
+ * @template: an XSLT template\r
+ *\r
+ * Free up the memory allocated by @template\r
+ */\r
+static void\r
+xsltFreeTemplate(xsltTemplatePtr template) {\r
+ if (template == NULL)\r
+ return;\r
+ if (template->match) xmlFree(template->match);\r
+/*\r
+* NOTE: @name and @nameURI are put into the string dict now.\r
+* if (template->name) xmlFree(template->name);\r
+* if (template->nameURI) xmlFree(template->nameURI);\r
+*/\r
+/*\r
+ if (template->mode) xmlFree(template->mode);\r
+ if (template->modeURI) xmlFree(template->modeURI);\r
+ */\r
+ if (template->inheritedNs) xmlFree(template->inheritedNs);\r
+ memset(template, -1, sizeof(xsltTemplate));\r
+ xmlFree(template);\r
+}\r
+\r
+/**\r
+ * xsltFreeTemplateList:\r
+ * @template: an XSLT template list\r
+ *\r
+ * Free up the memory allocated by all the elements of @template\r
+ */\r
+static void\r
+xsltFreeTemplateList(xsltTemplatePtr template) {\r
+ xsltTemplatePtr cur;\r
+\r
+ while (template != NULL) {\r
+ cur = template;\r
+ template = template->next;\r
+ xsltFreeTemplate(cur);\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+static void\r
+xsltFreeNsAliasList(xsltNsAliasPtr item)\r
+{\r
+ xsltNsAliasPtr tmp;\r
+ \r
+ while (item) {\r
+ tmp = item;\r
+ item = item->next;\r
+ xmlFree(tmp);\r
+ } \r
+ return;\r
+}\r
+\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+static void\r
+xsltFreeNamespaceMap(xsltNsMapPtr item)\r
+{\r
+ xsltNsMapPtr tmp;\r
+ \r
+ while (item) {\r
+ tmp = item;\r
+ item = item->next;\r
+ xmlFree(tmp);\r
+ } \r
+ return;\r
+}\r
+\r
+static xsltNsMapPtr\r
+xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,\r
+ xmlDocPtr doc,\r
+ xmlNsPtr ns,\r
+ xmlNodePtr elem)\r
+{\r
+ xsltNsMapPtr ret;\r
+\r
+ if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))\r
+ return(NULL);\r
+\r
+ ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Internal error: (xsltNewNamespaceMapItem) "\r
+ "memory allocation failed.\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltNsMap));\r
+ ret->doc = doc;\r
+ ret->ns = ns;\r
+ ret->origNsName = ns->href;\r
+ /*\r
+ * Store the item at current stylesheet-level.\r
+ */\r
+ if (cctxt->psData->nsMap != NULL)\r
+ ret->next = cctxt->psData->nsMap;\r
+ cctxt->psData->nsMap = ret;\r
+\r
+ return(ret);\r
+}\r
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */\r
+\r
+/**\r
+ * xsltCompilerVarInfoFree: \r
+ * @cctxt: the compilation context\r
+ * \r
+ * Frees the list of information for vars/params.\r
+ */\r
+static void\r
+xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)\r
+{\r
+ xsltVarInfoPtr ivar = cctxt->ivars, ivartmp; \r
+\r
+ while (ivar) {\r
+ ivartmp = ivar;\r
+ ivar = ivar->next;\r
+ xmlFree(ivartmp);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltCompilerCtxtFree:\r
+ *\r
+ * Free an XSLT compiler context. \r
+ */\r
+static void\r
+xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)\r
+{ \r
+ if (cctxt == NULL)\r
+ return;\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Freeing compilation context\n");\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### Max inodes: %d\n", cctxt->maxNodeInfos);\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### Max LREs : %d\n", cctxt->maxLREs);\r
+#endif\r
+ /*\r
+ * Free node-infos.\r
+ */\r
+ if (cctxt->inodeList != NULL) {\r
+ xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;\r
+ while (cur != NULL) {\r
+ tmp = cur;\r
+ cur = cur->next;\r
+ xmlFree(tmp);\r
+ }\r
+ }\r
+ if (cctxt->tmpList != NULL)\r
+ xsltPointerListFree(cctxt->tmpList);\r
+#ifdef XSLT_REFACTORED_XPATHCOMP\r
+ if (cctxt->xpathCtxt != NULL)\r
+ xmlXPathFreeContext(cctxt->xpathCtxt);\r
+#endif\r
+ if (cctxt->nsAliases != NULL)\r
+ xsltFreeNsAliasList(cctxt->nsAliases);\r
+\r
+ if (cctxt->ivars)\r
+ xsltCompilerVarInfoFree(cctxt);\r
+\r
+ xmlFree(cctxt);\r
+}\r
+\r
+/**\r
+ * xsltCompilerCreate:\r
+ *\r
+ * Creates an XSLT compiler context.\r
+ *\r
+ * Returns the pointer to the created xsltCompilerCtxt or\r
+ * NULL in case of an internal error.\r
+ */\r
+static xsltCompilerCtxtPtr\r
+xsltCompilationCtxtCreate(xsltStylesheetPtr style) {\r
+ xsltCompilerCtxtPtr ret;\r
+\r
+ ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, style, NULL,\r
+ "xsltCompilerCreate: allocation of compiler "\r
+ "context failed.\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltCompilerCtxt));\r
+\r
+ ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;\r
+ ret->tmpList = xsltPointerListCreate(20);\r
+ if (ret->tmpList == NULL) {\r
+ goto internal_err;\r
+ }\r
+#ifdef XSLT_REFACTORED_XPATHCOMP\r
+ /*\r
+ * Create the XPath compilation context in order\r
+ * to speed up precompilation of XPath expressions.\r
+ */\r
+ ret->xpathCtxt = xmlXPathNewContext(NULL);\r
+ if (ret->xpathCtxt == NULL)\r
+ goto internal_err;\r
+#endif\r
+ \r
+ return(ret);\r
+\r
+internal_err:\r
+ xsltCompilationCtxtFree(ret);\r
+ return(NULL);\r
+}\r
+\r
+static void\r
+xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)\r
+{\r
+ xsltEffectiveNsPtr tmp;\r
+\r
+ while (first != NULL) {\r
+ tmp = first;\r
+ first = first->nextInStore;\r
+ xmlFree(tmp);\r
+ }\r
+}\r
+\r
+static void\r
+xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)\r
+{\r
+ if (data == NULL)\r
+ return;\r
+\r
+ if (data->inScopeNamespaces != NULL) {\r
+ int i;\r
+ xsltNsListContainerPtr nsi;\r
+ xsltPointerListPtr list =\r
+ (xsltPointerListPtr) data->inScopeNamespaces;\r
+\r
+ for (i = 0; i < list->number; i++) {\r
+ /*\r
+ * REVISIT TODO: Free info of in-scope namespaces.\r
+ */\r
+ nsi = (xsltNsListContainerPtr) list->items[i];\r
+ if (nsi->list != NULL)\r
+ xmlFree(nsi->list);\r
+ xmlFree(nsi);\r
+ }\r
+ xsltPointerListFree(list);\r
+ data->inScopeNamespaces = NULL;\r
+ }\r
+\r
+ if (data->exclResultNamespaces != NULL) {\r
+ int i;\r
+ xsltPointerListPtr list = (xsltPointerListPtr)\r
+ data->exclResultNamespaces; \r
+ \r
+ for (i = 0; i < list->number; i++)\r
+ xsltPointerListFree((xsltPointerListPtr) list->items[i]);\r
+ \r
+ xsltPointerListFree(list);\r
+ data->exclResultNamespaces = NULL;\r
+ }\r
+\r
+ if (data->extElemNamespaces != NULL) {\r
+ xsltPointerListPtr list = (xsltPointerListPtr)\r
+ data->extElemNamespaces;\r
+ int i;\r
+\r
+ for (i = 0; i < list->number; i++)\r
+ xsltPointerListFree((xsltPointerListPtr) list->items[i]);\r
+\r
+ xsltPointerListFree(list);\r
+ data->extElemNamespaces = NULL;\r
+ }\r
+ if (data->effectiveNs) {\r
+ xsltLREEffectiveNsNodesFree(data->effectiveNs);\r
+ data->effectiveNs = NULL;\r
+ }\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ xsltFreeNamespaceMap(data->nsMap);\r
+#endif\r
+ xmlFree(data);\r
+}\r
+\r
+static xsltPrincipalStylesheetDataPtr\r
+xsltNewPrincipalStylesheetData(void)\r
+{\r
+ xsltPrincipalStylesheetDataPtr ret;\r
+\r
+ ret = (xsltPrincipalStylesheetDataPtr)\r
+ xmlMalloc(sizeof(xsltPrincipalStylesheetData));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewPrincipalStylesheetData: memory allocation failed.\n");\r
+ return(NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltPrincipalStylesheetData));\r
+ \r
+ /*\r
+ * Global list of in-scope namespaces.\r
+ */ \r
+ ret->inScopeNamespaces = xsltPointerListCreate(-1);\r
+ if (ret->inScopeNamespaces == NULL)\r
+ goto internal_err;\r
+ /*\r
+ * Global list of excluded result ns-decls.\r
+ */\r
+ ret->exclResultNamespaces = xsltPointerListCreate(-1);\r
+ if (ret->exclResultNamespaces == NULL)\r
+ goto internal_err;\r
+ /*\r
+ * Global list of extension instruction namespace names.\r
+ */ \r
+ ret->extElemNamespaces = xsltPointerListCreate(-1);\r
+ if (ret->extElemNamespaces == NULL)\r
+ goto internal_err;\r
+\r
+ return(ret);\r
+\r
+internal_err:\r
+\r
+ return(NULL);\r
+}\r
+\r
+#endif\r
+\r
+/**\r
+ * xsltNewStylesheet:\r
+ *\r
+ * Create a new XSLT Stylesheet\r
+ *\r
+ * Returns the newly allocated xsltStylesheetPtr or NULL in case of error\r
+ */\r
+xsltStylesheetPtr\r
+xsltNewStylesheet(void) {\r
+ xsltStylesheetPtr ret = NULL; \r
+\r
+ ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));\r
+ if (ret == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltNewStylesheet : malloc failed\n");\r
+ goto internal_err;\r
+ }\r
+ memset(ret, 0, sizeof(xsltStylesheet));\r
+\r
+ ret->omitXmlDeclaration = -1;\r
+ ret->standalone = -1;\r
+ ret->decimalFormat = xsltNewDecimalFormat(NULL);\r
+ ret->indent = -1;\r
+ ret->errors = 0;\r
+ ret->warnings = 0;\r
+ ret->exclPrefixNr = 0;\r
+ ret->exclPrefixMax = 0;\r
+ ret->exclPrefixTab = NULL;\r
+ ret->extInfos = NULL;\r
+ ret->extrasNr = 0;\r
+ ret->internalized = 1;\r
+ ret->literal_result = 0;\r
+ ret->dict = xmlDictCreate();\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "creating dictionary for stylesheet\n");\r
+#endif\r
+\r
+ xsltInit();\r
+\r
+ return(ret);\r
+\r
+internal_err:\r
+ if (ret != NULL)\r
+ xsltFreeStylesheet(ret);\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltAllocateExtra:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Allocate an extra runtime information slot statically while compiling\r
+ * the stylesheet and return its number\r
+ *\r
+ * Returns the number of the slot\r
+ */\r
+int\r
+xsltAllocateExtra(xsltStylesheetPtr style)\r
+{\r
+ return(style->extrasNr++);\r
+}\r
+\r
+/**\r
+ * xsltAllocateExtraCtxt:\r
+ * @ctxt: an XSLT transformation context\r
+ *\r
+ * Allocate an extra runtime information slot at run-time\r
+ * and return its number\r
+ * This make sure there is a slot ready in the transformation context\r
+ *\r
+ * Returns the number of the slot\r
+ */\r
+int\r
+xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)\r
+{\r
+ if (ctxt->extrasNr >= ctxt->extrasMax) {\r
+ int i;\r
+ if (ctxt->extrasNr == 0) {\r
+ ctxt->extrasMax = 20;\r
+ ctxt->extras = (xsltRuntimeExtraPtr)\r
+ xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));\r
+ if (ctxt->extras == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltAllocateExtraCtxt: out of memory\n");\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+ return(0);\r
+ }\r
+ for (i = 0;i < ctxt->extrasMax;i++) {\r
+ ctxt->extras[i].info = NULL;\r
+ ctxt->extras[i].deallocate = NULL;\r
+ ctxt->extras[i].val.ptr = NULL;\r
+ }\r
+\r
+ } else {\r
+ xsltRuntimeExtraPtr tmp;\r
+\r
+ ctxt->extrasMax += 100;\r
+ tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,\r
+ ctxt->extrasMax * sizeof(xsltRuntimeExtra));\r
+ if (tmp == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltAllocateExtraCtxt: out of memory\n");\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+ return(0);\r
+ }\r
+ ctxt->extras = tmp;\r
+ for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {\r
+ ctxt->extras[i].info = NULL;\r
+ ctxt->extras[i].deallocate = NULL;\r
+ ctxt->extras[i].val.ptr = NULL;\r
+ }\r
+ }\r
+ }\r
+ return(ctxt->extrasNr++);\r
+}\r
+\r
+/**\r
+ * xsltFreeStylesheetList:\r
+ * @style: an XSLT stylesheet list\r
+ *\r
+ * Free up the memory allocated by the list @style\r
+ */\r
+static void\r
+xsltFreeStylesheetList(xsltStylesheetPtr style) {\r
+ xsltStylesheetPtr next;\r
+\r
+ while (style != NULL) {\r
+ next = style->next;\r
+ xsltFreeStylesheet(style);\r
+ style = next;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltCleanupStylesheetTree:\r
+ *\r
+ * @doc: the document-node\r
+ * @node: the element where the stylesheet is rooted at\r
+ *\r
+ * Actually @node need not be the document-element, but\r
+ * currently Libxslt does not support embedeed stylesheets.\r
+ *\r
+ * Returns 0 if OK, -1 on API or internal errors.\r
+ */\r
+static int\r
+xsltCleanupStylesheetTree(xmlDocPtr doc, xmlNodePtr rootElem)\r
+{ \r
+#if 0 /* TODO: Currently disabled, since probably not needed. */\r
+ xmlNodePtr cur;\r
+\r
+ if ((doc == NULL) || (rootElem == NULL) ||\r
+ (rootElem->type != XML_ELEMENT_NODE) ||\r
+ (doc != rootElem->doc))\r
+ return(-1);\r
+\r
+ /*\r
+ * Cleanup was suggested by Aleksey Sanin:\r
+ * Clear the PSVI field to avoid problems if the\r
+ * node-tree of the stylesheet is intended to be used for\r
+ * further processing by the user (e.g. for compiling it\r
+ * once again - although not recommended).\r
+ */\r
+\r
+ cur = rootElem;\r
+ while (cur != NULL) {\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ /*\r
+ * Clear the PSVI field.\r
+ */\r
+ cur->psvi = NULL;\r
+ if (cur->children) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ }\r
+\r
+leave_node:\r
+ if (cur == rootElem)\r
+ break;\r
+ if (cur->next != NULL)\r
+ cur = cur->next;\r
+ else {\r
+ cur = cur->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ goto leave_node;\r
+ }\r
+ }\r
+#endif /* #if 0 */\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltFreeStylesheet:\r
+ * @style: an XSLT stylesheet\r
+ *\r
+ * Free up the memory allocated by @style\r
+ */\r
+void\r
+xsltFreeStylesheet(xsltStylesheetPtr style)\r
+{\r
+ if (style == NULL)\r
+ return;\r
+ \r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Start with a cleanup of the main stylesheet's doc.\r
+ */\r
+ if ((style->principal == style) && (style->doc))\r
+ xsltCleanupStylesheetTree(style->doc,\r
+ xmlDocGetRootElement(style->doc));\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ /*\r
+ * Restore changed ns-decls before freeing the document.\r
+ */\r
+ if ((style->doc != NULL) &&\r
+ XSLT_HAS_INTERNAL_NSMAP(style))\r
+ {\r
+ xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),\r
+ style->doc); \r
+ }\r
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */\r
+#else\r
+ /*\r
+ * Start with a cleanup of the main stylesheet's doc.\r
+ */\r
+ if ((style->parent == NULL) && (style->doc))\r
+ xsltCleanupStylesheetTree(style->doc,\r
+ xmlDocGetRootElement(style->doc));\r
+#endif /* XSLT_REFACTORED */\r
+\r
+ xsltFreeKeys(style);\r
+ xsltFreeExts(style);\r
+ xsltFreeTemplateHashes(style);\r
+ xsltFreeDecimalFormatList(style);\r
+ xsltFreeTemplateList(style->templates);\r
+ xsltFreeAttributeSetsHashes(style);\r
+ xsltFreeNamespaceAliasHashes(style);\r
+ xsltFreeStylePreComps(style);\r
+ /*\r
+ * Free documents of all included stylsheet modules of this\r
+ * stylesheet level.\r
+ */\r
+ xsltFreeStyleDocuments(style);\r
+ /*\r
+ * TODO: Best time to shutdown extension stuff?\r
+ */\r
+ xsltShutdownExts(style);\r
+ \r
+ if (style->variables != NULL)\r
+ xsltFreeStackElemList(style->variables);\r
+ if (style->cdataSection != NULL)\r
+ xmlHashFree(style->cdataSection, NULL);\r
+ if (style->stripSpaces != NULL)\r
+ xmlHashFree(style->stripSpaces, NULL);\r
+ if (style->nsHash != NULL)\r
+ xmlHashFree(style->nsHash, NULL);\r
+ if (style->exclPrefixTab != NULL)\r
+ xmlFree(style->exclPrefixTab);\r
+ if (style->method != NULL)\r
+ xmlFree(style->method);\r
+ if (style->methodURI != NULL)\r
+ xmlFree(style->methodURI);\r
+ if (style->version != NULL)\r
+ xmlFree(style->version);\r
+ if (style->encoding != NULL)\r
+ xmlFree(style->encoding);\r
+ if (style->doctypePublic != NULL)\r
+ xmlFree(style->doctypePublic);\r
+ if (style->doctypeSystem != NULL)\r
+ xmlFree(style->doctypeSystem);\r
+ if (style->mediaType != NULL)\r
+ xmlFree(style->mediaType);\r
+ if (style->attVTs)\r
+ xsltFreeAVTList(style->attVTs);\r
+ if (style->imports != NULL)\r
+ xsltFreeStylesheetList(style->imports);\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * If this is the principal stylesheet, then\r
+ * free its internal data.\r
+ */\r
+ if (style->principal == style) {\r
+ if (style->principalData) {\r
+ xsltFreePrincipalStylesheetData(style->principalData);\r
+ style->principalData = NULL;\r
+ }\r
+ } \r
+#endif\r
+ /*\r
+ * Better to free the main document of this stylesheet level\r
+ * at the end - so here.\r
+ */\r
+ if (style->doc != NULL) { \r
+ xmlFreeDoc(style->doc);\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "freeing dictionary from stylesheet\n");\r
+#endif\r
+ xmlDictFree(style->dict);\r
+\r
+ memset(style, -1, sizeof(xsltStylesheet));\r
+ xmlFree(style);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Parsing of an XSLT Stylesheet *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * This is now performed in an optimized way in xsltParseXSLTTemplate.\r
+ */\r
+#else\r
+/**\r
+ * xsltGetInheritedNsList:\r
+ * @style: the stylesheet\r
+ * @template: the template\r
+ * @node: the current node\r
+ *\r
+ * Search all the namespace applying to a given element except the ones \r
+ * from excluded output prefixes currently in scope. Initialize the\r
+ * template inheritedNs list with it.\r
+ *\r
+ * Returns the number of entries found\r
+ */\r
+static int\r
+xsltGetInheritedNsList(xsltStylesheetPtr style,\r
+ xsltTemplatePtr template,\r
+ xmlNodePtr node)\r
+{\r
+ xmlNsPtr cur;\r
+ xmlNsPtr *ret = NULL;\r
+ int nbns = 0;\r
+ int maxns = 10;\r
+ int i; \r
+\r
+ if ((style == NULL) || (template == NULL) || (node == NULL) ||\r
+ (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))\r
+ return(0);\r
+ while (node != NULL) {\r
+ if (node->type == XML_ELEMENT_NODE) {\r
+ cur = node->nsDef;\r
+ while (cur != NULL) {\r
+ if (xmlStrEqual(cur->href, XSLT_NAMESPACE))\r
+ goto skip_ns;\r
+\r
+ if ((cur->prefix != NULL) &&\r
+ (xsltCheckExtPrefix(style, cur->prefix)))\r
+ goto skip_ns;\r
+ /*\r
+ * Check if this namespace was excluded.\r
+ * Note that at this point only the exclusions defined\r
+ * on the topmost stylesheet element are in the exclusion-list.\r
+ */\r
+ for (i = 0;i < style->exclPrefixNr;i++) {\r
+ if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))\r
+ goto skip_ns;\r
+ }\r
+ if (ret == NULL) {\r
+ ret =\r
+ (xmlNsPtr *) xmlMalloc((maxns + 1) *\r
+ sizeof(xmlNsPtr));\r
+ if (ret == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltGetInheritedNsList : out of memory!\n");\r
+ return(0);\r
+ }\r
+ ret[nbns] = NULL;\r
+ }\r
+ /*\r
+ * Skip shadowed namespace bindings.\r
+ */\r
+ for (i = 0; i < nbns; i++) {\r
+ if ((cur->prefix == ret[i]->prefix) ||\r
+ (xmlStrEqual(cur->prefix, ret[i]->prefix)))\r
+ break;\r
+ }\r
+ if (i >= nbns) {\r
+ if (nbns >= maxns) {\r
+ maxns *= 2;\r
+ ret = (xmlNsPtr *) xmlRealloc(ret,\r
+ (maxns +\r
+ 1) *\r
+ sizeof(xmlNsPtr));\r
+ if (ret == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltGetInheritedNsList : realloc failed!\n");\r
+ return(0);\r
+ }\r
+ }\r
+ ret[nbns++] = cur;\r
+ ret[nbns] = NULL;\r
+ }\r
+skip_ns:\r
+ cur = cur->next;\r
+ }\r
+ }\r
+ node = node->parent;\r
+ }\r
+ if (nbns != 0) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "template has %d inherited namespaces\n", nbns);\r
+#endif\r
+ template->inheritedNsNr = nbns;\r
+ template->inheritedNs = ret;\r
+ }\r
+ return (nbns);\r
+}\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetOutput:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "output" element\r
+ *\r
+ * parse an XSLT stylesheet output element and record\r
+ * information related to the stylesheet output\r
+ */\r
+\r
+void\r
+xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)\r
+{\r
+ xmlChar *elements,\r
+ *prop;\r
+ xmlChar *element,\r
+ *end;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);\r
+ if (prop != NULL) {\r
+ if (style->version != NULL)\r
+ xmlFree(style->version);\r
+ style->version = prop;\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);\r
+ if (prop != NULL) {\r
+ if (style->encoding != NULL)\r
+ xmlFree(style->encoding);\r
+ style->encoding = prop;\r
+ }\r
+\r
+ /* relaxed to support xt:document\r
+ * TODO KB: What does "relaxed to support xt:document" mean?\r
+ */\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+\r
+ if (style->method != NULL)\r
+ xmlFree(style->method);\r
+ style->method = NULL;\r
+ if (style->methodURI != NULL)\r
+ xmlFree(style->methodURI);\r
+ style->methodURI = NULL;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(cur, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ } else if (URI == NULL) {\r
+ if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||\r
+ (xmlStrEqual(prop, (const xmlChar *) "html")) ||\r
+ (xmlStrEqual(prop, (const xmlChar *) "text"))) {\r
+ style->method = prop;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "invalid value for method: %s\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ } else {\r
+ style->method = prop;\r
+ style->methodURI = xmlStrdup(URI);\r
+ }\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);\r
+ if (prop != NULL) {\r
+ if (style->doctypeSystem != NULL)\r
+ xmlFree(style->doctypeSystem);\r
+ style->doctypeSystem = prop;\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);\r
+ if (prop != NULL) {\r
+ if (style->doctypePublic != NULL)\r
+ xmlFree(style->doctypePublic);\r
+ style->doctypePublic = prop;\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->standalone = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->standalone = 0;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "invalid value for standalone: %s\n", prop);\r
+ style->errors++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->indent = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->indent = 0;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "invalid value for indent: %s\n", prop);\r
+ style->errors++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *) "yes")) {\r
+ style->omitXmlDeclaration = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {\r
+ style->omitXmlDeclaration = 0;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "invalid value for omit-xml-declaration: %s\n",\r
+ prop);\r
+ style->errors++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",\r
+ NULL);\r
+ if (elements != NULL) {\r
+ if (style->cdataSection == NULL)\r
+ style->cdataSection = xmlHashCreate(10);\r
+ if (style->cdataSection == NULL)\r
+ return;\r
+\r
+ element = elements;\r
+ while (*element != 0) {\r
+ while (IS_BLANK(*element))\r
+ element++;\r
+ if (*element == 0)\r
+ break;\r
+ end = element;\r
+ while ((*end != 0) && (!IS_BLANK(*end)))\r
+ end++;\r
+ element = xmlStrndup(element, end - element);\r
+ if (element) { \r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add cdata section output element %s\n",\r
+ element);\r
+#endif\r
+ if (xmlValidateQName(BAD_CAST element, 0) != 0) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Attribute 'cdata-section-elements': The value "\r
+ "'%s' is not a valid QName.\n", element);\r
+ xmlFree(element);\r
+ style->errors++;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(cur, &element);\r
+ if (element == NULL) {\r
+ /*\r
+ * TODO: We'll report additionally an error\r
+ * via the stylesheet's error handling. \r
+ */\r
+ xsltTransformError(NULL, style, cur,\r
+ "Attribute 'cdata-section-elements': The value "\r
+ "'%s' is not a valid QName.\n", element);\r
+ style->errors++;\r
+ } else {\r
+ xmlNsPtr ns;\r
+ \r
+ /*\r
+ * XSLT-1.0 "Each QName is expanded into an\r
+ * expanded-name using the namespace declarations in\r
+ * effect on the xsl:output element in which the QName\r
+ * occurs; if there is a default namespace, it is used\r
+ * for QNames that do not have a prefix"\r
+ * NOTE: Fix of bug #339570.\r
+ */\r
+ if (URI == NULL) {\r
+ ns = xmlSearchNs(style->doc, cur, NULL);\r
+ if (ns != NULL)\r
+ URI = ns->href;\r
+ } \r
+ xmlHashAddEntry2(style->cdataSection, element, URI,\r
+ (void *) "cdata");\r
+ xmlFree(element);\r
+ }\r
+ }\r
+ }\r
+ element = end;\r
+ }\r
+ xmlFree(elements);\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);\r
+ if (prop != NULL) {\r
+ if (style->mediaType)\r
+ xmlFree(style->mediaType);\r
+ style->mediaType = prop;\r
+ }\r
+ if (cur->children != NULL) {\r
+ xsltParseContentError(style, cur->children);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetDecimalFormat:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "decimal-format" element\r
+ *\r
+ * <!-- Category: top-level-element -->\r
+ * <xsl:decimal-format\r
+ * name = qname, decimal-separator = char, grouping-separator = char,\r
+ * infinity = string, minus-sign = char, NaN = string, percent = char\r
+ * per-mille = char, zero-digit = char, digit = char,\r
+ * pattern-separator = char />\r
+ *\r
+ * parse an XSLT stylesheet decimal-format element and\r
+ * and record the formatting characteristics\r
+ */\r
+static void\r
+xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)\r
+{\r
+ xmlChar *prop;\r
+ xsltDecimalFormatPtr format;\r
+ xsltDecimalFormatPtr iter;\r
+ \r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+\r
+ format = style->decimalFormat;\r
+ \r
+ prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);\r
+ if (prop != NULL) {\r
+ format = xsltDecimalFormatGetByName(style, prop);\r
+ if (format != NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);\r
+ if (style != NULL) style->warnings++;\r
+ return;\r
+ }\r
+ format = xsltNewDecimalFormat(prop);\r
+ if (format == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");\r
+ if (style != NULL) style->errors++;\r
+ return;\r
+ }\r
+ /* Append new decimal-format structure */\r
+ for (iter = style->decimalFormat; iter->next; iter = iter->next)\r
+ ;\r
+ if (iter)\r
+ iter->next = format;\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);\r
+ if (prop != NULL) {\r
+ if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);\r
+ format->decimalPoint = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);\r
+ if (prop != NULL) {\r
+ if (format->grouping != NULL) xmlFree(format->grouping);\r
+ format->grouping = prop;\r
+ }\r
+\r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);\r
+ if (prop != NULL) {\r
+ if (format->infinity != NULL) xmlFree(format->infinity);\r
+ format->infinity = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);\r
+ if (prop != NULL) {\r
+ if (format->minusSign != NULL) xmlFree(format->minusSign);\r
+ format->minusSign = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);\r
+ if (prop != NULL) {\r
+ if (format->noNumber != NULL) xmlFree(format->noNumber);\r
+ format->noNumber = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);\r
+ if (prop != NULL) {\r
+ if (format->percent != NULL) xmlFree(format->percent);\r
+ format->percent = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);\r
+ if (prop != NULL) {\r
+ if (format->permille != NULL) xmlFree(format->permille);\r
+ format->permille = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);\r
+ if (prop != NULL) {\r
+ if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);\r
+ format->zeroDigit = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);\r
+ if (prop != NULL) {\r
+ if (format->digit != NULL) xmlFree(format->digit);\r
+ format->digit = prop;\r
+ }\r
+ \r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);\r
+ if (prop != NULL) {\r
+ if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);\r
+ format->patternSeparator = prop;\r
+ }\r
+ if (cur->children != NULL) {\r
+ xsltParseContentError(style, cur->children);\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetPreserveSpace:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "preserve-space" element\r
+ *\r
+ * parse an XSLT stylesheet preserve-space element and record\r
+ * elements needing preserving\r
+ */\r
+\r
+static void\r
+xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {\r
+ xmlChar *elements;\r
+ xmlChar *element, *end;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+\r
+ elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);\r
+ if (elements == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylesheetPreserveSpace: missing elements attribute\n");\r
+ if (style != NULL) style->warnings++;\r
+ return;\r
+ }\r
+\r
+ if (style->stripSpaces == NULL)\r
+ style->stripSpaces = xmlHashCreate(10);\r
+ if (style->stripSpaces == NULL)\r
+ return;\r
+\r
+ element = elements;\r
+ while (*element != 0) {\r
+ while (IS_BLANK(*element)) element++;\r
+ if (*element == 0)\r
+ break;\r
+ end = element;\r
+ while ((*end != 0) && (!IS_BLANK(*end))) end++;\r
+ element = xmlStrndup(element, end - element);\r
+ if (element) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add preserved space element %s\n", element);\r
+#endif\r
+ if (xmlStrEqual(element, (const xmlChar *)"*")) {\r
+ style->stripAll = -1;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(cur, &element);\r
+\r
+ xmlHashAddEntry2(style->stripSpaces, element, URI,\r
+ (xmlChar *) "preserve");\r
+ }\r
+ xmlFree(element);\r
+ }\r
+ element = end;\r
+ }\r
+ xmlFree(elements);\r
+ if (cur->children != NULL) {\r
+ xsltParseContentError(style, cur->children);\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+#else\r
+/**\r
+ * xsltParseStylesheetExtPrefix:\r
+ * @style: the XSLT stylesheet\r
+ * @template: the "extension-element-prefixes" prefix\r
+ *\r
+ * parse an XSLT stylesheet's "extension-element-prefix" attribute value\r
+ * and register the namespaces of extension instruction.\r
+ * SPEC "A namespace is designated as an extension namespace by using\r
+ * an extension-element-prefixes attribute on:\r
+ * 1) an xsl:stylesheet element\r
+ * 2) an xsl:extension-element-prefixes attribute on a\r
+ * literal result element \r
+ * 3) an extension instruction."\r
+ */\r
+static void\r
+xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,\r
+ int isXsltElem) {\r
+ xmlChar *prefixes;\r
+ xmlChar *prefix, *end;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+\r
+ if (isXsltElem) {\r
+ /* For xsl:stylesheet/xsl:transform. */\r
+ prefixes = xmlGetNsProp(cur,\r
+ (const xmlChar *)"extension-element-prefixes", NULL);\r
+ } else {\r
+ /* For literal result elements and extension instructions. */\r
+ prefixes = xmlGetNsProp(cur,\r
+ (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);\r
+ }\r
+ if (prefixes == NULL) {\r
+ return;\r
+ }\r
+\r
+ prefix = prefixes;\r
+ while (*prefix != 0) {\r
+ while (IS_BLANK(*prefix)) prefix++;\r
+ if (*prefix == 0)\r
+ break;\r
+ end = prefix;\r
+ while ((*end != 0) && (!IS_BLANK(*end))) end++;\r
+ prefix = xmlStrndup(prefix, end - prefix);\r
+ if (prefix) {\r
+ xmlNsPtr ns;\r
+\r
+ if (xmlStrEqual(prefix, (const xmlChar *)"#default"))\r
+ ns = xmlSearchNs(style->doc, cur, NULL);\r
+ else\r
+ ns = xmlSearchNs(style->doc, cur, prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:extension-element-prefix : undefined namespace %s\n",\r
+ prefix);\r
+ if (style != NULL) style->warnings++;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add extension prefix %s\n", prefix);\r
+#endif\r
+ xsltRegisterExtPrefix(style, prefix, ns->href);\r
+ }\r
+ xmlFree(prefix);\r
+ }\r
+ prefix = end;\r
+ }\r
+ xmlFree(prefixes);\r
+}\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetStripSpace:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the "strip-space" element\r
+ *\r
+ * parse an XSLT stylesheet's strip-space element and record\r
+ * the elements needing stripping\r
+ */\r
+\r
+static void\r
+xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {\r
+ xmlChar *elements;\r
+ xmlChar *element, *end;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return;\r
+\r
+ elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);\r
+ if (elements == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylesheetStripSpace: missing elements attribute\n");\r
+ if (style != NULL) style->warnings++;\r
+ return;\r
+ }\r
+\r
+ if (style->stripSpaces == NULL)\r
+ style->stripSpaces = xmlHashCreate(10);\r
+ if (style->stripSpaces == NULL)\r
+ return;\r
+\r
+ element = elements;\r
+ while (*element != 0) {\r
+ while (IS_BLANK(*element)) element++;\r
+ if (*element == 0)\r
+ break;\r
+ end = element;\r
+ while ((*end != 0) && (!IS_BLANK(*end))) end++;\r
+ element = xmlStrndup(element, end - element);\r
+ if (element) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "add stripped space element %s\n", element);\r
+#endif\r
+ if (xmlStrEqual(element, (const xmlChar *)"*")) {\r
+ style->stripAll = 1;\r
+ } else {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(cur, &element);\r
+\r
+ xmlHashAddEntry2(style->stripSpaces, element, URI,\r
+ (xmlChar *) "strip");\r
+ }\r
+ xmlFree(element);\r
+ }\r
+ element = end;\r
+ }\r
+ xmlFree(elements);\r
+ if (cur->children != NULL) {\r
+ xsltParseContentError(style, cur->children);\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+#else\r
+/**\r
+ * xsltParseStylesheetExcludePrefix:\r
+ * @style: the XSLT stylesheet\r
+ * @cur: the current point in the stylesheet\r
+ *\r
+ * parse an XSLT stylesheet exclude prefix and record\r
+ * namespaces needing stripping\r
+ *\r
+ * Returns the number of Excluded prefixes added at that level\r
+ */\r
+\r
+static int\r
+xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,\r
+ int isXsltElem)\r
+{\r
+ int nb = 0;\r
+ xmlChar *prefixes;\r
+ xmlChar *prefix, *end;\r
+\r
+ if ((cur == NULL) || (style == NULL))\r
+ return(0);\r
+\r
+ if (isXsltElem)\r
+ prefixes = xmlGetNsProp(cur,\r
+ (const xmlChar *)"exclude-result-prefixes", NULL);\r
+ else\r
+ prefixes = xmlGetNsProp(cur,\r
+ (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);\r
+\r
+ if (prefixes == NULL) {\r
+ return(0);\r
+ }\r
+\r
+ prefix = prefixes;\r
+ while (*prefix != 0) {\r
+ while (IS_BLANK(*prefix)) prefix++;\r
+ if (*prefix == 0)\r
+ break;\r
+ end = prefix;\r
+ while ((*end != 0) && (!IS_BLANK(*end))) end++;\r
+ prefix = xmlStrndup(prefix, end - prefix);\r
+ if (prefix) {\r
+ xmlNsPtr ns;\r
+\r
+ if (xmlStrEqual(prefix, (const xmlChar *)"#default"))\r
+ ns = xmlSearchNs(style->doc, cur, NULL);\r
+ else\r
+ ns = xmlSearchNs(style->doc, cur, prefix);\r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:exclude-result-prefixes : undefined namespace %s\n",\r
+ prefix);\r
+ if (style != NULL) style->warnings++;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "exclude result prefix %s\n", prefix);\r
+#endif\r
+ exclPrefixPush(style, (xmlChar *) ns->href);\r
+ nb++;\r
+ }\r
+ xmlFree(prefix);\r
+ }\r
+ prefix = end;\r
+ }\r
+ xmlFree(prefixes);\r
+ return(nb);\r
+}\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+/*\r
+* xsltTreeEnsureXMLDecl:\r
+* @doc: the doc\r
+* \r
+* BIG NOTE:\r
+* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".\r
+* Ensures that there is an XML namespace declaration on the doc.\r
+* \r
+* Returns the XML ns-struct or NULL on API and internal errors.\r
+*/\r
+static xmlNsPtr\r
+xsltTreeEnsureXMLDecl(xmlDocPtr doc)\r
+{\r
+ if (doc == NULL)\r
+ return (NULL);\r
+ if (doc->oldNs != NULL)\r
+ return (doc->oldNs);\r
+ {\r
+ xmlNsPtr ns;\r
+ ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));\r
+ if (ns == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltTreeEnsureXMLDecl: Failed to allocate "\r
+ "the XML namespace.\n"); \r
+ return (NULL);\r
+ }\r
+ memset(ns, 0, sizeof(xmlNs));\r
+ ns->type = XML_LOCAL_NAMESPACE;\r
+ /*\r
+ * URGENT TODO: revisit this.\r
+ */\r
+#ifdef LIBXML_NAMESPACE_DICT\r
+ if (doc->dict)\r
+ ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);\r
+ else\r
+ ns->href = xmlStrdup(XML_XML_NAMESPACE);\r
+#else\r
+ ns->href = xmlStrdup(XML_XML_NAMESPACE); \r
+#endif\r
+ ns->prefix = xmlStrdup((const xmlChar *)"xml");\r
+ doc->oldNs = ns;\r
+ return (ns);\r
+ }\r
+}\r
+\r
+/*\r
+* xsltTreeAcquireStoredNs:\r
+* @doc: the doc\r
+* @nsName: the namespace name\r
+* @prefix: the prefix\r
+* \r
+* BIG NOTE:\r
+* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".\r
+* Creates or reuses an xmlNs struct on doc->oldNs with\r
+* the given prefix and namespace name.\r
+* \r
+* Returns the aquired ns struct or NULL in case of an API\r
+* or internal error.\r
+*/\r
+static xmlNsPtr\r
+xsltTreeAcquireStoredNs(xmlDocPtr doc,\r
+ const xmlChar *nsName,\r
+ const xmlChar *prefix)\r
+{\r
+ xmlNsPtr ns;\r
+\r
+ if (doc == NULL)\r
+ return (NULL);\r
+ if (doc->oldNs != NULL)\r
+ ns = doc->oldNs;\r
+ else\r
+ ns = xsltTreeEnsureXMLDecl(doc);\r
+ if (ns == NULL)\r
+ return (NULL);\r
+ if (ns->next != NULL) {\r
+ /* Reuse. */\r
+ ns = ns->next;\r
+ while (ns != NULL) {\r
+ if ((ns->prefix == NULL) != (prefix == NULL)) {\r
+ /* NOP */\r
+ } else if (prefix == NULL) {\r
+ if (xmlStrEqual(ns->href, nsName))\r
+ return (ns);\r
+ } else {\r
+ if ((ns->prefix[0] == prefix[0]) &&\r
+ xmlStrEqual(ns->prefix, prefix) &&\r
+ xmlStrEqual(ns->href, nsName))\r
+ return (ns);\r
+ \r
+ }\r
+ if (ns->next == NULL)\r
+ break;\r
+ ns = ns->next;\r
+ }\r
+ }\r
+ /* Create. */\r
+ ns->next = xmlNewNs(NULL, nsName, prefix);\r
+ return (ns->next);\r
+}\r
+\r
+/**\r
+ * xsltLREBuildEffectiveNs:\r
+ *\r
+ * Apply ns-aliasing on the namespace of the given @elem and\r
+ * its attributes.\r
+ */\r
+static int\r
+xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr elem)\r
+{\r
+ xmlNsPtr ns;\r
+ xsltNsAliasPtr alias;\r
+\r
+ if ((cctxt == NULL) || (elem == NULL))\r
+ return(-1);\r
+ if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))\r
+ return(0);\r
+\r
+ alias = cctxt->nsAliases; \r
+ while (alias != NULL) {\r
+ if ( /* If both namespaces are NULL... */\r
+ ( (elem->ns == NULL) &&\r
+ ((alias->literalNs == NULL) ||\r
+ (alias->literalNs->href == NULL)) ) ||\r
+ /* ... or both namespace are equal */\r
+ ( (elem->ns != NULL) &&\r
+ (alias->literalNs != NULL) &&\r
+ xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )\r
+ {\r
+ if ((alias->targetNs != NULL) &&\r
+ (alias->targetNs->href != NULL))\r
+ {\r
+ /*\r
+ * Convert namespace.\r
+ */\r
+ if (elem->doc == alias->docOfTargetNs) {\r
+ /*\r
+ * This is the nice case: same docs.\r
+ * This will eventually assign a ns-decl which\r
+ * is shadowed, but this has no negative effect on\r
+ * the generation of the result tree.\r
+ */\r
+ elem->ns = alias->targetNs;\r
+ } else {\r
+ /*\r
+ * This target xmlNs originates from a different\r
+ * stylesheet tree. Try to locate it in the\r
+ * in-scope namespaces.\r
+ * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.\r
+ */\r
+ ns = xmlSearchNs(elem->doc, elem,\r
+ alias->targetNs->prefix); \r
+ /*\r
+ * If no matching ns-decl found, then assign a\r
+ * ns-decl stored in xmlDoc.\r
+ */\r
+ if ((ns == NULL) ||\r
+ (! xmlStrEqual(ns->href, alias->targetNs->href)))\r
+ {\r
+ /*\r
+ * BIG NOTE: The use of xsltTreeAcquireStoredNs()\r
+ * is not very efficient, but currently I don't\r
+ * see an other way of *safely* changing a node's\r
+ * namespace, since the xmlNs struct in\r
+ * alias->targetNs might come from an other\r
+ * stylesheet tree. So we need to anchor it in the\r
+ * current document, without adding it to the tree,\r
+ * which would otherwise change the in-scope-ns\r
+ * semantic of the tree.\r
+ */\r
+ ns = xsltTreeAcquireStoredNs(elem->doc,\r
+ alias->targetNs->href,\r
+ alias->targetNs->prefix);\r
+ \r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Internal error in "\r
+ "xsltLREBuildEffectiveNs(): "\r
+ "failed to acquire a stored "\r
+ "ns-declaration.\n");\r
+ cctxt->style->errors++;\r
+ return(-1);\r
+ \r
+ }\r
+ }\r
+ elem->ns = ns;\r
+ } \r
+ } else {\r
+ /*\r
+ * Move into or leave in the NULL namespace.\r
+ */\r
+ elem->ns = NULL;\r
+ }\r
+ break;\r
+ }\r
+ alias = alias->next;\r
+ }\r
+ /*\r
+ * Same with attributes of literal result elements.\r
+ */\r
+ if (elem->properties != NULL) {\r
+ xmlAttrPtr attr = elem->properties;\r
+ \r
+ while (attr != NULL) {\r
+ if (attr->ns == NULL) {\r
+ attr = attr->next;\r
+ continue;\r
+ }\r
+ alias = cctxt->nsAliases;\r
+ while (alias != NULL) {\r
+ if ( /* If both namespaces are NULL... */\r
+ ( (elem->ns == NULL) &&\r
+ ((alias->literalNs == NULL) ||\r
+ (alias->literalNs->href == NULL)) ) ||\r
+ /* ... or both namespace are equal */\r
+ ( (elem->ns != NULL) &&\r
+ (alias->literalNs != NULL) &&\r
+ xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )\r
+ {\r
+ if ((alias->targetNs != NULL) &&\r
+ (alias->targetNs->href != NULL))\r
+ { \r
+ if (elem->doc == alias->docOfTargetNs) {\r
+ elem->ns = alias->targetNs;\r
+ } else {\r
+ ns = xmlSearchNs(elem->doc, elem,\r
+ alias->targetNs->prefix);\r
+ if ((ns == NULL) ||\r
+ (! xmlStrEqual(ns->href, alias->targetNs->href)))\r
+ {\r
+ ns = xsltTreeAcquireStoredNs(elem->doc,\r
+ alias->targetNs->href,\r
+ alias->targetNs->prefix);\r
+ \r
+ if (ns == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Internal error in "\r
+ "xsltLREBuildEffectiveNs(): "\r
+ "failed to acquire a stored "\r
+ "ns-declaration.\n");\r
+ cctxt->style->errors++;\r
+ return(-1);\r
+ \r
+ }\r
+ }\r
+ elem->ns = ns;\r
+ }\r
+ } else {\r
+ /*\r
+ * Move into or leave in the NULL namespace.\r
+ */\r
+ elem->ns = NULL;\r
+ }\r
+ break;\r
+ }\r
+ alias = alias->next;\r
+ }\r
+ \r
+ attr = attr->next;\r
+ }\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltLREBuildEffectiveNsNodes:\r
+ *\r
+ * Computes the effective namespaces nodes for a literal result\r
+ * element.\r
+ * @effectiveNs is the set of effective ns-nodes\r
+ * on the literal result element, which will be added to the result\r
+ * element if not already existing in the result tree.\r
+ * This means that excluded namespaces (via exclude-result-prefixes,\r
+ * extension-element-prefixes and the XSLT namespace) not added\r
+ * to the set.\r
+ * Namespace-aliasing was applied on the @effectiveNs.\r
+ */\r
+static int\r
+xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,\r
+ xsltStyleItemLRElementInfoPtr item,\r
+ xmlNodePtr elem,\r
+ int isLRE)\r
+{\r
+ xmlNsPtr ns, tmpns;\r
+ xsltEffectiveNsPtr effNs, lastEffNs = NULL;\r
+ int i, j, holdByElem;\r
+ xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;\r
+ xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;\r
+\r
+ if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||\r
+ (item == NULL) || (item->effectiveNs != NULL))\r
+ return(-1);\r
+\r
+ if (item->inScopeNs == NULL) \r
+ return(0);\r
+\r
+ extElemNs = cctxt->inode->extElemNs;\r
+ exclResultNs = cctxt->inode->exclResultNs;\r
+\r
+ for (i = 0; i < item->inScopeNs->totalNumber; i++) {\r
+ ns = item->inScopeNs->list[i];\r
+ /*\r
+ * Skip namespaces designated as excluded namespaces\r
+ * -------------------------------------------------\r
+ *\r
+ * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces\r
+ * which are target namespaces of namespace-aliases\r
+ * regardless if designated as excluded.\r
+ *\r
+ * Exclude the XSLT namespace.\r
+ */\r
+ if (xmlStrEqual(ns->href, XSLT_NAMESPACE))\r
+ goto skip_ns;\r
+\r
+ /*\r
+ * Apply namespace aliasing\r
+ * ------------------------\r
+ *\r
+ * SPEC XSLT 2.0\r
+ * "- A namespace node whose string value is a literal namespace\r
+ * URI is not copied to the result tree.\r
+ * - A namespace node whose string value is a target namespace URI\r
+ * is copied to the result tree, whether or not the URI\r
+ * identifies an excluded namespace."\r
+ * \r
+ * NOTE: The ns-aliasing machanism is non-cascading.\r
+ * (checked with Saxon, Xalan and MSXML .NET).\r
+ * URGENT TODO: is style->nsAliases the effective list of\r
+ * ns-aliases, or do we need to lookup the whole\r
+ * import-tree?\r
+ * TODO: Get rid of import-tree lookup.\r
+ */\r
+ if (cctxt->hasNsAliases) {\r
+ xsltNsAliasPtr alias;\r
+ /*\r
+ * First check for being a target namespace.\r
+ */\r
+ alias = cctxt->nsAliases;\r
+ do {\r
+ /*\r
+ * TODO: Is xmlns="" handled already?\r
+ */\r
+ if ((alias->targetNs != NULL) &&\r
+ (xmlStrEqual(alias->targetNs->href, ns->href)))\r
+ {\r
+ /*\r
+ * Recognized as a target namespace; use it regardless\r
+ * if excluded otherwise.\r
+ */\r
+ goto add_effective_ns;\r
+ }\r
+ alias = alias->next;\r
+ } while (alias != NULL);\r
+\r
+ alias = cctxt->nsAliases;\r
+ do {\r
+ /*\r
+ * TODO: Is xmlns="" handled already?\r
+ */\r
+ if ((alias->literalNs != NULL) &&\r
+ (xmlStrEqual(alias->literalNs->href, ns->href)))\r
+ {\r
+ /*\r
+ * Recognized as an namespace alias; do not use it.\r
+ */\r
+ goto skip_ns;\r
+ }\r
+ alias = alias->next;\r
+ } while (alias != NULL);\r
+ }\r
+ \r
+ /*\r
+ * Exclude excluded result namespaces.\r
+ */\r
+ if (exclResultNs) {\r
+ for (j = 0; j < exclResultNs->number; j++)\r
+ if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))\r
+ goto skip_ns;\r
+ }\r
+ /*\r
+ * Exclude extension-element namespaces.\r
+ */\r
+ if (extElemNs) {\r
+ for (j = 0; j < extElemNs->number; j++)\r
+ if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))\r
+ goto skip_ns;\r
+ }\r
+\r
+add_effective_ns:\r
+ /*\r
+ * OPTIMIZE TODO: This information may not be needed.\r
+ */\r
+ if (isLRE && (elem->nsDef != NULL)) {\r
+ holdByElem = 0;\r
+ tmpns = elem->nsDef;\r
+ do {\r
+ if (tmpns == ns) {\r
+ holdByElem = 1;\r
+ break;\r
+ }\r
+ tmpns = tmpns->next;\r
+ } while (tmpns != NULL); \r
+ } else\r
+ holdByElem = 0;\r
+ \r
+ \r
+ /*\r
+ * Add the effective namespace declaration.\r
+ */\r
+ effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));\r
+ if (effNs == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Internal error in xsltLREBuildEffectiveNs(): "\r
+ "failed to allocate memory.\n");\r
+ cctxt->style->errors++;\r
+ return(-1);\r
+ }\r
+ if (cctxt->psData->effectiveNs == NULL) {\r
+ cctxt->psData->effectiveNs = effNs;\r
+ effNs->nextInStore = NULL; \r
+ } else {\r
+ effNs->nextInStore = cctxt->psData->effectiveNs;\r
+ cctxt->psData->effectiveNs = effNs;\r
+ }\r
+\r
+ effNs->next = NULL;\r
+ effNs->prefix = ns->prefix;\r
+ effNs->nsName = ns->href;\r
+ effNs->holdByElem = holdByElem;\r
+ \r
+ if (lastEffNs == NULL)\r
+ item->effectiveNs = effNs;\r
+ else\r
+ lastEffNs->next = effNs;\r
+ lastEffNs = effNs;\r
+ \r
+skip_ns:\r
+ {}\r
+ }\r
+ return(0);\r
+}\r
+\r
+\r
+/**\r
+ * xsltLREInfoCreate:\r
+ *\r
+ * @isLRE: indicates if the given @elem is a literal result element\r
+ *\r
+ * Creates a new info for a literal result element.\r
+ */\r
+static int\r
+xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr elem,\r
+ int isLRE)\r
+{\r
+ xsltStyleItemLRElementInfoPtr item;\r
+\r
+ if ((cctxt == NULL) || (cctxt->inode == NULL))\r
+ return(-1);\r
+\r
+ item = (xsltStyleItemLRElementInfoPtr)\r
+ xmlMalloc(sizeof(xsltStyleItemLRElementInfo));\r
+ if (item == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "Internal error in xsltLREInfoCreate(): "\r
+ "memory allocation failed.\n");\r
+ cctxt->style->errors++;\r
+ return(-1);\r
+ }\r
+ memset(item, 0, sizeof(xsltStyleItemLRElementInfo));\r
+ item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;\r
+ /*\r
+ * Store it in the stylesheet.\r
+ */\r
+ item->next = cctxt->style->preComps;\r
+ cctxt->style->preComps = (xsltElemPreCompPtr) item;\r
+ /*\r
+ * @inScopeNs are used for execution of XPath expressions\r
+ * in AVTs.\r
+ */\r
+ item->inScopeNs = cctxt->inode->inScopeNs;\r
+ \r
+ if (elem)\r
+ xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);\r
+\r
+ cctxt->inode->litResElemInfo = item;\r
+ cctxt->inode->nsChanged = 0;\r
+ cctxt->maxLREs++;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltCompilerVarInfoPush: \r
+ * @cctxt: the compilation context\r
+ * \r
+ * Pushes a new var/param info onto the stack.\r
+ *\r
+ * Returns the acquired variable info.\r
+ */ \r
+static xsltVarInfoPtr\r
+xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr inst,\r
+ const xmlChar *name,\r
+ const xmlChar *nsName)\r
+{\r
+ xsltVarInfoPtr ivar;\r
+\r
+ if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {\r
+ ivar = cctxt->ivar->next;\r
+ } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {\r
+ ivar = cctxt->ivars;\r
+ } else {\r
+ ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));\r
+ if (ivar == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, inst,\r
+ "xsltParseInScopeVarPush: xmlMalloc() failed!\n");\r
+ cctxt->style->errors++;\r
+ return(NULL);\r
+ }\r
+ /* memset(retVar, 0, sizeof(xsltInScopeVar)); */\r
+ if (cctxt->ivars == NULL) {\r
+ cctxt->ivars = ivar;\r
+ ivar->prev = NULL;\r
+ } else {\r
+ cctxt->ivar->next = ivar;\r
+ ivar->prev = cctxt->ivar;\r
+ }\r
+ cctxt->ivar = ivar;\r
+ ivar->next = NULL;\r
+ }\r
+ ivar->depth = cctxt->depth;\r
+ ivar->name = name;\r
+ ivar->nsName = nsName;\r
+ return(ivar);\r
+}\r
+\r
+/**\r
+ * xsltCompilerVarInfoPop: \r
+ * @cctxt: the compilation context\r
+ * \r
+ * Pops all var/param infos from the stack, which\r
+ * have the current depth.\r
+ */ \r
+static void\r
+xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)\r
+{\r
+\r
+ while ((cctxt->ivar != NULL) &&\r
+ (cctxt->ivar->depth > cctxt->depth))\r
+ {\r
+ cctxt->ivar = cctxt->ivar->prev;\r
+ }\r
+}\r
+\r
+/*\r
+* xsltCompilerNodePush:\r
+*\r
+* @cctxt: the compilation context\r
+* @node: the node to be pushed (this can also be the doc-node)\r
+*\r
+* Returns the current node info structure or\r
+* NULL in case of an internal error.\r
+*/\r
+xsltCompilerNodeInfoPtr\r
+xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{ \r
+ xsltCompilerNodeInfoPtr inode, iprev;\r
+\r
+ if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) { \r
+ inode = cctxt->inode->next;\r
+ } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {\r
+ inode = cctxt->inodeList; \r
+ } else {\r
+ /*\r
+ * Create a new node-info.\r
+ */\r
+ inode = (xsltCompilerNodeInfoPtr)\r
+ xmlMalloc(sizeof(xsltCompilerNodeInfo));\r
+ if (inode == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "xsltCompilerNodePush: malloc failed.\n");\r
+ return(NULL);\r
+ }\r
+ memset(inode, 0, sizeof(xsltCompilerNodeInfo));\r
+ if (cctxt->inodeList == NULL)\r
+ cctxt->inodeList = inode;\r
+ else {\r
+ cctxt->inodeLast->next = inode;\r
+ inode->prev = cctxt->inodeLast;\r
+ }\r
+ cctxt->inodeLast = inode;\r
+ cctxt->maxNodeInfos++; \r
+ if (cctxt->inode == NULL) {\r
+ cctxt->inode = inode;\r
+ /*\r
+ * Create an initial literal result element info for\r
+ * the root of the stylesheet.\r
+ */\r
+ xsltLREInfoCreate(cctxt, NULL, 0);\r
+ } \r
+ } \r
+ cctxt->depth++;\r
+ cctxt->inode = inode;\r
+ /*\r
+ * REVISIT TODO: Keep the reset always complete. \r
+ * NOTE: Be carefull with the @node, since it might be\r
+ * a doc-node.\r
+ */\r
+ inode->node = node;\r
+ inode->depth = cctxt->depth;\r
+ inode->templ = NULL;\r
+ inode->category = XSLT_ELEMENT_CATEGORY_XSLT;\r
+ inode->type = 0;\r
+ inode->item = NULL;\r
+ inode->curChildType = 0;\r
+ inode->extContentHandled = 0;\r
+ inode->isRoot = 0;\r
+ \r
+ if (inode->prev != NULL) {\r
+ iprev = inode->prev;\r
+ /*\r
+ * Inherit the following information:\r
+ * ---------------------------------\r
+ *\r
+ * In-scope namespaces\r
+ */\r
+ inode->inScopeNs = iprev->inScopeNs;\r
+ /*\r
+ * Info for literal result elements\r
+ */\r
+ inode->litResElemInfo = iprev->litResElemInfo;\r
+ inode->nsChanged = iprev->nsChanged;\r
+ /*\r
+ * Excluded result namespaces\r
+ */\r
+ inode->exclResultNs = iprev->exclResultNs;\r
+ /*\r
+ * Extension instruction namespaces\r
+ */\r
+ inode->extElemNs = iprev->extElemNs;\r
+ /*\r
+ * Whitespace preservation\r
+ */\r
+ inode->preserveWhitespace = iprev->preserveWhitespace;\r
+ /*\r
+ * Forwards-compatible mode\r
+ */\r
+ inode->forwardsCompat = iprev->forwardsCompat; \r
+ } else {\r
+ inode->inScopeNs = NULL;\r
+ inode->exclResultNs = NULL;\r
+ inode->extElemNs = NULL;\r
+ inode->preserveWhitespace = 0;\r
+ inode->forwardsCompat = 0;\r
+ }\r
+ \r
+ return(inode);\r
+}\r
+\r
+/*\r
+* xsltCompilerNodePop:\r
+*\r
+* @cctxt: the compilation context\r
+* @node: the node to be pushed (this can also be the doc-node)\r
+*\r
+* Pops the current node info.\r
+*/\r
+static void\r
+xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{ \r
+ if (cctxt->inode == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltCompilerNodePop: Top-node mismatch.\n");\r
+ return;\r
+ }\r
+ /*\r
+ * NOTE: Be carefull with the @node, since it might be\r
+ * a doc-node.\r
+ */\r
+ if (cctxt->inode->node != node) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltCompilerNodePop: Node mismatch.\n");\r
+ goto mismatch;\r
+ }\r
+ if (cctxt->inode->depth != cctxt->depth) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltCompilerNodePop: Depth mismatch.\n");\r
+ goto mismatch;\r
+ }\r
+ /*\r
+ * Pop information of variables.\r
+ */\r
+ if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))\r
+ xsltCompilerVarInfoPop(cctxt);\r
+\r
+ cctxt->depth--;\r
+ cctxt->inode = cctxt->inode->prev;\r
+ if (cctxt->inode != NULL)\r
+ cctxt->inode->curChildType = 0;\r
+ return;\r
+\r
+mismatch:\r
+ {\r
+ const xmlChar *nsName = NULL, *name = NULL;\r
+ const xmlChar *infnsName = NULL, *infname = NULL;\r
+ \r
+ if (node) {\r
+ if (node->type == XML_ELEMENT_NODE) {\r
+ name = node->name;\r
+ if (node->ns != NULL)\r
+ nsName = node->ns->href;\r
+ else\r
+ nsName = BAD_CAST "";\r
+ } else {\r
+ name = BAD_CAST "#document";\r
+ nsName = BAD_CAST "";\r
+ }\r
+ } else\r
+ name = BAD_CAST "Not given";\r
+\r
+ if (cctxt->inode->node) {\r
+ if (node->type == XML_ELEMENT_NODE) {\r
+ infname = cctxt->inode->node->name;\r
+ if (cctxt->inode->node->ns != NULL)\r
+ infnsName = cctxt->inode->node->ns->href;\r
+ else\r
+ infnsName = BAD_CAST "";\r
+ } else {\r
+ infname = BAD_CAST "#document";\r
+ infnsName = BAD_CAST "";\r
+ }\r
+ } else\r
+ infname = BAD_CAST "Not given";\r
+\r
+ \r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltCompilerNodePop: Given : '%s' URI '%s'\n",\r
+ name, nsName);\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",\r
+ infname, infnsName);\r
+ }\r
+}\r
+\r
+/*\r
+* xsltCompilerBuildInScopeNsList:\r
+*\r
+* Create and store the list of in-scope namespaces for the given\r
+* node in the stylesheet. If there are no changes in the in-scope\r
+* namespaces then the last ns-info of the ancestor axis will be returned.\r
+* Compilation-time only.\r
+*\r
+* Returns the ns-info or NULL if there are no namespaces in scope.\r
+*/\r
+static xsltNsListContainerPtr\r
+xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{\r
+ xsltNsListContainerPtr nsi = NULL;\r
+ xmlNsPtr *list = NULL, ns;\r
+ int i, maxns = 5;\r
+ /*\r
+ * Create a new ns-list for this position in the node-tree.\r
+ * xmlGetNsList() will return NULL, if there are no ns-decls in the\r
+ * tree. Note that the ns-decl for the XML namespace is not added\r
+ * to the resulting list; the XPath module handles the XML namespace\r
+ * internally.\r
+ */\r
+ while (node != NULL) {\r
+ if (node->type == XML_ELEMENT_NODE) {\r
+ ns = node->nsDef;\r
+ while (ns != NULL) {\r
+ if (nsi == NULL) {\r
+ nsi = (xsltNsListContainerPtr)\r
+ xmlMalloc(sizeof(xsltNsListContainer));\r
+ if (nsi == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "xsltCompilerBuildInScopeNsList: "\r
+ "malloc failed!\n");\r
+ goto internal_err;\r
+ }\r
+ memset(nsi, 0, sizeof(xsltNsListContainer));\r
+ nsi->list =\r
+ (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));\r
+ if (nsi->list == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "xsltCompilerBuildInScopeNsList: "\r
+ "malloc failed!\n");\r
+ goto internal_err;\r
+ }\r
+ nsi->list[0] = NULL;\r
+ }\r
+ /*\r
+ * Skip shadowed namespace bindings.\r
+ */\r
+ for (i = 0; i < nsi->totalNumber; i++) {\r
+ if ((ns->prefix == nsi->list[i]->prefix) ||\r
+ (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))\r
+ break;\r
+ }\r
+ if (i >= nsi->totalNumber) {\r
+ if (nsi->totalNumber +1 >= maxns) {\r
+ maxns *= 2;\r
+ nsi->list =\r
+ (xmlNsPtr *) xmlRealloc(nsi->list,\r
+ maxns * sizeof(xmlNsPtr));\r
+ if (nsi->list == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "xsltCompilerBuildInScopeNsList: "\r
+ "realloc failed!\n");\r
+ goto internal_err;\r
+ }\r
+ }\r
+ nsi->list[nsi->totalNumber++] = ns;\r
+ nsi->list[nsi->totalNumber] = NULL;\r
+ }\r
+\r
+ ns = ns->next;\r
+ }\r
+ }\r
+ node = node->parent;\r
+ }\r
+ if (nsi == NULL)\r
+ return(NULL);\r
+ /*\r
+ * Move the default namespace to last position.\r
+ */\r
+ nsi->xpathNumber = nsi->totalNumber;\r
+ for (i = 0; i < nsi->totalNumber; i++) {\r
+ if (nsi->list[i]->prefix == NULL) {\r
+ ns = nsi->list[i];\r
+ nsi->list[i] = nsi->list[nsi->totalNumber-1];\r
+ nsi->list[nsi->totalNumber-1] = ns;\r
+ nsi->xpathNumber--;\r
+ break;\r
+ }\r
+ }\r
+ /*\r
+ * Store the ns-list in the stylesheet.\r
+ */\r
+ if (xsltPointerListAddSize(\r
+ (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,\r
+ (void *) nsi, 5) == -1)\r
+ { \r
+ xmlFree(nsi);\r
+ nsi = NULL;\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");\r
+ goto internal_err;\r
+ }\r
+ /*\r
+ * Notify of change in status wrt namespaces.\r
+ */\r
+ if (cctxt->inode != NULL)\r
+ cctxt->inode->nsChanged = 1;\r
+\r
+ return(nsi);\r
+\r
+internal_err:\r
+ if (list != NULL)\r
+ xmlFree(list); \r
+ cctxt->style->errors++;\r
+ return(NULL);\r
+}\r
+\r
+static int\r
+xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,\r
+ xsltPointerListPtr list,\r
+ xmlNodePtr node,\r
+ const xmlChar *value)\r
+{\r
+ xmlChar *cur, *end;\r
+ xmlNsPtr ns;\r
+ \r
+ if ((cctxt == NULL) || (value == NULL) || (list == NULL))\r
+ return(-1);\r
+\r
+ list->number = 0;\r
+\r
+ cur = (xmlChar *) value;\r
+ while (*cur != 0) {\r
+ while (IS_BLANK(*cur)) cur++;\r
+ if (*cur == 0)\r
+ break;\r
+ end = cur;\r
+ while ((*end != 0) && (!IS_BLANK(*end))) end++;\r
+ cur = xmlStrndup(cur, end - cur);\r
+ if (cur == NULL) {\r
+ cur = end;\r
+ continue;\r
+ } \r
+ /*\r
+ * TODO: Export and use xmlSearchNsByPrefixStrict()\r
+ * in Libxml2, tree.c, since xmlSearchNs() is in most\r
+ * cases not efficient and in some cases not correct.\r
+ *\r
+ * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.\r
+ */\r
+ if ((cur[0] == '#') &&\r
+ xmlStrEqual(cur, (const xmlChar *)"#default"))\r
+ ns = xmlSearchNs(cctxt->style->doc, node, NULL);\r
+ else\r
+ ns = xmlSearchNs(cctxt->style->doc, node, cur); \r
+\r
+ if (ns == NULL) {\r
+ /*\r
+ * TODO: Better to report the attr-node, otherwise\r
+ * the user won't know which attribute was invalid.\r
+ */\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "No namespace binding in scope for prefix '%s'.\n", cur);\r
+ /*\r
+ * XSLT-1.0: "It is an error if there is no namespace\r
+ * bound to the prefix on the element bearing the\r
+ * exclude-result-prefixes or xsl:exclude-result-prefixes\r
+ * attribute."\r
+ */\r
+ cctxt->style->errors++;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "resolved prefix '%s'\n", cur);\r
+#endif\r
+ /*\r
+ * Note that we put the namespace name into the dict.\r
+ */\r
+ if (xsltPointerListAddSize(list,\r
+ (void *) xmlDictLookup(cctxt->style->dict,\r
+ ns->href, -1), 5) == -1)\r
+ {\r
+ xmlFree(cur);\r
+ goto internal_err;\r
+ }\r
+ }\r
+ xmlFree(cur);\r
+ \r
+ cur = end;\r
+ }\r
+ return(0);\r
+\r
+internal_err:\r
+ cctxt->style->errors++;\r
+ return(-1);\r
+}\r
+\r
+/**\r
+ * xsltCompilerUtilsCreateMergedList:\r
+ * @dest: the destination list (optional)\r
+ * @first: the first list\r
+ * @second: the second list (optional)\r
+ *\r
+ * Appends the content of @second to @first into @destination.\r
+ * If @destination is NULL a new list will be created.\r
+ *\r
+ * Returns the merged list of items or NULL if there's nothing to merge.\r
+ */\r
+static xsltPointerListPtr\r
+xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,\r
+ xsltPointerListPtr second)\r
+{\r
+ xsltPointerListPtr ret;\r
+ size_t num;\r
+\r
+ if (first)\r
+ num = first->number;\r
+ else\r
+ num = 0;\r
+ if (second)\r
+ num += second->number; \r
+ if (num == 0)\r
+ return(NULL);\r
+ ret = xsltPointerListCreate(num);\r
+ if (ret == NULL)\r
+ return(NULL);\r
+ /*\r
+ * Copy contents.\r
+ */\r
+ if ((first != NULL) && (first->number != 0)) {\r
+ memcpy(ret->items, first->items,\r
+ first->number * sizeof(void *));\r
+ if ((second != NULL) && (second->number != 0))\r
+ memcpy(ret->items + first->number, second->items,\r
+ second->number * sizeof(void *));\r
+ } else if ((second != NULL) && (second->number != 0))\r
+ memcpy(ret->items, (void *) second->items,\r
+ second->number * sizeof(void *));\r
+ ret->number = num;\r
+ return(ret);\r
+}\r
+\r
+/*\r
+* xsltParseExclResultPrefixes:\r
+*\r
+* Create and store the list of in-scope namespaces for the given\r
+* node in the stylesheet. If there are no changes in the in-scope\r
+* namespaces then the last ns-info of the ancestor axis will be returned.\r
+* Compilation-time only.\r
+*\r
+* Returns the ns-info or NULL if there are no namespaces in scope.\r
+*/\r
+static xsltPointerListPtr\r
+xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,\r
+ xsltPointerListPtr def,\r
+ int instrCategory)\r
+{ \r
+ xsltPointerListPtr list = NULL;\r
+ xmlChar *value;\r
+ xmlAttrPtr attr;\r
+\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(NULL);\r
+\r
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)\r
+ attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);\r
+ else\r
+ attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",\r
+ XSLT_NAMESPACE);\r
+ if (attr == NULL) \r
+ return(def);\r
+\r
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {\r
+ /*\r
+ * Mark the XSLT attr.\r
+ */\r
+ attr->psvi = (void *) xsltXSLTAttrMarker;\r
+ }\r
+\r
+ if ((attr->children != NULL) && \r
+ (attr->children->content != NULL))\r
+ value = attr->children->content;\r
+ else {\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Attribute 'exclude-result-prefixes': Invalid value.\n");\r
+ cctxt->style->errors++;\r
+ return(def);\r
+ } \r
+\r
+ if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,\r
+ BAD_CAST value) != 0)\r
+ goto exit;\r
+ if (cctxt->tmpList->number == 0) \r
+ goto exit; \r
+ /*\r
+ * Merge the list with the inherited list.\r
+ */\r
+ list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);\r
+ if (list == NULL)\r
+ goto exit; \r
+ /*\r
+ * Store the list in the stylesheet/compiler context.\r
+ */\r
+ if (xsltPointerListAddSize(\r
+ cctxt->psData->exclResultNamespaces, list, 5) == -1)\r
+ {\r
+ xsltPointerListFree(list);\r
+ list = NULL;\r
+ goto exit;\r
+ }\r
+ /*\r
+ * Notify of change in status wrt namespaces.\r
+ */\r
+ if (cctxt->inode != NULL)\r
+ cctxt->inode->nsChanged = 1;\r
+\r
+exit: \r
+ if (list != NULL)\r
+ return(list);\r
+ else\r
+ return(def);\r
+}\r
+\r
+/*\r
+* xsltParseExtElemPrefixes:\r
+*\r
+* Create and store the list of in-scope namespaces for the given\r
+* node in the stylesheet. If there are no changes in the in-scope\r
+* namespaces then the last ns-info of the ancestor axis will be returned.\r
+* Compilation-time only.\r
+*\r
+* Returns the ns-info or NULL if there are no namespaces in scope.\r
+*/\r
+static xsltPointerListPtr\r
+xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,\r
+ xsltPointerListPtr def,\r
+ int instrCategory)\r
+{ \r
+ xsltPointerListPtr list = NULL;\r
+ xmlAttrPtr attr;\r
+ xmlChar *value;\r
+ int i;\r
+\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(NULL);\r
+\r
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)\r
+ attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);\r
+ else\r
+ attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",\r
+ XSLT_NAMESPACE);\r
+ if (attr == NULL) \r
+ return(def);\r
+\r
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {\r
+ /*\r
+ * Mark the XSLT attr.\r
+ */\r
+ attr->psvi = (void *) xsltXSLTAttrMarker;\r
+ }\r
+\r
+ if ((attr->children != NULL) && \r
+ (attr->children->content != NULL))\r
+ value = attr->children->content;\r
+ else {\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Attribute 'extension-element-prefixes': Invalid value.\n");\r
+ cctxt->style->errors++;\r
+ return(def);\r
+ }\r
+\r
+\r
+ if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,\r
+ BAD_CAST value) != 0)\r
+ goto exit;\r
+\r
+ if (cctxt->tmpList->number == 0)\r
+ goto exit; \r
+ /*\r
+ * REVISIT: Register the extension namespaces.\r
+ */\r
+ for (i = 0; i < cctxt->tmpList->number; i++)\r
+ xsltRegisterExtPrefix(cctxt->style, NULL,\r
+ BAD_CAST cctxt->tmpList->items[i]);\r
+ /*\r
+ * Merge the list with the inherited list.\r
+ */\r
+ list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);\r
+ if (list == NULL)\r
+ goto exit;\r
+ /*\r
+ * Store the list in the stylesheet.\r
+ */\r
+ if (xsltPointerListAddSize(\r
+ cctxt->psData->extElemNamespaces, list, 5) == -1)\r
+ {\r
+ xsltPointerListFree(list);\r
+ list = NULL;\r
+ goto exit;\r
+ }\r
+ /*\r
+ * Notify of change in status wrt namespaces.\r
+ */\r
+ if (cctxt->inode != NULL)\r
+ cctxt->inode->nsChanged = 1;\r
+\r
+exit: \r
+ if (list != NULL)\r
+ return(list);\r
+ else\r
+ return(def);\r
+}\r
+\r
+/*\r
+* xsltParseAttrXSLTVersion:\r
+*\r
+* @cctxt: the compilation context\r
+* @node: the element-node\r
+* @isXsltElem: whether this is an XSLT element\r
+*\r
+* Parses the attribute xsl:version.\r
+*\r
+* Returns 1 if there was such an attribute, 0 if not and\r
+* -1 if an internal or API error occured.\r
+*/\r
+static int\r
+xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, \r
+ int instrCategory)\r
+{\r
+ xmlChar *value;\r
+ xmlAttrPtr attr;\r
+\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(-1);\r
+\r
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)\r
+ attr = xmlHasNsProp(node, BAD_CAST "version", NULL);\r
+ else\r
+ attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);\r
+\r
+ if (attr == NULL) \r
+ return(0);\r
+\r
+ attr->psvi = (void *) xsltXSLTAttrMarker;\r
+\r
+ if ((attr->children != NULL) && \r
+ (attr->children->content != NULL))\r
+ value = attr->children->content;\r
+ else {\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Attribute 'version': Invalid value.\n");\r
+ cctxt->style->errors++;\r
+ return(1);\r
+ }\r
+ \r
+ if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {\r
+ cctxt->inode->forwardsCompat = 1;\r
+ /*\r
+ * TODO: To what extent do we support the\r
+ * forwards-compatible mode?\r
+ */\r
+ /*\r
+ * Report this only once per compilation episode.\r
+ */\r
+ if (! cctxt->hasForwardsCompat) {\r
+ cctxt->hasForwardsCompat = 1;\r
+ cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Warning: the attribute xsl:version specifies a value "\r
+ "different from '1.0'. Switching to forwards-compatible "\r
+ "mode. Only features of XSLT 1.0 are supported by this "\r
+ "processor.\n");\r
+ cctxt->style->warnings++;\r
+ cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;\r
+ } \r
+ } else {\r
+ cctxt->inode->forwardsCompat = 0;\r
+ }\r
+\r
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {\r
+ /*\r
+ * Set a marker on XSLT attributes.\r
+ */\r
+ attr->psvi = (void *) xsltXSLTAttrMarker;\r
+ }\r
+ return(1);\r
+}\r
+\r
+static int\r
+xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{\r
+ xmlNodePtr deleteNode, cur, txt, textNode = NULL;\r
+ xmlDocPtr doc;\r
+ xsltStylesheetPtr style;\r
+ int internalize = 0, findSpaceAttr;\r
+ int xsltStylesheetElemDepth;\r
+ xmlAttrPtr attr;\r
+ xmlChar *value;\r
+ const xmlChar *name, *nsNameXSLT = NULL;\r
+ int strictWhitespace, inXSLText = 0;\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ xsltNsMapPtr nsMapItem;\r
+#endif\r
+\r
+ if ((cctxt == NULL) || (cctxt->style == NULL) ||\r
+ (node == NULL) || (node->type != XML_ELEMENT_NODE))\r
+ return(-1);\r
+\r
+ doc = node->doc;\r
+ if (doc == NULL)\r
+ goto internal_err;\r
+\r
+ style = cctxt->style;\r
+ if ((style->dict != NULL) && (doc->dict == style->dict))\r
+ internalize = 1;\r
+ else\r
+ style->internalized = 0;\r
+\r
+ /*\r
+ * Init value of xml:space. Since this might be an embedded\r
+ * stylesheet, this is needed to be performed on the element\r
+ * where the stylesheet is rooted at, taking xml:space of\r
+ * ancestors into account.\r
+ */\r
+ if (! cctxt->simplified)\r
+ xsltStylesheetElemDepth = cctxt->depth +1;\r
+ else\r
+ xsltStylesheetElemDepth = 0;\r
+\r
+ if (xmlNodeGetSpacePreserve(node) != 1)\r
+ cctxt->inode->preserveWhitespace = 0;\r
+ else\r
+ cctxt->inode->preserveWhitespace = 1; \r
+ \r
+ /*\r
+ * Eval if we should keep the old incorrect behaviour.\r
+ */\r
+ strictWhitespace = (cctxt->strict != 0) ? 1 : 0;\r
+\r
+ nsNameXSLT = xsltConstNamespaceNameXSLT;\r
+\r
+ deleteNode = NULL;\r
+ cur = node;\r
+ while (cur != NULL) {\r
+ if (deleteNode != NULL) {\r
+\r
+#ifdef WITH_XSLT_DEBUG_BLANKS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParsePreprocessStylesheetTree: removing node\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ deleteNode = NULL;\r
+ }\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ \r
+ /*\r
+ * Clear the PSVI field.\r
+ */\r
+ cur->psvi = NULL;\r
+\r
+ xsltCompilerNodePush(cctxt, cur);\r
+\r
+ inXSLText = 0;\r
+ textNode = NULL; \r
+ findSpaceAttr = 1; \r
+ cctxt->inode->stripWhitespace = 0;\r
+ /*\r
+ * TODO: I'd love to use a string pointer comparison here :-/\r
+ */\r
+ if (IS_XSLT_ELEM(cur)) {\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ if (cur->ns->href != nsNameXSLT) {\r
+ nsMapItem = xsltNewNamespaceMapItem(cctxt,\r
+ doc, cur->ns, cur);\r
+ if (nsMapItem == NULL)\r
+ goto internal_err;\r
+ cur->ns->href = nsNameXSLT;\r
+ }\r
+#endif\r
+\r
+ if (cur->name == NULL)\r
+ goto process_attributes;\r
+ /*\r
+ * Mark the XSLT element for later recognition.\r
+ * TODO: Using the marker is still too dangerous, since if\r
+ * the parsing mechanism leaves out an XSLT element, then\r
+ * this might hit the transformation-mechanism, which\r
+ * will break if it doesn't expect such a marker.\r
+ */\r
+ /* cur->psvi = (void *) xsltXSLTElemMarker; */\r
+\r
+ /*\r
+ * XSLT 2.0: "Any whitespace text node whose parent is\r
+ * one of the following elements is removed from the "\r
+ * tree, regardless of any xml:space attributes:..."\r
+ * xsl:apply-imports, \r
+ * xsl:apply-templates,\r
+ * xsl:attribute-set,\r
+ * xsl:call-template, \r
+ * xsl:choose,\r
+ * xsl:stylesheet, xsl:transform.\r
+ * XSLT 2.0: xsl:analyze-string,\r
+ * xsl:character-map,\r
+ * xsl:next-match \r
+ *\r
+ * TODO: I'd love to use a string pointer comparison here :-/\r
+ */ \r
+ name = cur->name;\r
+ switch (*name) {\r
+ case 't':\r
+ if ((name[0] == 't') && (name[1] == 'e') &&\r
+ (name[2] == 'x') && (name[3] == 't') &&\r
+ (name[4] == 0))\r
+ {\r
+ /*\r
+ * Process the xsl:text element.\r
+ * ----------------------------\r
+ * Mark it for later recognition.\r
+ */\r
+ cur->psvi = (void *) xsltXSLTTextMarker;\r
+ /*\r
+ * For stylesheets, the set of\r
+ * whitespace-preserving element names\r
+ * consists of just xsl:text.\r
+ */\r
+ findSpaceAttr = 0;\r
+ cctxt->inode->preserveWhitespace = 1;\r
+ inXSLText = 1;\r
+ } \r
+ break;\r
+ case 'c':\r
+ if (xmlStrEqual(name, BAD_CAST "choose") ||\r
+ xmlStrEqual(name, BAD_CAST "call-template"))\r
+ cctxt->inode->stripWhitespace = 1;\r
+ break;\r
+ case 'a':\r
+ if (xmlStrEqual(name, BAD_CAST "apply-templates") ||\r
+ xmlStrEqual(name, BAD_CAST "apply-imports") ||\r
+ xmlStrEqual(name, BAD_CAST "attribute-set"))\r
+\r
+ cctxt->inode->stripWhitespace = 1;\r
+ break;\r
+ default:\r
+ if (xsltStylesheetElemDepth == cctxt->depth) {\r
+ /*\r
+ * This is a xsl:stylesheet/xsl:transform.\r
+ */\r
+ cctxt->inode->stripWhitespace = 1;\r
+ break;\r
+ }\r
+\r
+ if ((cur->prev != NULL) &&\r
+ (cur->prev->type == XML_TEXT_NODE))\r
+ {\r
+ /*\r
+ * XSLT 2.0 : "Any whitespace text node whose\r
+ * following-sibling node is an xsl:param or\r
+ * xsl:sort element is removed from the tree,\r
+ * regardless of any xml:space attributes."\r
+ */\r
+ if (((*name == 'p') || (*name == 's')) &&\r
+ (xmlStrEqual(name, BAD_CAST "param") ||\r
+ xmlStrEqual(name, BAD_CAST "sort")))\r
+ {\r
+ do {\r
+ if (IS_BLANK_NODE(cur->prev)) {\r
+ txt = cur->prev;\r
+ xmlUnlinkNode(txt);\r
+ xmlFreeNode(txt);\r
+ } else {\r
+ /*\r
+ * This will result in a content\r
+ * error, when hitting the parsing\r
+ * functions.\r
+ */\r
+ break;\r
+ }\r
+ } while (cur->prev); \r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+process_attributes:\r
+ /*\r
+ * Process attributes.\r
+ * ------------------\r
+ */\r
+ if (cur->properties != NULL) {\r
+ if (cur->children == NULL)\r
+ findSpaceAttr = 0;\r
+ attr = cur->properties;\r
+ do {\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&\r
+ xmlStrEqual(attr->ns->href, nsNameXSLT))\r
+ { \r
+ nsMapItem = xsltNewNamespaceMapItem(cctxt,\r
+ doc, attr->ns, cur);\r
+ if (nsMapItem == NULL)\r
+ goto internal_err;\r
+ attr->ns->href = nsNameXSLT;\r
+ } \r
+#endif\r
+ if (internalize) {\r
+ /*\r
+ * Internalize the attribute's value; the goal is to\r
+ * speed up operations and minimize used space by\r
+ * compiled stylesheets.\r
+ */\r
+ txt = attr->children;\r
+ /*\r
+ * NOTE that this assumes only one\r
+ * text-node in the attribute's content.\r
+ */\r
+ if ((txt != NULL) && (txt->content != NULL) &&\r
+ (!xmlDictOwns(style->dict, txt->content)))\r
+ {\r
+ value = (xmlChar *) xmlDictLookup(style->dict,\r
+ txt->content, -1);\r
+ xmlNodeSetContent(txt, NULL);\r
+ txt->content = value;\r
+ }\r
+ }\r
+ /*\r
+ * Process xml:space attributes.\r
+ * ----------------------------\r
+ */\r
+ if ((findSpaceAttr != 0) &&\r
+ (attr->ns != NULL) &&\r
+ (attr->name != NULL) &&\r
+ (attr->name[0] == 's') && \r
+ (attr->ns->prefix != NULL) &&\r
+ (attr->ns->prefix[0] == 'x') &&\r
+ (attr->ns->prefix[1] == 'm') &&\r
+ (attr->ns->prefix[2] == 'l') &&\r
+ (attr->ns->prefix[3] == 0))\r
+ {\r
+ value = xmlGetNsProp(cur, BAD_CAST "space",\r
+ XML_XML_NAMESPACE);\r
+ if (value != NULL) {\r
+ if (xmlStrEqual(value, BAD_CAST "preserve")) {\r
+ cctxt->inode->preserveWhitespace = 1; \r
+ } else if (xmlStrEqual(value, BAD_CAST "default")) {\r
+ cctxt->inode->preserveWhitespace = 0;\r
+ } else {\r
+ /* Invalid value for xml:space. */\r
+ xsltTransformError(NULL, style, cur,\r
+ "Attribute xml:space: Invalid value.\n");\r
+ cctxt->style->warnings++;\r
+ }\r
+ findSpaceAttr = 0;\r
+ xmlFree(value);\r
+ }\r
+ \r
+ }\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+ }\r
+ /*\r
+ * We'll descend into the children of element nodes only.\r
+ */\r
+ if (cur->children != NULL) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ } else if ((cur->type == XML_TEXT_NODE) ||\r
+ (cur->type == XML_CDATA_SECTION_NODE))\r
+ {\r
+ /*\r
+ * Merge adjacent text/CDATA-section-nodes\r
+ * --------------------------------------- \r
+ * In order to avoid breaking of existing stylesheets,\r
+ * if the old behaviour is wanted (strictWhitespace == 0),\r
+ * then we *won't* merge adjacent text-nodes\r
+ * (except in xsl:text); this will ensure that whitespace-only\r
+ * text nodes are (incorrectly) not stripped in some cases.\r
+ * \r
+ * Example: : <foo> <!-- bar -->zoo</foo>\r
+ * Corrent (strict) result: <foo> zoo</foo>\r
+ * Incorrect (old) result : <foo>zoo</foo>\r
+ * \r
+ * NOTE that we *will* merge adjacent text-nodes if\r
+ * they are in xsl:text.\r
+ * Example, the following:\r
+ * <xsl:text> <!-- bar -->zoo<xsl:text>\r
+ * will result in both cases in:\r
+ * <xsl:text> zoo<xsl:text>\r
+ */\r
+ cur->type = XML_TEXT_NODE;\r
+ if ((strictWhitespace != 0) || (inXSLText != 0)) {\r
+ /*\r
+ * New behaviour; merge nodes.\r
+ */\r
+ if (textNode == NULL)\r
+ textNode = cur;\r
+ else {\r
+ if (cur->content != NULL)\r
+ xmlNodeAddContent(textNode, cur->content);\r
+ deleteNode = cur;\r
+ }\r
+ if ((cur->next == NULL) ||\r
+ (cur->next->type == XML_ELEMENT_NODE))\r
+ goto end_of_text;\r
+ else\r
+ goto next_sibling;\r
+ } else {\r
+ /*\r
+ * Old behaviour.\r
+ */\r
+ if (textNode == NULL)\r
+ textNode = cur;\r
+ goto end_of_text;\r
+ } \r
+ } else if ((cur->type == XML_COMMENT_NODE) ||\r
+ (cur->type == XML_PI_NODE))\r
+ { \r
+ /*\r
+ * Remove processing instructions and comments.\r
+ */\r
+ deleteNode = cur;\r
+ if ((cur->next == NULL) ||\r
+ (cur->next->type == XML_ELEMENT_NODE))\r
+ goto end_of_text;\r
+ else\r
+ goto next_sibling;\r
+ } else {\r
+ textNode = NULL;\r
+ /*\r
+ * Invalid node-type for this data-model.\r
+ */\r
+ xsltTransformError(NULL, style, cur,\r
+ "Invalid type of node for the XSLT data model.\n");\r
+ cctxt->style->errors++;\r
+ goto next_sibling;\r
+ }\r
+\r
+end_of_text:\r
+ if (textNode) {\r
+ value = textNode->content;\r
+ /*\r
+ * At this point all adjacent text/CDATA-section nodes\r
+ * have been merged.\r
+ *\r
+ * Strip whitespace-only text-nodes.\r
+ * (cctxt->inode->stripWhitespace)\r
+ */\r
+ if ((value == NULL) || (*value == 0) ||\r
+ (((cctxt->inode->stripWhitespace) ||\r
+ (! cctxt->inode->preserveWhitespace)) &&\r
+ IS_BLANK(*value) &&\r
+ xsltIsBlank(value)))\r
+ { \r
+ if (textNode != cur) {\r
+ xmlUnlinkNode(textNode);\r
+ xmlFreeNode(textNode);\r
+ } else\r
+ deleteNode = textNode;\r
+ textNode = NULL;\r
+ goto next_sibling;\r
+ }\r
+ /*\r
+ * Convert CDATA-section nodes to text-nodes.\r
+ * TODO: Can this produce problems?\r
+ */\r
+ if (textNode->type != XML_TEXT_NODE) {\r
+ textNode->type = XML_TEXT_NODE;\r
+ textNode->name = xmlStringText;\r
+ }\r
+ if (internalize &&\r
+ (textNode->content != NULL) &&\r
+ (!xmlDictOwns(style->dict, textNode->content)))\r
+ {\r
+ /*\r
+ * Internalize the string.\r
+ */\r
+ value = (xmlChar *) xmlDictLookup(style->dict,\r
+ textNode->content, -1);\r
+ xmlNodeSetContent(textNode, NULL);\r
+ textNode->content = value;\r
+ }\r
+ textNode = NULL;\r
+ /*\r
+ * Note that "disable-output-escaping" of the xsl:text\r
+ * element will be applied at a later level, when\r
+ * XSLT elements are processed.\r
+ */\r
+ }\r
+\r
+next_sibling:\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ xsltCompilerNodePop(cctxt, cur);\r
+ }\r
+ if (cur == node)\r
+ break;\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ } else {\r
+ cur = cur->parent;\r
+ inXSLText = 0;\r
+ goto next_sibling;\r
+ };\r
+ }\r
+ if (deleteNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParsePreprocessStylesheetTree: removing node\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ }\r
+ return(0);\r
+\r
+internal_err:\r
+ return(-1);\r
+}\r
+\r
+#endif /* XSLT_REFACTORED */\r
+\r
+#ifdef XSLT_REFACTORED\r
+#else\r
+static void\r
+xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)\r
+{\r
+ xmlNodePtr deleteNode;\r
+ int internalize = 0;\r
+\r
+ if ((style == NULL) || (cur == NULL))\r
+ return;\r
+\r
+ if ((cur->doc != NULL) && (style->dict != NULL) &&\r
+ (cur->doc->dict == style->dict))\r
+ internalize = 1;\r
+ else\r
+ style->internalized = 0;\r
+ /*\r
+ * This content comes from the stylesheet\r
+ * For stylesheets, the set of whitespace-preserving\r
+ * element names consists of just xsl:text.\r
+ */\r
+ deleteNode = NULL;\r
+ while (cur != NULL) {\r
+ if (deleteNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_BLANKS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltPrecomputeStylesheet: removing ignorable blank node\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ deleteNode = NULL;\r
+ }\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ int exclPrefixes;\r
+ /*\r
+ * Internalize attributes values.\r
+ */\r
+ if ((internalize) && (cur->properties != NULL)) {\r
+ xmlAttrPtr attr = cur->properties;\r
+ xmlNodePtr txt;\r
+\r
+ while (attr != NULL) {\r
+ txt = attr->children;\r
+ if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&\r
+ (txt->content != NULL) &&\r
+ (!xmlDictOwns(style->dict, txt->content)))\r
+ {\r
+ xmlChar *tmp;\r
+\r
+ /*\r
+ * internalize the text string, goal is to speed\r
+ * up operations and minimize used space by compiled\r
+ * stylesheets.\r
+ */\r
+ tmp = (xmlChar *) xmlDictLookup(style->dict,\r
+ txt->content, -1);\r
+ if (tmp != txt->content) {\r
+ xmlNodeSetContent(txt, NULL);\r
+ txt->content = tmp;\r
+ }\r
+ }\r
+ attr = attr->next;\r
+ }\r
+ }\r
+ if (IS_XSLT_ELEM(cur)) {\r
+ exclPrefixes = 0;\r
+ xsltStylePreCompute(style, cur);\r
+ if (IS_XSLT_NAME(cur, "text")) {\r
+ for (;exclPrefixes > 0;exclPrefixes--)\r
+ exclPrefixPop(style);\r
+ goto skip_children;\r
+ }\r
+ } else {\r
+ exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);\r
+ }\r
+ \r
+ if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {\r
+ xmlNsPtr ns = cur->nsDef, prev = NULL, next;\r
+ xmlNodePtr root = NULL;\r
+ int i, moved;\r
+\r
+ root = xmlDocGetRootElement(cur->doc);\r
+ if ((root != NULL) && (root != cur)) {\r
+ while (ns != NULL) {\r
+ moved = 0;\r
+ next = ns->next;\r
+ for (i = 0;i < style->exclPrefixNr;i++) {\r
+ if ((ns->prefix != NULL) && \r
+ (xmlStrEqual(ns->href,\r
+ style->exclPrefixTab[i]))) {\r
+ /*\r
+ * Move the namespace definition on the root\r
+ * element to avoid duplicating it without\r
+ * loosing it.\r
+ */\r
+ if (prev == NULL) {\r
+ cur->nsDef = ns->next;\r
+ } else {\r
+ prev->next = ns->next;\r
+ }\r
+ ns->next = root->nsDef;\r
+ root->nsDef = ns;\r
+ moved = 1;\r
+ break;\r
+ }\r
+ }\r
+ if (moved == 0)\r
+ prev = ns;\r
+ ns = next;\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * If we have prefixes locally, recurse and pop them up when\r
+ * going back\r
+ */\r
+ if (exclPrefixes > 0) {\r
+ xsltPrecomputeStylesheet(style, cur->children);\r
+ for (;exclPrefixes > 0;exclPrefixes--)\r
+ exclPrefixPop(style);\r
+ goto skip_children;\r
+ }\r
+ } else if (cur->type == XML_TEXT_NODE) {\r
+ if (IS_BLANK_NODE(cur)) {\r
+ if (xmlNodeGetSpacePreserve(cur) != 1) {\r
+ deleteNode = cur;\r
+ }\r
+ } else if ((cur->content != NULL) && (internalize) &&\r
+ (!xmlDictOwns(style->dict, cur->content))) {\r
+ xmlChar *tmp;\r
+\r
+ /*\r
+ * internalize the text string, goal is to speed\r
+ * up operations and minimize used space by compiled\r
+ * stylesheets.\r
+ */\r
+ tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);\r
+ xmlNodeSetContent(cur, NULL);\r
+ cur->content = tmp;\r
+ }\r
+ } else if ((cur->type != XML_ELEMENT_NODE) &&\r
+ (cur->type != XML_CDATA_SECTION_NODE)) {\r
+ deleteNode = cur;\r
+ goto skip_children;\r
+ }\r
+\r
+ /*\r
+ * Skip to next node\r
+ */\r
+ if (cur->children != NULL) {\r
+ if ((cur->children->type != XML_ENTITY_DECL) &&\r
+ (cur->children->type != XML_ENTITY_REF_NODE) &&\r
+ (cur->children->type != XML_ENTITY_NODE)) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ }\r
+\r
+skip_children:\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ continue;\r
+ } \r
+ do {\r
+\r
+ cur = cur->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ if (cur == (xmlNodePtr) style->doc) {\r
+ cur = NULL;\r
+ break;\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ break;\r
+ }\r
+ } while (cur != NULL);\r
+ }\r
+ if (deleteNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltPrecomputeStylesheet: removing ignorable blank node\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ }\r
+}\r
+#endif /* end of else XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltGatherNamespaces:\r
+ * @style: the XSLT stylesheet\r
+ *\r
+ * Browse the stylesheet and build the namspace hash table which\r
+ * will be used for XPath interpretation. If needed do a bit of normalization\r
+ */\r
+\r
+static void\r
+xsltGatherNamespaces(xsltStylesheetPtr style) {\r
+ xmlNodePtr cur;\r
+ const xmlChar *URI;\r
+\r
+ if (style == NULL)\r
+ return;\r
+ /* \r
+ * TODO: basically if the stylesheet uses the same prefix for different\r
+ * patterns, well they may be in problem, hopefully they will get\r
+ * a warning first.\r
+ */\r
+ /*\r
+ * TODO: Eliminate the use of the hash for XPath expressions.\r
+ * An expression should be evaluated in the context of the in-scope\r
+ * namespaces; eliminate the restriction of an XML document to contain\r
+ * no duplicate prefixes for different namespace names.\r
+ * \r
+ */\r
+ cur = xmlDocGetRootElement(style->doc);\r
+ while (cur != NULL) {\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ xmlNsPtr ns = cur->nsDef;\r
+ while (ns != NULL) {\r
+ if (ns->prefix != NULL) {\r
+ if (style->nsHash == NULL) {\r
+ style->nsHash = xmlHashCreate(10);\r
+ if (style->nsHash == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltGatherNamespaces: failed to create hash table\n");\r
+ style->errors++;\r
+ return;\r
+ }\r
+ }\r
+ URI = xmlHashLookup(style->nsHash, ns->prefix);\r
+ if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);\r
+ style->warnings++;\r
+ } else if (URI == NULL) {\r
+ xmlHashUpdateEntry(style->nsHash, ns->prefix,\r
+ (void *) ns->href, (xmlHashDeallocator)xmlFree);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);\r
+#endif\r
+ }\r
+ }\r
+ ns = ns->next;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Skip to next node\r
+ */\r
+ if (cur->children != NULL) {\r
+ if (cur->children->type != XML_ENTITY_DECL) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ \r
+ do {\r
+ cur = cur->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ if (cur == (xmlNodePtr) style->doc) {\r
+ cur = NULL;\r
+ break;\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ break;\r
+ }\r
+ } while (cur != NULL);\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+static xsltStyleType\r
+xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr node)\r
+{\r
+ if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||\r
+ (node->name == NULL))\r
+ return(0);\r
+\r
+ if (node->name[0] == 'a') {\r
+ if (IS_XSLT_NAME(node, "apply-templates"))\r
+ return(XSLT_FUNC_APPLYTEMPLATES);\r
+ else if (IS_XSLT_NAME(node, "attribute"))\r
+ return(XSLT_FUNC_ATTRIBUTE);\r
+ else if (IS_XSLT_NAME(node, "apply-imports"))\r
+ return(XSLT_FUNC_APPLYIMPORTS);\r
+ else if (IS_XSLT_NAME(node, "attribute-set"))\r
+ return(0);\r
+\r
+ } else if (node->name[0] == 'c') {\r
+ if (IS_XSLT_NAME(node, "choose"))\r
+ return(XSLT_FUNC_CHOOSE);\r
+ else if (IS_XSLT_NAME(node, "copy"))\r
+ return(XSLT_FUNC_COPY);\r
+ else if (IS_XSLT_NAME(node, "copy-of"))\r
+ return(XSLT_FUNC_COPYOF);\r
+ else if (IS_XSLT_NAME(node, "call-template"))\r
+ return(XSLT_FUNC_CALLTEMPLATE);\r
+ else if (IS_XSLT_NAME(node, "comment"))\r
+ return(XSLT_FUNC_COMMENT);\r
+\r
+ } else if (node->name[0] == 'd') {\r
+ if (IS_XSLT_NAME(node, "document"))\r
+ return(XSLT_FUNC_DOCUMENT);\r
+ else if (IS_XSLT_NAME(node, "decimal-format"))\r
+ return(0);\r
+\r
+ } else if (node->name[0] == 'e') {\r
+ if (IS_XSLT_NAME(node, "element"))\r
+ return(XSLT_FUNC_ELEMENT);\r
+\r
+ } else if (node->name[0] == 'f') {\r
+ if (IS_XSLT_NAME(node, "for-each"))\r
+ return(XSLT_FUNC_FOREACH);\r
+ else if (IS_XSLT_NAME(node, "fallback"))\r
+ return(XSLT_FUNC_FALLBACK);\r
+\r
+ } else if (*(node->name) == 'i') {\r
+ if (IS_XSLT_NAME(node, "if"))\r
+ return(XSLT_FUNC_IF);\r
+ else if (IS_XSLT_NAME(node, "include"))\r
+ return(0);\r
+ else if (IS_XSLT_NAME(node, "import"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 'k') {\r
+ if (IS_XSLT_NAME(node, "key"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 'm') {\r
+ if (IS_XSLT_NAME(node, "message"))\r
+ return(XSLT_FUNC_MESSAGE);\r
+\r
+ } else if (*(node->name) == 'n') {\r
+ if (IS_XSLT_NAME(node, "number"))\r
+ return(XSLT_FUNC_NUMBER);\r
+ else if (IS_XSLT_NAME(node, "namespace-alias"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 'o') {\r
+ if (IS_XSLT_NAME(node, "otherwise"))\r
+ return(XSLT_FUNC_OTHERWISE);\r
+ else if (IS_XSLT_NAME(node, "output"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 'p') {\r
+ if (IS_XSLT_NAME(node, "param"))\r
+ return(XSLT_FUNC_PARAM);\r
+ else if (IS_XSLT_NAME(node, "processing-instruction"))\r
+ return(XSLT_FUNC_PI);\r
+ else if (IS_XSLT_NAME(node, "preserve-space"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 's') {\r
+ if (IS_XSLT_NAME(node, "sort"))\r
+ return(XSLT_FUNC_SORT);\r
+ else if (IS_XSLT_NAME(node, "strip-space"))\r
+ return(0);\r
+ else if (IS_XSLT_NAME(node, "stylesheet"))\r
+ return(0);\r
+\r
+ } else if (node->name[0] == 't') {\r
+ if (IS_XSLT_NAME(node, "text"))\r
+ return(XSLT_FUNC_TEXT);\r
+ else if (IS_XSLT_NAME(node, "template"))\r
+ return(0);\r
+ else if (IS_XSLT_NAME(node, "transform"))\r
+ return(0);\r
+\r
+ } else if (*(node->name) == 'v') {\r
+ if (IS_XSLT_NAME(node, "value-of"))\r
+ return(XSLT_FUNC_VALUEOF);\r
+ else if (IS_XSLT_NAME(node, "variable"))\r
+ return(XSLT_FUNC_VARIABLE);\r
+\r
+ } else if (*(node->name) == 'w') {\r
+ if (IS_XSLT_NAME(node, "when"))\r
+ return(XSLT_FUNC_WHEN);\r
+ if (IS_XSLT_NAME(node, "with-param"))\r
+ return(XSLT_FUNC_WITHPARAM);\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltParseAnyXSLTElem:\r
+ *\r
+ * @cctxt: the compilation context\r
+ * @elem: the element node of the XSLT instruction\r
+ *\r
+ * Parses, validates the content models and compiles XSLT instructions.\r
+ *\r
+ * Returns 0 if everything's fine;\r
+ * -1 on API or internal errors.\r
+ */ \r
+int\r
+xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)\r
+{\r
+ if ((cctxt == NULL) || (elem == NULL) ||\r
+ (elem->type != XML_ELEMENT_NODE))\r
+ return(-1);\r
+\r
+ elem->psvi = NULL;\r
+\r
+ if (! (IS_XSLT_ELEM_FAST(elem)))\r
+ return(-1);\r
+ /*\r
+ * Detection of handled content of extension instructions.\r
+ */\r
+ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {\r
+ cctxt->inode->extContentHandled = 1;\r
+ }\r
+ \r
+ xsltCompilerNodePush(cctxt, elem);\r
+ /*\r
+ * URGENT TODO: Find a way to speed up this annoying redundant\r
+ * textual node-name and namespace comparison.\r
+ */\r
+ if (cctxt->inode->prev->curChildType != 0)\r
+ cctxt->inode->type = cctxt->inode->prev->curChildType;\r
+ else\r
+ cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem); \r
+ /*\r
+ * Update the in-scope namespaces if needed.\r
+ */\r
+ if (elem->nsDef != NULL)\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, elem);\r
+ /*\r
+ * xsltStylePreCompute():\r
+ * This will compile the information found on the current\r
+ * element's attributes. NOTE that this won't process the\r
+ * children of the instruction.\r
+ */\r
+ xsltStylePreCompute(cctxt->style, elem);\r
+ /*\r
+ * TODO: How to react on errors in xsltStylePreCompute() ?\r
+ */\r
+\r
+ /*\r
+ * Validate the content model of the XSLT-element.\r
+ */\r
+ switch (cctxt->inode->type) { \r
+ case XSLT_FUNC_APPLYIMPORTS:\r
+ /* EMPTY */\r
+ goto empty_content;\r
+ case XSLT_FUNC_APPLYTEMPLATES:\r
+ /* <!-- Content: (xsl:sort | xsl:with-param)* --> */\r
+ goto apply_templates; \r
+ case XSLT_FUNC_ATTRIBUTE: \r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_CALLTEMPLATE:\r
+ /* <!-- Content: xsl:with-param* --> */\r
+ goto call_template;\r
+ case XSLT_FUNC_CHOOSE: \r
+ /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */\r
+ goto choose;\r
+ case XSLT_FUNC_COMMENT:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor; \r
+ case XSLT_FUNC_COPY:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor; \r
+ case XSLT_FUNC_COPYOF:\r
+ /* EMPTY */\r
+ goto empty_content; \r
+ case XSLT_FUNC_DOCUMENT: /* Extra one */\r
+ /* ?? template ?? */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_ELEMENT:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_FALLBACK:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_FOREACH:\r
+ /* <!-- Content: (xsl:sort*, template) --> */\r
+ goto for_each;\r
+ case XSLT_FUNC_IF:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_OTHERWISE:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_MESSAGE:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_NUMBER:\r
+ /* EMPTY */\r
+ goto empty_content;\r
+ case XSLT_FUNC_PARAM:\r
+ /*\r
+ * Check for redefinition.\r
+ */\r
+ if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {\r
+ xsltVarInfoPtr ivar = cctxt->ivar;\r
+\r
+ do {\r
+ if ((ivar->name ==\r
+ ((xsltStyleItemParamPtr) elem->psvi)->name) &&\r
+ (ivar->nsName ==\r
+ ((xsltStyleItemParamPtr) elem->psvi)->ns))\r
+ {\r
+ elem->psvi = NULL;\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Redefinition of variable or parameter '%s'.\n",\r
+ ivar->name);\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ ivar = ivar->prev;\r
+ } while (ivar != NULL);\r
+ }\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_PI:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_SORT:\r
+ /* EMPTY */\r
+ goto empty_content;\r
+ case XSLT_FUNC_TEXT:\r
+ /* <!-- Content: #PCDATA --> */\r
+ goto text;\r
+ case XSLT_FUNC_VALUEOF:\r
+ /* EMPTY */\r
+ goto empty_content;\r
+ case XSLT_FUNC_VARIABLE:\r
+ /*\r
+ * Check for redefinition.\r
+ */\r
+ if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {\r
+ xsltVarInfoPtr ivar = cctxt->ivar; \r
+\r
+ do {\r
+ if ((ivar->name ==\r
+ ((xsltStyleItemVariablePtr) elem->psvi)->name) &&\r
+ (ivar->nsName ==\r
+ ((xsltStyleItemVariablePtr) elem->psvi)->ns))\r
+ {\r
+ elem->psvi = NULL;\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "Redefinition of variable or parameter '%s'.\n",\r
+ ivar->name);\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ ivar = ivar->prev;\r
+ } while (ivar != NULL);\r
+ }\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_WHEN:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ case XSLT_FUNC_WITHPARAM:\r
+ /* <!-- Content: template --> */\r
+ goto sequence_constructor;\r
+ default:\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",\r
+ elem->name); \r
+#endif\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "xsltParseXSLTNode: Internal error; "\r
+ "unhandled XSLT element '%s'.\n", elem->name);\r
+ cctxt->style->errors++;\r
+ goto internal_err;\r
+ }\r
+\r
+apply_templates:\r
+ /* <!-- Content: (xsl:sort | xsl:with-param)* --> */\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ do {\r
+ if (child->type == XML_ELEMENT_NODE) {\r
+ if (IS_XSLT_ELEM_FAST(child)) {\r
+ if (xmlStrEqual(child->name, BAD_CAST "with-param")) {\r
+ cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {\r
+ cctxt->inode->curChildType = XSLT_FUNC_SORT;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else\r
+ xsltParseContentError(cctxt->style, child);\r
+ } else\r
+ xsltParseContentError(cctxt->style, child);\r
+ }\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ } \r
+ goto exit;\r
+\r
+call_template:\r
+ /* <!-- Content: xsl:with-param* --> */\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ do {\r
+ if (child->type == XML_ELEMENT_NODE) {\r
+ if (IS_XSLT_ELEM_FAST(child)) {\r
+ xsltStyleType type;\r
+\r
+ type = xsltGetXSLTElementTypeByNode(cctxt, child);\r
+ if (type == XSLT_FUNC_WITHPARAM) {\r
+ cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else {\r
+ xsltParseContentError(cctxt->style, child);\r
+ }\r
+ } else\r
+ xsltParseContentError(cctxt->style, child);\r
+ }\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ } \r
+ goto exit;\r
+\r
+text:\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ do {\r
+ if ((child->type != XML_TEXT_NODE) &&\r
+ (child->type != XML_CDATA_SECTION_NODE))\r
+ {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "The XSLT 'text' element must have only character "\r
+ "data as content.\n");\r
+ }\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ }\r
+ goto exit;\r
+\r
+empty_content:\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ /*\r
+ * Relaxed behaviour: we will allow whitespace-only text-nodes.\r
+ */\r
+ do {\r
+ if (((child->type != XML_TEXT_NODE) &&\r
+ (child->type != XML_CDATA_SECTION_NODE)) ||\r
+ (! IS_BLANK_NODE(child)))\r
+ {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "This XSLT element must have no content.\n");\r
+ cctxt->style->errors++;\r
+ break;\r
+ }\r
+ child = child->next;\r
+ } while (child != NULL); \r
+ }\r
+ goto exit;\r
+\r
+choose:\r
+ /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */\r
+ /*\r
+ * TODO: text-nodes in between are *not* allowed in XSLT 1.0.\r
+ * The old behaviour did not check this.\r
+ * NOTE: In XSLT 2.0 they are stripped beforehand\r
+ * if whitespace-only (regardless of xml:space).\r
+ */\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ int nbWhen = 0, nbOtherwise = 0, err = 0;\r
+ do {\r
+ if (child->type == XML_ELEMENT_NODE) {\r
+ if (IS_XSLT_ELEM_FAST(child)) {\r
+ xsltStyleType type;\r
+ \r
+ type = xsltGetXSLTElementTypeByNode(cctxt, child);\r
+ if (type == XSLT_FUNC_WHEN) {\r
+ nbWhen++;\r
+ if (nbOtherwise) {\r
+ xsltParseContentError(cctxt->style, child);\r
+ err = 1;\r
+ break;\r
+ }\r
+ cctxt->inode->curChildType = XSLT_FUNC_WHEN;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else if (type == XSLT_FUNC_OTHERWISE) {\r
+ if (! nbWhen) {\r
+ xsltParseContentError(cctxt->style, child);\r
+ err = 1;\r
+ break;\r
+ } \r
+ if (nbOtherwise) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "The XSLT 'choose' element must not contain "\r
+ "more than one XSLT 'otherwise' element.\n");\r
+ cctxt->style->errors++;\r
+ err = 1;\r
+ break;\r
+ }\r
+ nbOtherwise++;\r
+ cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else\r
+ xsltParseContentError(cctxt->style, child);\r
+ } else\r
+ xsltParseContentError(cctxt->style, child);\r
+ } \r
+ /*\r
+ else\r
+ xsltParseContentError(cctxt, child);\r
+ */\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ if ((! err) && (! nbWhen)) {\r
+ xsltTransformError(NULL, cctxt->style, elem,\r
+ "The XSLT element 'choose' must contain at least one "\r
+ "XSLT element 'when'.\n");\r
+ cctxt->style->errors++;\r
+ } \r
+ } \r
+ goto exit;\r
+\r
+for_each:\r
+ /* <!-- Content: (xsl:sort*, template) --> */\r
+ /*\r
+ * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.\r
+ * The old behaviour did not allow this, but it catched this\r
+ * only at transformation-time.\r
+ * In XSLT 2.0 they are stripped beforehand if whitespace-only\r
+ * (regardless of xml:space).\r
+ */\r
+ if (elem->children != NULL) {\r
+ xmlNodePtr child = elem->children;\r
+ /*\r
+ * Parse xsl:sort first.\r
+ */\r
+ do { \r
+ if ((child->type == XML_ELEMENT_NODE) &&\r
+ IS_XSLT_ELEM_FAST(child))\r
+ { \r
+ if (xsltGetXSLTElementTypeByNode(cctxt, child) ==\r
+ XSLT_FUNC_SORT)\r
+ { \r
+ cctxt->inode->curChildType = XSLT_FUNC_SORT;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ } else\r
+ break;\r
+ } else\r
+ break;\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ /*\r
+ * Parse the sequece constructor.\r
+ */\r
+ if (child != NULL)\r
+ xsltParseSequenceConstructor(cctxt, child);\r
+ } \r
+ goto exit;\r
+\r
+sequence_constructor:\r
+ /*\r
+ * Parse the sequence constructor.\r
+ */\r
+ if (elem->children != NULL)\r
+ xsltParseSequenceConstructor(cctxt, elem->children);\r
+\r
+ /*\r
+ * Register information for vars/params. Only needed if there\r
+ * are any following siblings.\r
+ */\r
+ if ((elem->next != NULL) &&\r
+ ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||\r
+ (cctxt->inode->type == XSLT_FUNC_PARAM)))\r
+ { \r
+ if ((elem->psvi != NULL) &&\r
+ (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))\r
+ { \r
+ xsltCompilerVarInfoPush(cctxt, elem,\r
+ ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,\r
+ ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);\r
+ }\r
+ }\r
+\r
+error:\r
+exit:\r
+ xsltCompilerNodePop(cctxt, elem);\r
+ return(0);\r
+\r
+internal_err:\r
+ xsltCompilerNodePop(cctxt, elem);\r
+ return(-1);\r
+}\r
+\r
+/**\r
+ * xsltForwardsCompatUnkownItemCreate:\r
+ *\r
+ * @cctxt: the compilation context \r
+ *\r
+ * Creates a compiled representation of the unknown\r
+ * XSLT instruction.\r
+ *\r
+ * Returns the compiled representation.\r
+ */ \r
+static xsltStyleItemUknownPtr\r
+xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)\r
+{\r
+ xsltStyleItemUknownPtr item;\r
+\r
+ item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));\r
+ if (item == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, NULL,\r
+ "Internal error in xsltForwardsCompatUnkownItemCreate(): "\r
+ "Failed to allocate memory.\n");\r
+ cctxt->style->errors++;\r
+ return(NULL);\r
+ }\r
+ memset(item, 0, sizeof(xsltStyleItemUknown));\r
+ item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;\r
+ /*\r
+ * Store it in the stylesheet.\r
+ */\r
+ item->next = cctxt->style->preComps;\r
+ cctxt->style->preComps = (xsltElemPreCompPtr) item;\r
+ return(item);\r
+}\r
+\r
+/**\r
+ * xsltParseUnknownXSLTElem:\r
+ *\r
+ * @cctxt: the compilation context\r
+ * @node: the element of the unknown XSLT instruction\r
+ *\r
+ * Parses an unknown XSLT element.\r
+ * If forwards compatible mode is enabled this will allow\r
+ * such an unknown XSLT and; otherwise it is rejected.\r
+ *\r
+ * Returns 1 in the unknown XSLT instruction is rejected,\r
+ * 0 if everything's fine and\r
+ * -1 on API or internal errors.\r
+ */ \r
+static int\r
+xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr node)\r
+{\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(-1);\r
+\r
+ /*\r
+ * Detection of handled content of extension instructions.\r
+ */\r
+ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {\r
+ cctxt->inode->extContentHandled = 1;\r
+ } \r
+ if (cctxt->inode->forwardsCompat == 0) { \r
+ /*\r
+ * We are not in forwards-compatible mode, so raise an error.\r
+ */\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Unknown XSLT element '%s'.\n", node->name);\r
+ cctxt->style->errors++;\r
+ return(1);\r
+ }\r
+ /*\r
+ * Forwards-compatible mode.\r
+ * ------------------------\r
+ * \r
+ * Parse/compile xsl:fallback elements.\r
+ *\r
+ * QUESTION: Do we have to raise an error if there's no xsl:fallback?\r
+ * ANSWER: No, since in the stylesheet the fallback behaviour might\r
+ * also be provided by using the XSLT function "element-available".\r
+ */\r
+ if (cctxt->unknownItem == NULL) {\r
+ /*\r
+ * Create a singleton for all unknown XSLT instructions.\r
+ */\r
+ cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);\r
+ if (cctxt->unknownItem == NULL) {\r
+ node->psvi = NULL;\r
+ return(-1);\r
+ }\r
+ }\r
+ node->psvi = cctxt->unknownItem;\r
+ if (node->children == NULL)\r
+ return(0);\r
+ else {\r
+ xmlNodePtr child = node->children;\r
+\r
+ xsltCompilerNodePush(cctxt, node);\r
+ /*\r
+ * Update the in-scope namespaces if needed.\r
+ */\r
+ if (node->nsDef != NULL)\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, node);\r
+ /*\r
+ * Parse all xsl:fallback children.\r
+ */\r
+ do {\r
+ if ((child->type == XML_ELEMENT_NODE) &&\r
+ IS_XSLT_ELEM_FAST(child) &&\r
+ IS_XSLT_NAME(child, "fallback"))\r
+ {\r
+ cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;\r
+ xsltParseAnyXSLTElem(cctxt, child);\r
+ }\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ \r
+ xsltCompilerNodePop(cctxt, node);\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltParseSequenceConstructor:\r
+ *\r
+ * @cctxt: the compilation context\r
+ * @cur: the start-node of the content to be parsed\r
+ *\r
+ * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).\r
+ * This will additionally remove xsl:text elements from the tree.\r
+ */ \r
+void\r
+xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)\r
+{\r
+ xsltStyleType type;\r
+ xmlNodePtr deleteNode = NULL;\r
+\r
+ if (cctxt == NULL) {\r
+ xmlGenericError(xmlGenericErrorContext,\r
+ "xsltParseSequenceConstructor: Bad arguments\n");\r
+ cctxt->style->errors++;\r
+ return;\r
+ }\r
+ /*\r
+ * Detection of handled content of extension instructions.\r
+ */\r
+ if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {\r
+ cctxt->inode->extContentHandled = 1;\r
+ }\r
+ if (cur == NULL)\r
+ return;\r
+ /*\r
+ * This is the content reffered to as a "template".\r
+ * E.g. an xsl:element has such content model:\r
+ * <xsl:element\r
+ * name = { qname }\r
+ * namespace = { uri-reference }\r
+ * use-attribute-sets = qnames>\r
+ * <!-- Content: template -->\r
+ *\r
+ * NOTE that in XSLT-2 the term "template" was abandoned due to\r
+ * confusion with xsl:template and the term "sequence constructor"\r
+ * was introduced instead.\r
+ *\r
+ * The following XSLT-instructions are allowed to appear:\r
+ * xsl:apply-templates, xsl:call-template, xsl:apply-imports,\r
+ * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,\r
+ * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,\r
+ * xsl:message, xsl:fallback,\r
+ * xsl:processing-instruction, xsl:comment, xsl:element\r
+ * xsl:attribute. \r
+ * Additional allowed content:\r
+ * 1) extension instructions\r
+ * 2) literal result elements\r
+ * 3) PCDATA\r
+ *\r
+ * NOTE that this content model does *not* allow xsl:param.\r
+ */ \r
+ while (cur != NULL) {\r
+ if (deleteNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_BLANKS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseSequenceConstructor: removing xsl:text element\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ deleteNode = NULL;\r
+ }\r
+ if (cur->type == XML_ELEMENT_NODE) { \r
+ \r
+ if (cur->psvi == xsltXSLTTextMarker) {\r
+ /*\r
+ * xsl:text elements\r
+ * --------------------------------------------------------\r
+ */\r
+ xmlNodePtr tmp;\r
+\r
+ cur->psvi = NULL;\r
+ /*\r
+ * Mark the xsl:text element for later deletion.\r
+ */\r
+ deleteNode = cur;\r
+ /*\r
+ * Validate content.\r
+ */\r
+ tmp = cur->children;\r
+ if (tmp) {\r
+ /*\r
+ * We don't expect more than one text-node in the\r
+ * content, since we already merged adjacent\r
+ * text/CDATA-nodes and eliminated PI/comment-nodes.\r
+ */\r
+ if ((tmp->type == XML_TEXT_NODE) ||\r
+ (tmp->next == NULL))\r
+ {\r
+ /*\r
+ * Leave the contained text-node in the tree.\r
+ */\r
+ xmlUnlinkNode(tmp);\r
+ xmlAddPrevSibling(cur, tmp);\r
+ } else {\r
+ tmp = NULL;\r
+ xsltTransformError(NULL, cctxt->style, cur,\r
+ "Element 'xsl:text': Invalid type "\r
+ "of node found in content.\n");\r
+ cctxt->style->errors++;\r
+ } \r
+ }\r
+ if (cur->properties) {\r
+ xmlAttrPtr attr;\r
+ /*\r
+ * TODO: We need to report errors for\r
+ * invalid attrs.\r
+ */\r
+ attr = cur->properties;\r
+ do {\r
+ if ((attr->ns == NULL) &&\r
+ (attr->name != NULL) &&\r
+ (attr->name[0] == 'd') &&\r
+ xmlStrEqual(attr->name,\r
+ BAD_CAST "disable-output-escaping"))\r
+ {\r
+ /*\r
+ * Attr "disable-output-escaping".\r
+ * XSLT-2: This attribute is deprecated.\r
+ */\r
+ if ((attr->children != NULL) &&\r
+ xmlStrEqual(attr->children->content,\r
+ BAD_CAST "yes"))\r
+ {\r
+ /*\r
+ * Disable output escaping for this\r
+ * text node.\r
+ */\r
+ if (tmp)\r
+ tmp->name = xmlStringTextNoenc;\r
+ } else if ((attr->children == NULL) ||\r
+ (attr->children->content == NULL) ||\r
+ (!xmlStrEqual(attr->children->content,\r
+ BAD_CAST "no")))\r
+ {\r
+ xsltTransformError(NULL, cctxt->style,\r
+ cur,\r
+ "Attribute 'disable-output-escaping': "\r
+ "Invalid value. Expected is "\r
+ "'yes' or 'no'.\n");\r
+ cctxt->style->errors++;\r
+ }\r
+ break;\r
+ }\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+ }\r
+ } else if (IS_XSLT_ELEM_FAST(cur)) {\r
+ /*\r
+ * TODO: Using the XSLT-marker is still not stable yet.\r
+ */\r
+ /* if (cur->psvi == xsltXSLTElemMarker) { */ \r
+ /*\r
+ * XSLT instructions\r
+ * --------------------------------------------------------\r
+ */\r
+ cur->psvi = NULL;\r
+ type = xsltGetXSLTElementTypeByNode(cctxt, cur);\r
+ switch (type) {\r
+ case XSLT_FUNC_APPLYIMPORTS:\r
+ case XSLT_FUNC_APPLYTEMPLATES:\r
+ case XSLT_FUNC_ATTRIBUTE:\r
+ case XSLT_FUNC_CALLTEMPLATE:\r
+ case XSLT_FUNC_CHOOSE:\r
+ case XSLT_FUNC_COMMENT:\r
+ case XSLT_FUNC_COPY:\r
+ case XSLT_FUNC_COPYOF:\r
+ case XSLT_FUNC_DOCUMENT: /* Extra one */\r
+ case XSLT_FUNC_ELEMENT:\r
+ case XSLT_FUNC_FALLBACK:\r
+ case XSLT_FUNC_FOREACH:\r
+ case XSLT_FUNC_IF:\r
+ case XSLT_FUNC_MESSAGE:\r
+ case XSLT_FUNC_NUMBER:\r
+ case XSLT_FUNC_PI:\r
+ case XSLT_FUNC_TEXT:\r
+ case XSLT_FUNC_VALUEOF:\r
+ case XSLT_FUNC_VARIABLE:\r
+ /*\r
+ * Parse the XSLT element.\r
+ */\r
+ cctxt->inode->curChildType = type;\r
+ xsltParseAnyXSLTElem(cctxt, cur);\r
+ break;\r
+ default:\r
+ xsltParseUnknownXSLTElem(cctxt, cur); \r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ } else {\r
+ /*\r
+ * Non-XSLT elements\r
+ * -----------------\r
+ */\r
+ xsltCompilerNodePush(cctxt, cur);\r
+ /*\r
+ * Update the in-scope namespaces if needed.\r
+ */\r
+ if (cur->nsDef != NULL)\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, cur);\r
+ /*\r
+ * The current element is either a literal result element\r
+ * or an extension instruction.\r
+ *\r
+ * Process attr "xsl:extension-element-prefixes".\r
+ * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be\r
+ * processed by the implementor of the extension function;\r
+ * i.e., it won't be handled by the XSLT processor.\r
+ */\r
+ /* SPEC 1.0:\r
+ * "exclude-result-prefixes" is only allowed on literal\r
+ * result elements and "xsl:exclude-result-prefixes"\r
+ * on xsl:stylesheet/xsl:transform.\r
+ * SPEC 2.0:\r
+ * "There are a number of standard attributes\r
+ * that may appear on any XSLT element: specifically\r
+ * version, exclude-result-prefixes,\r
+ * extension-element-prefixes, xpath-default-namespace,\r
+ * default-collation, and use-when."\r
+ *\r
+ * SPEC 2.0:\r
+ * For literal result elements:\r
+ * "xsl:version, xsl:exclude-result-prefixes,\r
+ * xsl:extension-element-prefixes,\r
+ * xsl:xpath-default-namespace,\r
+ * xsl:default-collation, or xsl:use-when."\r
+ */\r
+ if (cur->properties)\r
+ cctxt->inode->extElemNs =\r
+ xsltParseExtElemPrefixes(cctxt,\r
+ cur, cctxt->inode->extElemNs,\r
+ XSLT_ELEMENT_CATEGORY_LRE);\r
+ /*\r
+ * Eval if we have an extension instruction here.\r
+ */\r
+ if ((cur->ns != NULL) &&\r
+ (cctxt->inode->extElemNs != NULL) &&\r
+ (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))\r
+ {\r
+ /*\r
+ * Extension instructions\r
+ * ----------------------------------------------------\r
+ * Mark the node information.\r
+ */\r
+ cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;\r
+ cctxt->inode->extContentHandled = 0;\r
+ if (cur->psvi != NULL) {\r
+ cur->psvi = NULL;\r
+ /*\r
+ * TODO: Temporary sanity check.\r
+ */\r
+ xsltTransformError(NULL, cctxt->style, cur,\r
+ "Internal error in xsltParseSequenceConstructor(): "\r
+ "Occupied PSVI field.\n");\r
+ cctxt->style->errors++;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ cur->psvi = (void *)\r
+ xsltPreComputeExtModuleElement(cctxt->style, cur);\r
+ \r
+ if (cur->psvi == NULL) {\r
+ /*\r
+ * OLD COMMENT: "Unknown element, maybe registered\r
+ * at the context level. Mark it for later\r
+ * recognition."\r
+ * QUESTION: What does the xsltExtMarker mean?\r
+ * ANSWER: It is used in\r
+ * xsltApplySequenceConstructor() at\r
+ * transformation-time to look out for extension\r
+ * registered in the transformation context.\r
+ */\r
+ cur->psvi = (void *) xsltExtMarker;\r
+ }\r
+ /*\r
+ * BIG NOTE: Now the ugly part. In previous versions\r
+ * of Libxslt (until 1.1.16), all the content of an\r
+ * extension instruction was processed and compiled without\r
+ * the need of the extension-author to explicitely call\r
+ * such a processing;.We now need to mimic this old\r
+ * behaviour in order to avoid breaking old code\r
+ * on the extension-author's side.\r
+ * The mechanism:\r
+ * 1) If the author does *not* set the\r
+ * compile-time-flag @extContentHandled, then we'll\r
+ * parse the content assuming that it's a "template"\r
+ * (or "sequence constructor in XSLT 2.0 terms).\r
+ * NOTE: If the extension is registered at\r
+ * transformation-time only, then there's no way of\r
+ * knowing that content shall be valid, and we'll\r
+ * process the content the same way.\r
+ * 2) If the author *does* set the flag, then we'll assume\r
+ * that the author has handled the parsing him/herself\r
+ * (e.g. called xsltParseSequenceConstructor(), etc.\r
+ * explicitely in his/her code).\r
+ */\r
+ if ((cur->children != NULL) &&\r
+ (cctxt->inode->extContentHandled == 0))\r
+ {\r
+ /*\r
+ * Default parsing of the content using the\r
+ * sequence-constructor model.\r
+ */\r
+ xsltParseSequenceConstructor(cctxt, cur->children);\r
+ }\r
+ } else {\r
+ /*\r
+ * Literal result element\r
+ * ----------------------------------------------------\r
+ * Allowed XSLT attributes:\r
+ * xsl:extension-element-prefixes CDATA #IMPLIED\r
+ * xsl:exclude-result-prefixes CDATA #IMPLIED\r
+ * TODO: xsl:use-attribute-sets %qnames; #IMPLIED\r
+ * xsl:version NMTOKEN #IMPLIED\r
+ */\r
+ cur->psvi = NULL;\r
+ cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;\r
+ if (cur->properties != NULL) {\r
+ xmlAttrPtr attr = cur->properties;\r
+ /*\r
+ * Attribute "xsl:exclude-result-prefixes".\r
+ */\r
+ cctxt->inode->exclResultNs =\r
+ xsltParseExclResultPrefixes(cctxt, cur,\r
+ cctxt->inode->exclResultNs,\r
+ XSLT_ELEMENT_CATEGORY_LRE);\r
+ /*\r
+ * Attribute "xsl:version".\r
+ */\r
+ xsltParseAttrXSLTVersion(cctxt, cur,\r
+ XSLT_ELEMENT_CATEGORY_LRE);\r
+ /*\r
+ * Report invalid XSLT attributes. \r
+ * For XSLT 1.0 only xsl:use-attribute-sets is allowed\r
+ * next to xsl:version, xsl:exclude-result-prefixes and\r
+ * xsl:extension-element-prefixes.\r
+ *\r
+ * Mark all XSLT attributes, in order to skip such\r
+ * attributes when instantiating the LRE.\r
+ */\r
+ do {\r
+ if ((attr->psvi != xsltXSLTAttrMarker) &&\r
+ IS_XSLT_ATTR_FAST(attr))\r
+ { \r
+ if (! xmlStrEqual(attr->name,\r
+ BAD_CAST "use-attribute-sets"))\r
+ { \r
+ xsltTransformError(NULL, cctxt->style,\r
+ cur,\r
+ "Unknown XSLT attribute '%s'.\n",\r
+ attr->name);\r
+ cctxt->style->errors++;\r
+ } else {\r
+ /*\r
+ * XSLT attr marker.\r
+ */\r
+ attr->psvi = (void *) xsltXSLTAttrMarker;\r
+ }\r
+ }\r
+ attr = attr->next;\r
+ } while (attr != NULL);\r
+ }\r
+ /*\r
+ * Create/reuse info for the literal result element.\r
+ */\r
+ if (cctxt->inode->nsChanged)\r
+ xsltLREInfoCreate(cctxt, cur, 1);\r
+ cur->psvi = cctxt->inode->litResElemInfo;\r
+ /*\r
+ * Apply ns-aliasing on the element and on its attributes.\r
+ */\r
+ if (cctxt->hasNsAliases)\r
+ xsltLREBuildEffectiveNs(cctxt, cur);\r
+ /*\r
+ * Compile attribute value templates (AVT).\r
+ */\r
+ if (cur->properties) {\r
+ xmlAttrPtr attr = cur->properties;\r
+ \r
+ while (attr != NULL) {\r
+ xsltCompileAttr(cctxt->style, attr);\r
+ attr = attr->next;\r
+ }\r
+ }\r
+ /*\r
+ * Parse the content, which is defined to be a "template"\r
+ * (or "sequence constructor" in XSLT 2.0 terms).\r
+ */\r
+ if (cur->children != NULL) {\r
+ xsltParseSequenceConstructor(cctxt, cur->children);\r
+ }\r
+ }\r
+ /*\r
+ * Leave the non-XSLT element.\r
+ */\r
+ xsltCompilerNodePop(cctxt, cur);\r
+ }\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ if (deleteNode != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_BLANKS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseSequenceConstructor: removing xsl:text element\n");\r
+#endif\r
+ xmlUnlinkNode(deleteNode);\r
+ xmlFreeNode(deleteNode);\r
+ deleteNode = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltParseTemplateContent:\r
+ * @style: the XSLT stylesheet\r
+ * @templ: the node containing the content to be parsed\r
+ *\r
+ * Parses and compiles the content-model of an xsl:template element.\r
+ * Note that this is *not* the "template" content model (or "sequence\r
+ * constructor" in XSLT 2.0); it it allows addional xsl:param\r
+ * elements as immediate children of @templ.\r
+ *\r
+ * Called by: \r
+ * exsltFuncFunctionComp() (EXSLT, functions.c)\r
+ * So this is intended to be called from extension functions.\r
+ */\r
+void\r
+xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {\r
+ if ((style == NULL) || (templ == NULL))\r
+ return;\r
+\r
+ /*\r
+ * Detection of handled content of extension instructions.\r
+ */\r
+ if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {\r
+ XSLT_CCTXT(style)->inode->extContentHandled = 1;\r
+ }\r
+\r
+ if (templ->children != NULL) { \r
+ xmlNodePtr child = templ->children;\r
+ /*\r
+ * Process xsl:param elements, which can only occur as the\r
+ * immediate children of xsl:template (well, and of any\r
+ * user-defined extension instruction if needed).\r
+ */ \r
+ do {\r
+ if ((child->type == XML_ELEMENT_NODE) &&\r
+ IS_XSLT_ELEM_FAST(child) &&\r
+ IS_XSLT_NAME(child, "param"))\r
+ {\r
+ XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;\r
+ xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);\r
+ } else\r
+ break;\r
+ child = child->next;\r
+ } while (child != NULL);\r
+ /*\r
+ * Parse the content and register the pattern.\r
+ */\r
+ xsltParseSequenceConstructor(XSLT_CCTXT(style), child);\r
+ }\r
+}\r
+\r
+#else /* XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseTemplateContent:\r
+ * @style: the XSLT stylesheet\r
+ * @templ: the container node (can be a document for literal results)\r
+ *\r
+ * parse a template content-model\r
+ * Clean-up the template content from unwanted ignorable blank nodes\r
+ * and process xslt:text\r
+ */\r
+void\r
+xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {\r
+ xmlNodePtr cur, delete;\r
+ /*\r
+ * This content comes from the stylesheet\r
+ * For stylesheets, the set of whitespace-preserving\r
+ * element names consists of just xsl:text.\r
+ */\r
+ cur = templ->children;\r
+ delete = NULL;\r
+ while (cur != NULL) {\r
+ if (delete != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_BLANKS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseTemplateContent: removing text\n");\r
+#endif\r
+ xmlUnlinkNode(delete);\r
+ xmlFreeNode(delete);\r
+ delete = NULL;\r
+ }\r
+ if (IS_XSLT_ELEM(cur)) {\r
+ if (IS_XSLT_NAME(cur, "text")) {\r
+ /*\r
+ * TODO: Processing of xsl:text should be moved to\r
+ * xsltPrecomputeStylesheet(), since otherwise this\r
+ * will be performed for every multiply included\r
+ * stylesheet; i.e. this here is not skipped with\r
+ * the use of the style->nopreproc flag.\r
+ */\r
+ if (cur->children != NULL) {\r
+ xmlChar *prop;\r
+ xmlNodePtr text = cur->children, next;\r
+ int noesc = 0;\r
+ \r
+ prop = xmlGetNsProp(cur,\r
+ (const xmlChar *)"disable-output-escaping",\r
+ NULL);\r
+ if (prop != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "Disable escaping: %s\n", text->content);\r
+#endif\r
+ if (xmlStrEqual(prop, (const xmlChar *)"yes")) {\r
+ noesc = 1;\r
+ } else if (!xmlStrEqual(prop,\r
+ (const xmlChar *)"no")){\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsl:text: disable-output-escaping allows only yes or no\n");\r
+ style->warnings++;\r
+\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ while (text != NULL) {\r
+ if (text->type == XML_COMMENT_NODE) {\r
+ text = text->next;\r
+ continue;\r
+ }\r
+ if ((text->type != XML_TEXT_NODE) &&\r
+ (text->type != XML_CDATA_SECTION_NODE)) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseTemplateContent: xslt:text content problem\n");\r
+ style->errors++;\r
+ break;\r
+ }\r
+ if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))\r
+ text->name = xmlStringTextNoenc;\r
+ text = text->next;\r
+ }\r
+\r
+ /*\r
+ * replace xsl:text by the list of childs\r
+ */\r
+ if (text == NULL) {\r
+ text = cur->children;\r
+ while (text != NULL) {\r
+ if ((style->internalized) &&\r
+ (text->content != NULL) &&\r
+ (!xmlDictOwns(style->dict, text->content))) {\r
+\r
+ /*\r
+ * internalize the text string\r
+ */\r
+ if (text->doc->dict != NULL) {\r
+ const xmlChar *tmp;\r
+ \r
+ tmp = xmlDictLookup(text->doc->dict,\r
+ text->content, -1);\r
+ if (tmp != text->content) {\r
+ xmlNodeSetContent(text, NULL);\r
+ text->content = (xmlChar *) tmp;\r
+ }\r
+ }\r
+ }\r
+\r
+ next = text->next;\r
+ xmlUnlinkNode(text);\r
+ xmlAddPrevSibling(cur, text);\r
+ text = next;\r
+ }\r
+ }\r
+ }\r
+ delete = cur;\r
+ goto skip_children;\r
+ }\r
+ }\r
+ else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&\r
+ (xsltCheckExtPrefix(style, cur->ns->prefix)))\r
+ {\r
+ /*\r
+ * okay this is an extension element compile it too\r
+ */\r
+ xsltStylePreCompute(style, cur);\r
+ } else {\r
+ /*\r
+ * This is an element which will be output as part of the\r
+ * template exectution, precompile AVT if found.\r
+ */\r
+ if ((cur->ns == NULL) && (style->defaultAlias != NULL) &&\r
+ (cur->type == XML_ELEMENT_NODE)) {\r
+ cur->ns = xmlSearchNsByHref(cur->doc, cur,\r
+ style->defaultAlias);\r
+ }\r
+ if (cur->properties != NULL) {\r
+ xmlAttrPtr attr = cur->properties;\r
+\r
+ while (attr != NULL) {\r
+ xsltCompileAttr(style, attr);\r
+ attr = attr->next;\r
+ }\r
+ }\r
+ }\r
+ /*\r
+ * Skip to next node\r
+ */\r
+ if (cur->children != NULL) {\r
+ if (cur->children->type != XML_ENTITY_DECL) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ }\r
+skip_children:\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ \r
+ do {\r
+ cur = cur->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ if (cur == templ) {\r
+ cur = NULL;\r
+ break;\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ break;\r
+ }\r
+ } while (cur != NULL);\r
+ }\r
+ if (delete != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseTemplateContent: removing text\n");\r
+#endif\r
+ xmlUnlinkNode(delete);\r
+ xmlFreeNode(delete);\r
+ delete = NULL;\r
+ }\r
+\r
+ /*\r
+ * Skip the first params\r
+ */\r
+ cur = templ->children;\r
+ while (cur != NULL) {\r
+ if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))\r
+ break;\r
+ cur = cur->next;\r
+ }\r
+\r
+ /*\r
+ * Browse the remainder of the template\r
+ */\r
+ while (cur != NULL) {\r
+ if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {\r
+ xmlNodePtr param = cur;\r
+\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseTemplateContent: ignoring misplaced param element\n");\r
+ if (style != NULL) style->warnings++;\r
+ cur = cur->next;\r
+ xmlUnlinkNode(param);\r
+ xmlFreeNode(param);\r
+ } else\r
+ break;\r
+ }\r
+}\r
+\r
+#endif /* else XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetKey:\r
+ * @style: the XSLT stylesheet\r
+ * @key: the "key" element\r
+ *\r
+ * <!-- Category: top-level-element -->\r
+ * <xsl:key name = qname, match = pattern, use = expression />\r
+ *\r
+ * parse an XSLT stylesheet key definition and register it\r
+ */\r
+\r
+static void\r
+xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {\r
+ xmlChar *prop = NULL;\r
+ xmlChar *use = NULL;\r
+ xmlChar *match = NULL;\r
+ xmlChar *name = NULL;\r
+ xmlChar *nameURI = NULL;\r
+\r
+ if ((style == NULL) || (key == NULL))\r
+ return;\r
+\r
+ /*\r
+ * Get arguments\r
+ */\r
+ prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(key, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ } else {\r
+ name = prop;\r
+ if (URI != NULL)\r
+ nameURI = xmlStrdup(URI);\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetKey: name %s\n", name);\r
+#endif\r
+ } else {\r
+ xsltTransformError(NULL, style, key,\r
+ "xsl:key : error missing name\n");\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);\r
+ if (match == NULL) {\r
+ xsltTransformError(NULL, style, key,\r
+ "xsl:key : error missing match\n");\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);\r
+ if (use == NULL) {\r
+ xsltTransformError(NULL, style, key,\r
+ "xsl:key : error missing use\n");\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+\r
+ /*\r
+ * register the keys\r
+ */\r
+ xsltAddKey(style, name, nameURI, match, use, key);\r
+\r
+\r
+error:\r
+ if (use != NULL)\r
+ xmlFree(use);\r
+ if (match != NULL)\r
+ xmlFree(match);\r
+ if (name != NULL)\r
+ xmlFree(name);\r
+ if (nameURI != NULL)\r
+ xmlFree(nameURI);\r
+\r
+ if (key->children != NULL) {\r
+ xsltParseContentError(style, key->children);\r
+ }\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+/**\r
+ * xsltParseXSLTTemplate:\r
+ * @style: the XSLT stylesheet\r
+ * @template: the "template" element\r
+ *\r
+ * parse an XSLT stylesheet template building the associated structures\r
+ * TODO: Is @style ever expected to be NULL?\r
+ *\r
+ * Called from:\r
+ * xsltParseXSLTStylesheet()\r
+ * xsltParseStylesheetTop()\r
+ */\r
+\r
+static void\r
+xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {\r
+ xsltTemplatePtr templ;\r
+ xmlChar *prop; \r
+ double priority; \r
+\r
+ if ((cctxt == NULL) || (templNode == NULL))\r
+ return;\r
+\r
+ /*\r
+ * Create and link the structure\r
+ */\r
+ templ = xsltNewTemplate();\r
+ if (templ == NULL)\r
+ return;\r
+\r
+ xsltCompilerNodePush(cctxt, templNode);\r
+ if (templNode->nsDef != NULL)\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, templNode);\r
+\r
+ templ->next = cctxt->style->templates;\r
+ cctxt->style->templates = templ;\r
+ templ->style = cctxt->style; \r
+\r
+ /*\r
+ * Attribute "mode".\r
+ */\r
+ prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);\r
+ if (prop != NULL) { \r
+ const xmlChar *modeURI;\r
+\r
+ /*\r
+ * TODO: We need a standardized function for extraction\r
+ * of namespace names and local names from QNames.\r
+ * Don't use xsltGetQNameURI() as it cannot channeö\r
+ * reports through the context.\r
+ */\r
+ modeURI = xsltGetQNameURI(templNode, &prop);\r
+ if (prop == NULL) {\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);\r
+ xmlFree(prop);\r
+ prop = NULL;\r
+ if (xmlValidateNCName(templ->mode, 0)) {\r
+ xsltTransformError(NULL, cctxt->style, templNode,\r
+ "xsl:template: Attribute 'mode': The local part '%s' "\r
+ "of the value is not a valid NCName.\n", templ->name);\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ if (modeURI != NULL)\r
+ templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseXSLTTemplate: mode %s\n", templ->mode);\r
+#endif\r
+ }\r
+ /*\r
+ * Attribute "match".\r
+ */\r
+ prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);\r
+ if (prop != NULL) {\r
+ templ->match = prop;\r
+ prop = NULL;\r
+ }\r
+ /*\r
+ * Attribute "priority".\r
+ */\r
+ prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);\r
+ if (prop != NULL) {\r
+ priority = xmlXPathStringEvalNumber(prop);\r
+ templ->priority = (float) priority;\r
+ xmlFree(prop);\r
+ prop = NULL;\r
+ }\r
+ /*\r
+ * Attribute "name".\r
+ */\r
+ prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *nameURI;\r
+ xsltTemplatePtr curTempl;\r
+ \r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ nameURI = xsltGetQNameURI(templNode, &prop);\r
+ if (prop == NULL) {\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);\r
+ xmlFree(prop);\r
+ prop = NULL;\r
+ if (xmlValidateNCName(templ->name, 0)) {\r
+ xsltTransformError(NULL, cctxt->style, templNode,\r
+ "xsl:template: Attribute 'name': The local part '%s' of "\r
+ "the value is not a valid NCName.\n", templ->name);\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ } \r
+ if (nameURI != NULL)\r
+ templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);\r
+ curTempl = templ->next;\r
+ while (curTempl != NULL) {\r
+ if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&\r
+ xmlStrEqual(curTempl->nameURI, nameURI) ) ||\r
+ (nameURI == NULL && curTempl->nameURI == NULL &&\r
+ xmlStrEqual(curTempl->name, templ->name)))\r
+ {\r
+ xsltTransformError(NULL, cctxt->style, templNode,\r
+ "xsl:template: error duplicate name '%s'\n", templ->name);\r
+ cctxt->style->errors++;\r
+ goto error;\r
+ }\r
+ curTempl = curTempl->next;\r
+ }\r
+ }\r
+ if (templNode->children != NULL) {\r
+ xsltParseTemplateContent(cctxt->style, templNode); \r
+ /*\r
+ * MAYBE TODO: Custom behaviour: In order to stay compatible with\r
+ * Xalan and MSXML(.NET), we could allow whitespace\r
+ * to appear before an xml:param element; this whitespace\r
+ * will additionally become part of the "template".\r
+ * NOTE that this is totally deviates from the spec, but\r
+ * is the de facto behaviour of Xalan and MSXML(.NET).\r
+ * Personally I wouldn't allow this, since if we have:\r
+ * <xsl:template ...xml:space="preserve">\r
+ * <xsl:param name="foo"/>\r
+ * <xsl:param name="bar"/>\r
+ * <xsl:param name="zoo"/>\r
+ * ... the whitespace between every xsl:param would be\r
+ * added to the result tree.\r
+ */ \r
+ } \r
+ \r
+ templ->elem = templNode;\r
+ templ->content = templNode->children;\r
+ xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);\r
+\r
+error:\r
+ xsltCompilerNodePop(cctxt, templNode);\r
+ return;\r
+}\r
+\r
+#else /* XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetTemplate:\r
+ * @style: the XSLT stylesheet\r
+ * @template: the "template" element\r
+ *\r
+ * parse an XSLT stylesheet template building the associated structures\r
+ */\r
+\r
+static void\r
+xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {\r
+ xsltTemplatePtr ret;\r
+ xmlChar *prop;\r
+ xmlChar *mode = NULL;\r
+ xmlChar *modeURI = NULL;\r
+ double priority;\r
+\r
+ if (template == NULL)\r
+ return;\r
+\r
+ /*\r
+ * Create and link the structure\r
+ */\r
+ ret = xsltNewTemplate();\r
+ if (ret == NULL)\r
+ return;\r
+ ret->next = style->templates;\r
+ style->templates = ret;\r
+ ret->style = style;\r
+ \r
+ /*\r
+ * Get inherited namespaces\r
+ */\r
+ /*\r
+ * TODO: Apply the optimized in-scope-namespace mechanism\r
+ * as for the other XSLT instructions.\r
+ */\r
+ xsltGetInheritedNsList(style, ret, template);\r
+\r
+ /*\r
+ * Get arguments\r
+ */\r
+ prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+\r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(template, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ } else {\r
+ mode = prop;\r
+ if (URI != NULL)\r
+ modeURI = xmlStrdup(URI);\r
+ }\r
+ ret->mode = xmlDictLookup(style->dict, mode, -1);\r
+ ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetTemplate: mode %s\n", mode);\r
+#endif\r
+ if (mode != NULL) xmlFree(mode);\r
+ if (modeURI != NULL) xmlFree(modeURI);\r
+ }\r
+ prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);\r
+ if (prop != NULL) {\r
+ if (ret->match != NULL) xmlFree(ret->match);\r
+ ret->match = prop;\r
+ }\r
+\r
+ prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);\r
+ if (prop != NULL) {\r
+ priority = xmlXPathStringEvalNumber(prop);\r
+ ret->priority = (float) priority;\r
+ xmlFree(prop);\r
+ }\r
+\r
+ prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);\r
+ if (prop != NULL) {\r
+ const xmlChar *URI;\r
+ xsltTemplatePtr cur;\r
+ \r
+ /*\r
+ * TODO: Don't use xsltGetQNameURI().\r
+ */\r
+ URI = xsltGetQNameURI(template, &prop);\r
+ if (prop == NULL) {\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ } else {\r
+ if (xmlValidateNCName(prop,0)) {\r
+ xsltTransformError(NULL, style, template,\r
+ "xsl:template : error invalid name '%s'\n", prop);\r
+ if (style != NULL) style->errors++;\r
+ goto error;\r
+ }\r
+ ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);\r
+ xmlFree(prop);\r
+ prop = NULL;\r
+ if (URI != NULL)\r
+ ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);\r
+ else\r
+ ret->nameURI = NULL;\r
+ cur = ret->next;\r
+ while (cur != NULL) {\r
+ if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&\r
+ xmlStrEqual(cur->nameURI, URI) ) ||\r
+ (URI == NULL && cur->nameURI == NULL &&\r
+ xmlStrEqual(cur->name, ret->name))) {\r
+ xsltTransformError(NULL, style, template,\r
+ "xsl:template: error duplicate name '%s'\n", ret->name);\r
+ style->errors++;\r
+ goto error;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * parse the content and register the pattern\r
+ */\r
+ xsltParseTemplateContent(style, template);\r
+ ret->elem = template;\r
+ ret->content = template->children;\r
+ xsltAddTemplate(style, ret, ret->mode, ret->modeURI);\r
+\r
+error:\r
+ return;\r
+}\r
+\r
+#endif /* else XSLT_REFACTORED */\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+/**\r
+ * xsltIncludeComp:\r
+ * @cctxt: the compilation contenxt\r
+ * @node: the xsl:include node\r
+ *\r
+ * Process the xslt include node on the source node\r
+ */\r
+static xsltStyleItemIncludePtr\r
+xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {\r
+ xsltStyleItemIncludePtr item;\r
+\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(NULL);\r
+\r
+ node->psvi = NULL;\r
+ item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));\r
+ if (item == NULL) {\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "xsltIncludeComp : malloc failed\n");\r
+ cctxt->style->errors++;\r
+ return(NULL);\r
+ }\r
+ memset(item, 0, sizeof(xsltStyleItemInclude));\r
+\r
+ node->psvi = item;\r
+ item->inst = node;\r
+ item->type = XSLT_FUNC_INCLUDE;\r
+\r
+ item->next = cctxt->style->preComps;\r
+ cctxt->style->preComps = (xsltElemPreCompPtr) item;\r
+\r
+ return(item);\r
+}\r
+\r
+/**\r
+ * xsltParseFindTopLevelElem:\r
+ */\r
+static int\r
+xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr cur,\r
+ const xmlChar *name,\r
+ const xmlChar *namespaceURI,\r
+ int breakOnOtherElem, \r
+ xmlNodePtr *resultNode)\r
+{\r
+ if (name == NULL)\r
+ return(-1);\r
+\r
+ *resultNode = NULL;\r
+ while (cur != NULL) {\r
+ if (cur->type == XML_ELEMENT_NODE) {\r
+ if ((cur->ns != NULL) && (cur->name != NULL)) {\r
+ if ((*(cur->name) == *name) &&\r
+ xmlStrEqual(cur->name, name) &&\r
+ xmlStrEqual(cur->ns->href, namespaceURI)) \r
+ {\r
+ *resultNode = cur;\r
+ return(1);\r
+ }\r
+ }\r
+ if (breakOnOtherElem)\r
+ break;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ *resultNode = cur;\r
+ return(0);\r
+}\r
+\r
+static int\r
+xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr node,\r
+ xsltStyleType type)\r
+{\r
+ int ret = 0;\r
+\r
+ /*\r
+ * TODO: The reason why this function exists:\r
+ * due to historical reasons some of the\r
+ * top-level declarations are processed by functions\r
+ * in other files. Since we need still to set\r
+ * up the node-info and generate information like\r
+ * in-scope namespaces, this is a wrapper around\r
+ * those old parsing functions.\r
+ */\r
+ xsltCompilerNodePush(cctxt, node);\r
+ if (node->nsDef != NULL)\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, node);\r
+ cctxt->inode->type = type;\r
+\r
+ switch (type) {\r
+ case XSLT_FUNC_INCLUDE:\r
+ {\r
+ int oldIsInclude;\r
+\r
+ if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)\r
+ goto exit; \r
+ /*\r
+ * Mark this stylesheet tree as being currently included.\r
+ */\r
+ oldIsInclude = cctxt->isInclude;\r
+ cctxt->isInclude = 1;\r
+ \r
+ if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {\r
+ cctxt->style->errors++;\r
+ }\r
+ cctxt->isInclude = oldIsInclude;\r
+ }\r
+ break;\r
+ case XSLT_FUNC_PARAM:\r
+ xsltStylePreCompute(cctxt->style, node);\r
+ xsltParseGlobalParam(cctxt->style, node);\r
+ break;\r
+ case XSLT_FUNC_VARIABLE:\r
+ xsltStylePreCompute(cctxt->style, node);\r
+ xsltParseGlobalVariable(cctxt->style, node);\r
+ break;\r
+ case XSLT_FUNC_ATTRSET:\r
+ xsltParseStylesheetAttributeSet(cctxt->style, node);\r
+ break;\r
+ default:\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "Internal error: (xsltParseTopLevelXSLTElem) "\r
+ "Cannot handle this top-level declaration.\n");\r
+ cctxt->style->errors++;\r
+ ret = -1;\r
+ }\r
+\r
+exit:\r
+ xsltCompilerNodePop(cctxt, node);\r
+\r
+ return(ret);\r
+}\r
+\r
+#if 0\r
+static int\r
+xsltParseRemoveWhitespace(xmlNodePtr node)\r
+{\r
+ if ((node == NULL) || (node->children == NULL))\r
+ return(0);\r
+ else {\r
+ xmlNodePtr delNode = NULL, child = node->children;\r
+\r
+ do {\r
+ if (delNode) {\r
+ xmlUnlinkNode(delNode);\r
+ xmlFreeNode(delNode);\r
+ delNode = NULL;\r
+ }\r
+ if (((child->type == XML_TEXT_NODE) ||\r
+ (child->type == XML_CDATA_SECTION_NODE)) &&\r
+ (IS_BLANK_NODE(child)))\r
+ delNode = child; \r
+ child = child->next;\r
+ } while (child != NULL);\r
+ if (delNode) {\r
+ xmlUnlinkNode(delNode);\r
+ xmlFreeNode(delNode);\r
+ delNode = NULL;\r
+ }\r
+ }\r
+ return(0);\r
+}\r
+#endif\r
+\r
+static int\r
+xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ int templates = 0;\r
+#endif\r
+ xmlNodePtr cur, start = NULL;\r
+ xsltStylesheetPtr style;\r
+\r
+ if ((cctxt == NULL) || (node == NULL) ||\r
+ (node->type != XML_ELEMENT_NODE))\r
+ return(-1); \r
+\r
+ style = cctxt->style; \r
+ /*\r
+ * At this stage all import declarations of all stylesheet modules\r
+ * with the same stylesheet level have been processed.\r
+ * Now we can safely parse the rest of the declarations.\r
+ */\r
+ if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))\r
+ {\r
+ xsltDocumentPtr include;\r
+ /*\r
+ * URGENT TODO: Make this work with simplified stylesheets!\r
+ * I.e., when we won't find an xsl:stylesheet element.\r
+ */\r
+ /*\r
+ * This is as include declaration.\r
+ */\r
+ include = ((xsltStyleItemIncludePtr) node->psvi)->include;\r
+ if (include == NULL) {\r
+ /* TODO: raise error? */\r
+ return(-1);\r
+ }\r
+ /*\r
+ * TODO: Actually an xsl:include should locate an embedded\r
+ * stylesheet as well; so the document-element won't always\r
+ * be the element where the actual stylesheet is rooted at.\r
+ * But such embedded stylesheets are not supported by Libxslt yet.\r
+ */\r
+ node = xmlDocGetRootElement(include->doc);\r
+ if (node == NULL) {\r
+ return(-1);\r
+ }\r
+ } \r
+ \r
+ if (node->children == NULL)\r
+ return(0);\r
+ /*\r
+ * Push the xsl:stylesheet/xsl:transform element.\r
+ */ \r
+ xsltCompilerNodePush(cctxt, node);\r
+ cctxt->inode->isRoot = 1;\r
+ cctxt->inode->nsChanged = 0;\r
+ /*\r
+ * Start with the naked dummy info for literal result elements.\r
+ */\r
+ cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;\r
+\r
+ /*\r
+ * In every case, we need to have\r
+ * the in-scope namespaces of the element, where the\r
+ * stylesheet is rooted at, regardless if it's an XSLT\r
+ * instruction or a literal result instruction (or if\r
+ * this is an embedded stylesheet).\r
+ */ \r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, node);\r
+\r
+ /*\r
+ * Process attributes of xsl:stylesheet/xsl:transform.\r
+ * --------------------------------------------------\r
+ * Allowed are:\r
+ * id = id\r
+ * extension-element-prefixes = tokens\r
+ * exclude-result-prefixes = tokens\r
+ * version = number (mandatory) \r
+ */\r
+ if (xsltParseAttrXSLTVersion(cctxt, node,\r
+ XSLT_ELEMENT_CATEGORY_XSLT) == 0)\r
+ { \r
+ /*\r
+ * Attribute "version".\r
+ * XSLT 1.0: "An xsl:stylesheet element *must* have a version\r
+ * attribute, indicating the version of XSLT that the\r
+ * stylesheet requires".\r
+ * The root element of a simplified stylesheet must also have\r
+ * this attribute.\r
+ */\r
+#ifdef XSLT_REFACTORED_MANDATORY_VERSION\r
+ if (isXsltElem)\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "The attribute 'version' is missing.\n");\r
+ cctxt->style->errors++; \r
+#else\r
+ /* OLD behaviour. */\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "xsl:version is missing: document may not be a stylesheet\n");\r
+ cctxt->style->warnings++;\r
+#endif\r
+ } \r
+ /*\r
+ * The namespaces declared by the attributes\r
+ * "extension-element-prefixes" and\r
+ * "exclude-result-prefixes" are local to *this*\r
+ * stylesheet tree; i.e., they are *not* visible to\r
+ * other stylesheet-modules, whether imported or included.\r
+ * \r
+ * Attribute "extension-element-prefixes".\r
+ */\r
+ cctxt->inode->extElemNs =\r
+ xsltParseExtElemPrefixes(cctxt, node, NULL,\r
+ XSLT_ELEMENT_CATEGORY_XSLT);\r
+ /*\r
+ * Attribute "exclude-result-prefixes".\r
+ */\r
+ cctxt->inode->exclResultNs =\r
+ xsltParseExclResultPrefixes(cctxt, node, NULL,\r
+ XSLT_ELEMENT_CATEGORY_XSLT);\r
+ /*\r
+ * Create/reuse info for the literal result element.\r
+ */\r
+ if (cctxt->inode->nsChanged)\r
+ xsltLREInfoCreate(cctxt, node, 0);\r
+ /*\r
+ * Processed top-level elements:\r
+ * ----------------------------\r
+ * xsl:variable, xsl:param (QName, in-scope ns,\r
+ * expression (vars allowed))\r
+ * xsl:attribute-set (QName, in-scope ns)\r
+ * xsl:strip-space, xsl:preserve-space (XPath NameTests,\r
+ * in-scope ns)\r
+ * I *think* global scope, merge with includes\r
+ * xsl:output (QName, in-scope ns)\r
+ * xsl:key (QName, in-scope ns, pattern,\r
+ * expression (vars *not* allowed))\r
+ * xsl:decimal-format (QName, needs in-scope ns)\r
+ * xsl:namespace-alias (in-scope ns)\r
+ * global scope, merge with includes\r
+ * xsl:template (last, QName, pattern)\r
+ *\r
+ * (whitespace-only text-nodes have *not* been removed\r
+ * yet; this will be done in xsltParseSequenceConstructor)\r
+ *\r
+ * Report misplaced child-nodes first.\r
+ */\r
+ cur = node->children;\r
+ while (cur != NULL) {\r
+ if (cur->type == XML_TEXT_NODE) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Misplaced text node (content: '%s').\n",\r
+ (cur->content != NULL) ? cur->content : BAD_CAST "");\r
+ style->errors++;\r
+ } else if (cur->type != XML_ELEMENT_NODE) {\r
+ xsltTransformError(NULL, style, cur, "Misplaced node.\n");\r
+ style->errors++;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ /*\r
+ * Skip xsl:import elements; they have been processed\r
+ * already.\r
+ */\r
+ cur = node->children;\r
+ while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)\r
+ cur = cur->next;\r
+ if (cur == NULL)\r
+ goto exit;\r
+\r
+ start = cur;\r
+ /*\r
+ * Process all top-level xsl:param elements.\r
+ */\r
+ while ((cur != NULL) &&\r
+ xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)\r
+ {\r
+ xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); \r
+ cur = cur->next;\r
+ } \r
+ /*\r
+ * Process all top-level xsl:variable elements.\r
+ */\r
+ cur = start;\r
+ while ((cur != NULL) &&\r
+ xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)\r
+ {\r
+ xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);\r
+ cur = cur->next;\r
+ } \r
+ /*\r
+ * Process all the rest of top-level elements.\r
+ */\r
+ cur = start;\r
+ while (cur != NULL) { \r
+ /*\r
+ * Process element nodes.\r
+ */\r
+ if (cur->type == XML_ELEMENT_NODE) { \r
+ if (cur->ns == NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Unexpected top-level element in no namespace.\n");\r
+ style->errors++;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ /*\r
+ * Process all XSLT elements.\r
+ */\r
+ if (IS_XSLT_ELEM_FAST(cur)) {\r
+ /*\r
+ * xsl:import is only allowed at the beginning.\r
+ */\r
+ if (IS_XSLT_NAME(cur, "import")) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Misplaced xsl:import element.\n");\r
+ style->errors++;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ /* \r
+ * TODO: Change the return type of the parsing functions\r
+ * to int.\r
+ */\r
+ if (IS_XSLT_NAME(cur, "template")) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ templates++;\r
+#endif\r
+ /*\r
+ * TODO: Is the position of xsl:template in the\r
+ * tree significant? If not it would be easier to\r
+ * parse them at a later stage.\r
+ */\r
+ xsltParseXSLTTemplate(cctxt, cur);\r
+ } else if (IS_XSLT_NAME(cur, "variable")) {\r
+ /* NOP; done already */\r
+ } else if (IS_XSLT_NAME(cur, "param")) {\r
+ /* NOP; done already */\r
+ } else if (IS_XSLT_NAME(cur, "include")) { \r
+ if (cur->psvi != NULL) \r
+ xsltParseXSLTStylesheetElemCore(cctxt, cur);\r
+ else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Internal error: "\r
+ "(xsltParseXSLTStylesheetElemCore) "\r
+ "The xsl:include element was not compiled.\n");\r
+ style->errors++;\r
+ }\r
+ } else if (IS_XSLT_NAME(cur, "strip-space")) {\r
+ /* No node info needed. */\r
+ xsltParseStylesheetStripSpace(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "preserve-space")) {\r
+ /* No node info needed. */\r
+ xsltParseStylesheetPreserveSpace(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "output")) {\r
+ /* No node-info needed. */\r
+ xsltParseStylesheetOutput(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "key")) {\r
+ /* TODO: node-info needed for expressions ? */\r
+ xsltParseStylesheetKey(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "decimal-format")) {\r
+ /* No node-info needed. */ \r
+ xsltParseStylesheetDecimalFormat(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "attribute-set")) { \r
+ xsltParseTopLevelXSLTElem(cctxt, cur,\r
+ XSLT_FUNC_ATTRSET); \r
+ } else if (IS_XSLT_NAME(cur, "namespace-alias")) {\r
+ /* NOP; done already */ \r
+ } else {\r
+ if (cctxt->inode->forwardsCompat) {\r
+ /*\r
+ * Forwards-compatible mode:\r
+ *\r
+ * XSLT-1: "if it is a top-level element and\r
+ * XSLT 1.0 does not allow such elements as top-level\r
+ * elements, then the element must be ignored along\r
+ * with its content;"\r
+ */\r
+ /*\r
+ * TODO: I don't think we should generate a warning.\r
+ */\r
+ xsltTransformError(NULL, style, cur,\r
+ "Forwards-compatible mode: Ignoring unknown XSLT "\r
+ "element '%s'.\n", cur->name);\r
+ style->warnings++;\r
+ } else {\r
+ xsltTransformError(NULL, style, cur,\r
+ "Unknown XSLT element '%s'.\n", cur->name);\r
+ style->errors++;\r
+ }\r
+ }\r
+ } else {\r
+ xsltTopLevelFunction function;\r
+\r
+ /*\r
+ * Process non-XSLT elements, which are in a\r
+ * non-NULL namespace.\r
+ */\r
+ /*\r
+ * QUESTION: What does xsltExtModuleTopLevelLookup()\r
+ * do exactly?\r
+ */\r
+ function = xsltExtModuleTopLevelLookup(cur->name,\r
+ cur->ns->href);\r
+ if (function != NULL)\r
+ function(style, cur);\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseXSLTStylesheetElemCore : User-defined "\r
+ "data element '%s'.\n", cur->name);\r
+#endif\r
+ }\r
+ }\r
+ cur = cur->next;\r
+ }\r
+\r
+exit:\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### END of parsing top-level elements of doc '%s'.\n",\r
+ node->doc->URL);\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### Templates: %d\n", templates);\r
+#ifdef XSLT_REFACTORED\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### Max inodes: %d\n", cctxt->maxNodeInfos);\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "### Max LREs : %d\n", cctxt->maxLREs);\r
+#endif /* XSLT_REFACTORED */\r
+#endif /* WITH_XSLT_DEBUG_PARSING */\r
+\r
+ xsltCompilerNodePop(cctxt, node);\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltParseXSLTStylesheet:\r
+ * @cctxt: the compiler context\r
+ * @node: the xsl:stylesheet/xsl:transform element-node\r
+ *\r
+ * Parses the xsl:stylesheet and xsl:transform element. \r
+ *\r
+ * <xsl:stylesheet\r
+ * id = id\r
+ * extension-element-prefixes = tokens\r
+ * exclude-result-prefixes = tokens\r
+ * version = number>\r
+ * <!-- Content: (xsl:import*, top-level-elements) -->\r
+ * </xsl:stylesheet>\r
+ *\r
+ * BIG TODO: The xsl:include stuff.\r
+ * \r
+ * Called by xsltParseStylesheetTree()\r
+ *\r
+ * Returns 0 on success, a positive result on errors and\r
+ * -1 on API or internal errors.\r
+ */\r
+static int\r
+xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)\r
+{\r
+ xmlNodePtr cur, start;\r
+\r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(-1);\r
+ \r
+ if (node->children == NULL)\r
+ goto exit;\r
+\r
+ /*\r
+ * Process top-level elements:\r
+ * xsl:import (must be first)\r
+ * xsl:include (this is just a pre-processing)\r
+ */\r
+ cur = node->children;\r
+ /*\r
+ * Process xsl:import elements.\r
+ * XSLT 1.0: "The xsl:import element children must precede all\r
+ * other element children of an xsl:stylesheet element,\r
+ * including any xsl:include element children."\r
+ */ \r
+ while ((cur != NULL) &&\r
+ xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)\r
+ {\r
+ if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {\r
+ cctxt->style->errors++;\r
+ }\r
+ cur = cur->next;\r
+ }\r
+ if (cur == NULL)\r
+ goto exit;\r
+ start = cur;\r
+ /*\r
+ * Pre-process all xsl:include elements.\r
+ */\r
+ cur = start;\r
+ while ((cur != NULL) &&\r
+ xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)\r
+ {\r
+ xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);\r
+ cur = cur->next;\r
+ }\r
+ /*\r
+ * Pre-process all xsl:namespace-alias elements.\r
+ * URGENT TODO: This won't work correctly: the order of included\r
+ * aliases and aliases defined here is significant.\r
+ */\r
+ cur = start;\r
+ while ((cur != NULL) &&\r
+ xsltParseFindTopLevelElem(cctxt, cur,\r
+ BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)\r
+ {\r
+ xsltNamespaceAlias(cctxt->style, cur);\r
+ cur = cur->next;\r
+ }\r
+\r
+ if (cctxt->isInclude) {\r
+ /*\r
+ * If this stylesheet is intended for inclusion, then\r
+ * we will process only imports and includes. \r
+ */\r
+ goto exit;\r
+ } \r
+ /*\r
+ * Now parse the rest of the top-level elements.\r
+ */\r
+ xsltParseXSLTStylesheetElemCore(cctxt, node); \r
+exit:\r
+\r
+ return(0);\r
+}\r
+\r
+#else /* XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetTop:\r
+ * @style: the XSLT stylesheet\r
+ * @top: the top level "stylesheet" or "transform" element\r
+ *\r
+ * scan the top level elements of an XSL stylesheet\r
+ */\r
+static void\r
+xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {\r
+ xmlNodePtr cur;\r
+ xmlChar *prop;\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ int templates = 0;\r
+#endif\r
+\r
+ if (top == NULL)\r
+ return;\r
+\r
+ prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, style, top,\r
+ "xsl:version is missing: document may not be a stylesheet\n");\r
+ if (style != NULL) style->warnings++;\r
+ } else {\r
+ if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&\r
+ (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {\r
+ xsltTransformError(NULL, style, top,\r
+ "xsl:version: only 1.0 features are supported\n");\r
+ /* TODO set up compatibility when not XSLT 1.0 */\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+\r
+ cur = top->children;\r
+\r
+ /*\r
+ * process xsl:import elements\r
+ */\r
+ while (cur != NULL) {\r
+ if (IS_BLANK_NODE(cur)) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {\r
+ if (xsltParseStylesheetImport(style, cur) != 0)\r
+ if (style != NULL) style->errors++;\r
+ } else\r
+ break;\r
+ cur = cur->next;\r
+ }\r
+\r
+ /*\r
+ * process other top-level elements\r
+ */\r
+ while (cur != NULL) {\r
+ if (IS_BLANK_NODE(cur)) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if (cur->type == XML_TEXT_NODE) {\r
+ if (cur->content != NULL) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "misplaced text node: '%s'\n", cur->content);\r
+ }\r
+ if (style != NULL) style->errors++;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "Found a top-level element %s with null namespace URI\n",\r
+ cur->name);\r
+ if (style != NULL) style->errors++;\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {\r
+ xsltTopLevelFunction function;\r
+\r
+ function = xsltExtModuleTopLevelLookup(cur->name,\r
+ cur->ns->href);\r
+ if (function != NULL)\r
+ function(style, cur);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetTop : found foreign element %s\n",\r
+ cur->name);\r
+#endif\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ if (IS_XSLT_NAME(cur, "import")) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylesheetTop: ignoring misplaced import element\n");\r
+ if (style != NULL) style->errors++;\r
+ } else if (IS_XSLT_NAME(cur, "include")) {\r
+ if (xsltParseStylesheetInclude(style, cur) != 0)\r
+ if (style != NULL) style->errors++;\r
+ } else if (IS_XSLT_NAME(cur, "strip-space")) {\r
+ xsltParseStylesheetStripSpace(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "preserve-space")) {\r
+ xsltParseStylesheetPreserveSpace(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "output")) {\r
+ xsltParseStylesheetOutput(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "key")) {\r
+ xsltParseStylesheetKey(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "decimal-format")) {\r
+ xsltParseStylesheetDecimalFormat(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "attribute-set")) {\r
+ xsltParseStylesheetAttributeSet(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "variable")) {\r
+ xsltParseGlobalVariable(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "param")) {\r
+ xsltParseGlobalParam(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "template")) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ templates++;\r
+#endif\r
+ xsltParseStylesheetTemplate(style, cur);\r
+ } else if (IS_XSLT_NAME(cur, "namespace-alias")) {\r
+ xsltNamespaceAlias(style, cur);\r
+ } else {\r
+ /*\r
+ * BUG TODO: The version of the *doc* is irrelevant for\r
+ * the forwards-compatible mode.\r
+ */\r
+ if ((style != NULL) && (style->doc->version != NULL) &&\r
+ (!strncmp((const char *) style->doc->version, "1.0", 3))) {\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylesheetTop: unknown %s element\n",\r
+ cur->name);\r
+ if (style != NULL) style->errors++;\r
+ }\r
+ else {\r
+ /* do Forwards-Compatible Processing */\r
+ xsltTransformError(NULL, style, cur,\r
+ "xsltParseStylesheetTop: ignoring unknown %s element\n",\r
+ cur->name);\r
+ if (style != NULL) style->warnings++;\r
+ }\r
+ }\r
+ cur = cur->next;\r
+ }\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "parsed %d templates\n", templates);\r
+#endif\r
+}\r
+\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+#ifdef XSLT_REFACTORED\r
+/**\r
+ * xsltParseSimplifiedStylesheetTree:\r
+ *\r
+ * @style: the stylesheet (TODO: Change this to the compiler context)\r
+ * @doc: the document containing the stylesheet.\r
+ * @node: the node where the stylesheet is rooted at\r
+ *\r
+ * Returns 0 in case of success, a positive result if an error occurred\r
+ * and -1 on API and internal errors.\r
+ */\r
+static int\r
+xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,\r
+ xmlDocPtr doc,\r
+ xmlNodePtr node)\r
+{\r
+ xsltTemplatePtr templ;\r
+ \r
+ if ((cctxt == NULL) || (node == NULL))\r
+ return(-1);\r
+\r
+ if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)\r
+ {\r
+ /*\r
+ * TODO: Adjust report, since this might be an\r
+ * embedded stylesheet.\r
+ */\r
+ xsltTransformError(NULL, cctxt->style, node,\r
+ "The attribute 'xsl:version' is missing; cannot identify "\r
+ "this document as an XSLT stylesheet document.\n");\r
+ cctxt->style->errors++;\r
+ return(1);\r
+ }\r
+ \r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");\r
+#endif \r
+ \r
+ /*\r
+ * Create and link the template\r
+ */\r
+ templ = xsltNewTemplate();\r
+ if (templ == NULL) {\r
+ return(-1);\r
+ }\r
+ templ->next = cctxt->style->templates;\r
+ cctxt->style->templates = templ;\r
+ templ->match = xmlStrdup(BAD_CAST "/");\r
+\r
+ /*\r
+ * Note that we push the document-node in this special case.\r
+ */\r
+ xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);\r
+ /*\r
+ * In every case, we need to have\r
+ * the in-scope namespaces of the element, where the\r
+ * stylesheet is rooted at, regardless if it's an XSLT\r
+ * instruction or a literal result instruction (or if\r
+ * this is an embedded stylesheet).\r
+ */\r
+ cctxt->inode->inScopeNs =\r
+ xsltCompilerBuildInScopeNsList(cctxt, node);\r
+ /*\r
+ * Parse the content and register the match-pattern.\r
+ */\r
+ xsltParseSequenceConstructor(cctxt, node);\r
+ xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);\r
+\r
+ templ->elem = (xmlNodePtr) doc;\r
+ templ->content = node;\r
+ xsltAddTemplate(cctxt->style, templ, NULL, NULL);\r
+ cctxt->style->literal_result = 1;\r
+ return(0);\r
+}\r
+\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+int\r
+xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)\r
+{\r
+ if (doc == NULL)\r
+ return(-1);\r
+ /*\r
+ * Revert the changes we have applied to the namespace-URIs of\r
+ * ns-decls.\r
+ */ \r
+ while (ns != NULL) {\r
+ if ((ns->doc == doc) && (ns->ns != NULL)) {\r
+ ns->ns->href = ns->origNsName;\r
+ ns->origNsName = NULL;\r
+ ns->ns = NULL; \r
+ }\r
+ ns = ns->next;\r
+ }\r
+ return(0);\r
+}\r
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */\r
+\r
+/**\r
+ * xsltParseStylesheetProcess:\r
+ * @style: the XSLT stylesheet (the current stylesheet-level)\r
+ * @doc: and xmlDoc parsed XML\r
+ *\r
+ * Parses an XSLT stylesheet, adding the associated structures.\r
+ * Called by:\r
+ * xsltParseStylesheetImportedDoc() (xslt.c)\r
+ * xsltParseStylesheetInclude() (imports.c)\r
+ *\r
+ * Returns the value of the @style parameter if everything\r
+ * went right, NULL if something went amiss.\r
+ */\r
+xsltStylesheetPtr\r
+xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)\r
+{\r
+ xsltCompilerCtxtPtr cctxt;\r
+ xmlNodePtr cur;\r
+ int oldIsSimplifiedStylesheet;\r
+\r
+\r
+ if ((style == NULL) || (doc == NULL))\r
+ return(NULL);\r
+\r
+ cctxt = XSLT_CCTXT(style);\r
+\r
+ cur = xmlDocGetRootElement(doc);\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, style, (xmlNodePtr) doc,\r
+ "xsltParseStylesheetProcess : empty stylesheet\n");\r
+ return(NULL);\r
+ }\r
+ oldIsSimplifiedStylesheet = cctxt->simplified;\r
+\r
+ if ((IS_XSLT_ELEM(cur)) && \r
+ ((IS_XSLT_NAME(cur, "stylesheet")) ||\r
+ (IS_XSLT_NAME(cur, "transform")))) { \r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetProcess : found stylesheet\n");\r
+#endif\r
+ cctxt->simplified = 0;\r
+ style->literal_result = 0;\r
+ } else {\r
+ cctxt->simplified = 1;\r
+ style->literal_result = 1;\r
+ }\r
+ /*\r
+ * Pre-process the stylesheet if not already done before.\r
+ * This will remove PIs and comments, merge adjacent\r
+ * text nodes, internalize strings, etc.\r
+ */\r
+ if (! style->nopreproc)\r
+ xsltParsePreprocessStylesheetTree(cctxt, cur);\r
+ /*\r
+ * Parse and compile the stylesheet.\r
+ */\r
+ if (style->literal_result == 0) {\r
+ if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)\r
+ return(NULL);\r
+ } else {\r
+ if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)\r
+ return(NULL);\r
+ } \r
+\r
+ cctxt->simplified = oldIsSimplifiedStylesheet;\r
+\r
+ return(style);\r
+}\r
+\r
+#else /* XSLT_REFACTORED */\r
+\r
+xsltStylesheetPtr\r
+xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {\r
+ xmlNodePtr cur;\r
+\r
+ if (doc == NULL)\r
+ return(NULL);\r
+ if (ret == NULL)\r
+ return(ret);\r
+ \r
+ /*\r
+ * First steps, remove blank nodes,\r
+ * locate the xsl:stylesheet element and the\r
+ * namespace declaration.\r
+ */\r
+ cur = xmlDocGetRootElement(doc);\r
+ if (cur == NULL) {\r
+ xsltTransformError(NULL, ret, (xmlNodePtr) doc,\r
+ "xsltParseStylesheetProcess : empty stylesheet\n");\r
+ return(NULL);\r
+ }\r
+\r
+ if ((IS_XSLT_ELEM(cur)) && \r
+ ((IS_XSLT_NAME(cur, "stylesheet")) ||\r
+ (IS_XSLT_NAME(cur, "transform")))) { \r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetProcess : found stylesheet\n");\r
+#endif\r
+ ret->literal_result = 0;\r
+ xsltParseStylesheetExcludePrefix(ret, cur, 1);\r
+ xsltParseStylesheetExtPrefix(ret, cur, 1);\r
+ } else {\r
+ xsltParseStylesheetExcludePrefix(ret, cur, 0);\r
+ xsltParseStylesheetExtPrefix(ret, cur, 0);\r
+ ret->literal_result = 1;\r
+ }\r
+ if (!ret->nopreproc) {\r
+ xsltPrecomputeStylesheet(ret, cur);\r
+ }\r
+ if (ret->literal_result == 0) {\r
+ xsltParseStylesheetTop(ret, cur);\r
+ } else {\r
+ xmlChar *prop;\r
+ xsltTemplatePtr template;\r
+\r
+ /*\r
+ * the document itself might be the template, check xsl:version\r
+ */\r
+ prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);\r
+ if (prop == NULL) {\r
+ xsltTransformError(NULL, ret, cur,\r
+ "xsltParseStylesheetProcess : document is not a stylesheet\n");\r
+ return(NULL);\r
+ }\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetProcess : document is stylesheet\n");\r
+#endif\r
+ \r
+ if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {\r
+ xsltTransformError(NULL, ret, cur,\r
+ "xsl:version: only 1.0 features are supported\n");\r
+ /* TODO set up compatibility when not XSLT 1.0 */\r
+ ret->warnings++;\r
+ }\r
+ xmlFree(prop);\r
+\r
+ /*\r
+ * Create and link the template\r
+ */\r
+ template = xsltNewTemplate();\r
+ if (template == NULL) {\r
+ return(NULL);\r
+ }\r
+ template->next = ret->templates;\r
+ ret->templates = template;\r
+ template->match = xmlStrdup((const xmlChar *)"/");\r
+\r
+ /*\r
+ * parse the content and register the pattern\r
+ */\r
+ xsltParseTemplateContent(ret, (xmlNodePtr) doc);\r
+ template->elem = (xmlNodePtr) doc;\r
+ template->content = doc->children;\r
+ xsltAddTemplate(ret, template, NULL, NULL);\r
+ ret->literal_result = 1; \r
+ }\r
+\r
+ return(ret);\r
+}\r
+\r
+#endif /* else of XSLT_REFACTORED */\r
+\r
+/**\r
+ * xsltParseStylesheetImportedDoc:\r
+ * @doc: an xmlDoc parsed XML\r
+ * @style: pointer to the parent stylesheet (if it exists)\r
+ *\r
+ * parse an XSLT stylesheet building the associated structures\r
+ * except the processing not needed for imported documents.\r
+ *\r
+ * Returns a new XSLT stylesheet structure.\r
+ */\r
+\r
+xsltStylesheetPtr\r
+xsltParseStylesheetImportedDoc(xmlDocPtr doc,\r
+ xsltStylesheetPtr parentStyle) {\r
+ xsltStylesheetPtr retStyle;\r
+\r
+ if (doc == NULL)\r
+ return(NULL);\r
+\r
+ retStyle = xsltNewStylesheet();\r
+ if (retStyle == NULL)\r
+ return(NULL);\r
+ /*\r
+ * Set the importing stylesheet module; also used to detect recursion.\r
+ */\r
+ retStyle->parent = parentStyle;\r
+ /*\r
+ * Adjust the string dict.\r
+ */\r
+ if (doc->dict != NULL) {\r
+ xmlDictFree(retStyle->dict);\r
+ retStyle->dict = doc->dict;\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing dictionary from %s for stylesheet\n",\r
+ doc->URL);\r
+#endif\r
+ xmlDictReference(retStyle->dict);\r
+ } \r
+ \r
+ /*\r
+ * TODO: Eliminate xsltGatherNamespaces(); we must not restrict\r
+ * the stylesheet to containt distinct namespace prefixes.\r
+ */\r
+ xsltGatherNamespaces(retStyle);\r
+\r
+#ifdef XSLT_REFACTORED\r
+ {\r
+ xsltCompilerCtxtPtr cctxt;\r
+ xsltStylesheetPtr oldCurSheet;\r
+ \r
+ if (parentStyle == NULL) {\r
+ xsltPrincipalStylesheetDataPtr principalData;\r
+ /*\r
+ * Principal stylesheet\r
+ * --------------------\r
+ */\r
+ retStyle->principal = retStyle;\r
+ /*\r
+ * Create extra data for the principal stylesheet.\r
+ */\r
+ principalData = xsltNewPrincipalStylesheetData();\r
+ if (principalData == NULL) {\r
+ xsltFreeStylesheet(retStyle);\r
+ return(NULL);\r
+ }\r
+ retStyle->principalData = principalData;\r
+ /*\r
+ * Create the compilation context\r
+ * ------------------------------\r
+ * (only once; for the principal stylesheet).\r
+ * This is currently the only function where the\r
+ * compilation context is created.\r
+ */\r
+ cctxt = xsltCompilationCtxtCreate(retStyle);\r
+ if (cctxt == NULL) {\r
+ xsltFreeStylesheet(retStyle);\r
+ return(NULL);\r
+ } \r
+ retStyle->compCtxt = (void *) cctxt;\r
+ cctxt->style = retStyle;\r
+ cctxt->dict = retStyle->dict;\r
+ cctxt->psData = principalData;\r
+ /*\r
+ * Push initial dummy node info.\r
+ */\r
+ cctxt->depth = -1;\r
+ xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);\r
+ } else {\r
+ /*\r
+ * Imported stylesheet.\r
+ */\r
+ retStyle->principal = parentStyle->principal;\r
+ cctxt = parentStyle->compCtxt;\r
+ retStyle->compCtxt = cctxt;\r
+ }\r
+ /*\r
+ * Save the old and set the current stylesheet structure in the\r
+ * compilation context.\r
+ */\r
+ oldCurSheet = cctxt->style;\r
+ cctxt->style = retStyle;\r
+ \r
+ retStyle->doc = doc;\r
+ xsltParseStylesheetProcess(retStyle, doc);\r
+ \r
+ cctxt->style = oldCurSheet;\r
+ if (parentStyle == NULL) {\r
+ /*\r
+ * Pop the initial dummy node info.\r
+ */\r
+ xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);\r
+ } else {\r
+ /*\r
+ * Clear the compilation context of imported\r
+ * stylesheets.\r
+ * TODO: really?\r
+ */\r
+ /* retStyle->compCtxt = NULL; */\r
+ }\r
+ /*\r
+ * Free the stylesheet if there were errors.\r
+ */\r
+ if (retStyle != NULL) {\r
+ if (retStyle->errors != 0) {\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ /*\r
+ * Restore all changes made to namespace URIs of ns-decls.\r
+ */\r
+ if (cctxt->psData->nsMap) \r
+ xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);\r
+#endif\r
+ /*\r
+ * Detach the doc from the stylesheet; otherwise the doc\r
+ * will be freed in xsltFreeStylesheet().\r
+ */\r
+ retStyle->doc = NULL;\r
+ /*\r
+ * Cleanup the doc if its the main stylesheet.\r
+ */\r
+ if (parentStyle == NULL) {\r
+ xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));\r
+ if (retStyle->compCtxt != NULL) { \r
+ xsltCompilationCtxtFree(retStyle->compCtxt);\r
+ retStyle->compCtxt = NULL;\r
+ }\r
+ }\r
+\r
+ xsltFreeStylesheet(retStyle);\r
+ retStyle = NULL;\r
+ }\r
+ }\r
+ }\r
+ \r
+#else /* XSLT_REFACTORED */\r
+ /*\r
+ * Old behaviour.\r
+ */\r
+ retStyle->doc = doc;\r
+ xsltParseStylesheetProcess(retStyle, doc);\r
+ if (retStyle != NULL) {\r
+ if (retStyle->errors != 0) {\r
+ retStyle->doc = NULL;\r
+ if (parentStyle == NULL)\r
+ xsltCleanupStylesheetTree(doc,\r
+ xmlDocGetRootElement(doc));\r
+ xsltFreeStylesheet(retStyle);\r
+ retStyle = NULL;\r
+ }\r
+ }\r
+#endif /* else of XSLT_REFACTORED */\r
+ \r
+ return(retStyle);\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetDoc:\r
+ * @doc: and xmlDoc parsed XML\r
+ *\r
+ * parse an XSLT stylesheet building the associated structures\r
+ *\r
+ * Returns a new XSLT stylesheet structure.\r
+ */\r
+\r
+xsltStylesheetPtr\r
+xsltParseStylesheetDoc(xmlDocPtr doc) {\r
+ xsltStylesheetPtr ret;\r
+\r
+ ret = xsltParseStylesheetImportedDoc(doc, NULL);\r
+ if (ret == NULL)\r
+ return(NULL);\r
+\r
+ xsltResolveStylesheetAttributeSet(ret);\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Free the compilation context.\r
+ * TODO: Check if it's better to move this cleanup to\r
+ * xsltParseStylesheetImportedDoc().\r
+ */\r
+ if (ret->compCtxt != NULL) {\r
+ xsltCompilationCtxtFree(XSLT_CCTXT(ret));\r
+ ret->compCtxt = NULL;\r
+ }\r
+#endif\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltParseStylesheetFile:\r
+ * @filename: the filename/URL to the stylesheet\r
+ *\r
+ * Load and parse an XSLT stylesheet\r
+ *\r
+ * Returns a new XSLT stylesheet structure.\r
+ */\r
+\r
+xsltStylesheetPtr\r
+xsltParseStylesheetFile(const xmlChar* filename) {\r
+ xsltSecurityPrefsPtr sec;\r
+ xsltStylesheetPtr ret;\r
+ xmlDocPtr doc;\r
+ \r
+\r
+ if (filename == NULL)\r
+ return(NULL);\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltParseStylesheetFile : parse %s\n", filename);\r
+#endif\r
+\r
+ /*\r
+ * Security framework check\r
+ */\r
+ sec = xsltGetDefaultSecurityPrefs();\r
+ if (sec != NULL) {\r
+ int res;\r
+\r
+ res = xsltCheckRead(sec, NULL, filename);\r
+ if (res == 0) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltParseStylesheetFile: read rights for %s denied\n",\r
+ filename);\r
+ return(NULL);\r
+ }\r
+ }\r
+\r
+ doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,\r
+ NULL, XSLT_LOAD_START);\r
+ if (doc == NULL) {\r
+ xsltTransformError(NULL, NULL, NULL,\r
+ "xsltParseStylesheetFile : cannot parse %s\n", filename);\r
+ return(NULL);\r
+ }\r
+ ret = xsltParseStylesheetDoc(doc);\r
+ if (ret == NULL) {\r
+ xmlFreeDoc(doc);\r
+ return(NULL);\r
+ }\r
+\r
+ return(ret);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Handling of Stylesheet PI *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#define CUR (*cur)\r
+#define SKIP(val) cur += (val)\r
+#define NXT(val) cur[(val)]\r
+#define SKIP_BLANKS \\r
+ while (IS_BLANK(CUR)) NEXT\r
+#define NEXT ((*cur) ? cur++ : cur)\r
+\r
+/**\r
+ * xsltParseStylesheetPI:\r
+ * @value: the value of the PI\r
+ *\r
+ * This function checks that the type is text/xml and extracts\r
+ * the URI-Reference for the stylesheet\r
+ *\r
+ * Returns the URI-Reference for the stylesheet or NULL (it need to\r
+ * be freed by the caller)\r
+ */\r
+static xmlChar *\r
+xsltParseStylesheetPI(const xmlChar *value) {\r
+ const xmlChar *cur;\r
+ const xmlChar *start;\r
+ xmlChar *val;\r
+ xmlChar tmp;\r
+ xmlChar *href = NULL;\r
+ int isXml = 0;\r
+\r
+ if (value == NULL)\r
+ return(NULL);\r
+\r
+ cur = value;\r
+ while (CUR != 0) {\r
+ SKIP_BLANKS;\r
+ if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&\r
+ (NXT(3) == 'e')) {\r
+ SKIP(4);\r
+ SKIP_BLANKS;\r
+ if (CUR != '=')\r
+ continue;\r
+ NEXT;\r
+ if ((CUR != '\'') && (CUR != '"'))\r
+ continue;\r
+ tmp = CUR;\r
+ NEXT;\r
+ start = cur;\r
+ while ((CUR != 0) && (CUR != tmp))\r
+ NEXT;\r
+ if (CUR != tmp)\r
+ continue;\r
+ val = xmlStrndup(start, cur - start);\r
+ NEXT;\r
+ if (val == NULL) \r
+ return(NULL);\r
+ if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&\r
+ (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {\r
+ xmlFree(val);\r
+ break;\r
+ }\r
+ isXml = 1;\r
+ xmlFree(val);\r
+ } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&\r
+ (NXT(3) == 'f')) {\r
+ SKIP(4);\r
+ SKIP_BLANKS;\r
+ if (CUR != '=')\r
+ continue;\r
+ NEXT;\r
+ if ((CUR != '\'') && (CUR != '"'))\r
+ continue;\r
+ tmp = CUR;\r
+ NEXT;\r
+ start = cur;\r
+ while ((CUR != 0) && (CUR != tmp))\r
+ NEXT;\r
+ if (CUR != tmp)\r
+ continue;\r
+ if (href == NULL)\r
+ href = xmlStrndup(start, cur - start);\r
+ NEXT;\r
+ } else {\r
+ while ((CUR != 0) && (!IS_BLANK(CUR)))\r
+ NEXT;\r
+ }\r
+ \r
+ }\r
+\r
+ if (!isXml) {\r
+ if (href != NULL)\r
+ xmlFree(href);\r
+ href = NULL;\r
+ }\r
+ return(href);\r
+}\r
+\r
+/**\r
+ * xsltLoadStylesheetPI:\r
+ * @doc: a document to process\r
+ *\r
+ * This function tries to locate the stylesheet PI in the given document\r
+ * If found, and if contained within the document, it will extract \r
+ * that subtree to build the stylesheet to process @doc (doc itself will\r
+ * be modified). If found but referencing an external document it will\r
+ * attempt to load it and generate a stylesheet from it. In both cases,\r
+ * the resulting stylesheet and the document need to be freed once the\r
+ * transformation is done.\r
+ *\r
+ * Returns a new XSLT stylesheet structure or NULL if not found.\r
+ */\r
+xsltStylesheetPtr\r
+xsltLoadStylesheetPI(xmlDocPtr doc) {\r
+ xmlNodePtr child;\r
+ xsltStylesheetPtr ret = NULL;\r
+ xmlChar *href = NULL;\r
+ xmlURIPtr URI;\r
+\r
+ if (doc == NULL)\r
+ return(NULL);\r
+\r
+ /*\r
+ * Find the text/xml stylesheet PI id any before the root\r
+ */\r
+ child = doc->children;\r
+ while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {\r
+ if ((child->type == XML_PI_NODE) &&\r
+ (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {\r
+ href = xsltParseStylesheetPI(child->content);\r
+ if (href != NULL)\r
+ break;\r
+ }\r
+ child = child->next;\r
+ }\r
+\r
+ /*\r
+ * If found check the href to select processing\r
+ */\r
+ if (href != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltLoadStylesheetPI : found PI href=%s\n", href);\r
+#endif\r
+ URI = xmlParseURI((const char *) href);\r
+ if (URI == NULL) {\r
+ xsltTransformError(NULL, NULL, child,\r
+ "xml-stylesheet : href %s is not valid\n", href);\r
+ xmlFree(href);\r
+ return(NULL);\r
+ }\r
+ if ((URI->fragment != NULL) && (URI->scheme == NULL) &&\r
+ (URI->opaque == NULL) && (URI->authority == NULL) &&\r
+ (URI->server == NULL) && (URI->user == NULL) &&\r
+ (URI->path == NULL) && (URI->query == NULL)) {\r
+ xmlAttrPtr ID;\r
+\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltLoadStylesheetPI : Reference to ID %s\n", href);\r
+#endif\r
+ if (URI->fragment[0] == '#')\r
+ ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));\r
+ else\r
+ ID = xmlGetID(doc, (const xmlChar *) URI->fragment);\r
+ if (ID == NULL) {\r
+ xsltTransformError(NULL, NULL, child,\r
+ "xml-stylesheet : no ID %s found\n", URI->fragment);\r
+ } else {\r
+ xmlDocPtr fake;\r
+ xmlNodePtr subtree;\r
+\r
+ /*\r
+ * move the subtree in a new document passed to\r
+ * the stylesheet analyzer\r
+ */\r
+ subtree = ID->parent;\r
+ fake = xmlNewDoc(NULL);\r
+ if (fake != NULL) {\r
+ /*\r
+ * the dictionnary should be shared since nodes are\r
+ * moved over.\r
+ */\r
+ fake->dict = doc->dict;\r
+ xmlDictReference(doc->dict);\r
+#ifdef WITH_XSLT_DEBUG\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "reusing dictionary from %s for stylesheet\n",\r
+ doc->URL);\r
+#endif\r
+\r
+ xmlUnlinkNode(subtree);\r
+ xmlAddChild((xmlNodePtr) fake, subtree);\r
+ ret = xsltParseStylesheetDoc(fake);\r
+ if (ret == NULL)\r
+ xmlFreeDoc(fake);\r
+ }\r
+ }\r
+ } else {\r
+ xmlChar *URL, *base;\r
+\r
+ /*\r
+ * Reference to an external stylesheet\r
+ */\r
+\r
+ base = xmlNodeGetBase(doc, (xmlNodePtr) doc);\r
+ URL = xmlBuildURI(href, base);\r
+ if (URL != NULL) {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltLoadStylesheetPI : fetching %s\n", URL);\r
+#endif\r
+ ret = xsltParseStylesheetFile(URL);\r
+ xmlFree(URL);\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PARSING\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltLoadStylesheetPI : fetching %s\n", href);\r
+#endif\r
+ ret = xsltParseStylesheetFile(href);\r
+ }\r
+ if (base != NULL)\r
+ xmlFree(base);\r
+ }\r
+ xmlFreeURI(URI);\r
+ xmlFree(href);\r
+ }\r
+ return(ret);\r
+}\r
-/*
- * Summary: internal data structures, constants and functions
- * Description: Internal data structures, constants and functions used
- * by the XSLT engine.
- * They are not part of the API or ABI, i.e. they can change
- * without prior notice, use carefully.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
-
-#ifndef __XML_XSLT_INTERNALS_H__
-#define __XML_XSLT_INTERNALS_H__
-
-#include <libxml/tree.h>
-#include <libxml/hash.h>
-#include <libxml/xpath.h>
-#include <libxml/xmlerror.h>
-#include <libxml/dict.h>
-#include <libxml/xmlstring.h>
-#include <libxslt/xslt.h>
-#include "xsltexports.h"
-#include "numbersInternals.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \
- (((n)->type == XML_TEXT_NODE) || \
- ((n)->type == XML_CDATA_SECTION_NODE)))
-
-
-#if 0
-
-extern const xmlChar *xsltDocFragFake;
-
-#define XSLT_MARK_RES_TREE_FRAG(n) (n)->psvi = (void *) xsltDocFragFake;
-
-#define XSLT_IS_RES_TREE_FRAG(n) \
- ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
- ((n)->psvi == xsltDocFragFake))
-
-#else
-
-#define XSLT_MARK_RES_TREE_FRAG(n) \
- (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
-
-#define XSLT_IS_RES_TREE_FRAG(n) \
- ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
- ((n)->name != NULL) && ((n)->name[0] == ' ') && \
- xmlStrEqual(BAD_CAST (n)->name, BAD_CAST " fake node libxslt"))
-
-#endif
-
-/**
- * XSLT_REFACTORED_KEYCOMP:
- *
- * Internal define to enable on-demand xsl:key computation.
- */
-#define XSLT_REFACTORED_KEYCOMP
-
-/**
- * XSLT_REFACTORED:
- *
- * Internal define to enable the refactored parts of Libxslt.
- */
-/* #define XSLT_REFACTORED */
-/* ==================================================================== */
-
-#ifdef XSLT_REFACTORED
-
-extern const xmlChar *xsltXSLTAttrMarker;
-
-/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
-
-/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
-
-/**
- * XSLT_REFACTORED_XSLT_NSCOMP
- *
- * Internal define to enable the pointer-comparison of
- * namespaces of XSLT elements.
- */
-/* #define XSLT_REFACTORED_XSLT_NSCOMP */
-
-/**
- * XSLT_REFACTORED_XPATHCOMP
- *
- * Internal define to enable the optimization of the
- * compilation of XPath expressions.
- */
-#define XSLT_REFACTORED_XPATHCOMP
-
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
-
-extern const xmlChar *xsltConstNamespaceNameXSLT;
-
-#define IS_XSLT_ELEM_FAST(n) \
- (((n) != NULL) && ((n)->ns != NULL) && \
- ((n)->ns->href == xsltConstNamespaceNameXSLT))
-
-#define IS_XSLT_ATTR_FAST(a) \
- (((a) != NULL) && ((a)->ns != NULL) && \
- ((a)->ns->href == xsltConstNamespaceNameXSLT))
-
-#define XSLT_HAS_INTERNAL_NSMAP(s) \
- (((s) != NULL) && ((s)->principal) && \
- ((s)->principal->principalData) && \
- ((s)->principal->principalData->nsMap))
-
-#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap)
-
-#else /* XSLT_REFACTORED_XSLT_NSCOMP */
-
-#define IS_XSLT_ELEM_FAST(n) \
- (((n) != NULL) && ((n)->ns != NULL) && \
- (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
-
-#define IS_XSLT_ATTR_FAST(a) \
- (((a) != NULL) && ((a)->ns != NULL) && \
- (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE)))
-
-
-#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
-
-
-/**
- * XSLT_REFACTORED_MANDATORY_VERSION:
- *
- * TODO: Currently disabled to surpress regression test failures, since
- * the old behaviour was that a missing version attribute
- * produced a only a warning and not an error, which was incerrect.
- * So the regression tests need to be fixed if this is enabled.
- */
-/* #define XSLT_REFACTORED_MANDATORY_VERSION */
-
-/**
- * xsltPointerList:
- *
- * Pointer-list for various purposes.
- */
-typedef struct _xsltPointerList xsltPointerList;
-typedef xsltPointerList *xsltPointerListPtr;
-struct _xsltPointerList {
- void **items;
- int number;
- int size;
-};
-
-#endif
-
-/**
- * XSLT_REFACTORED_PARSING:
- *
- * Internal define to enable the refactored parts of Libxslt
- * related to parsing.
- */
-/* #define XSLT_REFACTORED_PARSING */
-
-/**
- * XSLT_MAX_SORT:
- *
- * Max number of specified xsl:sort on an element.
- */
-#define XSLT_MAX_SORT 15
-
-/**
- * XSLT_PAT_NO_PRIORITY:
- *
- * Specific value for pattern without priority expressed.
- */
-#define XSLT_PAT_NO_PRIORITY -12345789
-
-/**
- * xsltRuntimeExtra:
- *
- * Extra information added to the transformation context.
- */
-typedef struct _xsltRuntimeExtra xsltRuntimeExtra;
-typedef xsltRuntimeExtra *xsltRuntimeExtraPtr;
-struct _xsltRuntimeExtra {
- void *info; /* pointer to the extra data */
- xmlFreeFunc deallocate; /* pointer to the deallocation routine */
- union { /* dual-purpose field */
- void *ptr; /* data not needing deallocation */
- int ival; /* integer value storage */
- } val;
-};
-
-/**
- * XSLT_RUNTIME_EXTRA_LST:
- * @ctxt: the transformation context
- * @nr: the index
- *
- * Macro used to access extra information stored in the context
- */
-#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info
-/**
- * XSLT_RUNTIME_EXTRA_FREE:
- * @ctxt: the transformation context
- * @nr: the index
- *
- * Macro used to free extra information stored in the context
- */
-#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate
-/**
- * XSLT_RUNTIME_EXTRA:
- * @ctxt: the transformation context
- * @nr: the index
- *
- * Macro used to define extra information stored in the context
- */
-#define XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ
-
-/**
- * xsltTemplate:
- *
- * The in-memory structure corresponding to an XSLT Template.
- */
-typedef struct _xsltTemplate xsltTemplate;
-typedef xsltTemplate *xsltTemplatePtr;
-struct _xsltTemplate {
- struct _xsltTemplate *next;/* chained list sorted by priority */
- struct _xsltStylesheet *style;/* the containing stylesheet */
- xmlChar *match; /* the matching string */
- float priority; /* as given from the stylesheet, not computed */
- const xmlChar *name; /* the local part of the name QName */
- const xmlChar *nameURI; /* the URI part of the name QName */
- const xmlChar *mode;/* the local part of the mode QName */
- const xmlChar *modeURI;/* the URI part of the mode QName */
- xmlNodePtr content; /* the template replacement value */
- xmlNodePtr elem; /* the source element */
-
- /*
- * TODO: @inheritedNsNr and @inheritedNs won't be used in the
- * refactored code.
- */
- int inheritedNsNr; /* number of inherited namespaces */
- xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */
-
- /* Profiling informations */
- int nbCalls; /* the number of time the template was called */
- unsigned long time; /* the time spent in this template */
-};
-
-/**
- * xsltDecimalFormat:
- *
- * Data structure of decimal-format.
- */
-typedef struct _xsltDecimalFormat xsltDecimalFormat;
-typedef xsltDecimalFormat *xsltDecimalFormatPtr;
-struct _xsltDecimalFormat {
- struct _xsltDecimalFormat *next; /* chained list */
- xmlChar *name;
- /* Used for interpretation of pattern */
- xmlChar *digit;
- xmlChar *patternSeparator;
- /* May appear in result */
- xmlChar *minusSign;
- xmlChar *infinity;
- xmlChar *noNumber; /* Not-a-number */
- /* Used for interpretation of pattern and may appear in result */
- xmlChar *decimalPoint;
- xmlChar *grouping;
- xmlChar *percent;
- xmlChar *permille;
- xmlChar *zeroDigit;
-};
-
-/**
- * xsltDocument:
- *
- * Data structure associated to a parsed document.
- */
-
-typedef struct _xsltDocument xsltDocument;
-typedef xsltDocument *xsltDocumentPtr;
-struct _xsltDocument {
- struct _xsltDocument *next; /* documents are kept in a chained list */
- int main; /* is this the main document */
- xmlDocPtr doc; /* the parsed document */
- void *keys; /* key tables storage */
- struct _xsltDocument *includes; /* subsidiary includes */
- int preproc; /* pre-processing already done */
- int nbKeysComputed;
-};
-
-/**
- * xsltKeyDef:
- *
- * Representation of an xsl:key.
- */
-typedef struct _xsltKeyDef xsltKeyDef;
-typedef xsltKeyDef *xsltKeyDefPtr;
-struct _xsltKeyDef {
- struct _xsltKeyDef *next;
- xmlNodePtr inst;
- xmlChar *name;
- xmlChar *nameURI;
- xmlChar *match;
- xmlChar *use;
- xmlXPathCompExprPtr comp;
- xmlXPathCompExprPtr usecomp;
- xmlNsPtr *nsList; /* the namespaces in scope */
- int nsNr; /* the number of namespaces in scope */
-};
-
-/**
- * xsltKeyTable:
- *
- * Holds the computed keys for key definitions of the same QName.
- * Is owned by an xsltDocument.
- */
-typedef struct _xsltKeyTable xsltKeyTable;
-typedef xsltKeyTable *xsltKeyTablePtr;
-struct _xsltKeyTable {
- struct _xsltKeyTable *next;
- xmlChar *name;
- xmlChar *nameURI;
- xmlHashTablePtr keys;
-};
-
-/*
- * The in-memory structure corresponding to an XSLT Stylesheet.
- * NOTE: most of the content is simply linked from the doc tree
- * structure, no specific allocation is made.
- */
-typedef struct _xsltStylesheet xsltStylesheet;
-typedef xsltStylesheet *xsltStylesheetPtr;
-
-typedef struct _xsltTransformContext xsltTransformContext;
-typedef xsltTransformContext *xsltTransformContextPtr;
-
-/**
- * xsltElemPreComp:
- *
- * The in-memory structure corresponding to element precomputed data,
- * designed to be extended by extension implementors.
- */
-typedef struct _xsltElemPreComp xsltElemPreComp;
-typedef xsltElemPreComp *xsltElemPreCompPtr;
-
-/**
- * xsltTransformFunction:
- * @ctxt: the XSLT transformation context
- * @node: the input node
- * @inst: the stylesheet node
- * @comp: the compiled information from the stylesheet
- *
- * Signature of the function associated to elements part of the
- * stylesheet language like xsl:if or xsl:apply-templates.
- */
-typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- xmlNodePtr inst,
- xsltElemPreCompPtr comp);
-
-/**
- * xsltSortFunc:
- * @ctxt: a transformation context
- * @sorts: the node-set to sort
- * @nbsorts: the number of sorts
- *
- * Signature of the function to use during sorting
- */
-typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
- int nbsorts);
-
-typedef enum {
- XSLT_FUNC_COPY=1,
- XSLT_FUNC_SORT,
- XSLT_FUNC_TEXT,
- XSLT_FUNC_ELEMENT,
- XSLT_FUNC_ATTRIBUTE,
- XSLT_FUNC_COMMENT,
- XSLT_FUNC_PI,
- XSLT_FUNC_COPYOF,
- XSLT_FUNC_VALUEOF,
- XSLT_FUNC_NUMBER,
- XSLT_FUNC_APPLYIMPORTS,
- XSLT_FUNC_CALLTEMPLATE,
- XSLT_FUNC_APPLYTEMPLATES,
- XSLT_FUNC_CHOOSE,
- XSLT_FUNC_IF,
- XSLT_FUNC_FOREACH,
- XSLT_FUNC_DOCUMENT,
- XSLT_FUNC_WITHPARAM,
- XSLT_FUNC_PARAM,
- XSLT_FUNC_VARIABLE,
- XSLT_FUNC_WHEN,
- XSLT_FUNC_EXTENSION,
-#ifdef XSLT_REFACTORED
- XSLT_FUNC_OTHERWISE,
- XSLT_FUNC_FALLBACK,
- XSLT_FUNC_MESSAGE,
- XSLT_FUNC_INCLUDE,
- XSLT_FUNC_ATTRSET,
- XSLT_FUNC_LITERAL_RESULT_ELEMENT,
- XSLT_FUNC_UNKOWN_FORWARDS_COMPAT,
-#endif
-} xsltStyleType;
-
-/**
- * xsltElemPreCompDeallocator:
- * @comp: the #xsltElemPreComp to free up
- *
- * Deallocates an #xsltElemPreComp structure.
- */
-typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp);
-
-/**
- * xsltElemPreComp:
- *
- * The basic structure for compiled items of the AST of the XSLT processor.
- * This structure is also intended to be extended by extension implementors.
- * TODO: This is somehow not nice, since it has a "free" field, which
- * derived stylesheet-structs do not have.
- */
-struct _xsltElemPreComp {
- xsltElemPreCompPtr next; /* next item in the global chained
- list hold by xsltStylesheet. */
- xsltStyleType type; /* type of the element */
- xsltTransformFunction func; /* handling function */
- xmlNodePtr inst; /* the node in the stylesheet's tree
- corresponding to this item */
-
- /* end of common part */
- xsltElemPreCompDeallocator free; /* the deallocator */
-};
-
-/**
- * xsltStylePreComp:
- *
- * The abstract basic structure for items of the XSLT processor.
- * This includes:
- * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.)
- * 2) compiled forms of literal result elements
- * 3) compiled forms of extension elements
- */
-typedef struct _xsltStylePreComp xsltStylePreComp;
-typedef xsltStylePreComp *xsltStylePreCompPtr;
-
-#ifdef XSLT_REFACTORED
-
-/*
-* Some pointer-list utility functions.
-*/
-XSLTPUBFUN xsltPointerListPtr XSLTCALL
- xsltPointerListCreate (int initialSize);
-XSLTPUBFUN void XSLTCALL
- xsltPointerListFree (xsltPointerListPtr list);
-XSLTPUBFUN void XSLTCALL
- xsltPointerListClear (xsltPointerListPtr list);
-XSLTPUBFUN int XSLTCALL
- xsltPointerListAddSize (xsltPointerListPtr list,
- void *item,
- int initialSize);
-
-/************************************************************************
- * *
- * Refactored structures *
- * *
- ************************************************************************/
-
-typedef struct _xsltNsListContainer xsltNsListContainer;
-typedef xsltNsListContainer *xsltNsListContainerPtr;
-struct _xsltNsListContainer {
- xmlNsPtr *list;
- int totalNumber;
- int xpathNumber;
-};
-
-/**
- * XSLT_ITEM_COMPATIBILITY_FIELDS:
- *
- * Fields for API compatibility to the structure
- * _xsltElemPreComp which is used for extension functions.
- * TODO: Evaluate if we really need such a compatibility.
- */
-#define XSLT_ITEM_COMPATIBILITY_FIELDS \
- xsltElemPreCompPtr next;\
- xsltStyleType type;\
- xsltTransformFunction func;\
- xmlNodePtr inst;
-
-/**
- * XSLT_ITEM_NAVIGATION_FIELDS:
- *
- * Currently empty.
- * TODO: It is intended to hold navigational fields in the future.
- */
-#define XSLT_ITEM_NAVIGATION_FIELDS
-/*
- xsltStylePreCompPtr parent;\
- xsltStylePreCompPtr children;\
- xsltStylePreCompPtr nextItem;
-*/
-
-/**
- * XSLT_ITEM_NSINSCOPE_FIELDS:
- *
- * The in-scope namespaces.
- */
-#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs;
-
-/**
- * XSLT_ITEM_COMMON_FIELDS:
- *
- * Common fields used for all items.
- */
-#define XSLT_ITEM_COMMON_FIELDS \
- XSLT_ITEM_COMPATIBILITY_FIELDS \
- XSLT_ITEM_NAVIGATION_FIELDS \
- XSLT_ITEM_NSINSCOPE_FIELDS
-
-/**
- * _xsltStylePreComp:
- *
- * The abstract basic structure for items of the XSLT processor.
- * This includes:
- * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.)
- * 2) compiled forms of literal result elements
- * 3) various properties for XSLT instructions (e.g. xsl:when,
- * xsl:with-param)
- *
- * REVISIT TODO: Keep this structure equal to the fields
- * defined by XSLT_ITEM_COMMON_FIELDS
- */
-struct _xsltStylePreComp {
- xsltElemPreCompPtr next; /* next item in the global chained
- list hold by xsltStylesheet */
- xsltStyleType type; /* type of the item */
- xsltTransformFunction func; /* handling function */
- xmlNodePtr inst; /* the node in the stylesheet's tree
- corresponding to this item. */
- /* Currently no navigational fields. */
- xsltNsListContainerPtr inScopeNs;
-};
-
-/**
- * xsltStyleBasicEmptyItem:
- *
- * Abstract structure only used as a short-cut for
- * XSLT items with no extra fields.
- * NOTE that it is intended that this structure looks the same as
- * _xsltStylePreComp.
- */
-typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem;
-typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr;
-
-struct _xsltStyleBasicEmptyItem {
- XSLT_ITEM_COMMON_FIELDS
-};
-
-/**
- * xsltStyleBasicExpressionItem:
- *
- * Abstract structure only used as a short-cut for
- * XSLT items with just an expression.
- */
-typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem;
-typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr;
-
-struct _xsltStyleBasicExpressionItem {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *select; /* TODO: Change this to "expression". */
- xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */
-};
-
-/************************************************************************
- * *
- * XSLT-instructions/declarations *
- * *
- ************************************************************************/
-
-/**
- * xsltStyleItemElement:
- *
- * <!-- Category: instruction -->
- * <xsl:element
- * name = { qname }
- * namespace = { uri-reference }
- * use-attribute-sets = qnames>
- * <!-- Content: template -->
- * </xsl:element>
- */
-typedef struct _xsltStyleItemElement xsltStyleItemElement;
-typedef xsltStyleItemElement *xsltStyleItemElementPtr;
-
-struct _xsltStyleItemElement {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *use;
- int has_use;
- const xmlChar *name;
- int has_name;
- const xmlChar *ns;
- const xmlChar *nsPrefix;
- int has_ns;
-};
-
-/**
- * xsltStyleItemAttribute:
- *
- * <!-- Category: instruction -->
- * <xsl:attribute
- * name = { qname }
- * namespace = { uri-reference }>
- * <!-- Content: template -->
- * </xsl:attribute>
- */
-typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute;
-typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr;
-
-struct _xsltStyleItemAttribute {
- XSLT_ITEM_COMMON_FIELDS
- const xmlChar *name;
- int has_name;
- const xmlChar *ns;
- const xmlChar *nsPrefix;
- int has_ns;
-};
-
-/**
- * xsltStyleItemText:
- *
- * <!-- Category: instruction -->
- * <xsl:text
- * disable-output-escaping = "yes" | "no">
- * <!-- Content: #PCDATA -->
- * </xsl:text>
- */
-typedef struct _xsltStyleItemText xsltStyleItemText;
-typedef xsltStyleItemText *xsltStyleItemTextPtr;
-
-struct _xsltStyleItemText {
- XSLT_ITEM_COMMON_FIELDS
- int noescape; /* text */
-};
-
-/**
- * xsltStyleItemComment:
- *
- * <!-- Category: instruction -->
- * <xsl:comment>
- * <!-- Content: template -->
- * </xsl:comment>
- */
-typedef xsltStyleBasicEmptyItem xsltStyleItemComment;
-typedef xsltStyleItemComment *xsltStyleItemCommentPtr;
-
-/**
- * xsltStyleItemPI:
- *
- * <!-- Category: instruction -->
- * <xsl:processing-instruction
- * name = { ncname }>
- * <!-- Content: template -->
- * </xsl:processing-instruction>
- */
-typedef struct _xsltStyleItemPI xsltStyleItemPI;
-typedef xsltStyleItemPI *xsltStyleItemPIPtr;
-
-struct _xsltStyleItemPI {
- XSLT_ITEM_COMMON_FIELDS
- const xmlChar *name;
- int has_name;
-};
-
-/**
- * xsltStyleItemApplyImports:
- *
- * <!-- Category: instruction -->
- * <xsl:apply-imports />
- */
-typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports;
-typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr;
-
-/**
- * xsltStyleItemApplyTemplates:
- *
- * <!-- Category: instruction -->
- * <xsl:apply-templates
- * select = node-set-expression
- * mode = qname>
- * <!-- Content: (xsl:sort | xsl:with-param)* -->
- * </xsl:apply-templates>
- */
-typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates;
-typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr;
-
-struct _xsltStyleItemApplyTemplates {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *mode; /* apply-templates */
- const xmlChar *modeURI; /* apply-templates */
- const xmlChar *select; /* sort, copy-of, value-of, apply-templates */
- xmlXPathCompExprPtr comp; /* a precompiled XPath expression */
- /* TODO: with-params */
-};
-
-/**
- * xsltStyleItemCallTemplate:
- *
- * <!-- Category: instruction -->
- * <xsl:call-template
- * name = qname>
- * <!-- Content: xsl:with-param* -->
- * </xsl:call-template>
- */
-typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate;
-typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr;
-
-struct _xsltStyleItemCallTemplate {
- XSLT_ITEM_COMMON_FIELDS
-
- xsltTemplatePtr templ; /* call-template */
- const xmlChar *name; /* element, attribute, pi */
- int has_name; /* element, attribute, pi */
- const xmlChar *ns; /* element */
- int has_ns; /* element */
- /* TODO: with-params */
-};
-
-/**
- * xsltStyleItemCopy:
- *
- * <!-- Category: instruction -->
- * <xsl:copy
- * use-attribute-sets = qnames>
- * <!-- Content: template -->
- * </xsl:copy>
- */
-typedef struct _xsltStyleItemCopy xsltStyleItemCopy;
-typedef xsltStyleItemCopy *xsltStyleItemCopyPtr;
-
-struct _xsltStyleItemCopy {
- XSLT_ITEM_COMMON_FIELDS
- const xmlChar *use; /* copy, element */
- int has_use; /* copy, element */
-};
-
-/**
- * xsltStyleItemIf:
- *
- * <!-- Category: instruction -->
- * <xsl:if
- * test = boolean-expression>
- * <!-- Content: template -->
- * </xsl:if>
- */
-typedef struct _xsltStyleItemIf xsltStyleItemIf;
-typedef xsltStyleItemIf *xsltStyleItemIfPtr;
-
-struct _xsltStyleItemIf {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *test; /* if */
- xmlXPathCompExprPtr comp; /* a precompiled XPath expression */
-};
-
-
-/**
- * xsltStyleItemCopyOf:
- *
- * <!-- Category: instruction -->
- * <xsl:copy-of
- * select = expression />
- */
-typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf;
-typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr;
-
-/**
- * xsltStyleItemValueOf:
- *
- * <!-- Category: instruction -->
- * <xsl:value-of
- * select = string-expression
- * disable-output-escaping = "yes" | "no" />
- */
-typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf;
-typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr;
-
-struct _xsltStyleItemValueOf {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *select;
- xmlXPathCompExprPtr comp; /* a precompiled XPath expression */
- int noescape;
-};
-
-/**
- * xsltStyleItemNumber:
- *
- * <!-- Category: instruction -->
- * <xsl:number
- * level = "single" | "multiple" | "any"
- * count = pattern
- * from = pattern
- * value = number-expression
- * format = { string }
- * lang = { nmtoken }
- * letter-value = { "alphabetic" | "traditional" }
- * grouping-separator = { char }
- * grouping-size = { number } />
- */
-typedef struct _xsltStyleItemNumber xsltStyleItemNumber;
-typedef xsltStyleItemNumber *xsltStyleItemNumberPtr;
-
-struct _xsltStyleItemNumber {
- XSLT_ITEM_COMMON_FIELDS
- xsltNumberData numdata; /* number */
-};
-
-/**
- * xsltStyleItemChoose:
- *
- * <!-- Category: instruction -->
- * <xsl:choose>
- * <!-- Content: (xsl:when+, xsl:otherwise?) -->
- * </xsl:choose>
- */
-typedef xsltStyleBasicEmptyItem xsltStyleItemChoose;
-typedef xsltStyleItemChoose *xsltStyleItemChoosePtr;
-
-/**
- * xsltStyleItemFallback:
- *
- * <!-- Category: instruction -->
- * <xsl:fallback>
- * <!-- Content: template -->
- * </xsl:fallback>
- */
-typedef xsltStyleBasicEmptyItem xsltStyleItemFallback;
-typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr;
-
-/**
- * xsltStyleItemForEach:
- *
- * <!-- Category: instruction -->
- * <xsl:for-each
- * select = node-set-expression>
- * <!-- Content: (xsl:sort*, template) -->
- * </xsl:for-each>
- */
-typedef xsltStyleBasicExpressionItem xsltStyleItemForEach;
-typedef xsltStyleItemForEach *xsltStyleItemForEachPtr;
-
-/**
- * xsltStyleItemMessage:
- *
- * <!-- Category: instruction -->
- * <xsl:message
- * terminate = "yes" | "no">
- * <!-- Content: template -->
- * </xsl:message>
- */
-typedef struct _xsltStyleItemMessage xsltStyleItemMessage;
-typedef xsltStyleItemMessage *xsltStyleItemMessagePtr;
-
-struct _xsltStyleItemMessage {
- XSLT_ITEM_COMMON_FIELDS
- int terminate;
-};
-
-/**
- * xsltStyleItemDocument:
- *
- * NOTE: This is not an instruction of XSLT 1.0.
- */
-typedef struct _xsltStyleItemDocument xsltStyleItemDocument;
-typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr;
-
-struct _xsltStyleItemDocument {
- XSLT_ITEM_COMMON_FIELDS
- int ver11; /* assigned: in xsltDocumentComp;
- read: nowhere;
- TODO: Check if we need. */
- const xmlChar *filename; /* document URL */
- int has_filename;
-};
-
-/************************************************************************
- * *
- * Non-instructions (actually properties of instructions/declarations) *
- * *
- ************************************************************************/
-
-/**
- * xsltStyleBasicItemVariable:
- *
- * Basic struct for xsl:variable, xsl:param and xsl:with-param.
- * It's currently important to have equal fields, since
- * xsltParseStylesheetCallerParam() is used with xsl:with-param from
- * the xslt side and with xsl:param from the exslt side (in
- * exsltFuncFunctionFunction()).
- *
- * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param
- * have additional different fields.
- */
-typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable;
-typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr;
-
-struct _xsltStyleBasicItemVariable {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *select;
- xmlXPathCompExprPtr comp;
-
- const xmlChar *name;
- int has_name;
- const xmlChar *ns;
- int has_ns;
-};
-
-/**
- * xsltStyleItemVariable:
- *
- * <!-- Category: top-level-element -->
- * <xsl:param
- * name = qname
- * select = expression>
- * <!-- Content: template -->
- * </xsl:param>
- */
-typedef xsltStyleBasicItemVariable xsltStyleItemVariable;
-typedef xsltStyleItemVariable *xsltStyleItemVariablePtr;
-
-/**
- * xsltStyleItemParam:
- *
- * <!-- Category: top-level-element -->
- * <xsl:param
- * name = qname
- * select = expression>
- * <!-- Content: template -->
- * </xsl:param>
- */
-typedef xsltStyleBasicItemVariable xsltStyleItemParam;
-typedef xsltStyleItemParam *xsltStyleItemParamPtr;
-
-/**
- * xsltStyleItemWithParam:
- *
- * <xsl:with-param
- * name = qname
- * select = expression>
- * <!-- Content: template -->
- * </xsl:with-param>
- */
-typedef xsltStyleBasicItemVariable xsltStyleItemWithParam;
-typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr;
-
-/**
- * xsltStyleItemSort:
- *
- * Reflects the XSLT xsl:sort item.
- * Allowed parents: xsl:apply-templates, xsl:for-each
- * <xsl:sort
- * select = string-expression
- * lang = { nmtoken }
- * data-type = { "text" | "number" | qname-but-not-ncname }
- * order = { "ascending" | "descending" }
- * case-order = { "upper-first" | "lower-first" } />
- */
-typedef struct _xsltStyleItemSort xsltStyleItemSort;
-typedef xsltStyleItemSort *xsltStyleItemSortPtr;
-
-struct _xsltStyleItemSort {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *stype; /* sort */
- int has_stype; /* sort */
- int number; /* sort */
- const xmlChar *order; /* sort */
- int has_order; /* sort */
- int descending; /* sort */
- const xmlChar *lang; /* sort */
- int has_lang; /* sort */
- const xmlChar *case_order; /* sort */
- int lower_first; /* sort */
-
- const xmlChar *use;
- int has_use;
-
- const xmlChar *select; /* sort, copy-of, value-of, apply-templates */
-
- xmlXPathCompExprPtr comp; /* a precompiled XPath expression */
-};
-
-
-/**
- * xsltStyleItemWhen:
- *
- * <xsl:when
- * test = boolean-expression>
- * <!-- Content: template -->
- * </xsl:when>
- * Allowed parent: xsl:choose
- */
-typedef struct _xsltStyleItemWhen xsltStyleItemWhen;
-typedef xsltStyleItemWhen *xsltStyleItemWhenPtr;
-
-struct _xsltStyleItemWhen {
- XSLT_ITEM_COMMON_FIELDS
-
- const xmlChar *test;
- xmlXPathCompExprPtr comp;
-};
-
-/**
- * xsltStyleItemOtherwise:
- *
- * Allowed parent: xsl:choose
- * <xsl:otherwise>
- * <!-- Content: template -->
- * </xsl:otherwise>
- */
-typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise;
-typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr;
-
-struct _xsltStyleItemOtherwise {
- XSLT_ITEM_COMMON_FIELDS
-};
-
-typedef struct _xsltStyleItemInclude xsltStyleItemInclude;
-typedef xsltStyleItemInclude *xsltStyleItemIncludePtr;
-
-struct _xsltStyleItemInclude {
- XSLT_ITEM_COMMON_FIELDS
- xsltDocumentPtr include;
-};
-
-/************************************************************************
- * *
- * XSLT elements in forwards-compatible mode *
- * *
- ************************************************************************/
-
-typedef struct _xsltStyleItemUknown xsltStyleItemUknown;
-typedef xsltStyleItemUknown *xsltStyleItemUknownPtr;
-struct _xsltStyleItemUknown {
- XSLT_ITEM_COMMON_FIELDS
-};
-
-
-/************************************************************************
- * *
- * Extension elements *
- * *
- ************************************************************************/
-
-/*
- * xsltStyleItemExtElement:
- *
- * Reflects extension elements.
- *
- * NOTE: Due to the fact that the structure xsltElemPreComp is most
- * probably already heavily in use out there by users, so we cannot
- * easily change it, we'll create an intermediate structure which will
- * hold an xsltElemPreCompPtr.
- * BIG NOTE: The only problem I see here is that the user processes the
- * content of the stylesheet tree, possibly he'll lookup the node->psvi
- * fields in order to find subsequent extension functions.
- * In this case, the user's code will break, since the node->psvi
- * field will hold now the xsltStyleItemExtElementPtr and not
- * the xsltElemPreCompPtr.
- * However the place where the structure is anchored in the node-tree,
- * namely node->psvi, has beed already once been moved from node->_private
- * to node->psvi, so we have a precedent here, which, I think, should allow
- * us to change such semantics without headaches.
- */
-typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement;
-typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr;
-struct _xsltStyleItemExtElement {
- XSLT_ITEM_COMMON_FIELDS
- xsltElemPreCompPtr item;
-};
-
-/************************************************************************
- * *
- * Literal result elements *
- * *
- ************************************************************************/
-
-typedef struct _xsltEffectiveNs xsltEffectiveNs;
-typedef xsltEffectiveNs *xsltEffectiveNsPtr;
-struct _xsltEffectiveNs {
- xsltEffectiveNsPtr nextInStore; /* storage next */
- xsltEffectiveNsPtr next; /* next item in the list */
- const xmlChar *prefix;
- const xmlChar *nsName;
- /*
- * Indicates if eclared on the literal result element; dunno if really
- * needed.
- */
- int holdByElem;
-};
-
-/*
- * Info for literal result elements.
- * This will be set on the elem->psvi field and will be
- * shared by literal result elements, which have the same
- * excluded result namespaces; i.e., this *won't* be created uniquely
- * for every literal result element.
- */
-typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo;
-typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr;
-struct _xsltStyleItemLRElementInfo {
- XSLT_ITEM_COMMON_FIELDS
- /*
- * @effectiveNs is the set of effective ns-nodes
- * on the literal result element, which will be added to the result
- * element if not already existing in the result tree.
- * This means that excluded namespaces (via exclude-result-prefixes,
- * extension-element-prefixes and the XSLT namespace) not added
- * to the set.
- * Namespace-aliasing was applied on the @effectiveNs.
- */
- xsltEffectiveNsPtr effectiveNs;
-
-};
-
-#ifdef XSLT_REFACTORED
-
-typedef struct _xsltNsAlias xsltNsAlias;
-typedef xsltNsAlias *xsltNsAliasPtr;
-struct _xsltNsAlias {
- xsltNsAliasPtr next; /* next in the list */
- xmlNsPtr literalNs;
- xmlNsPtr targetNs;
- xmlDocPtr docOfTargetNs;
-};
-#endif
-
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
-
-typedef struct _xsltNsMap xsltNsMap;
-typedef xsltNsMap *xsltNsMapPtr;
-struct _xsltNsMap {
- xsltNsMapPtr next; /* next in the list */
- xmlDocPtr doc;
- xmlNodePtr elem; /* the element holding the ns-decl */
- xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */
- const xmlChar *origNsName; /* the original XML namespace name */
- const xmlChar *newNsName; /* the mapped XML namespace name */
-};
-#endif
-
-/************************************************************************
- * *
- * Compile-time structures for *internal* use only *
- * *
- ************************************************************************/
-
-typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData;
-typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr;
-
-typedef struct _xsltNsList xsltNsList;
-typedef xsltNsList *xsltNsListPtr;
-struct _xsltNsList {
- xsltNsListPtr next; /* next in the list */
- xmlNsPtr ns;
-};
-
-#define XSLT_ELEMENT_CATEGORY_XSLT 0
-#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
-#define XSLT_ELEMENT_CATEGORY_LRE 2
-
-/**
- * xsltCompilerNodeInfo:
- *
- * Per-node information during compile-time.
- */
-typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo;
-typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr;
-struct _xsltCompilerNodeInfo {
- xsltCompilerNodeInfoPtr next;
- xsltCompilerNodeInfoPtr prev;
- xmlNodePtr node;
- int depth;
- xsltTemplatePtr templ; /* The owning template */
- int category; /* XSLT element, LR-element or
- extension element */
- xsltStyleType type;
- xsltElemPreCompPtr item; /* The compiled information */
- /* The current in-scope namespaces */
- xsltNsListContainerPtr inScopeNs;
- /* The current excluded result namespaces */
- xsltPointerListPtr exclResultNs;
- /* The current extension instruction namespaces */
- xsltPointerListPtr extElemNs;
- /* The current info for literal result elements. */
- xsltStyleItemLRElementInfoPtr litResElemInfo;
- /*
- * Set to 1 if in-scope namespaces changed,
- * or excluded result namespaces changed,
- * or extension element namespaces changed.
- * This will trigger creation of new infos
- * for literal result elements.
- */
- int nsChanged;
- int preserveWhitespace;
- int stripWhitespace;
- int isRoot; /* whether this is the stylesheet's root node */
- int forwardsCompat; /* whether forwards-compatible mode is enabled */
- /* whether the content of an extension element was processed */
- int extContentHandled;
- /* the type of the current child */
- xsltStyleType curChildType;
-};
-
-#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt)
-
-typedef enum {
- XSLT_ERROR_SEVERITY_ERROR = 0,
- XSLT_ERROR_SEVERITY_WARNING
-} xsltErrorSeverityType;
-
-typedef struct _xsltCompilerCtxt xsltCompilerCtxt;
-typedef xsltCompilerCtxt *xsltCompilerCtxtPtr;
-struct _xsltCompilerCtxt {
- void *errorCtxt; /* user specific error context */
- /*
- * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */
- xsltErrorSeverityType errSeverity;
- int warnings; /* TODO: number of warnings found at
- compilation */
- int errors; /* TODO: number of errors found at
- compilation */
- xmlDictPtr dict;
- xsltStylesheetPtr style;
- int simplified; /* whether this is a simplified stylesheet */
- /* TODO: structured/unstructured error contexts. */
- int depth; /* Current depth of processing */
-
- xsltCompilerNodeInfoPtr inode;
- xsltCompilerNodeInfoPtr inodeList;
- xsltCompilerNodeInfoPtr inodeLast;
- xsltPointerListPtr tmpList; /* Used for various purposes */
- /*
- * The XSLT version as specified by the stylesheet's root element.
- */
- int isInclude;
- int hasForwardsCompat; /* whether forwards-compatible mode was used
- in a parsing episode */
- int maxNodeInfos; /* TEMP TODO: just for the interest */
- int maxLREs; /* TEMP TODO: just for the interest */
- /*
- * In order to keep the old behaviour, applying strict rules of
- * the spec can be turned off. This has effect only on special
- * mechanisms like whitespace-stripping in the stylesheet.
- */
- int strict;
- xsltPrincipalStylesheetDataPtr psData;
-#ifdef XSLT_REFACTORED_XPATHCOMP
- xmlXPathContextPtr xpathCtxt;
-#endif
- xsltStyleItemUknownPtr unknownItem;
- int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
- xsltNsAliasPtr nsAliases;
-};
-
-#else /* XSLT_REFACTORED */
-/*
-* The old structures before refactoring.
-*/
-
-/**
- * _xsltStylePreComp:
- *
- * The in-memory structure corresponding to XSLT stylesheet constructs
- * precomputed data.
- */
-struct _xsltStylePreComp {
- xsltElemPreCompPtr next; /* chained list */
- xsltStyleType type; /* type of the element */
- xsltTransformFunction func; /* handling function */
- xmlNodePtr inst; /* the instruction */
-
- /*
- * Pre computed values.
- */
-
- const xmlChar *stype; /* sort */
- int has_stype; /* sort */
- int number; /* sort */
- const xmlChar *order; /* sort */
- int has_order; /* sort */
- int descending; /* sort */
- const xmlChar *lang; /* sort */
- int has_lang; /* sort */
- const xmlChar *case_order; /* sort */
- int lower_first; /* sort */
-
- const xmlChar *use; /* copy, element */
- int has_use; /* copy, element */
-
- int noescape; /* text */
-
- const xmlChar *name; /* element, attribute, pi */
- int has_name; /* element, attribute, pi */
- const xmlChar *ns; /* element */
- int has_ns; /* element */
-
- const xmlChar *mode; /* apply-templates */
- const xmlChar *modeURI; /* apply-templates */
-
- const xmlChar *test; /* if */
-
- xsltTemplatePtr templ; /* call-template */
-
- const xmlChar *select; /* sort, copy-of, value-of, apply-templates */
-
- int ver11; /* document */
- const xmlChar *filename; /* document URL */
- int has_filename; /* document */
-
- xsltNumberData numdata; /* number */
-
- xmlXPathCompExprPtr comp; /* a precompiled XPath expression */
- xmlNsPtr *nsList; /* the namespaces in scope */
- int nsNr; /* the number of namespaces in scope */
-};
-
-#endif /* XSLT_REFACTORED */
-
-/*
- * The in-memory structure corresponding to an XSLT Variable
- * or Param.
- */
-typedef struct _xsltStackElem xsltStackElem;
-typedef xsltStackElem *xsltStackElemPtr;
-struct _xsltStackElem {
- struct _xsltStackElem *next;/* chained list */
- xsltStylePreCompPtr comp; /* the compiled form */
- int computed; /* was the evaluation done */
- const xmlChar *name; /* the local part of the name QName */
- const xmlChar *nameURI; /* the URI part of the name QName */
- const xmlChar *select; /* the eval string */
- xmlNodePtr tree; /* the tree if no eval string or the location */
- xmlXPathObjectPtr value; /* The value if computed */
-};
-
-#ifdef XSLT_REFACTORED
-
-struct _xsltPrincipalStylesheetData {
- /*
- * Namespace dictionary for ns-prefixes and ns-names:
- * TODO: Shared between stylesheets, and XPath mechanisms.
- * Not used yet.
- */
- xmlDictPtr namespaceDict;
- /*
- * Global list of in-scope namespaces.
- */
- xsltPointerListPtr inScopeNamespaces;
- /*
- * Global list of information for [xsl:]excluded-result-prefixes.
- */
- xsltPointerListPtr exclResultNamespaces;
- /*
- * Global list of information for [xsl:]extension-element-prefixes.
- */
- xsltPointerListPtr extElemNamespaces;
- xsltEffectiveNsPtr effectiveNs;
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
- /*
- * Namespace name map to get rid of string comparison of namespace names.
- */
- xsltNsMapPtr nsMap;
-#endif
-};
-
-
-#endif
-/*
- * Note that we added a @compCtxt field to anchor an stylesheet compilation
- * context, since, due to historical reasons, various compile-time function
- * take only the stylesheet as argument and not a compilation context.
- */
-struct _xsltStylesheet {
- /*
- * The stylesheet import relation is kept as a tree.
- */
- struct _xsltStylesheet *parent;
- struct _xsltStylesheet *next;
- struct _xsltStylesheet *imports;
-
- xsltDocumentPtr docList; /* the include document list */
-
- /*
- * General data on the style sheet document.
- */
- xmlDocPtr doc; /* the parsed XML stylesheet */
- xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and
- preserve space elements */
- int stripAll; /* strip-space * (1) preserve-space * (-1) */
- xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */
-
- /*
- * Global variable or parameters.
- */
- xsltStackElemPtr variables; /* linked list of param and variables */
-
- /*
- * Template descriptions.
- */
- xsltTemplatePtr templates; /* the ordered list of templates */
- void *templatesHash; /* hash table or wherever compiled templates
- informations are stored */
- void *rootMatch; /* template based on / */
- void *keyMatch; /* template based on key() */
- void *elemMatch; /* template based on * */
- void *attrMatch; /* template based on @* */
- void *parentMatch; /* template based on .. */
- void *textMatch; /* template based on text() */
- void *piMatch; /* template based on processing-instruction() */
- void *commentMatch; /* template based on comment() */
-
- /*
- * Namespace aliases.
- * NOTE: Not used in the refactored code.
- */
- xmlHashTablePtr nsAliases; /* the namespace alias hash tables */
-
- /*
- * Attribute sets.
- */
- xmlHashTablePtr attributeSets;/* the attribute sets hash tables */
-
- /*
- * Namespaces.
- * TODO: Eliminate this.
- */
- xmlHashTablePtr nsHash; /* the set of namespaces in use:
- ATTENTION: This is used for
- execution of XPath expressions; unfortunately
- it restricts the stylesheet to have distinct
- prefixes.
- TODO: We need to get rid of this.
- */
- void *nsDefs; /* ATTENTION TODO: This is currently used to store
- xsltExtDefPtr (in extensions.c) and
- *not* xmlNsPtr.
- */
-
- /*
- * Key definitions.
- */
- void *keys; /* key definitions */
-
- /*
- * Output related stuff.
- */
- xmlChar *method; /* the output method */
- xmlChar *methodURI; /* associated namespace if any */
- xmlChar *version; /* version string */
- xmlChar *encoding; /* encoding string */
- int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */
-
- /*
- * Number formatting.
- */
- xsltDecimalFormatPtr decimalFormat;
- int standalone; /* standalone = "yes" | "no" */
- xmlChar *doctypePublic; /* doctype-public string */
- xmlChar *doctypeSystem; /* doctype-system string */
- int indent; /* should output being indented */
- xmlChar *mediaType; /* media-type string */
-
- /*
- * Precomputed blocks.
- */
- xsltElemPreCompPtr preComps;/* list of precomputed blocks */
- int warnings; /* number of warnings found at compilation */
- int errors; /* number of errors found at compilation */
-
- xmlChar *exclPrefix; /* last excluded prefixes */
- xmlChar **exclPrefixTab; /* array of excluded prefixes */
- int exclPrefixNr; /* number of excluded prefixes in scope */
- int exclPrefixMax; /* size of the array */
-
- void *_private; /* user defined data */
-
- /*
- * Extensions.
- */
- xmlHashTablePtr extInfos; /* the extension data */
- int extrasNr; /* the number of extras required */
-
- /*
- * For keeping track of nested includes
- */
- xsltDocumentPtr includes; /* points to last nested include */
-
- /*
- * dictionary: shared between stylesheet, context and documents.
- */
- xmlDictPtr dict;
- /*
- * precompiled attribute value templates.
- */
- void *attVTs;
- /*
- * if namespace-alias has an alias for the default stylesheet prefix
- * NOTE: Not used in the refactored code.
- */
- const xmlChar *defaultAlias;
- /*
- * bypass pre-processing (already done) (used in imports)
- */
- int nopreproc;
- /*
- * all document text strings were internalized
- */
- int internalized;
- /*
- * Literal Result Element as Stylesheet c.f. section 2.3
- */
- int literal_result;
- /*
- * The principal stylesheet
- */
- xsltStylesheetPtr principal;
-#ifdef XSLT_REFACTORED
- /*
- * Compilation context used during compile-time.
- */
- xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */
-
- xsltPrincipalStylesheetDataPtr principalData;
-#endif
-};
-
-/*
- * The in-memory structure corresponding to an XSLT Transformation.
- */
-typedef enum {
- XSLT_OUTPUT_XML = 0,
- XSLT_OUTPUT_HTML,
- XSLT_OUTPUT_TEXT
-} xsltOutputType;
-
-typedef enum {
- XSLT_STATE_OK = 0,
- XSLT_STATE_ERROR,
- XSLT_STATE_STOPPED
-} xsltTransformState;
-
-struct _xsltTransformContext {
- xsltStylesheetPtr style; /* the stylesheet used */
- xsltOutputType type; /* the type of output */
-
- xsltTemplatePtr templ; /* the current template */
- int templNr; /* Nb of templates in the stack */
- int templMax; /* Size of the templtes stack */
- xsltTemplatePtr *templTab; /* the template stack */
-
- xsltStackElemPtr vars; /* the current variable list */
- int varsNr; /* Nb of variable list in the stack */
- int varsMax; /* Size of the variable list stack */
- xsltStackElemPtr *varsTab; /* the variable list stack */
- int varsBase; /* the var base for current templ */
-
- /*
- * Extensions
- */
- xmlHashTablePtr extFunctions; /* the extension functions */
- xmlHashTablePtr extElements; /* the extension elements */
- xmlHashTablePtr extInfos; /* the extension data */
-
- const xmlChar *mode; /* the current mode */
- const xmlChar *modeURI; /* the current mode URI */
-
- xsltDocumentPtr docList; /* the document list */
-
- xsltDocumentPtr document; /* the current document */
- xmlNodePtr node; /* the current node being processed */
- xmlNodeSetPtr nodeList; /* the current node list */
- /* xmlNodePtr current; the node */
-
- xmlDocPtr output; /* the resulting document */
- xmlNodePtr insert; /* the insertion node */
-
- xmlXPathContextPtr xpathCtxt; /* the XPath context */
- xsltTransformState state; /* the current state */
-
- /*
- * Global variables
- */
- xmlHashTablePtr globalVars; /* the global variables and params */
-
- xmlNodePtr inst; /* the instruction in the stylesheet */
-
- int xinclude; /* should XInclude be processed */
-
- const char * outputFile; /* the output URI if known */
-
- int profile; /* is this run profiled */
- long prof; /* the current profiled value */
- int profNr; /* Nb of templates in the stack */
- int profMax; /* Size of the templtaes stack */
- long *profTab; /* the profile template stack */
-
- void *_private; /* user defined data */
-
- int extrasNr; /* the number of extras used */
- int extrasMax; /* the number of extras allocated */
- xsltRuntimeExtraPtr extras; /* extra per runtime informations */
-
- xsltDocumentPtr styleList; /* the stylesheet docs list */
- void * sec; /* the security preferences if any */
-
- xmlGenericErrorFunc error; /* a specific error handler */
- void * errctx; /* context for the error handler */
-
- xsltSortFunc sortfunc; /* a ctxt specific sort routine */
-
- /*
- * handling of temporary Result Value Tree
- */
- xmlDocPtr tmpRVT; /* list of RVT without persistance */
- xmlDocPtr persistRVT; /* list of persistant RVTs */
- int ctxtflags; /* context processing flags */
-
- /*
- * Speed optimization when coalescing text nodes
- */
- const xmlChar *lasttext; /* last text node content */
- unsigned int lasttsize; /* last text node size */
- unsigned int lasttuse; /* last text node use */
- /*
- * Per Context Debugging
- */
- int debugStatus; /* the context level debug status */
- unsigned long* traceCode; /* pointer to the variable holding the mask */
-
- int parserOptions; /* parser options xmlParserOption */
-
- /*
- * dictionnary: shared between stylesheet, context and documents.
- */
- xmlDictPtr dict;
- /*
- * temporary storage for doc ptr, currently only used for
- * global var evaluation
- */
- xmlDocPtr tmpDoc;
- /*
- * all document text strings are internalized
- */
- int internalized;
- int nbKeys;
- int hasTemplKeyPatterns;
-};
-
-/**
- * CHECK_STOPPED:
- *
- * Macro to check if the XSLT processing should be stopped.
- * Will return from the function.
- */
-#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return;
-
-/**
- * CHECK_STOPPEDE:
- *
- * Macro to check if the XSLT processing should be stopped.
- * Will goto the error: label.
- */
-#define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error;
-
-/**
- * CHECK_STOPPED0:
- *
- * Macro to check if the XSLT processing should be stopped.
- * Will return from the function with a 0 value.
- */
-#define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0);
-
-/*
- * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about
- * possible incompatibilities between function pointers and object
- * pointers. It is defined in libxml/hash.h within recent versions
- * of libxml2, but is put here for compatibility.
- */
-#ifndef XML_CAST_FPTR
-/**
- * XML_CAST_FPTR:
- * @fptr: pointer to a function
- *
- * Macro to do a casting from an object pointer to a
- * function pointer without encountering a warning from
- * gcc
- *
- * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr))
- * This macro violated ISO C aliasing rules (gcc4 on s390 broke)
- * so it is disabled now
- */
-
-#define XML_CAST_FPTR(fptr) fptr
-#endif
-/*
- * Functions associated to the internal types
-xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet,
- xmlChar *name);
- */
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltNewStylesheet (void);
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltParseStylesheetFile (const xmlChar* filename);
-XSLTPUBFUN void XSLTCALL
- xsltFreeStylesheet (xsltStylesheetPtr style);
-XSLTPUBFUN int XSLTCALL
- xsltIsBlank (xmlChar *str);
-XSLTPUBFUN void XSLTCALL
- xsltFreeStackElemList (xsltStackElemPtr elem);
-XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL
- xsltDecimalFormatGetByName(xsltStylesheetPtr style,
- xmlChar *name);
-
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltParseStylesheetProcess(xsltStylesheetPtr ret,
- xmlDocPtr doc);
-XSLTPUBFUN void XSLTCALL
- xsltParseStylesheetOutput(xsltStylesheetPtr style,
- xmlNodePtr cur);
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltParseStylesheetDoc (xmlDocPtr doc);
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltParseStylesheetImportedDoc(xmlDocPtr doc,
- xsltStylesheetPtr style);
-XSLTPUBFUN xsltStylesheetPtr XSLTCALL
- xsltLoadStylesheetPI (xmlDocPtr doc);
-XSLTPUBFUN void XSLTCALL
- xsltNumberFormat (xsltTransformContextPtr ctxt,
- xsltNumberDataPtr data,
- xmlNodePtr node);
-XSLTPUBFUN xmlXPathError XSLTCALL
- xsltFormatNumberConversion(xsltDecimalFormatPtr self,
- xmlChar *format,
- double number,
- xmlChar **result);
-
-XSLTPUBFUN void XSLTCALL
- xsltParseTemplateContent(xsltStylesheetPtr style,
- xmlNodePtr templ);
-XSLTPUBFUN int XSLTCALL
- xsltAllocateExtra (xsltStylesheetPtr style);
-XSLTPUBFUN int XSLTCALL
- xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt);
-/*
- * Extra functions for Result Value Trees
- */
-XSLTPUBFUN xmlDocPtr XSLTCALL
- xsltCreateRVT (xsltTransformContextPtr ctxt);
-XSLTPUBFUN int XSLTCALL
- xsltRegisterTmpRVT (xsltTransformContextPtr ctxt,
- xmlDocPtr RVT);
-XSLTPUBFUN int XSLTCALL
- xsltRegisterPersistRVT (xsltTransformContextPtr ctxt,
- xmlDocPtr RVT);
-XSLTPUBFUN void XSLTCALL
- xsltFreeRVTs (xsltTransformContextPtr ctxt);
-
-/*
- * Extra functions for Attribute Value Templates
- */
-XSLTPUBFUN void XSLTCALL
- xsltCompileAttr (xsltStylesheetPtr style,
- xmlAttrPtr attr);
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltEvalAVT (xsltTransformContextPtr ctxt,
- void *avt,
- xmlNodePtr node);
-XSLTPUBFUN void XSLTCALL
- xsltFreeAVTList (void *avt);
-
-/*
- * Extra function for successful xsltCleanupGlobals / xsltInit sequence.
- */
-
-XSLTPUBFUN void XSLTCALL
- xsltUninit (void);
-
-/************************************************************************
- * *
- * Compile-time functions for *internal* use only *
- * *
- ************************************************************************/
-
-#ifdef XSLT_REFACTORED
-XSLTPUBFUN void XSLTCALL
- xsltParseSequenceConstructor(
- xsltCompilerCtxtPtr cctxt,
- xmlNodePtr start);
-XSLTPUBFUN int XSLTCALL
- xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem);
-#ifdef XSLT_REFACTORED_XSLT_NSCOMP
-XSLTPUBFUN int XSLTCALL
- xsltRestoreDocumentNamespaces(
- xsltNsMapPtr ns,
- xmlDocPtr doc);
-#endif
-#endif /* XSLT_REFACTORED */
-
-/************************************************************************
- * *
- * Transformation-time functions for *internal* use only *
- * *
- ************************************************************************/
-XSLTPUBFUN int XSLTCALL
- xsltInitCtxtKey (xsltTransformContextPtr ctxt,
- xsltDocumentPtr doc,
- xsltKeyDefPtr keyd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XML_XSLT_H__ */
-
+/*\r
+ * Summary: internal data structures, constants and functions\r
+ * Description: Internal data structures, constants and functions used\r
+ * by the XSLT engine. \r
+ * They are not part of the API or ABI, i.e. they can change\r
+ * without prior notice, use carefully.\r
+ *\r
+ * Copy: See Copyright for the status of this software.\r
+ *\r
+ * Author: Daniel Veillard\r
+ */\r
+\r
+#ifndef __XML_XSLT_INTERNALS_H__\r
+#define __XML_XSLT_INTERNALS_H__\r
+\r
+#include <libxml/tree.h>\r
+#include <libxml/hash.h>\r
+#include <libxml/xpath.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/dict.h>\r
+#include <libxml/xmlstring.h>\r
+#include <libxslt/xslt.h>\r
+#include "xsltexports.h"\r
+#include "numbersInternals.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* #define XSLT_DEBUG_PROFILE_CACHE */\r
+\r
+#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \\r
+ (((n)->type == XML_TEXT_NODE) || \\r
+ ((n)->type == XML_CDATA_SECTION_NODE)))\r
+\r
+\r
+#define XSLT_MARK_RES_TREE_FRAG(n) \\r
+ (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");\r
+\r
+#define XSLT_IS_RES_TREE_FRAG(n) \\r
+ ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \\r
+ ((n)->name != NULL) && ((n)->name[0] == ' '))\r
+\r
+/**\r
+ * XSLT_REFACTORED_KEYCOMP:\r
+ *\r
+ * Internal define to enable on-demand xsl:key computation.\r
+ */\r
+#define XSLT_REFACTORED_KEYCOMP\r
+\r
+/**\r
+ * XSLT_FAST_IF:\r
+ *\r
+ * Internal define to enable usage of xmlXPathCompiledEvalToBoolean()\r
+ * for XSLT "tests"; e.g. in <xsl:if test="/foo/bar">\r
+ */\r
+#define XSLT_FAST_IF\r
+\r
+/**\r
+ * XSLT_REFACTORED:\r
+ *\r
+ * Internal define to enable the refactored parts of Libxslt.\r
+ */\r
+/* #define XSLT_REFACTORED */\r
+/* ==================================================================== */\r
+\r
+#define XSLT_REFACTORED_VARS\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+extern const xmlChar *xsltXSLTAttrMarker;\r
+\r
+\r
+/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */\r
+\r
+/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */\r
+\r
+/**\r
+ * XSLT_REFACTORED_XSLT_NSCOMP\r
+ *\r
+ * Internal define to enable the pointer-comparison of\r
+ * namespaces of XSLT elements. \r
+ */\r
+/* #define XSLT_REFACTORED_XSLT_NSCOMP */\r
+\r
+/**\r
+ * XSLT_REFACTORED_XPATHCOMP\r
+ *\r
+ * Internal define to enable the optimization of the\r
+ * compilation of XPath expressions.\r
+ */\r
+#define XSLT_REFACTORED_XPATHCOMP\r
+\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+\r
+extern const xmlChar *xsltConstNamespaceNameXSLT;\r
+\r
+#define IS_XSLT_ELEM_FAST(n) \\r
+ (((n) != NULL) && ((n)->ns != NULL) && \\r
+ ((n)->ns->href == xsltConstNamespaceNameXSLT))\r
+\r
+#define IS_XSLT_ATTR_FAST(a) \\r
+ (((a) != NULL) && ((a)->ns != NULL) && \\r
+ ((a)->ns->href == xsltConstNamespaceNameXSLT))\r
+\r
+#define XSLT_HAS_INTERNAL_NSMAP(s) \\r
+ (((s) != NULL) && ((s)->principal) && \\r
+ ((s)->principal->principalData) && \\r
+ ((s)->principal->principalData->nsMap))\r
+\r
+#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap)\r
+\r
+#else /* XSLT_REFACTORED_XSLT_NSCOMP */\r
+\r
+#define IS_XSLT_ELEM_FAST(n) \\r
+ (((n) != NULL) && ((n)->ns != NULL) && \\r
+ (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))\r
+\r
+#define IS_XSLT_ATTR_FAST(a) \\r
+ (((a) != NULL) && ((a)->ns != NULL) && \\r
+ (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE)))\r
+\r
+\r
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */\r
+\r
+\r
+/**\r
+ * XSLT_REFACTORED_MANDATORY_VERSION:\r
+ *\r
+ * TODO: Currently disabled to surpress regression test failures, since\r
+ * the old behaviour was that a missing version attribute\r
+ * produced a only a warning and not an error, which was incerrect.\r
+ * So the regression tests need to be fixed if this is enabled.\r
+ */\r
+/* #define XSLT_REFACTORED_MANDATORY_VERSION */\r
+\r
+/**\r
+ * xsltPointerList:\r
+ *\r
+ * Pointer-list for various purposes.\r
+ */\r
+typedef struct _xsltPointerList xsltPointerList;\r
+typedef xsltPointerList *xsltPointerListPtr;\r
+struct _xsltPointerList {\r
+ void **items;\r
+ int number;\r
+ int size;\r
+};\r
+\r
+#endif\r
+\r
+/**\r
+ * XSLT_REFACTORED_PARSING:\r
+ *\r
+ * Internal define to enable the refactored parts of Libxslt\r
+ * related to parsing.\r
+ */\r
+/* #define XSLT_REFACTORED_PARSING */\r
+\r
+/**\r
+ * XSLT_MAX_SORT:\r
+ *\r
+ * Max number of specified xsl:sort on an element.\r
+ */\r
+#define XSLT_MAX_SORT 15\r
+\r
+/**\r
+ * XSLT_PAT_NO_PRIORITY:\r
+ *\r
+ * Specific value for pattern without priority expressed.\r
+ */\r
+#define XSLT_PAT_NO_PRIORITY -12345789\r
+\r
+/**\r
+ * xsltRuntimeExtra:\r
+ *\r
+ * Extra information added to the transformation context.\r
+ */\r
+typedef struct _xsltRuntimeExtra xsltRuntimeExtra;\r
+typedef xsltRuntimeExtra *xsltRuntimeExtraPtr;\r
+struct _xsltRuntimeExtra {\r
+ void *info; /* pointer to the extra data */\r
+ xmlFreeFunc deallocate; /* pointer to the deallocation routine */\r
+ union { /* dual-purpose field */\r
+ void *ptr; /* data not needing deallocation */\r
+ int ival; /* integer value storage */\r
+ } val;\r
+};\r
+\r
+/**\r
+ * XSLT_RUNTIME_EXTRA_LST:\r
+ * @ctxt: the transformation context\r
+ * @nr: the index\r
+ *\r
+ * Macro used to access extra information stored in the context\r
+ */\r
+#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info\r
+/**\r
+ * XSLT_RUNTIME_EXTRA_FREE:\r
+ * @ctxt: the transformation context\r
+ * @nr: the index\r
+ *\r
+ * Macro used to free extra information stored in the context\r
+ */\r
+#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate\r
+/**\r
+ * XSLT_RUNTIME_EXTRA:\r
+ * @ctxt: the transformation context\r
+ * @nr: the index\r
+ *\r
+ * Macro used to define extra information stored in the context\r
+ */\r
+#define XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ\r
+\r
+/**\r
+ * xsltTemplate:\r
+ *\r
+ * The in-memory structure corresponding to an XSLT Template.\r
+ */\r
+typedef struct _xsltTemplate xsltTemplate;\r
+typedef xsltTemplate *xsltTemplatePtr;\r
+struct _xsltTemplate {\r
+ struct _xsltTemplate *next;/* chained list sorted by priority */\r
+ struct _xsltStylesheet *style;/* the containing stylesheet */\r
+ xmlChar *match; /* the matching string */\r
+ float priority; /* as given from the stylesheet, not computed */\r
+ const xmlChar *name; /* the local part of the name QName */\r
+ const xmlChar *nameURI; /* the URI part of the name QName */\r
+ const xmlChar *mode;/* the local part of the mode QName */\r
+ const xmlChar *modeURI;/* the URI part of the mode QName */\r
+ xmlNodePtr content; /* the template replacement value */\r
+ xmlNodePtr elem; /* the source element */\r
+\r
+ /*\r
+ * TODO: @inheritedNsNr and @inheritedNs won't be used in the\r
+ * refactored code.\r
+ */\r
+ int inheritedNsNr; /* number of inherited namespaces */\r
+ xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */\r
+\r
+ /* Profiling informations */\r
+ int nbCalls; /* the number of time the template was called */\r
+ unsigned long time; /* the time spent in this template */\r
+ void *params; /* xsl:param instructions */\r
+};\r
+\r
+/**\r
+ * xsltDecimalFormat:\r
+ *\r
+ * Data structure of decimal-format.\r
+ */\r
+typedef struct _xsltDecimalFormat xsltDecimalFormat;\r
+typedef xsltDecimalFormat *xsltDecimalFormatPtr;\r
+struct _xsltDecimalFormat {\r
+ struct _xsltDecimalFormat *next; /* chained list */\r
+ xmlChar *name;\r
+ /* Used for interpretation of pattern */\r
+ xmlChar *digit;\r
+ xmlChar *patternSeparator;\r
+ /* May appear in result */\r
+ xmlChar *minusSign;\r
+ xmlChar *infinity;\r
+ xmlChar *noNumber; /* Not-a-number */\r
+ /* Used for interpretation of pattern and may appear in result */\r
+ xmlChar *decimalPoint;\r
+ xmlChar *grouping;\r
+ xmlChar *percent;\r
+ xmlChar *permille;\r
+ xmlChar *zeroDigit;\r
+};\r
+\r
+/**\r
+ * xsltDocument:\r
+ *\r
+ * Data structure associated to a parsed document.\r
+ */\r
+typedef struct _xsltDocument xsltDocument;\r
+typedef xsltDocument *xsltDocumentPtr;\r
+struct _xsltDocument {\r
+ struct _xsltDocument *next; /* documents are kept in a chained list */\r
+ int main; /* is this the main document */\r
+ xmlDocPtr doc; /* the parsed document */\r
+ void *keys; /* key tables storage */\r
+ struct _xsltDocument *includes; /* subsidiary includes */\r
+ int preproc; /* pre-processing already done */\r
+ int nbKeysComputed;\r
+};\r
+\r
+/**\r
+ * xsltKeyDef:\r
+ *\r
+ * Representation of an xsl:key.\r
+ */\r
+typedef struct _xsltKeyDef xsltKeyDef;\r
+typedef xsltKeyDef *xsltKeyDefPtr;\r
+struct _xsltKeyDef {\r
+ struct _xsltKeyDef *next;\r
+ xmlNodePtr inst;\r
+ xmlChar *name;\r
+ xmlChar *nameURI;\r
+ xmlChar *match;\r
+ xmlChar *use;\r
+ xmlXPathCompExprPtr comp;\r
+ xmlXPathCompExprPtr usecomp;\r
+ xmlNsPtr *nsList; /* the namespaces in scope */\r
+ int nsNr; /* the number of namespaces in scope */\r
+};\r
+\r
+/**\r
+ * xsltKeyTable:\r
+ *\r
+ * Holds the computed keys for key definitions of the same QName.\r
+ * Is owned by an xsltDocument.\r
+ */\r
+typedef struct _xsltKeyTable xsltKeyTable;\r
+typedef xsltKeyTable *xsltKeyTablePtr;\r
+struct _xsltKeyTable {\r
+ struct _xsltKeyTable *next;\r
+ xmlChar *name;\r
+ xmlChar *nameURI;\r
+ xmlHashTablePtr keys;\r
+};\r
+\r
+/*\r
+ * The in-memory structure corresponding to an XSLT Stylesheet.\r
+ * NOTE: most of the content is simply linked from the doc tree\r
+ * structure, no specific allocation is made.\r
+ */\r
+typedef struct _xsltStylesheet xsltStylesheet;\r
+typedef xsltStylesheet *xsltStylesheetPtr;\r
+\r
+typedef struct _xsltTransformContext xsltTransformContext;\r
+typedef xsltTransformContext *xsltTransformContextPtr;\r
+\r
+/**\r
+ * xsltElemPreComp:\r
+ *\r
+ * The in-memory structure corresponding to element precomputed data,\r
+ * designed to be extended by extension implementors.\r
+ */\r
+typedef struct _xsltElemPreComp xsltElemPreComp;\r
+typedef xsltElemPreComp *xsltElemPreCompPtr;\r
+\r
+/**\r
+ * xsltTransformFunction:\r
+ * @ctxt: the XSLT transformation context\r
+ * @node: the input node\r
+ * @inst: the stylesheet node\r
+ * @comp: the compiled information from the stylesheet\r
+ *\r
+ * Signature of the function associated to elements part of the\r
+ * stylesheet language like xsl:if or xsl:apply-templates.\r
+ */\r
+typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node,\r
+ xmlNodePtr inst,\r
+ xsltElemPreCompPtr comp);\r
+\r
+/**\r
+ * xsltSortFunc:\r
+ * @ctxt: a transformation context\r
+ * @sorts: the node-set to sort\r
+ * @nbsorts: the number of sorts\r
+ *\r
+ * Signature of the function to use during sorting\r
+ */\r
+typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts,\r
+ int nbsorts);\r
+\r
+typedef enum {\r
+ XSLT_FUNC_COPY=1,\r
+ XSLT_FUNC_SORT,\r
+ XSLT_FUNC_TEXT,\r
+ XSLT_FUNC_ELEMENT,\r
+ XSLT_FUNC_ATTRIBUTE,\r
+ XSLT_FUNC_COMMENT,\r
+ XSLT_FUNC_PI,\r
+ XSLT_FUNC_COPYOF,\r
+ XSLT_FUNC_VALUEOF,\r
+ XSLT_FUNC_NUMBER,\r
+ XSLT_FUNC_APPLYIMPORTS,\r
+ XSLT_FUNC_CALLTEMPLATE,\r
+ XSLT_FUNC_APPLYTEMPLATES,\r
+ XSLT_FUNC_CHOOSE,\r
+ XSLT_FUNC_IF,\r
+ XSLT_FUNC_FOREACH,\r
+ XSLT_FUNC_DOCUMENT,\r
+ XSLT_FUNC_WITHPARAM,\r
+ XSLT_FUNC_PARAM,\r
+ XSLT_FUNC_VARIABLE,\r
+ XSLT_FUNC_WHEN,\r
+ XSLT_FUNC_EXTENSION,\r
+#ifdef XSLT_REFACTORED\r
+ XSLT_FUNC_OTHERWISE,\r
+ XSLT_FUNC_FALLBACK,\r
+ XSLT_FUNC_MESSAGE,\r
+ XSLT_FUNC_INCLUDE,\r
+ XSLT_FUNC_ATTRSET,\r
+ XSLT_FUNC_LITERAL_RESULT_ELEMENT,\r
+ XSLT_FUNC_UNKOWN_FORWARDS_COMPAT,\r
+#endif\r
+} xsltStyleType;\r
+\r
+/**\r
+ * xsltElemPreCompDeallocator:\r
+ * @comp: the #xsltElemPreComp to free up\r
+ *\r
+ * Deallocates an #xsltElemPreComp structure.\r
+ */\r
+typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp);\r
+\r
+/**\r
+ * xsltElemPreComp:\r
+ *\r
+ * The basic structure for compiled items of the AST of the XSLT processor.\r
+ * This structure is also intended to be extended by extension implementors.\r
+ * TODO: This is somehow not nice, since it has a "free" field, which\r
+ * derived stylesheet-structs do not have.\r
+ */\r
+struct _xsltElemPreComp {\r
+ xsltElemPreCompPtr next; /* next item in the global chained\r
+ list hold by xsltStylesheet. */\r
+ xsltStyleType type; /* type of the element */\r
+ xsltTransformFunction func; /* handling function */\r
+ xmlNodePtr inst; /* the node in the stylesheet's tree\r
+ corresponding to this item */\r
+\r
+ /* end of common part */\r
+ xsltElemPreCompDeallocator free; /* the deallocator */\r
+};\r
+\r
+/**\r
+ * xsltStylePreComp:\r
+ *\r
+ * The abstract basic structure for items of the XSLT processor.\r
+ * This includes:\r
+ * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.)\r
+ * 2) compiled forms of literal result elements\r
+ * 3) compiled forms of extension elements\r
+ */\r
+typedef struct _xsltStylePreComp xsltStylePreComp;\r
+typedef xsltStylePreComp *xsltStylePreCompPtr;\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+/*\r
+* Some pointer-list utility functions.\r
+*/\r
+XSLTPUBFUN xsltPointerListPtr XSLTCALL\r
+ xsltPointerListCreate (int initialSize);\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltPointerListFree (xsltPointerListPtr list);\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltPointerListClear (xsltPointerListPtr list);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltPointerListAddSize (xsltPointerListPtr list, \r
+ void *item,\r
+ int initialSize);\r
+\r
+/************************************************************************\r
+ * *\r
+ * Refactored structures *\r
+ * *\r
+ ************************************************************************/\r
+\r
+typedef struct _xsltNsListContainer xsltNsListContainer;\r
+typedef xsltNsListContainer *xsltNsListContainerPtr;\r
+struct _xsltNsListContainer {\r
+ xmlNsPtr *list;\r
+ int totalNumber;\r
+ int xpathNumber; \r
+};\r
+\r
+/**\r
+ * XSLT_ITEM_COMPATIBILITY_FIELDS:\r
+ * \r
+ * Fields for API compatibility to the structure\r
+ * _xsltElemPreComp which is used for extension functions.\r
+ * Note that @next is used for storage; it does not reflect a next\r
+ * sibling in the tree.\r
+ * TODO: Evaluate if we really need such a compatibility.\r
+ */\r
+#define XSLT_ITEM_COMPATIBILITY_FIELDS \\r
+ xsltElemPreCompPtr next;\\r
+ xsltStyleType type;\\r
+ xsltTransformFunction func;\\r
+ xmlNodePtr inst;\r
+\r
+/**\r
+ * XSLT_ITEM_NAVIGATION_FIELDS:\r
+ *\r
+ * Currently empty.\r
+ * TODO: It is intended to hold navigational fields in the future.\r
+ */\r
+#define XSLT_ITEM_NAVIGATION_FIELDS\r
+/*\r
+ xsltStylePreCompPtr parent;\\r
+ xsltStylePreCompPtr children;\\r
+ xsltStylePreCompPtr nextItem; \r
+*/\r
+\r
+/**\r
+ * XSLT_ITEM_NSINSCOPE_FIELDS:\r
+ *\r
+ * The in-scope namespaces.\r
+ */\r
+#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs;\r
+\r
+/**\r
+ * XSLT_ITEM_COMMON_FIELDS:\r
+ *\r
+ * Common fields used for all items.\r
+ */\r
+#define XSLT_ITEM_COMMON_FIELDS \\r
+ XSLT_ITEM_COMPATIBILITY_FIELDS \\r
+ XSLT_ITEM_NAVIGATION_FIELDS \\r
+ XSLT_ITEM_NSINSCOPE_FIELDS\r
+\r
+/**\r
+ * _xsltStylePreComp: \r
+ *\r
+ * The abstract basic structure for items of the XSLT processor.\r
+ * This includes:\r
+ * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.)\r
+ * 2) compiled forms of literal result elements\r
+ * 3) various properties for XSLT instructions (e.g. xsl:when,\r
+ * xsl:with-param)\r
+ *\r
+ * REVISIT TODO: Keep this structure equal to the fields\r
+ * defined by XSLT_ITEM_COMMON_FIELDS\r
+ */\r
+struct _xsltStylePreComp {\r
+ xsltElemPreCompPtr next; /* next item in the global chained\r
+ list hold by xsltStylesheet */\r
+ xsltStyleType type; /* type of the item */ \r
+ xsltTransformFunction func; /* handling function */\r
+ xmlNodePtr inst; /* the node in the stylesheet's tree\r
+ corresponding to this item. */\r
+ /* Currently no navigational fields. */\r
+ xsltNsListContainerPtr inScopeNs;\r
+};\r
+\r
+/**\r
+ * xsltStyleBasicEmptyItem:\r
+ * \r
+ * Abstract structure only used as a short-cut for\r
+ * XSLT items with no extra fields.\r
+ * NOTE that it is intended that this structure looks the same as\r
+ * _xsltStylePreComp.\r
+ */\r
+typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem;\r
+typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr;\r
+\r
+struct _xsltStyleBasicEmptyItem {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+};\r
+\r
+/**\r
+ * xsltStyleBasicExpressionItem:\r
+ * \r
+ * Abstract structure only used as a short-cut for\r
+ * XSLT items with just an expression.\r
+ */\r
+typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem;\r
+typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr;\r
+\r
+struct _xsltStyleBasicExpressionItem {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *select; /* TODO: Change this to "expression". */\r
+ xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */\r
+};\r
+\r
+/************************************************************************\r
+ * *\r
+ * XSLT-instructions/declarations *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltStyleItemElement:\r
+ * \r
+ * <!-- Category: instruction -->\r
+ * <xsl:element\r
+ * name = { qname }\r
+ * namespace = { uri-reference }\r
+ * use-attribute-sets = qnames>\r
+ * <!-- Content: template -->\r
+ * </xsl:element>\r
+ */\r
+typedef struct _xsltStyleItemElement xsltStyleItemElement;\r
+typedef xsltStyleItemElement *xsltStyleItemElementPtr;\r
+\r
+struct _xsltStyleItemElement {\r
+ XSLT_ITEM_COMMON_FIELDS \r
+\r
+ const xmlChar *use;\r
+ int has_use;\r
+ const xmlChar *name; \r
+ int has_name;\r
+ const xmlChar *ns;\r
+ const xmlChar *nsPrefix;\r
+ int has_ns;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemAttribute:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:attribute\r
+ * name = { qname }\r
+ * namespace = { uri-reference }>\r
+ * <!-- Content: template -->\r
+ * </xsl:attribute>\r
+ */\r
+typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute;\r
+typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr;\r
+\r
+struct _xsltStyleItemAttribute {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ const xmlChar *name;\r
+ int has_name;\r
+ const xmlChar *ns;\r
+ const xmlChar *nsPrefix;\r
+ int has_ns;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemText:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:text\r
+ * disable-output-escaping = "yes" | "no">\r
+ * <!-- Content: #PCDATA -->\r
+ * </xsl:text>\r
+ */\r
+typedef struct _xsltStyleItemText xsltStyleItemText;\r
+typedef xsltStyleItemText *xsltStyleItemTextPtr;\r
+\r
+struct _xsltStyleItemText {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ int noescape; /* text */\r
+};\r
+\r
+/**\r
+ * xsltStyleItemComment:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:comment>\r
+ * <!-- Content: template -->\r
+ * </xsl:comment>\r
+ */\r
+typedef xsltStyleBasicEmptyItem xsltStyleItemComment;\r
+typedef xsltStyleItemComment *xsltStyleItemCommentPtr;\r
+\r
+/**\r
+ * xsltStyleItemPI:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:processing-instruction\r
+ * name = { ncname }>\r
+ * <!-- Content: template -->\r
+ * </xsl:processing-instruction>\r
+ */\r
+typedef struct _xsltStyleItemPI xsltStyleItemPI;\r
+typedef xsltStyleItemPI *xsltStyleItemPIPtr;\r
+\r
+struct _xsltStyleItemPI {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ const xmlChar *name;\r
+ int has_name;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemApplyImports:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:apply-imports />\r
+ */\r
+typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports;\r
+typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr;\r
+\r
+/**\r
+ * xsltStyleItemApplyTemplates:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:apply-templates\r
+ * select = node-set-expression\r
+ * mode = qname>\r
+ * <!-- Content: (xsl:sort | xsl:with-param)* -->\r
+ * </xsl:apply-templates>\r
+ */\r
+typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates;\r
+typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr;\r
+\r
+struct _xsltStyleItemApplyTemplates {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *mode; /* apply-templates */\r
+ const xmlChar *modeURI; /* apply-templates */\r
+ const xmlChar *select; /* sort, copy-of, value-of, apply-templates */\r
+ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */\r
+ /* TODO: with-params */\r
+};\r
+\r
+/**\r
+ * xsltStyleItemCallTemplate:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:call-template\r
+ * name = qname>\r
+ * <!-- Content: xsl:with-param* -->\r
+ * </xsl:call-template>\r
+ */\r
+typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate;\r
+typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr;\r
+\r
+struct _xsltStyleItemCallTemplate {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ xsltTemplatePtr templ; /* call-template */\r
+ const xmlChar *name; /* element, attribute, pi */\r
+ int has_name; /* element, attribute, pi */\r
+ const xmlChar *ns; /* element */\r
+ int has_ns; /* element */\r
+ /* TODO: with-params */\r
+};\r
+\r
+/**\r
+ * xsltStyleItemCopy:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:copy\r
+ * use-attribute-sets = qnames>\r
+ * <!-- Content: template -->\r
+ * </xsl:copy>\r
+ */\r
+typedef struct _xsltStyleItemCopy xsltStyleItemCopy;\r
+typedef xsltStyleItemCopy *xsltStyleItemCopyPtr;\r
+\r
+struct _xsltStyleItemCopy {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ const xmlChar *use; /* copy, element */\r
+ int has_use; /* copy, element */ \r
+};\r
+\r
+/**\r
+ * xsltStyleItemIf:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:if\r
+ * test = boolean-expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:if>\r
+ */\r
+typedef struct _xsltStyleItemIf xsltStyleItemIf;\r
+typedef xsltStyleItemIf *xsltStyleItemIfPtr;\r
+\r
+struct _xsltStyleItemIf {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *test; /* if */\r
+ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */\r
+};\r
+\r
+\r
+/**\r
+ * xsltStyleItemCopyOf:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:copy-of\r
+ * select = expression />\r
+ */\r
+typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf;\r
+typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr;\r
+\r
+/**\r
+ * xsltStyleItemValueOf:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:value-of\r
+ * select = string-expression\r
+ * disable-output-escaping = "yes" | "no" />\r
+ */\r
+typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf;\r
+typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr;\r
+\r
+struct _xsltStyleItemValueOf {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *select;\r
+ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */\r
+ int noescape;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemNumber:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:number\r
+ * level = "single" | "multiple" | "any"\r
+ * count = pattern\r
+ * from = pattern\r
+ * value = number-expression\r
+ * format = { string }\r
+ * lang = { nmtoken }\r
+ * letter-value = { "alphabetic" | "traditional" }\r
+ * grouping-separator = { char }\r
+ * grouping-size = { number } />\r
+ */\r
+typedef struct _xsltStyleItemNumber xsltStyleItemNumber;\r
+typedef xsltStyleItemNumber *xsltStyleItemNumberPtr;\r
+\r
+struct _xsltStyleItemNumber {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ xsltNumberData numdata; /* number */\r
+};\r
+\r
+/**\r
+ * xsltStyleItemChoose:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:choose>\r
+ * <!-- Content: (xsl:when+, xsl:otherwise?) -->\r
+ * </xsl:choose>\r
+ */\r
+typedef xsltStyleBasicEmptyItem xsltStyleItemChoose;\r
+typedef xsltStyleItemChoose *xsltStyleItemChoosePtr;\r
+\r
+/**\r
+ * xsltStyleItemFallback:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:fallback>\r
+ * <!-- Content: template -->\r
+ * </xsl:fallback>\r
+ */\r
+typedef xsltStyleBasicEmptyItem xsltStyleItemFallback;\r
+typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr;\r
+\r
+/**\r
+ * xsltStyleItemForEach:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:for-each\r
+ * select = node-set-expression>\r
+ * <!-- Content: (xsl:sort*, template) -->\r
+ * </xsl:for-each>\r
+ */\r
+typedef xsltStyleBasicExpressionItem xsltStyleItemForEach;\r
+typedef xsltStyleItemForEach *xsltStyleItemForEachPtr;\r
+\r
+/**\r
+ * xsltStyleItemMessage:\r
+ *\r
+ * <!-- Category: instruction -->\r
+ * <xsl:message\r
+ * terminate = "yes" | "no">\r
+ * <!-- Content: template -->\r
+ * </xsl:message>\r
+ */\r
+typedef struct _xsltStyleItemMessage xsltStyleItemMessage;\r
+typedef xsltStyleItemMessage *xsltStyleItemMessagePtr;\r
+\r
+struct _xsltStyleItemMessage {\r
+ XSLT_ITEM_COMMON_FIELDS \r
+ int terminate;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemDocument:\r
+ *\r
+ * NOTE: This is not an instruction of XSLT 1.0.\r
+ */\r
+typedef struct _xsltStyleItemDocument xsltStyleItemDocument;\r
+typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr;\r
+\r
+struct _xsltStyleItemDocument {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ int ver11; /* assigned: in xsltDocumentComp;\r
+ read: nowhere;\r
+ TODO: Check if we need. */\r
+ const xmlChar *filename; /* document URL */\r
+ int has_filename;\r
+}; \r
+\r
+/************************************************************************\r
+ * *\r
+ * Non-instructions (actually properties of instructions/declarations) *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltStyleBasicItemVariable:\r
+ *\r
+ * Basic struct for xsl:variable, xsl:param and xsl:with-param.\r
+ * It's currently important to have equal fields, since\r
+ * xsltParseStylesheetCallerParam() is used with xsl:with-param from\r
+ * the xslt side and with xsl:param from the exslt side (in\r
+ * exsltFuncFunctionFunction()).\r
+ *\r
+ * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param\r
+ * have additional different fields.\r
+ */\r
+typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable;\r
+typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr;\r
+\r
+struct _xsltStyleBasicItemVariable {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *select;\r
+ xmlXPathCompExprPtr comp;\r
+\r
+ const xmlChar *name;\r
+ int has_name;\r
+ const xmlChar *ns;\r
+ int has_ns;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemVariable:\r
+ *\r
+ * <!-- Category: top-level-element -->\r
+ * <xsl:param\r
+ * name = qname\r
+ * select = expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:param>\r
+ */\r
+typedef xsltStyleBasicItemVariable xsltStyleItemVariable;\r
+typedef xsltStyleItemVariable *xsltStyleItemVariablePtr;\r
+\r
+/**\r
+ * xsltStyleItemParam:\r
+ *\r
+ * <!-- Category: top-level-element -->\r
+ * <xsl:param\r
+ * name = qname\r
+ * select = expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:param>\r
+ */\r
+typedef struct _xsltStyleItemParam xsltStyleItemParam;\r
+typedef xsltStyleItemParam *xsltStyleItemParamPtr;\r
+\r
+struct _xsltStyleItemParam {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *select;\r
+ xmlXPathCompExprPtr comp;\r
+\r
+ const xmlChar *name;\r
+ int has_name;\r
+ const xmlChar *ns;\r
+ int has_ns; \r
+};\r
+\r
+/**\r
+ * xsltStyleItemWithParam:\r
+ *\r
+ * <xsl:with-param\r
+ * name = qname\r
+ * select = expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:with-param>\r
+ */\r
+typedef xsltStyleBasicItemVariable xsltStyleItemWithParam;\r
+typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr;\r
+\r
+/**\r
+ * xsltStyleItemSort:\r
+ *\r
+ * Reflects the XSLT xsl:sort item.\r
+ * Allowed parents: xsl:apply-templates, xsl:for-each\r
+ * <xsl:sort\r
+ * select = string-expression\r
+ * lang = { nmtoken }\r
+ * data-type = { "text" | "number" | qname-but-not-ncname }\r
+ * order = { "ascending" | "descending" }\r
+ * case-order = { "upper-first" | "lower-first" } />\r
+ */\r
+typedef struct _xsltStyleItemSort xsltStyleItemSort;\r
+typedef xsltStyleItemSort *xsltStyleItemSortPtr;\r
+\r
+struct _xsltStyleItemSort {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *stype; /* sort */\r
+ int has_stype; /* sort */\r
+ int number; /* sort */\r
+ const xmlChar *order; /* sort */\r
+ int has_order; /* sort */\r
+ int descending; /* sort */\r
+ const xmlChar *lang; /* sort */\r
+ int has_lang; /* sort */\r
+ const xmlChar *case_order; /* sort */\r
+ int lower_first; /* sort */\r
+\r
+ const xmlChar *use;\r
+ int has_use;\r
+\r
+ const xmlChar *select; /* sort, copy-of, value-of, apply-templates */\r
+\r
+ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */\r
+};\r
+\r
+\r
+/**\r
+ * xsltStyleItemWhen:\r
+ * \r
+ * <xsl:when\r
+ * test = boolean-expression>\r
+ * <!-- Content: template -->\r
+ * </xsl:when>\r
+ * Allowed parent: xsl:choose\r
+ */\r
+typedef struct _xsltStyleItemWhen xsltStyleItemWhen;\r
+typedef xsltStyleItemWhen *xsltStyleItemWhenPtr;\r
+\r
+struct _xsltStyleItemWhen {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+\r
+ const xmlChar *test;\r
+ xmlXPathCompExprPtr comp;\r
+};\r
+\r
+/**\r
+ * xsltStyleItemOtherwise:\r
+ *\r
+ * Allowed parent: xsl:choose\r
+ * <xsl:otherwise>\r
+ * <!-- Content: template -->\r
+ * </xsl:otherwise>\r
+ */\r
+typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise;\r
+typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr;\r
+\r
+struct _xsltStyleItemOtherwise {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+};\r
+\r
+typedef struct _xsltStyleItemInclude xsltStyleItemInclude;\r
+typedef xsltStyleItemInclude *xsltStyleItemIncludePtr;\r
+\r
+struct _xsltStyleItemInclude {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ xsltDocumentPtr include;\r
+};\r
+\r
+/************************************************************************\r
+ * *\r
+ * XSLT elements in forwards-compatible mode *\r
+ * *\r
+ ************************************************************************/\r
+\r
+typedef struct _xsltStyleItemUknown xsltStyleItemUknown;\r
+typedef xsltStyleItemUknown *xsltStyleItemUknownPtr;\r
+struct _xsltStyleItemUknown {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+};\r
+\r
+\r
+/************************************************************************\r
+ * *\r
+ * Extension elements *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/*\r
+ * xsltStyleItemExtElement:\r
+ *\r
+ * Reflects extension elements.\r
+ *\r
+ * NOTE: Due to the fact that the structure xsltElemPreComp is most\r
+ * probably already heavily in use out there by users, so we cannot\r
+ * easily change it, we'll create an intermediate structure which will\r
+ * hold an xsltElemPreCompPtr.\r
+ * BIG NOTE: The only problem I see here is that the user processes the\r
+ * content of the stylesheet tree, possibly he'll lookup the node->psvi\r
+ * fields in order to find subsequent extension functions.\r
+ * In this case, the user's code will break, since the node->psvi\r
+ * field will hold now the xsltStyleItemExtElementPtr and not\r
+ * the xsltElemPreCompPtr.\r
+ * However the place where the structure is anchored in the node-tree,\r
+ * namely node->psvi, has beed already once been moved from node->_private\r
+ * to node->psvi, so we have a precedent here, which, I think, should allow\r
+ * us to change such semantics without headaches.\r
+ */\r
+typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement;\r
+typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr;\r
+struct _xsltStyleItemExtElement {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ xsltElemPreCompPtr item; \r
+};\r
+\r
+/************************************************************************\r
+ * *\r
+ * Literal result elements *\r
+ * *\r
+ ************************************************************************/\r
+\r
+typedef struct _xsltEffectiveNs xsltEffectiveNs;\r
+typedef xsltEffectiveNs *xsltEffectiveNsPtr;\r
+struct _xsltEffectiveNs {\r
+ xsltEffectiveNsPtr nextInStore; /* storage next */\r
+ xsltEffectiveNsPtr next; /* next item in the list */\r
+ const xmlChar *prefix;\r
+ const xmlChar *nsName;\r
+ /* \r
+ * Indicates if eclared on the literal result element; dunno if really\r
+ * needed.\r
+ */\r
+ int holdByElem;\r
+};\r
+\r
+/*\r
+ * Info for literal result elements.\r
+ * This will be set on the elem->psvi field and will be\r
+ * shared by literal result elements, which have the same\r
+ * excluded result namespaces; i.e., this *won't* be created uniquely\r
+ * for every literal result element.\r
+ */\r
+typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo;\r
+typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr;\r
+struct _xsltStyleItemLRElementInfo {\r
+ XSLT_ITEM_COMMON_FIELDS\r
+ /*\r
+ * @effectiveNs is the set of effective ns-nodes\r
+ * on the literal result element, which will be added to the result\r
+ * element if not already existing in the result tree.\r
+ * This means that excluded namespaces (via exclude-result-prefixes,\r
+ * extension-element-prefixes and the XSLT namespace) not added\r
+ * to the set.\r
+ * Namespace-aliasing was applied on the @effectiveNs.\r
+ */\r
+ xsltEffectiveNsPtr effectiveNs;\r
+\r
+};\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+typedef struct _xsltNsAlias xsltNsAlias;\r
+typedef xsltNsAlias *xsltNsAliasPtr;\r
+struct _xsltNsAlias {\r
+ xsltNsAliasPtr next; /* next in the list */ \r
+ xmlNsPtr literalNs;\r
+ xmlNsPtr targetNs;\r
+ xmlDocPtr docOfTargetNs;\r
+};\r
+#endif\r
+\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+\r
+typedef struct _xsltNsMap xsltNsMap;\r
+typedef xsltNsMap *xsltNsMapPtr;\r
+struct _xsltNsMap {\r
+ xsltNsMapPtr next; /* next in the list */\r
+ xmlDocPtr doc;\r
+ xmlNodePtr elem; /* the element holding the ns-decl */\r
+ xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */\r
+ const xmlChar *origNsName; /* the original XML namespace name */\r
+ const xmlChar *newNsName; /* the mapped XML namespace name */ \r
+};\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * Compile-time structures for *internal* use only *\r
+ * *\r
+ ************************************************************************/\r
+\r
+typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData;\r
+typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr;\r
+\r
+typedef struct _xsltNsList xsltNsList;\r
+typedef xsltNsList *xsltNsListPtr;\r
+struct _xsltNsList {\r
+ xsltNsListPtr next; /* next in the list */\r
+ xmlNsPtr ns;\r
+};\r
+\r
+/*\r
+* xsltVarInfo:\r
+*\r
+* Used at compilation time for parameters and variables.\r
+*/\r
+typedef struct _xsltVarInfo xsltVarInfo;\r
+typedef xsltVarInfo *xsltVarInfoPtr;\r
+struct _xsltVarInfo {\r
+ xsltVarInfoPtr next; /* next in the list */\r
+ xsltVarInfoPtr prev;\r
+ int depth; /* the depth in the tree */\r
+ const xmlChar *name;\r
+ const xmlChar *nsName;\r
+};\r
+\r
+#define XSLT_ELEMENT_CATEGORY_XSLT 0\r
+#define XSLT_ELEMENT_CATEGORY_EXTENSION 1\r
+#define XSLT_ELEMENT_CATEGORY_LRE 2\r
+\r
+/**\r
+ * xsltCompilerNodeInfo:\r
+ *\r
+ * Per-node information during compile-time.\r
+ */\r
+typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo;\r
+typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr;\r
+struct _xsltCompilerNodeInfo {\r
+ xsltCompilerNodeInfoPtr next;\r
+ xsltCompilerNodeInfoPtr prev;\r
+ xmlNodePtr node;\r
+ int depth;\r
+ xsltTemplatePtr templ; /* The owning template */\r
+ int category; /* XSLT element, LR-element or\r
+ extension element */\r
+ xsltStyleType type;\r
+ xsltElemPreCompPtr item; /* The compiled information */\r
+ /* The current in-scope namespaces */\r
+ xsltNsListContainerPtr inScopeNs;\r
+ /* The current excluded result namespaces */\r
+ xsltPointerListPtr exclResultNs; \r
+ /* The current extension instruction namespaces */\r
+ xsltPointerListPtr extElemNs;\r
+\r
+ /* The current info for literal result elements. */\r
+ xsltStyleItemLRElementInfoPtr litResElemInfo;\r
+ /* \r
+ * Set to 1 if in-scope namespaces changed,\r
+ * or excluded result namespaces changed,\r
+ * or extension element namespaces changed.\r
+ * This will trigger creation of new infos\r
+ * for literal result elements.\r
+ */\r
+ int nsChanged;\r
+ int preserveWhitespace;\r
+ int stripWhitespace;\r
+ int isRoot; /* whether this is the stylesheet's root node */\r
+ int forwardsCompat; /* whether forwards-compatible mode is enabled */\r
+ /* whether the content of an extension element was processed */\r
+ int extContentHandled;\r
+ /* the type of the current child */\r
+ xsltStyleType curChildType; \r
+};\r
+\r
+#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) \r
+\r
+typedef enum {\r
+ XSLT_ERROR_SEVERITY_ERROR = 0,\r
+ XSLT_ERROR_SEVERITY_WARNING\r
+} xsltErrorSeverityType;\r
+\r
+typedef struct _xsltCompilerCtxt xsltCompilerCtxt;\r
+typedef xsltCompilerCtxt *xsltCompilerCtxtPtr;\r
+struct _xsltCompilerCtxt {\r
+ void *errorCtxt; /* user specific error context */\r
+ /*\r
+ * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */\r
+ xsltErrorSeverityType errSeverity; \r
+ int warnings; /* TODO: number of warnings found at\r
+ compilation */\r
+ int errors; /* TODO: number of errors found at\r
+ compilation */\r
+ xmlDictPtr dict;\r
+ xsltStylesheetPtr style;\r
+ int simplified; /* whether this is a simplified stylesheet */\r
+ /* TODO: structured/unstructured error contexts. */\r
+ int depth; /* Current depth of processing */\r
+ \r
+ xsltCompilerNodeInfoPtr inode;\r
+ xsltCompilerNodeInfoPtr inodeList;\r
+ xsltCompilerNodeInfoPtr inodeLast;\r
+ xsltPointerListPtr tmpList; /* Used for various purposes */\r
+ /*\r
+ * The XSLT version as specified by the stylesheet's root element.\r
+ */\r
+ int isInclude;\r
+ int hasForwardsCompat; /* whether forwards-compatible mode was used\r
+ in a parsing episode */\r
+ int maxNodeInfos; /* TEMP TODO: just for the interest */\r
+ int maxLREs; /* TEMP TODO: just for the interest */\r
+ /* \r
+ * In order to keep the old behaviour, applying strict rules of\r
+ * the spec can be turned off. This has effect only on special\r
+ * mechanisms like whitespace-stripping in the stylesheet.\r
+ */\r
+ int strict;\r
+ xsltPrincipalStylesheetDataPtr psData;\r
+#ifdef XSLT_REFACTORED_XPATHCOMP\r
+ xmlXPathContextPtr xpathCtxt;\r
+#endif\r
+ xsltStyleItemUknownPtr unknownItem;\r
+ int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */\r
+ xsltNsAliasPtr nsAliases;\r
+ xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */\r
+ xsltVarInfoPtr ivar; /* topmost local variable/param. */\r
+}; \r
+\r
+#else /* XSLT_REFACTORED */\r
+/*\r
+* The old structures before refactoring.\r
+*/\r
+\r
+/**\r
+ * _xsltStylePreComp:\r
+ *\r
+ * The in-memory structure corresponding to XSLT stylesheet constructs\r
+ * precomputed data.\r
+ */\r
+struct _xsltStylePreComp {\r
+ xsltElemPreCompPtr next; /* chained list */\r
+ xsltStyleType type; /* type of the element */\r
+ xsltTransformFunction func; /* handling function */\r
+ xmlNodePtr inst; /* the instruction */\r
+\r
+ /*\r
+ * Pre computed values.\r
+ */\r
+\r
+ const xmlChar *stype; /* sort */\r
+ int has_stype; /* sort */\r
+ int number; /* sort */\r
+ const xmlChar *order; /* sort */\r
+ int has_order; /* sort */\r
+ int descending; /* sort */\r
+ const xmlChar *lang; /* sort */\r
+ int has_lang; /* sort */\r
+ const xmlChar *case_order; /* sort */\r
+ int lower_first; /* sort */\r
+\r
+ const xmlChar *use; /* copy, element */\r
+ int has_use; /* copy, element */\r
+\r
+ int noescape; /* text */\r
+\r
+ const xmlChar *name; /* element, attribute, pi */\r
+ int has_name; /* element, attribute, pi */\r
+ const xmlChar *ns; /* element */\r
+ int has_ns; /* element */\r
+\r
+ const xmlChar *mode; /* apply-templates */\r
+ const xmlChar *modeURI; /* apply-templates */\r
+\r
+ const xmlChar *test; /* if */\r
+\r
+ xsltTemplatePtr templ; /* call-template */\r
+\r
+ const xmlChar *select; /* sort, copy-of, value-of, apply-templates */\r
+\r
+ int ver11; /* document */\r
+ const xmlChar *filename; /* document URL */\r
+ int has_filename; /* document */\r
+\r
+ xsltNumberData numdata; /* number */\r
+\r
+ xmlXPathCompExprPtr comp; /* a precompiled XPath expression */\r
+ xmlNsPtr *nsList; /* the namespaces in scope */\r
+ int nsNr; /* the number of namespaces in scope */\r
+};\r
+\r
+#endif /* XSLT_REFACTORED */\r
+\r
+\r
+#define XSLT_VAR_GLOBAL 1<<0\r
+#define XSLT_VAR_IN_SELECT 1<<1\r
+#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)\r
+/*\r
+ * The in-memory structure corresponding to an XSLT Variable\r
+ * or Param.\r
+ */\r
+typedef struct _xsltStackElem xsltStackElem;\r
+typedef xsltStackElem *xsltStackElemPtr;\r
+struct _xsltStackElem {\r
+ struct _xsltStackElem *next;/* chained list */\r
+ xsltStylePreCompPtr comp; /* the compiled form */\r
+ int computed; /* was the evaluation done */\r
+ const xmlChar *name; /* the local part of the name QName */\r
+ const xmlChar *nameURI; /* the URI part of the name QName */\r
+ const xmlChar *select; /* the eval string */\r
+ xmlNodePtr tree; /* the sequence constructor if no eval\r
+ string or the location */\r
+ xmlXPathObjectPtr value; /* The value if computed */\r
+ xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0)\r
+ which are bound to the variable's lifetime. */\r
+ int level; /* the depth in the tree;\r
+ -1 if persistent (e.g. a given xsl:with-param) */\r
+ xsltTransformContextPtr context; /* The transformation context; needed to cache\r
+ the variables */\r
+ int flags;\r
+};\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+struct _xsltPrincipalStylesheetData {\r
+ /*\r
+ * Namespace dictionary for ns-prefixes and ns-names:\r
+ * TODO: Shared between stylesheets, and XPath mechanisms.\r
+ * Not used yet.\r
+ */\r
+ xmlDictPtr namespaceDict;\r
+ /*\r
+ * Global list of in-scope namespaces.\r
+ */\r
+ xsltPointerListPtr inScopeNamespaces;\r
+ /*\r
+ * Global list of information for [xsl:]excluded-result-prefixes.\r
+ */\r
+ xsltPointerListPtr exclResultNamespaces;\r
+ /*\r
+ * Global list of information for [xsl:]extension-element-prefixes.\r
+ */\r
+ xsltPointerListPtr extElemNamespaces;\r
+ xsltEffectiveNsPtr effectiveNs;\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+ /*\r
+ * Namespace name map to get rid of string comparison of namespace names.\r
+ */\r
+ xsltNsMapPtr nsMap;\r
+#endif\r
+};\r
+\r
+ \r
+#endif\r
+/*\r
+ * Note that we added a @compCtxt field to anchor an stylesheet compilation\r
+ * context, since, due to historical reasons, various compile-time function\r
+ * take only the stylesheet as argument and not a compilation context.\r
+ */\r
+struct _xsltStylesheet {\r
+ /*\r
+ * The stylesheet import relation is kept as a tree.\r
+ */\r
+ struct _xsltStylesheet *parent;\r
+ struct _xsltStylesheet *next;\r
+ struct _xsltStylesheet *imports;\r
+\r
+ xsltDocumentPtr docList; /* the include document list */\r
+\r
+ /*\r
+ * General data on the style sheet document.\r
+ */\r
+ xmlDocPtr doc; /* the parsed XML stylesheet */\r
+ xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and\r
+ preserve space elements */\r
+ int stripAll; /* strip-space * (1) preserve-space * (-1) */\r
+ xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */\r
+\r
+ /*\r
+ * Global variable or parameters.\r
+ */\r
+ xsltStackElemPtr variables; /* linked list of param and variables */\r
+\r
+ /*\r
+ * Template descriptions.\r
+ */\r
+ xsltTemplatePtr templates; /* the ordered list of templates */\r
+ void *templatesHash; /* hash table or wherever compiled templates\r
+ informations are stored */\r
+ void *rootMatch; /* template based on / */\r
+ void *keyMatch; /* template based on key() */\r
+ void *elemMatch; /* template based on * */\r
+ void *attrMatch; /* template based on @* */\r
+ void *parentMatch; /* template based on .. */\r
+ void *textMatch; /* template based on text() */\r
+ void *piMatch; /* template based on processing-instruction() */\r
+ void *commentMatch; /* template based on comment() */\r
+ \r
+ /*\r
+ * Namespace aliases.\r
+ * NOTE: Not used in the refactored code.\r
+ */\r
+ xmlHashTablePtr nsAliases; /* the namespace alias hash tables */\r
+\r
+ /*\r
+ * Attribute sets.\r
+ */\r
+ xmlHashTablePtr attributeSets;/* the attribute sets hash tables */\r
+\r
+ /*\r
+ * Namespaces.\r
+ * TODO: Eliminate this.\r
+ */\r
+ xmlHashTablePtr nsHash; /* the set of namespaces in use:\r
+ ATTENTION: This is used for\r
+ execution of XPath expressions; unfortunately\r
+ it restricts the stylesheet to have distinct\r
+ prefixes.\r
+ TODO: We need to get rid of this. \r
+ */\r
+ void *nsDefs; /* ATTENTION TODO: This is currently used to store\r
+ xsltExtDefPtr (in extensions.c) and\r
+ *not* xmlNsPtr.\r
+ */\r
+\r
+ /*\r
+ * Key definitions.\r
+ */\r
+ void *keys; /* key definitions */\r
+\r
+ /*\r
+ * Output related stuff.\r
+ */\r
+ xmlChar *method; /* the output method */\r
+ xmlChar *methodURI; /* associated namespace if any */\r
+ xmlChar *version; /* version string */\r
+ xmlChar *encoding; /* encoding string */\r
+ int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */\r
+\r
+ /* \r
+ * Number formatting.\r
+ */\r
+ xsltDecimalFormatPtr decimalFormat;\r
+ int standalone; /* standalone = "yes" | "no" */\r
+ xmlChar *doctypePublic; /* doctype-public string */\r
+ xmlChar *doctypeSystem; /* doctype-system string */\r
+ int indent; /* should output being indented */\r
+ xmlChar *mediaType; /* media-type string */\r
+\r
+ /*\r
+ * Precomputed blocks.\r
+ */\r
+ xsltElemPreCompPtr preComps;/* list of precomputed blocks */\r
+ int warnings; /* number of warnings found at compilation */\r
+ int errors; /* number of errors found at compilation */\r
+\r
+ xmlChar *exclPrefix; /* last excluded prefixes */\r
+ xmlChar **exclPrefixTab; /* array of excluded prefixes */\r
+ int exclPrefixNr; /* number of excluded prefixes in scope */\r
+ int exclPrefixMax; /* size of the array */\r
+\r
+ void *_private; /* user defined data */\r
+\r
+ /*\r
+ * Extensions.\r
+ */\r
+ xmlHashTablePtr extInfos; /* the extension data */\r
+ int extrasNr; /* the number of extras required */\r
+\r
+ /*\r
+ * For keeping track of nested includes\r
+ */\r
+ xsltDocumentPtr includes; /* points to last nested include */\r
+\r
+ /*\r
+ * dictionary: shared between stylesheet, context and documents.\r
+ */\r
+ xmlDictPtr dict;\r
+ /*\r
+ * precompiled attribute value templates.\r
+ */\r
+ void *attVTs;\r
+ /*\r
+ * if namespace-alias has an alias for the default stylesheet prefix\r
+ * NOTE: Not used in the refactored code.\r
+ */\r
+ const xmlChar *defaultAlias;\r
+ /*\r
+ * bypass pre-processing (already done) (used in imports)\r
+ */\r
+ int nopreproc;\r
+ /*\r
+ * all document text strings were internalized\r
+ */\r
+ int internalized;\r
+ /*\r
+ * Literal Result Element as Stylesheet c.f. section 2.3\r
+ */\r
+ int literal_result;\r
+ /*\r
+ * The principal stylesheet\r
+ */\r
+ xsltStylesheetPtr principal;\r
+#ifdef XSLT_REFACTORED\r
+ /*\r
+ * Compilation context used during compile-time.\r
+ */\r
+ xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */\r
+\r
+ xsltPrincipalStylesheetDataPtr principalData; \r
+#endif\r
+};\r
+\r
+typedef struct _xsltTransformCache xsltTransformCache;\r
+typedef xsltTransformCache *xsltTransformCachePtr;\r
+struct _xsltTransformCache {\r
+ xmlDocPtr RVT;\r
+ int nbRVT;\r
+ xsltStackElemPtr stackItems;\r
+ int nbStackItems;\r
+#ifdef XSLT_DEBUG_PROFILE_CACHE\r
+ int dbgCachedRVTs;\r
+ int dbgReusedRVTs;\r
+ int dbgCachedVars;\r
+ int dbgReusedVars;\r
+#endif\r
+};\r
+\r
+/*\r
+ * The in-memory structure corresponding to an XSLT Transformation.\r
+ */\r
+typedef enum {\r
+ XSLT_OUTPUT_XML = 0,\r
+ XSLT_OUTPUT_HTML,\r
+ XSLT_OUTPUT_TEXT\r
+} xsltOutputType;\r
+\r
+typedef enum {\r
+ XSLT_STATE_OK = 0,\r
+ XSLT_STATE_ERROR,\r
+ XSLT_STATE_STOPPED\r
+} xsltTransformState;\r
+\r
+struct _xsltTransformContext {\r
+ xsltStylesheetPtr style; /* the stylesheet used */\r
+ xsltOutputType type; /* the type of output */\r
+\r
+ xsltTemplatePtr templ; /* the current template */\r
+ int templNr; /* Nb of templates in the stack */\r
+ int templMax; /* Size of the templtes stack */\r
+ xsltTemplatePtr *templTab; /* the template stack */\r
+\r
+ xsltStackElemPtr vars; /* the current variable list */\r
+ int varsNr; /* Nb of variable list in the stack */\r
+ int varsMax; /* Size of the variable list stack */\r
+ xsltStackElemPtr *varsTab; /* the variable list stack */\r
+ int varsBase; /* the var base for current templ */\r
+\r
+ /*\r
+ * Extensions\r
+ */\r
+ xmlHashTablePtr extFunctions; /* the extension functions */\r
+ xmlHashTablePtr extElements; /* the extension elements */\r
+ xmlHashTablePtr extInfos; /* the extension data */\r
+\r
+ const xmlChar *mode; /* the current mode */\r
+ const xmlChar *modeURI; /* the current mode URI */\r
+\r
+ xsltDocumentPtr docList; /* the document list */\r
+\r
+ xsltDocumentPtr document; /* the current source document; can be NULL if an RTF */\r
+ xmlNodePtr node; /* the current node being processed */\r
+ xmlNodeSetPtr nodeList; /* the current node list */\r
+ /* xmlNodePtr current; the node */\r
+\r
+ xmlDocPtr output; /* the resulting document */\r
+ xmlNodePtr insert; /* the insertion node */\r
+\r
+ xmlXPathContextPtr xpathCtxt; /* the XPath context */\r
+ xsltTransformState state; /* the current state */\r
+\r
+ /*\r
+ * Global variables\r
+ */\r
+ xmlHashTablePtr globalVars; /* the global variables and params */\r
+\r
+ xmlNodePtr inst; /* the instruction in the stylesheet */\r
+\r
+ int xinclude; /* should XInclude be processed */\r
+\r
+ const char * outputFile; /* the output URI if known */\r
+\r
+ int profile; /* is this run profiled */\r
+ long prof; /* the current profiled value */\r
+ int profNr; /* Nb of templates in the stack */\r
+ int profMax; /* Size of the templtaes stack */\r
+ long *profTab; /* the profile template stack */\r
+\r
+ void *_private; /* user defined data */\r
+\r
+ int extrasNr; /* the number of extras used */\r
+ int extrasMax; /* the number of extras allocated */\r
+ xsltRuntimeExtraPtr extras; /* extra per runtime informations */\r
+\r
+ xsltDocumentPtr styleList; /* the stylesheet docs list */\r
+ void * sec; /* the security preferences if any */\r
+\r
+ xmlGenericErrorFunc error; /* a specific error handler */\r
+ void * errctx; /* context for the error handler */\r
+\r
+ xsltSortFunc sortfunc; /* a ctxt specific sort routine */\r
+\r
+ /*\r
+ * handling of temporary Result Value Tree\r
+ * (XSLT 1.0 term: "Result Tree Fragment")\r
+ */\r
+ xmlDocPtr tmpRVT; /* list of RVT without persistance */\r
+ xmlDocPtr persistRVT; /* list of persistant RVTs */\r
+ int ctxtflags; /* context processing flags */\r
+\r
+ /*\r
+ * Speed optimization when coalescing text nodes\r
+ */\r
+ const xmlChar *lasttext; /* last text node content */\r
+ unsigned int lasttsize; /* last text node size */\r
+ unsigned int lasttuse; /* last text node use */\r
+ /*\r
+ * Per Context Debugging\r
+ */\r
+ int debugStatus; /* the context level debug status */\r
+ unsigned long* traceCode; /* pointer to the variable holding the mask */\r
+\r
+ int parserOptions; /* parser options xmlParserOption */\r
+\r
+ /*\r
+ * dictionnary: shared between stylesheet, context and documents.\r
+ */\r
+ xmlDictPtr dict;\r
+ /*\r
+ * The current source doc; one of: the initial source doc, a RTF\r
+ * or a source doc aquired via the document() function.\r
+ */\r
+ xmlDocPtr tmpDoc;\r
+ /*\r
+ * all document text strings are internalized\r
+ */\r
+ int internalized;\r
+ int nbKeys;\r
+ int hasTemplKeyPatterns; \r
+ xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */ \r
+ xmlNodePtr initialContextNode;\r
+ xmlDocPtr initialContextDoc;\r
+ xsltTransformCachePtr cache;\r
+ void *contextVariable; /* the current variable item */\r
+ xmlDocPtr localRVT; /* list of local tree fragments; will be freed when\r
+ the instruction which created the fragment\r
+ exits */\r
+ xmlDocPtr localRVTBase; \r
+};\r
+\r
+/**\r
+ * CHECK_STOPPED:\r
+ *\r
+ * Macro to check if the XSLT processing should be stopped.\r
+ * Will return from the function.\r
+ */\r
+#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return;\r
+\r
+/**\r
+ * CHECK_STOPPEDE:\r
+ *\r
+ * Macro to check if the XSLT processing should be stopped.\r
+ * Will goto the error: label.\r
+ */\r
+#define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error;\r
+\r
+/**\r
+ * CHECK_STOPPED0:\r
+ *\r
+ * Macro to check if the XSLT processing should be stopped.\r
+ * Will return from the function with a 0 value.\r
+ */\r
+#define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0);\r
+\r
+/*\r
+ * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about\r
+ * possible incompatibilities between function pointers and object\r
+ * pointers. It is defined in libxml/hash.h within recent versions\r
+ * of libxml2, but is put here for compatibility.\r
+ */\r
+#ifndef XML_CAST_FPTR\r
+/**\r
+ * XML_CAST_FPTR:\r
+ * @fptr: pointer to a function\r
+ *\r
+ * Macro to do a casting from an object pointer to a\r
+ * function pointer without encountering a warning from\r
+ * gcc\r
+ *\r
+ * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr))\r
+ * This macro violated ISO C aliasing rules (gcc4 on s390 broke)\r
+ * so it is disabled now\r
+ */\r
+\r
+#define XML_CAST_FPTR(fptr) fptr\r
+#endif\r
+/*\r
+ * Functions associated to the internal types\r
+xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet,\r
+ xmlChar *name);\r
+ */\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltNewStylesheet (void);\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltParseStylesheetFile (const xmlChar* filename);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltFreeStylesheet (xsltStylesheetPtr style);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltIsBlank (xmlChar *str);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltFreeStackElemList (xsltStackElemPtr elem);\r
+XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL \r
+ xsltDecimalFormatGetByName(xsltStylesheetPtr style,\r
+ xmlChar *name);\r
+\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltParseStylesheetProcess(xsltStylesheetPtr ret,\r
+ xmlDocPtr doc);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltParseStylesheetOutput(xsltStylesheetPtr style,\r
+ xmlNodePtr cur);\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltParseStylesheetDoc (xmlDocPtr doc);\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltParseStylesheetImportedDoc(xmlDocPtr doc,\r
+ xsltStylesheetPtr style);\r
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL \r
+ xsltLoadStylesheetPI (xmlDocPtr doc);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltNumberFormat (xsltTransformContextPtr ctxt,\r
+ xsltNumberDataPtr data,\r
+ xmlNodePtr node);\r
+XSLTPUBFUN xmlXPathError XSLTCALL \r
+ xsltFormatNumberConversion(xsltDecimalFormatPtr self,\r
+ xmlChar *format,\r
+ double number,\r
+ xmlChar **result);\r
+\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltParseTemplateContent(xsltStylesheetPtr style,\r
+ xmlNodePtr templ);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltAllocateExtra (xsltStylesheetPtr style);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt);\r
+/*\r
+ * Extra functions for Result Value Trees\r
+ */\r
+XSLTPUBFUN xmlDocPtr XSLTCALL \r
+ xsltCreateRVT (xsltTransformContextPtr ctxt);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltRegisterTmpRVT (xsltTransformContextPtr ctxt,\r
+ xmlDocPtr RVT);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltRegisterLocalRVT (xsltTransformContextPtr ctxt,\r
+ xmlDocPtr RVT);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltRegisterPersistRVT (xsltTransformContextPtr ctxt,\r
+ xmlDocPtr RVT);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltExtensionInstructionResultRegister(\r
+ xsltTransformContextPtr ctxt,\r
+ xmlXPathObjectPtr obj);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltExtensionInstructionResultFinalize(\r
+ xsltTransformContextPtr ctxt);\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltFreeRVTs (xsltTransformContextPtr ctxt);\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltReleaseRVT (xsltTransformContextPtr ctxt,\r
+ xmlDocPtr RVT);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltTransStorageAdd (xsltTransformContextPtr ctxt,\r
+ void *id,\r
+ void *data);\r
+XSLTPUBFUN void * XSLTCALL\r
+ xsltTransStorageRemove (xsltTransformContextPtr ctxt,\r
+ void *id);\r
+\r
+/*\r
+ * Extra functions for Attribute Value Templates\r
+ */\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltCompileAttr (xsltStylesheetPtr style,\r
+ xmlAttrPtr attr);\r
+XSLTPUBFUN xmlChar * XSLTCALL\r
+ xsltEvalAVT (xsltTransformContextPtr ctxt,\r
+ void *avt,\r
+ xmlNodePtr node);\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltFreeAVTList (void *avt);\r
+\r
+/*\r
+ * Extra function for successful xsltCleanupGlobals / xsltInit sequence.\r
+ */\r
+\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltUninit (void);\r
+\r
+/************************************************************************\r
+ * *\r
+ * Compile-time functions for *internal* use only *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#ifdef XSLT_REFACTORED \r
+XSLTPUBFUN void XSLTCALL\r
+ xsltParseSequenceConstructor(\r
+ xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr start);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt,\r
+ xmlNodePtr elem);\r
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltRestoreDocumentNamespaces(\r
+ xsltNsMapPtr ns,\r
+ xmlDocPtr doc);\r
+#endif\r
+#endif /* XSLT_REFACTORED */\r
+\r
+/************************************************************************\r
+ * *\r
+ * Transformation-time functions for *internal* use only *\r
+ * *\r
+ ************************************************************************/\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltInitCtxtKey (xsltTransformContextPtr ctxt,\r
+ xsltDocumentPtr doc,\r
+ xsltKeyDefPtr keyd);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __XML_XSLT_H__ */\r
+\r
-/*
- * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
-
-#define IN_LIBXSLT
-#include "libxslt.h"
-
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <stdarg.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/tree.h>
-#include <libxml/HTMLtree.h>
-#include <libxml/xmlerror.h>
-#include <libxml/xmlIO.h>
-#include "xsltutils.h"
-#include "templates.h"
-#include "xsltInternals.h"
-#include "imports.h"
-#include "transform.h"
-
-/* gettimeofday on Windows ??? */
-#if defined(WIN32) && !defined(__CYGWIN__)
-#ifdef _MSC_VER
-#include <winsock2.h>
-#pragma comment(lib, "ws2_32.lib")
-#define gettimeofday(p1,p2)
-#define HAVE_GETTIMEOFDAY
-#define XSLT_WIN32_PERFORMANCE_COUNTER
-#endif /* _MS_VER */
-#endif /* WIN32 */
-
-#ifdef XSLT_NEED_TRIO
-#include "trio.h"
-#define vsnprintf trio_vsnprintf
-#endif
-
-/************************************************************************
- * *
- * Convenience function *
- * *
- ************************************************************************/
-
-/**
- * xsltGetCNsProp:
- * @style: the stylesheet
- * @node: the node
- * @name: the attribute name
- * @nameSpace: the URI of the namespace
- *
- * Similar to xmlGetNsProp() but with a slightly different semantic
- *
- * Search and get the value of an attribute associated to a node
- * This attribute has to be anchored in the namespace specified,
- * or has no namespace and the element is in that namespace.
- *
- * This does the entity substitution.
- * This function looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
- *
- * Returns the attribute value or NULL if not found. The string is allocated
- * in the stylesheet dictionnary.
- */
-const xmlChar *
-xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
- const xmlChar *name, const xmlChar *nameSpace) {
- xmlAttrPtr prop;
- xmlDocPtr doc;
- xmlNsPtr ns;
- xmlChar *tmp;
- const xmlChar *ret;
-
- if ((node == NULL) || (style == NULL) || (style->dict == NULL))
- return(NULL);
-
- prop = node->properties;
- if (nameSpace == NULL) {
- return xmlGetProp(node, name);
- }
- while (prop != NULL) {
- /*
- * One need to have
- * - same attribute names
- * - and the attribute carrying that namespace
- */
- if ((xmlStrEqual(prop->name, name)) &&
- (((prop->ns == NULL) && (node->ns != NULL) &&
- (xmlStrEqual(node->ns->href, nameSpace))) ||
- ((prop->ns != NULL) &&
- (xmlStrEqual(prop->ns->href, nameSpace))))) {
-
- tmp = xmlNodeListGetString(node->doc, prop->children, 1);
- if (tmp == NULL)
- ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
- else {
- ret = xmlDictLookup(style->dict, tmp, -1);
- xmlFree(tmp);
- }
- return ret;
- }
- prop = prop->next;
- }
- tmp = NULL;
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- if (doc->intSubset != NULL) {
- xmlAttributePtr attrDecl;
-
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
-
- if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
- /*
- * The DTD declaration only allows a prefix search
- */
- ns = xmlSearchNs(doc, node, attrDecl->prefix);
- if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
- return(xmlDictLookup(style->dict,
- attrDecl->defaultValue, -1));
- }
- }
- }
- return(NULL);
-}
-/**
- * xsltGetNsProp:
- * @node: the node
- * @name: the attribute name
- * @nameSpace: the URI of the namespace
- *
- * Similar to xmlGetNsProp() but with a slightly different semantic
- *
- * Search and get the value of an attribute associated to a node
- * This attribute has to be anchored in the namespace specified,
- * or has no namespace and the element is in that namespace.
- *
- * This does the entity substitution.
- * This function looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
- *
- * Returns the attribute value or NULL if not found.
- * It's up to the caller to free the memory.
- */
-xmlChar *
-xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
- xmlAttrPtr prop;
- xmlDocPtr doc;
- xmlNsPtr ns;
-
- if (node == NULL)
- return(NULL);
-
- prop = node->properties;
- /*
- * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
- * is not namespace-aware and will return an attribute with equal
- * name regardless of its namespace.
- * Example:
- * <xsl:element foo:name="myName"/>
- * So this would return "myName" even if an attribute @name
- * in the XSLT was requested.
- */
- if (nameSpace == NULL)
- return(xmlGetProp(node, name));
- while (prop != NULL) {
- /*
- * One need to have
- * - same attribute names
- * - and the attribute carrying that namespace
- */
- if ((xmlStrEqual(prop->name, name)) &&
- (((prop->ns == NULL) && (node->ns != NULL) &&
- (xmlStrEqual(node->ns->href, nameSpace))) ||
- ((prop->ns != NULL) &&
- (xmlStrEqual(prop->ns->href, nameSpace))))) {
- xmlChar *ret;
-
- ret = xmlNodeListGetString(node->doc, prop->children, 1);
- if (ret == NULL) return(xmlStrdup((xmlChar *)""));
- return(ret);
- }
- prop = prop->next;
- }
-
- /*
- * Check if there is a default declaration in the internal
- * or external subsets
- */
- doc = node->doc;
- if (doc != NULL) {
- if (doc->intSubset != NULL) {
- xmlAttributePtr attrDecl;
-
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
-
- if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
- /*
- * The DTD declaration only allows a prefix search
- */
- ns = xmlSearchNs(doc, node, attrDecl->prefix);
- if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
- return(xmlStrdup(attrDecl->defaultValue));
- }
- }
- }
- return(NULL);
-}
-
-/**
- * xsltGetUTF8Char:
- * @utf: a sequence of UTF-8 encoded bytes
- * @len: a pointer to @bytes len
- *
- * Read one UTF8 Char from @utf
- * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
- * and use the original API
- *
- * Returns the char value or -1 in case of error and update @len with the
- * number of bytes used
- */
-int
-xsltGetUTF8Char(const unsigned char *utf, int *len) {
- unsigned int c;
-
- if (utf == NULL)
- goto error;
- if (len == NULL)
- goto error;
- if (*len < 1)
- goto error;
-
- c = utf[0];
- if (c & 0x80) {
- if (*len < 2)
- goto error;
- if ((utf[1] & 0xc0) != 0x80)
- goto error;
- if ((c & 0xe0) == 0xe0) {
- if (*len < 3)
- goto error;
- if ((utf[2] & 0xc0) != 0x80)
- goto error;
- if ((c & 0xf0) == 0xf0) {
- if (*len < 4)
- goto error;
- if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
- goto error;
- *len = 4;
- /* 4-byte code */
- c = (utf[0] & 0x7) << 18;
- c |= (utf[1] & 0x3f) << 12;
- c |= (utf[2] & 0x3f) << 6;
- c |= utf[3] & 0x3f;
- } else {
- /* 3-byte code */
- *len = 3;
- c = (utf[0] & 0xf) << 12;
- c |= (utf[1] & 0x3f) << 6;
- c |= utf[2] & 0x3f;
- }
- } else {
- /* 2-byte code */
- *len = 2;
- c = (utf[0] & 0x1f) << 6;
- c |= utf[1] & 0x3f;
- }
- } else {
- /* 1-byte code */
- *len = 1;
- }
- return(c);
-
-error:
- if (len != NULL)
- *len = 0;
- return(-1);
-}
-
-#ifdef XSLT_REFACTORED
-
-/**
- * xsltPointerListAddSize:
- * @list: the pointer list structure
- * @item: the item to be stored
- * @initialSize: the initial size of the list
- *
- * Adds an item to the list.
- *
- * Returns the position of the added item in the list or
- * -1 in case of an error.
- */
-int
-xsltPointerListAddSize(xsltPointerListPtr list,
- void *item,
- int initialSize)
-{
- if (list->items == NULL) {
- if (initialSize <= 0)
- initialSize = 1;
- list->items = (void **) xmlMalloc(
- initialSize * sizeof(void *));
- if (list->items == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltPointerListAddSize: memory allocation failure.\n");
- return(-1);
- }
- list->number = 0;
- list->size = initialSize;
- } else if (list->size <= list->number) {
- list->size *= 2;
- list->items = (void **) xmlRealloc(list->items,
- list->size * sizeof(void *));
- if (list->items == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltPointerListAddSize: memory re-allocation failure.\n");
- list->size = 0;
- return(-1);
- }
- }
- list->items[list->number++] = item;
- return(0);
-}
-
-/**
- * xsltPointerListCreate:
- *
- * Creates an xsltPointerList structure.
- *
- * Returns a xsltPointerList structure or NULL in case of an error.
- */
-xsltPointerListPtr
-xsltPointerListCreate(int initialSize)
-{
- xsltPointerListPtr ret;
-
- ret = xmlMalloc(sizeof(xsltPointerList));
- if (ret == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltPointerListCreate: memory allocation failure.\n");
- return (NULL);
- }
- memset(ret, 0, sizeof(xsltPointerList));
- if (initialSize > 0) {
- xsltPointerListAddSize(ret, NULL, initialSize);
- ret->number = 0;
- }
- return (ret);
-}
-
-/**
- * xsltPointerListFree:
- *
- * Frees the xsltPointerList structure. This does not free
- * the content of the list.
- */
-void
-xsltPointerListFree(xsltPointerListPtr list)
-{
- if (list == NULL)
- return;
- if (list->items != NULL)
- xmlFree(list->items);
- xmlFree(list);
-}
-
-/**
- * xsltPointerListFree:
- *
- * Resets the list, but does not free the allocated array
- * and does not free the content of the list.
- */
-void
-xsltPointerListClear(xsltPointerListPtr list)
-{
- if (list->items != NULL) {
- xmlFree(list->items);
- list->items = NULL;
- }
- list->number = 0;
- list->size = 0;
-}
-
-#endif /* XSLT_REFACTORED */
-
-/************************************************************************
- * *
- * Handling of XSLT stylesheets messages *
- * *
- ************************************************************************/
-
-/**
- * xsltMessage:
- * @ctxt: an XSLT processing context
- * @node: The current node
- * @inst: The node containing the message instruction
- *
- * Process and xsl:message construct
- */
-void
-xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
- xmlChar *prop, *message;
- int terminate = 0;
-
- if ((ctxt == NULL) || (inst == NULL))
- return;
-
- prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
- if (prop != NULL) {
- if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
- terminate = 1;
- } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
- terminate = 0;
- } else {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:message : terminate expecting 'yes' or 'no'\n");
- ctxt->state = XSLT_STATE_ERROR;
- }
- xmlFree(prop);
- }
- message = xsltEvalTemplateString(ctxt, node, inst);
- if (message != NULL) {
- int len = xmlStrlen(message);
-
- xsltGenericError(xsltGenericErrorContext, "%s",
- (const char *)message);
- if ((len > 0) && (message[len - 1] != '\n'))
- xsltGenericError(xsltGenericErrorContext, "\n");
- xmlFree(message);
- }
- if (terminate)
- ctxt->state = XSLT_STATE_STOPPED;
-}
-
-/************************************************************************
- * *
- * Handling of out of context errors *
- * *
- ************************************************************************/
-
-#define XSLT_GET_VAR_STR(msg, str) { \
- int size; \
- int chars; \
- char *larger; \
- va_list ap; \
- \
- str = (char *) xmlMalloc(150); \
- if (str == NULL) \
- return; \
- \
- size = 150; \
- \
- while (1) { \
- va_start(ap, msg); \
- chars = vsnprintf(str, size, msg, ap); \
- va_end(ap); \
- if ((chars > -1) && (chars < size)) \
- break; \
- if (chars > -1) \
- size += chars + 1; \
- else \
- size += 100; \
- if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
- xmlFree(str); \
- return; \
- } \
- str = larger; \
- } \
-}
-/**
- * xsltGenericErrorDefaultFunc:
- * @ctx: an error context
- * @msg: the message to display/transmit
- * @...: extra parameters for the message display
- *
- * Default handler for out of context error messages.
- */
-static void
-xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
- va_list args;
-
- if (xsltGenericErrorContext == NULL)
- xsltGenericErrorContext = (void *) stderr;
-
- va_start(args, msg);
- vfprintf((FILE *)xsltGenericErrorContext, msg, args);
- va_end(args);
-}
-
-xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
-void *xsltGenericErrorContext = NULL;
-
-
-/**
- * xsltSetGenericErrorFunc:
- * @ctx: the new error handling context
- * @handler: the new handler function
- *
- * Function to reset the handler and the error context for out of
- * context error messages.
- * This simply means that @handler will be called for subsequent
- * error messages while not parsing nor validating. And @ctx will
- * be passed as first argument to @handler
- * One can simply force messages to be emitted to another FILE * than
- * stderr by setting @ctx to this file handle and @handler to NULL.
- */
-void
-xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
- xsltGenericErrorContext = ctx;
- if (handler != NULL)
- xsltGenericError = handler;
- else
- xsltGenericError = xsltGenericErrorDefaultFunc;
-}
-
-/**
- * xsltGenericDebugDefaultFunc:
- * @ctx: an error context
- * @msg: the message to display/transmit
- * @...: extra parameters for the message display
- *
- * Default handler for out of context error messages.
- */
-static void
-xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
- va_list args;
-
- if (xsltGenericDebugContext == NULL)
- return;
-
- va_start(args, msg);
- vfprintf((FILE *)xsltGenericDebugContext, msg, args);
- va_end(args);
-}
-
-xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
-void *xsltGenericDebugContext = NULL;
-
-
-/**
- * xsltSetGenericDebugFunc:
- * @ctx: the new error handling context
- * @handler: the new handler function
- *
- * Function to reset the handler and the error context for out of
- * context error messages.
- * This simply means that @handler will be called for subsequent
- * error messages while not parsing or validating. And @ctx will
- * be passed as first argument to @handler
- * One can simply force messages to be emitted to another FILE * than
- * stderr by setting @ctx to this file handle and @handler to NULL.
- */
-void
-xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
- xsltGenericDebugContext = ctx;
- if (handler != NULL)
- xsltGenericDebug = handler;
- else
- xsltGenericDebug = xsltGenericDebugDefaultFunc;
-}
-
-/**
- * xsltPrintErrorContext:
- * @ctxt: the transformation context
- * @style: the stylesheet
- * @node: the current node being processed
- *
- * Display the context of an error.
- */
-void
-xsltPrintErrorContext(xsltTransformContextPtr ctxt,
- xsltStylesheetPtr style, xmlNodePtr node) {
- int line = 0;
- const xmlChar *file = NULL;
- const xmlChar *name = NULL;
- const char *type = "error";
- xmlGenericErrorFunc error = xsltGenericError;
- void *errctx = xsltGenericErrorContext;
-
- if (ctxt != NULL) {
- ctxt->state = XSLT_STATE_ERROR;
- if (ctxt->error != NULL) {
- error = ctxt->error;
- errctx = ctxt->errctx;
- }
- }
- if ((node == NULL) && (ctxt != NULL))
- node = ctxt->inst;
-
- if (node != NULL) {
- if ((node->type == XML_DOCUMENT_NODE) ||
- (node->type == XML_HTML_DOCUMENT_NODE)) {
- xmlDocPtr doc = (xmlDocPtr) node;
-
- file = doc->URL;
- } else {
- line = xmlGetLineNo(node);
- if ((node->doc != NULL) && (node->doc->URL != NULL))
- file = node->doc->URL;
- if (node->name != NULL)
- name = node->name;
- }
- }
-
- if (ctxt != NULL)
- type = "runtime error";
- else if (style != NULL) {
-#ifdef XSLT_REFACTORED
- if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
- type = "compilation warning";
- else
- type = "compilation error";
-#else
- type = "compilation error";
-#endif
- }
-
- if ((file != NULL) && (line != 0) && (name != NULL))
- error(errctx, "%s: file %s line %d element %s\n",
- type, file, line, name);
- else if ((file != NULL) && (name != NULL))
- error(errctx, "%s: file %s element %s\n", type, file, name);
- else if ((file != NULL) && (line != 0))
- error(errctx, "%s: file %s line %d\n", type, file, line);
- else if (file != NULL)
- error(errctx, "%s: file %s\n", type, file);
- else if (name != NULL)
- error(errctx, "%s: element %s\n", type, name);
- else
- error(errctx, "%s\n", type);
-}
-
-/**
- * xsltSetTransformErrorFunc:
- * @ctxt: the XSLT transformation context
- * @ctx: the new error handling context
- * @handler: the new handler function
- *
- * Function to reset the handler and the error context for out of
- * context error messages specific to a given XSLT transromation.
- *
- * This simply means that @handler will be called for subsequent
- * error messages while running the transformation.
- */
-void
-xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
- void *ctx, xmlGenericErrorFunc handler)
-{
- ctxt->error = handler;
- ctxt->errctx = ctx;
-}
-
-/**
- * xsltTransformError:
- * @ctxt: an XSLT transformation context
- * @style: the XSLT stylesheet used
- * @node: the current node in the stylesheet
- * @msg: the message to display/transmit
- * @...: extra parameters for the message display
- *
- * Display and format an error messages, gives file, line, position and
- * extra parameters, will use the specific transformation context if available
- */
-void
-xsltTransformError(xsltTransformContextPtr ctxt,
- xsltStylesheetPtr style,
- xmlNodePtr node,
- const char *msg, ...) {
- xmlGenericErrorFunc error = xsltGenericError;
- void *errctx = xsltGenericErrorContext;
- char * str;
-
- if (ctxt != NULL) {
- ctxt->state = XSLT_STATE_ERROR;
- if (ctxt->error != NULL) {
- error = ctxt->error;
- errctx = ctxt->errctx;
- }
- }
- if ((node == NULL) && (ctxt != NULL))
- node = ctxt->inst;
- xsltPrintErrorContext(ctxt, style, node);
- XSLT_GET_VAR_STR(msg, str);
- error(errctx, "%s", str);
- if (str != NULL)
- xmlFree(str);
-}
-
-/************************************************************************
- * *
- * QNames *
- * *
- ************************************************************************/
-
-/**
- * xsltSplitQName:
- * @dict: a dictionnary
- * @name: the full QName
- * @prefix: the return value
- *
- * Split QNames into prefix and local names, both allocated from a dictionnary.
- *
- * Returns: the localname or NULL in case of error.
- */
-const xmlChar *
-xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
- int len = 0;
- const xmlChar *ret = NULL;
-
- *prefix = NULL;
- if ((name == NULL) || (dict == NULL)) return(NULL);
- if (name[0] == ':')
- return(xmlDictLookup(dict, name, -1));
- while ((name[len] != 0) && (name[len] != ':')) len++;
- if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
- *prefix = xmlDictLookup(dict, name, len);
- ret = xmlDictLookup(dict, &name[len + 1], -1);
- return(ret);
-}
-
-/**
- * xsltGetQNameURI:
- * @node: the node holding the QName
- * @name: pointer to the initial QName value
- *
- * This function analyzes @name, if the name contains a prefix,
- * the function seaches the associated namespace in scope for it.
- * It will also replace @name value with the NCName, the old value being
- * freed.
- * Errors in the prefix lookup are signalled by setting @name to NULL.
- *
- * NOTE: the namespace returned is a pointer to the place where it is
- * defined and hence has the same lifespan as the document holding it.
- *
- * Returns the namespace URI if there is a prefix, or NULL if @name is
- * not prefixed.
- */
-const xmlChar *
-xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
-{
- int len = 0;
- xmlChar *qname;
- xmlNsPtr ns;
-
- if (name == NULL)
- return(NULL);
- qname = *name;
- if ((qname == NULL) || (*qname == 0))
- return(NULL);
- if (node == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "QName: no element for namespace lookup %s\n",
- qname);
- xmlFree(qname);
- *name = NULL;
- return(NULL);
- }
-
- /* nasty but valid */
- if (qname[0] == ':')
- return(NULL);
-
- /*
- * we are not trying to validate but just to cut, and yes it will
- * work even if this is a set of UTF-8 encoded chars
- */
- while ((qname[len] != 0) && (qname[len] != ':'))
- len++;
-
- if (qname[len] == 0)
- return(NULL);
-
- /*
- * handle xml: separately, this one is magical
- */
- if ((qname[0] == 'x') && (qname[1] == 'm') &&
- (qname[2] == 'l') && (qname[3] == ':')) {
- if (qname[4] == 0)
- return(NULL);
- *name = xmlStrdup(&qname[4]);
- xmlFree(qname);
- return(XML_XML_NAMESPACE);
- }
-
- qname[len] = 0;
- ns = xmlSearchNs(node->doc, node, qname);
- if (ns == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "%s:%s : no namespace bound to prefix %s\n",
- qname, &qname[len + 1], qname);
- *name = NULL;
- xmlFree(qname);
- return(NULL);
- }
- *name = xmlStrdup(&qname[len + 1]);
- xmlFree(qname);
- return(ns->href);
-}
-
-/**
- * xsltGetQNameURI2:
- * @style: stylesheet pointer
- * @node: the node holding the QName
- * @name: pointer to the initial QName value
- *
- * This function is similar to xsltGetQNameURI, but is used when
- * @name is a dictionary entry.
- *
- * Returns the namespace URI if there is a prefix, or NULL if @name is
- * not prefixed.
- */
-const xmlChar *
-xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
- const xmlChar **name) {
- int len = 0;
- xmlChar *qname;
- xmlNsPtr ns;
-
- if (name == NULL)
- return(NULL);
- qname = (xmlChar *)*name;
- if ((qname == NULL) || (*qname == 0))
- return(NULL);
- if (node == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "QName: no element for namespace lookup %s\n",
- qname);
- *name = NULL;
- return(NULL);
- }
-
- /*
- * we are not trying to validate but just to cut, and yes it will
- * work even if this is a set of UTF-8 encoded chars
- */
- while ((qname[len] != 0) && (qname[len] != ':'))
- len++;
-
- if (qname[len] == 0)
- return(NULL);
-
- /*
- * handle xml: separately, this one is magical
- */
- if ((qname[0] == 'x') && (qname[1] == 'm') &&
- (qname[2] == 'l') && (qname[3] == ':')) {
- if (qname[4] == 0)
- return(NULL);
- *name = xmlDictLookup(style->dict, &qname[4], -1);
- return(XML_XML_NAMESPACE);
- }
-
- qname = xmlStrndup(*name, len);
- ns = xmlSearchNs(node->doc, node, qname);
- if (ns == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "%s : no namespace bound to prefix %s\n",
- *name, qname);
- *name = NULL;
- xmlFree(qname);
- return(NULL);
- }
- *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
- xmlFree(qname);
- return(ns->href);
-}
-
-/************************************************************************
- * *
- * Sorting *
- * *
- ************************************************************************/
-
-/**
- * xsltDocumentSortFunction:
- * @list: the node set
- *
- * reorder the current node list @list accordingly to the document order
- * This function is slow, obsolete and should not be used anymore.
- */
-void
-xsltDocumentSortFunction(xmlNodeSetPtr list) {
- int i, j;
- int len, tst;
- xmlNodePtr node;
-
- if (list == NULL)
- return;
- len = list->nodeNr;
- if (len <= 1)
- return;
- /* TODO: sort is really not optimized, does it needs to ? */
- for (i = 0;i < len -1;i++) {
- for (j = i + 1; j < len; j++) {
- tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
- if (tst == -1) {
- node = list->nodeTab[i];
- list->nodeTab[i] = list->nodeTab[j];
- list->nodeTab[j] = node;
- }
- }
- }
-}
-
-/**
- * xsltComputeSortResult:
- * @ctxt: a XSLT process context
- * @sort: node list
- *
- * reorder the current node list accordingly to the set of sorting
- * requirement provided by the array of nodes.
- *
- * Returns a ordered XPath nodeset or NULL in case of error.
- */
-xmlXPathObjectPtr *
-xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemSortPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- xmlXPathObjectPtr *results = NULL;
- xmlNodeSetPtr list = NULL;
- xmlXPathObjectPtr res;
- int len = 0;
- int i;
- xmlNodePtr oldNode;
- xmlNodePtr oldInst;
- int oldPos, oldSize ;
- int oldNsNr;
- xmlNsPtr *oldNamespaces;
-
- comp = sort->psvi;
- if (comp == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:sort : compilation failed\n");
- return(NULL);
- }
-
- if ((comp->select == NULL) || (comp->comp == NULL))
- return(NULL);
-
- list = ctxt->nodeList;
- if ((list == NULL) || (list->nodeNr <= 1))
- return(NULL);
-
- len = list->nodeNr;
-
- /* TODO: xsl:sort lang attribute */
- /* TODO: xsl:sort case-order attribute */
-
-
- results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
- if (results == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltComputeSortResult: memory allocation failure\n");
- return(NULL);
- }
-
- oldNode = ctxt->node;
- oldInst = ctxt->inst;
- oldPos = ctxt->xpathCtxt->proximityPosition;
- oldSize = ctxt->xpathCtxt->contextSize;
- oldNsNr = ctxt->xpathCtxt->nsNr;
- oldNamespaces = ctxt->xpathCtxt->namespaces;
- for (i = 0;i < len;i++) {
- ctxt->inst = sort;
- ctxt->xpathCtxt->contextSize = len;
- ctxt->xpathCtxt->proximityPosition = i + 1;
- ctxt->node = list->nodeTab[i];
- ctxt->xpathCtxt->node = ctxt->node;
-#ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- ctxt->xpathCtxt->namespaces = NULL;
- ctxt->xpathCtxt->nsNr = 0;
- }
-#else
- ctxt->xpathCtxt->namespaces = comp->nsList;
- ctxt->xpathCtxt->nsNr = comp->nsNr;
-#endif
- res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
- if (res != NULL) {
- if (res->type != XPATH_STRING)
- res = xmlXPathConvertString(res);
- if (comp->number)
- res = xmlXPathConvertNumber(res);
- res->index = i; /* Save original pos for dupl resolv */
- if (comp->number) {
- if (res->type == XPATH_NUMBER) {
- results[i] = res;
- } else {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltComputeSortResult: select didn't evaluate to a number\n");
-#endif
- results[i] = NULL;
- }
- } else {
- if (res->type == XPATH_STRING) {
- results[i] = res;
- } else {
-#ifdef WITH_XSLT_DEBUG_PROCESS
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltComputeSortResult: select didn't evaluate to a string\n");
-#endif
- results[i] = NULL;
- }
- }
- } else {
- ctxt->state = XSLT_STATE_STOPPED;
- results[i] = NULL;
- }
- }
- ctxt->node = oldNode;
- ctxt->inst = oldInst;
- ctxt->xpathCtxt->contextSize = oldSize;
- ctxt->xpathCtxt->proximityPosition = oldPos;
- ctxt->xpathCtxt->nsNr = oldNsNr;
- ctxt->xpathCtxt->namespaces = oldNamespaces;
-
- return(results);
-}
-
-/**
- * xsltDefaultSortFunction:
- * @ctxt: a XSLT process context
- * @sorts: array of sort nodes
- * @nbsorts: the number of sorts in the array
- *
- * reorder the current node list accordingly to the set of sorting
- * requirement provided by the arry of nodes.
- */
-void
-xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
- int nbsorts) {
-#ifdef XSLT_REFACTORED
- xsltStyleItemSortPtr comp;
-#else
- xsltStylePreCompPtr comp;
-#endif
- xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
- xmlXPathObjectPtr *results = NULL, *res;
- xmlNodeSetPtr list = NULL;
- int descending, number, desc, numb;
- int len = 0;
- int i, j, incr;
- int tst;
- int depth;
- xmlNodePtr node;
- xmlXPathObjectPtr tmp;
- int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
-
- if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
- (nbsorts >= XSLT_MAX_SORT))
- return;
- if (sorts[0] == NULL)
- return;
- comp = sorts[0]->psvi;
- if (comp == NULL)
- return;
-
- list = ctxt->nodeList;
- if ((list == NULL) || (list->nodeNr <= 1))
- return; /* nothing to do */
-
- for (j = 0; j < nbsorts; j++) {
- comp = sorts[j]->psvi;
- tempstype[j] = 0;
- if ((comp->stype == NULL) && (comp->has_stype != 0)) {
- comp->stype =
- xsltEvalAttrValueTemplate(ctxt, sorts[j],
- (const xmlChar *) "data-type",
- XSLT_NAMESPACE);
- if (comp->stype != NULL) {
- tempstype[j] = 1;
- if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
- comp->number = 0;
- else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
- comp->number = 1;
- else {
- xsltTransformError(ctxt, NULL, sorts[j],
- "xsltDoSortFunction: no support for data-type = %s\n",
- comp->stype);
- comp->number = 0; /* use default */
- }
- }
- }
- temporder[j] = 0;
- if ((comp->order == NULL) && (comp->has_order != 0)) {
- comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
- (const xmlChar *) "order",
- XSLT_NAMESPACE);
- if (comp->order != NULL) {
- temporder[j] = 1;
- if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
- comp->descending = 0;
- else if (xmlStrEqual(comp->order,
- (const xmlChar *) "descending"))
- comp->descending = 1;
- else {
- xsltTransformError(ctxt, NULL, sorts[j],
- "xsltDoSortFunction: invalid value %s for order\n",
- comp->order);
- comp->descending = 0; /* use default */
- }
- }
- }
- }
-
- len = list->nodeNr;
-
- resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
- for (i = 1;i < XSLT_MAX_SORT;i++)
- resultsTab[i] = NULL;
-
- results = resultsTab[0];
-
- comp = sorts[0]->psvi;
- descending = comp->descending;
- number = comp->number;
- if (results == NULL)
- return;
-
- /* Shell's sort of node-set */
- for (incr = len / 2; incr > 0; incr /= 2) {
- for (i = incr; i < len; i++) {
- j = i - incr;
- if (results[i] == NULL)
- continue;
-
- while (j >= 0) {
- if (results[j] == NULL)
- tst = 1;
- else {
- if (number) {
- /* We make NaN smaller than number in accordance
- with XSLT spec */
- if (xmlXPathIsNaN(results[j]->floatval)) {
- if (xmlXPathIsNaN(results[j + incr]->floatval))
- tst = 0;
- else
- tst = -1;
- } else if (xmlXPathIsNaN(results[j + incr]->floatval))
- tst = 1;
- else if (results[j]->floatval ==
- results[j + incr]->floatval)
- tst = 0;
- else if (results[j]->floatval >
- results[j + incr]->floatval)
- tst = 1;
- else tst = -1;
- } else {
- tst = xmlStrcmp(results[j]->stringval,
- results[j + incr]->stringval);
- }
- if (descending)
- tst = -tst;
- }
- if (tst == 0) {
- /*
- * Okay we need to use multi level sorts
- */
- depth = 1;
- while (depth < nbsorts) {
- if (sorts[depth] == NULL)
- break;
- comp = sorts[depth]->psvi;
- if (comp == NULL)
- break;
- desc = comp->descending;
- numb = comp->number;
-
- /*
- * Compute the result of the next level for the
- * full set, this might be optimized ... or not
- */
- if (resultsTab[depth] == NULL)
- resultsTab[depth] = xsltComputeSortResult(ctxt,
- sorts[depth]);
- res = resultsTab[depth];
- if (res == NULL)
- break;
- if (res[j] == NULL) {
- if (res[j+incr] != NULL)
- tst = 1;
- } else {
- if (numb) {
- /* We make NaN smaller than number in
- accordance with XSLT spec */
- if (xmlXPathIsNaN(res[j]->floatval)) {
- if (xmlXPathIsNaN(res[j +
- incr]->floatval))
- tst = 0;
- else
- tst = -1;
- } else if (xmlXPathIsNaN(res[j + incr]->
- floatval))
- tst = 1;
- else if (res[j]->floatval == res[j + incr]->
- floatval)
- tst = 0;
- else if (res[j]->floatval >
- res[j + incr]->floatval)
- tst = 1;
- else tst = -1;
- } else {
- tst = xmlStrcmp(res[j]->stringval,
- res[j + incr]->stringval);
- }
- if (desc)
- tst = -tst;
- }
-
- /*
- * if we still can't differenciate at this level
- * try one level deeper.
- */
- if (tst != 0)
- break;
- depth++;
- }
- }
- if (tst == 0) {
- tst = results[j]->index > results[j + incr]->index;
- }
- if (tst > 0) {
- tmp = results[j];
- results[j] = results[j + incr];
- results[j + incr] = tmp;
- node = list->nodeTab[j];
- list->nodeTab[j] = list->nodeTab[j + incr];
- list->nodeTab[j + incr] = node;
- depth = 1;
- while (depth < nbsorts) {
- if (sorts[depth] == NULL)
- break;
- if (resultsTab[depth] == NULL)
- break;
- res = resultsTab[depth];
- tmp = res[j];
- res[j] = res[j + incr];
- res[j + incr] = tmp;
- depth++;
- }
- j -= incr;
- } else
- break;
- }
- }
- }
-
- for (j = 0; j < nbsorts; j++) {
- comp = sorts[j]->psvi;
- if (tempstype[j] == 1) {
- /* The data-type needs to be recomputed each time */
- xmlFree((void *)(comp->stype));
- comp->stype = NULL;
- }
- if (temporder[j] == 1) {
- /* The order needs to be recomputed each time */
- xmlFree((void *)(comp->order));
- comp->order = NULL;
- }
- if (resultsTab[j] != NULL) {
- for (i = 0;i < len;i++)
- xmlXPathFreeObject(resultsTab[j][i]);
- xmlFree(resultsTab[j]);
- }
- }
-}
-
-
-static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
-
-/**
- * xsltDoSortFunction:
- * @ctxt: a XSLT process context
- * @sorts: array of sort nodes
- * @nbsorts: the number of sorts in the array
- *
- * reorder the current node list accordingly to the set of sorting
- * requirement provided by the arry of nodes.
- * This is a wrapper function, the actual function used is specified
- * using xsltSetCtxtSortFunc() to set the context specific sort function,
- * or xsltSetSortFunc() to set the global sort function.
- * If a sort function is set on the context, this will get called.
- * Otherwise the global sort function is called.
- */
-void
-xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
- int nbsorts)
-{
- if (ctxt->sortfunc != NULL)
- (ctxt->sortfunc)(ctxt, sorts, nbsorts);
- else if (xsltSortFunction != NULL)
- xsltSortFunction(ctxt, sorts, nbsorts);
-}
-
-/**
- * xsltSetSortFunc:
- * @handler: the new handler function
- *
- * Function to reset the global handler for XSLT sorting.
- * If the handler is NULL, the default sort function will be used.
- */
-void
-xsltSetSortFunc(xsltSortFunc handler) {
- if (handler != NULL)
- xsltSortFunction = handler;
- else
- xsltSortFunction = xsltDefaultSortFunction;
-}
-
-/**
- * xsltSetCtxtSortFunc:
- * @ctxt: a XSLT process context
- * @handler: the new handler function
- *
- * Function to set the handler for XSLT sorting
- * for the specified context.
- * If the handler is NULL, then the global
- * sort function will be called
- */
-void
-xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
- ctxt->sortfunc = handler;
-}
-
-/************************************************************************
- * *
- * Parsing options *
- * *
- ************************************************************************/
-
-/**
- * xsltSetCtxtParseOptions:
- * @ctxt: a XSLT process context
- * @options: a combination of libxml2 xmlParserOption
- *
- * Change the default parser option passed by the XSLT engine to the
- * parser when using document() loading.
- *
- * Returns the previous options or -1 in case of error
- */
-int
-xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
-{
- int oldopts;
-
- if (ctxt == NULL)
- return(-1);
- oldopts = ctxt->parserOptions;
- ctxt->parserOptions = options;
- return(oldopts);
-}
-
-/************************************************************************
- * *
- * Output *
- * *
- ************************************************************************/
-
-/**
- * xsltSaveResultTo:
- * @buf: an output buffer
- * @result: the result xmlDocPtr
- * @style: the stylesheet
- *
- * Save the result @result obtained by applying the @style stylesheet
- * to an I/O output channel @buf
- *
- * Returns the number of byte written or -1 in case of failure.
- */
-int
-xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
- xsltStylesheetPtr style) {
- const xmlChar *encoding;
- int base;
- const xmlChar *method;
- int indent;
-
- if ((buf == NULL) || (result == NULL) || (style == NULL))
- return(-1);
- if ((result->children == NULL) ||
- ((result->children->type == XML_DTD_NODE) &&
- (result->children->next == NULL)))
- return(0);
-
- if ((style->methodURI != NULL) &&
- ((style->method == NULL) ||
- (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
- xsltGenericError(xsltGenericErrorContext,
- "xsltSaveResultTo : unknown ouput method\n");
- return(-1);
- }
-
- base = buf->written;
-
- XSLT_GET_IMPORT_PTR(method, style, method)
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- XSLT_GET_IMPORT_INT(indent, style, indent);
-
- if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
- method = (const xmlChar *) "html";
-
- if ((method != NULL) &&
- (xmlStrEqual(method, (const xmlChar *) "html"))) {
- if (encoding != NULL) {
- htmlSetMetaEncoding(result, (const xmlChar *) encoding);
- } else {
- htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
- }
- if (indent == -1)
- indent = 1;
- htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
- indent);
- xmlOutputBufferFlush(buf);
- } else if ((method != NULL) &&
- (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
- if (encoding != NULL) {
- htmlSetMetaEncoding(result, (const xmlChar *) encoding);
- } else {
- htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
- }
- htmlDocContentDumpOutput(buf, result, (const char *) encoding);
- xmlOutputBufferFlush(buf);
- } else if ((method != NULL) &&
- (xmlStrEqual(method, (const xmlChar *) "text"))) {
- xmlNodePtr cur;
-
- cur = result->children;
- while (cur != NULL) {
- if (cur->type == XML_TEXT_NODE)
- xmlOutputBufferWriteString(buf, (const char *) cur->content);
-
- /*
- * Skip to next node
- */
- if (cur->children != NULL) {
- if ((cur->children->type != XML_ENTITY_DECL) &&
- (cur->children->type != XML_ENTITY_REF_NODE) &&
- (cur->children->type != XML_ENTITY_NODE)) {
- cur = cur->children;
- continue;
- }
- }
- if (cur->next != NULL) {
- cur = cur->next;
- continue;
- }
-
- do {
- cur = cur->parent;
- if (cur == NULL)
- break;
- if (cur == (xmlNodePtr) style->doc) {
- cur = NULL;
- break;
- }
- if (cur->next != NULL) {
- cur = cur->next;
- break;
- }
- } while (cur != NULL);
- }
- xmlOutputBufferFlush(buf);
- } else {
- int omitXmlDecl;
- int standalone;
-
- XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
- XSLT_GET_IMPORT_INT(standalone, style, standalone);
-
- if (omitXmlDecl != 1) {
- xmlOutputBufferWriteString(buf, "<?xml version=");
- if (result->version != NULL)
- xmlBufferWriteQuotedString(buf->buffer, result->version);
- else
- xmlOutputBufferWriteString(buf, "\"1.0\"");
- if (encoding == NULL) {
- if (result->encoding != NULL)
- encoding = result->encoding;
- else if (result->charset != XML_CHAR_ENCODING_UTF8)
- encoding = (const xmlChar *)
- xmlGetCharEncodingName((xmlCharEncoding)
- result->charset);
- }
- if (encoding != NULL) {
- xmlOutputBufferWriteString(buf, " encoding=");
- xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
- }
- switch (standalone) {
- case 0:
- xmlOutputBufferWriteString(buf, " standalone=\"no\"");
- break;
- case 1:
- xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
- break;
- default:
- break;
- }
- xmlOutputBufferWriteString(buf, "?>\n");
- }
- if (result->children != NULL) {
- xmlNodePtr child = result->children;
-
- while (child != NULL) {
- xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
- (const char *) encoding);
- if ((child->type == XML_DTD_NODE) ||
- ((child->type == XML_COMMENT_NODE) &&
- (child->next != NULL)))
- xmlOutputBufferWriteString(buf, "\n");
- child = child->next;
- }
- xmlOutputBufferWriteString(buf, "\n");
- }
- xmlOutputBufferFlush(buf);
- }
- return(buf->written - base);
-}
-
-/**
- * xsltSaveResultToFilename:
- * @URL: a filename or URL
- * @result: the result xmlDocPtr
- * @style: the stylesheet
- * @compression: the compression factor (0 - 9 included)
- *
- * Save the result @result obtained by applying the @style stylesheet
- * to a file or @URL
- *
- * Returns the number of byte written or -1 in case of failure.
- */
-int
-xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
- xsltStylesheetPtr style, int compression) {
- xmlOutputBufferPtr buf;
- const xmlChar *encoding;
- int ret;
-
- if ((URL == NULL) || (result == NULL) || (style == NULL))
- return(-1);
- if (result->children == NULL)
- return(0);
-
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if (encoding != NULL) {
- xmlCharEncodingHandlerPtr encoder;
-
- encoder = xmlFindCharEncodingHandler((char *)encoding);
- if ((encoder != NULL) &&
- (xmlStrEqual((const xmlChar *)encoder->name,
- (const xmlChar *) "UTF-8")))
- encoder = NULL;
- buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
- } else {
- buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
- }
- if (buf == NULL)
- return(-1);
- xsltSaveResultTo(buf, result, style);
- ret = xmlOutputBufferClose(buf);
- return(ret);
-}
-
-/**
- * xsltSaveResultToFile:
- * @file: a FILE * I/O
- * @result: the result xmlDocPtr
- * @style: the stylesheet
- *
- * Save the result @result obtained by applying the @style stylesheet
- * to an open FILE * I/O.
- * This does not close the FILE @file
- *
- * Returns the number of bytes written or -1 in case of failure.
- */
-int
-xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
- xmlOutputBufferPtr buf;
- const xmlChar *encoding;
- int ret;
-
- if ((file == NULL) || (result == NULL) || (style == NULL))
- return(-1);
- if (result->children == NULL)
- return(0);
-
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if (encoding != NULL) {
- xmlCharEncodingHandlerPtr encoder;
-
- encoder = xmlFindCharEncodingHandler((char *)encoding);
- if ((encoder != NULL) &&
- (xmlStrEqual((const xmlChar *)encoder->name,
- (const xmlChar *) "UTF-8")))
- encoder = NULL;
- buf = xmlOutputBufferCreateFile(file, encoder);
- } else {
- buf = xmlOutputBufferCreateFile(file, NULL);
- }
-
- if (buf == NULL)
- return(-1);
- xsltSaveResultTo(buf, result, style);
- ret = xmlOutputBufferClose(buf);
- return(ret);
-}
-
-/**
- * xsltSaveResultToFd:
- * @fd: a file descriptor
- * @result: the result xmlDocPtr
- * @style: the stylesheet
- *
- * Save the result @result obtained by applying the @style stylesheet
- * to an open file descriptor
- * This does not close the descriptor.
- *
- * Returns the number of bytes written or -1 in case of failure.
- */
-int
-xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
- xmlOutputBufferPtr buf;
- const xmlChar *encoding;
- int ret;
-
- if ((fd < 0) || (result == NULL) || (style == NULL))
- return(-1);
- if (result->children == NULL)
- return(0);
-
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if (encoding != NULL) {
- xmlCharEncodingHandlerPtr encoder;
-
- encoder = xmlFindCharEncodingHandler((char *)encoding);
- if ((encoder != NULL) &&
- (xmlStrEqual((const xmlChar *)encoder->name,
- (const xmlChar *) "UTF-8")))
- encoder = NULL;
- buf = xmlOutputBufferCreateFd(fd, encoder);
- } else {
- buf = xmlOutputBufferCreateFd(fd, NULL);
- }
- if (buf == NULL)
- return(-1);
- xsltSaveResultTo(buf, result, style);
- ret = xmlOutputBufferClose(buf);
- return(ret);
-}
-
-/**
- * xsltSaveResultToString:
- * @doc_txt_ptr: Memory pointer for allocated XML text
- * @doc_txt_len: Length of the generated XML text
- * @result: the result xmlDocPtr
- * @style: the stylesheet
- *
- * Save the result @result obtained by applying the @style stylesheet
- * to a new allocated string.
- *
- * Returns 0 in case of success and -1 in case of error
- */
-int
-xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len,
- xmlDocPtr result, xsltStylesheetPtr style) {
- xmlOutputBufferPtr buf;
- const xmlChar *encoding;
-
- *doc_txt_ptr = NULL;
- *doc_txt_len = 0;
- if (result->children == NULL)
- return(0);
-
- XSLT_GET_IMPORT_PTR(encoding, style, encoding)
- if (encoding != NULL) {
- xmlCharEncodingHandlerPtr encoder;
-
- encoder = xmlFindCharEncodingHandler((char *)encoding);
- if ((encoder != NULL) &&
- (xmlStrEqual((const xmlChar *)encoder->name,
- (const xmlChar *) "UTF-8")))
- encoder = NULL;
- buf = xmlAllocOutputBuffer(encoder);
- } else {
- buf = xmlAllocOutputBuffer(NULL);
- }
- if (buf == NULL)
- return(-1);
- xsltSaveResultTo(buf, result, style);
- if (buf->conv != NULL) {
- *doc_txt_len = buf->conv->use;
- *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
- } else {
- *doc_txt_len = buf->buffer->use;
- *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
- }
- (void)xmlOutputBufferClose(buf);
- return 0;
-}
-
-/************************************************************************
- * *
- * Generating profiling informations *
- * *
- ************************************************************************/
-
-static long calibration = -1;
-
-/**
- * xsltCalibrateTimestamps:
- *
- * Used for to calibrate the xsltTimestamp() function
- * Should work if launched at startup and we don't loose our quantum :-)
- *
- * Returns the number of milliseconds used by xsltTimestamp()
- */
-static long
-xsltCalibrateTimestamps(void) {
- register int i;
-
- for (i = 0;i < 999;i++)
- xsltTimestamp();
- return(xsltTimestamp() / 1000);
-}
-
-/**
- * xsltCalibrateAdjust:
- * @delta: a negative dealy value found
- *
- * Used for to correct the calibration for xsltTimestamp()
- */
-void
-xsltCalibrateAdjust(long delta) {
- calibration += delta;
-}
-
-/**
- * xsltTimestamp:
- *
- * Used for gathering profiling data
- *
- * Returns the number of tenth of milliseconds since the beginning of the
- * profiling
- */
-long
-xsltTimestamp(void)
-{
-#ifdef XSLT_WIN32_PERFORMANCE_COUNTER
- BOOL ok;
- LARGE_INTEGER performanceCount;
- LARGE_INTEGER performanceFrequency;
- LONGLONG quadCount;
- double seconds;
- static LONGLONG startupQuadCount = 0;
- static LONGLONG startupQuadFreq = 0;
-
- ok = QueryPerformanceCounter(&performanceCount);
- if (!ok)
- return 0;
- quadCount = performanceCount.QuadPart;
- if (calibration < 0) {
- calibration = 0;
- ok = QueryPerformanceFrequency(&performanceFrequency);
- if (!ok)
- return 0;
- startupQuadFreq = performanceFrequency.QuadPart;
- startupQuadCount = quadCount;
- return (0);
- }
- if (startupQuadFreq == 0)
- return 0;
- seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
- return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
-
-#else /* XSLT_WIN32_PERFORMANCE_COUNTER */
-#ifdef HAVE_GETTIMEOFDAY
- static struct timeval startup;
- struct timeval cur;
- long tics;
-
- if (calibration < 0) {
- gettimeofday(&startup, NULL);
- calibration = 0;
- calibration = xsltCalibrateTimestamps();
- gettimeofday(&startup, NULL);
- return (0);
- }
-
- gettimeofday(&cur, NULL);
- tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
- tics += (cur.tv_usec - startup.tv_usec) /
- (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
-
- tics -= calibration;
- return(tics);
-#else
-
- /* Neither gettimeofday() nor Win32 performance counter available */
-
- return (0);
-
-#endif /* HAVE_GETTIMEOFDAY */
-#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
-}
-
-#define MAX_TEMPLATES 10000
-
-/**
- * xsltSaveProfiling:
- * @ctxt: an XSLT context
- * @output: a FILE * for saving the informations
- *
- * Save the profiling informations on @output
- */
-void
-xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
- int nb, i,j;
- int max;
- int total;
- long totalt;
- xsltTemplatePtr *templates;
- xsltStylesheetPtr style;
- xsltTemplatePtr template;
-
- if ((output == NULL) || (ctxt == NULL))
- return;
- if (ctxt->profile == 0)
- return;
-
- nb = 0;
- max = MAX_TEMPLATES;
- templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
- if (templates == NULL)
- return;
-
- style = ctxt->style;
- while (style != NULL) {
- template = style->templates;
- while (template != NULL) {
- if (nb >= max)
- break;
-
- if (template->nbCalls > 0)
- templates[nb++] = template;
- template = template->next;
- }
-
- style = xsltNextImport(style);
- }
-
- for (i = 0;i < nb -1;i++) {
- for (j = i + 1; j < nb; j++) {
- if ((templates[i]->time <= templates[j]->time) ||
- ((templates[i]->time == templates[j]->time) &&
- (templates[i]->nbCalls <= templates[j]->nbCalls))) {
- template = templates[j];
- templates[j] = templates[i];
- templates[i] = template;
- }
- }
- }
-
- fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",
- "number", "match", "name", "mode");
- total = 0;
- totalt = 0;
- for (i = 0;i < nb;i++) {
- fprintf(output, "%5d ", i);
- if (templates[i]->match != NULL) {
- if (xmlStrlen(templates[i]->match) > 20)
- fprintf(output, "%s\n%26s", templates[i]->match, "");
- else
- fprintf(output, "%20s", templates[i]->match);
- } else {
- fprintf(output, "%20s", "");
- }
- if (templates[i]->name != NULL) {
- if (xmlStrlen(templates[i]->name) > 20)
- fprintf(output, "%s\n%46s", templates[i]->name, "");
- else
- fprintf(output, "%20s", templates[i]->name);
- } else {
- fprintf(output, "%20s", "");
- }
- if (templates[i]->mode != NULL) {
- if (xmlStrlen(templates[i]->mode) > 10)
- fprintf(output, "%s\n%56s", templates[i]->mode, "");
- else
- fprintf(output, "%10s", templates[i]->mode);
- } else {
- fprintf(output, "%10s", "");
- }
- fprintf(output, " %6d", templates[i]->nbCalls);
- fprintf(output, " %6ld %6ld\n", templates[i]->time,
- templates[i]->time / templates[i]->nbCalls);
- total += templates[i]->nbCalls;
- totalt += templates[i]->time;
- }
- fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
-
- xmlFree(templates);
-}
-
-/************************************************************************
- * *
- * Fetching profiling informations *
- * *
- ************************************************************************/
-
-/**
- * xsltGetProfileInformation:
- * @ctxt: a transformation context
- *
- * This function should be called after the transformation completed
- * to extract template processing profiling informations if availble.
- * The informations are returned as an XML document tree like
- * <?xml version="1.0"?>
- * <profile>
- * <template rank="1" match="*" name=""
- * mode="" calls="6" time="48" average="8"/>
- * <template rank="2" match="item2|item3" name=""
- * mode="" calls="10" time="30" average="3"/>
- * <template rank="3" match="item1" name=""
- * mode="" calls="5" time="17" average="3"/>
- * </profile>
- * The caller will need to free up the returned tree with xmlFreeDoc()
- *
- * Returns the xmlDocPtr corresponding to the result or NULL if not available.
- */
-
-xmlDocPtr
-xsltGetProfileInformation(xsltTransformContextPtr ctxt)
-{
- xmlDocPtr ret = NULL;
- xmlNodePtr root, child;
- char buf[100];
-
- xsltStylesheetPtr style;
- xsltTemplatePtr *templates;
- xsltTemplatePtr templ;
- int nb = 0, max = 0, i, j;
-
- if (!ctxt)
- return NULL;
-
- if (!ctxt->profile)
- return NULL;
-
- nb = 0;
- max = 10000;
- templates =
- (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
- if (templates == NULL)
- return NULL;
-
- /*
- * collect all the templates in an array
- */
- style = ctxt->style;
- while (style != NULL) {
- templ = style->templates;
- while (templ != NULL) {
- if (nb >= max)
- break;
-
- if (templ->nbCalls > 0)
- templates[nb++] = templ;
- templ = templ->next;
- }
-
- style = (xsltStylesheetPtr) xsltNextImport(style);
- }
-
- /*
- * Sort the array by time spent
- */
- for (i = 0; i < nb - 1; i++) {
- for (j = i + 1; j < nb; j++) {
- if ((templates[i]->time <= templates[j]->time) ||
- ((templates[i]->time == templates[j]->time) &&
- (templates[i]->nbCalls <= templates[j]->nbCalls))) {
- templ = templates[j];
- templates[j] = templates[i];
- templates[i] = templ;
- }
- }
- }
-
- /*
- * Generate a document corresponding to the results.
- */
- ret = xmlNewDoc(BAD_CAST "1.0");
- root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
- xmlDocSetRootElement(ret, root);
-
- for (i = 0; i < nb; i++) {
- child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
- sprintf(buf, "%d", i + 1);
- xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
- xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
- xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
- xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
-
- sprintf(buf, "%d", templates[i]->nbCalls);
- xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
-
- sprintf(buf, "%ld", templates[i]->time);
- xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
-
- sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
- xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
- };
-
- xmlFree(templates);
-
- return ret;
-}
-
-/************************************************************************
- * *
- * Hooks for libxml2 XPath *
- * *
- ************************************************************************/
-
-/**
- * xsltXPathCompile:
- * @style: the stylesheet
- * @str: the XPath expression
- *
- * Compile an XPath expression
- *
- * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
- * the caller has to free the object.
- */
-xmlXPathCompExprPtr
-xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
- xmlXPathContextPtr xpathCtxt;
- xmlXPathCompExprPtr ret;
-
- if (style != NULL) {
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if (XSLT_CCTXT(style)) {
- /*
- * Proposed by Jerome Pesenti
- * --------------------------
- * For better efficiency we'll reuse the compilation
- * context's XPath context. For the common stylesheet using
- * XPath expressions this will reduce compilation time to
- * about 50%.
- *
- * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
- */
- xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
- xpathCtxt->doc = style->doc;
- } else
- xpathCtxt = xmlXPathNewContext(style->doc);
-#else
- xpathCtxt = xmlXPathNewContext(style->doc);
-#endif
- xpathCtxt->dict = style->dict;
- } else {
- xpathCtxt = xmlXPathNewContext(NULL);
- }
- /*
- * Compile the expression.
- */
- ret = xmlXPathCtxtCompile(xpathCtxt, str);
-
-#ifdef XSLT_REFACTORED_XPATHCOMP
- if ((style == NULL) || (! XSLT_CCTXT(style))) {
- xmlXPathFreeContext(xpathCtxt);
- }
-#else
- xmlXPathFreeContext(xpathCtxt);
-#endif
- /*
- * TODO: there is a lot of optimizations which should be possible
- * like variable slot precomputations, function precomputations, etc.
- */
-
- return(ret);
-}
-
-/************************************************************************
- * *
- * Hooks for the debugger *
- * *
- ************************************************************************/
-
-/*
- * There is currently only 3 debugging callback defined
- * Debugger callbacks are disabled by default
- */
-#define XSLT_CALLBACK_NUMBER 3
-
-typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
-typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
-struct _xsltDebuggerCallbacks {
- xsltHandleDebuggerCallback handler;
- xsltAddCallCallback add;
- xsltDropCallCallback drop;
-};
-
-static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
- NULL, /* handler */
- NULL, /* add */
- NULL /* drop */
-};
-
-int xslDebugStatus;
-
-/**
- * xsltSetDebuggerStatus:
- * @value : the value to be set
- *
- * This function sets the value of xslDebugStatus.
- */
-void
-xsltSetDebuggerStatus(int value)
-{
- xslDebugStatus = value;
-}
-
-/**
- * xsltGetDebuggerStatus:
- *
- * Get xslDebugStatus.
- *
- * Returns the value of xslDebugStatus.
- */
-int
-xsltGetDebuggerStatus(void)
-{
- return(xslDebugStatus);
-}
-
-/**
- * xsltSetDebuggerCallbacks:
- * @no : number of callbacks
- * @block : the block of callbacks
- *
- * This function allow to plug a debugger into the XSLT library
- * @block points to a block of memory containing the address of @no
- * callback routines.
- *
- * Returns 0 in case of success and -1 in case of error
- */
-int
-xsltSetDebuggerCallbacks(int no, void *block)
-{
- xsltDebuggerCallbacksPtr callbacks;
-
- if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
- return(-1);
-
- callbacks = (xsltDebuggerCallbacksPtr) block;
- xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
- xsltDebuggerCurrentCallbacks.add = callbacks->add;
- xsltDebuggerCurrentCallbacks.drop = callbacks->drop;
- return(0);
-}
-
-/**
- * xslHandleDebugger:
- * @cur : source node being executed
- * @node : data node being processed
- * @templ : temlate that applies to node
- * @ctxt : the xslt transform context
- *
- * If either cur or node are a breakpoint, or xslDebugStatus in state
- * where debugging must occcur at this time then transfer control
- * to the xslDebugBreak function
- */
-void
-xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
- xsltTransformContextPtr ctxt)
-{
- if (xsltDebuggerCurrentCallbacks.handler != NULL)
- xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
-}
-
-/**
- * xslAddCall:
- * @templ : current template being applied
- * @source : the source node being processed
- *
- * Add template "call" to call stack
- * Returns : 1 on sucess 0 otherwise an error may be printed if
- * WITH_XSLT_DEBUG_BREAKPOINTS is defined
- */
-int
-xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
-{
- if (xsltDebuggerCurrentCallbacks.add != NULL)
- return(xsltDebuggerCurrentCallbacks.add(templ, source));
- return(0);
-}
-
-/**
- * xslDropCall:
- *
- * Drop the topmost item off the call stack
- */
-void
-xslDropCall(void)
-{
- if (xsltDebuggerCurrentCallbacks.drop != NULL)
- xsltDebuggerCurrentCallbacks.drop();
-}
-
+/*\r
+ * xsltutils.c: Utilities for the XSL Transformation 1.0 engine\r
+ *\r
+ * Reference:\r
+ * http://www.w3.org/TR/1999/REC-xslt-19991116\r
+ *\r
+ * See Copyright for the status of this software.\r
+ *\r
+ * daniel@veillard.com\r
+ */\r
+\r
+#define IN_LIBXSLT\r
+#include "libxslt.h"\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#ifdef HAVE_SYS_TIME_H\r
+#include <sys/time.h>\r
+#endif\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+#ifdef HAVE_STDLIB_H\r
+#include <stdlib.h>\r
+#endif\r
+#include <stdarg.h>\r
+\r
+#include <libxml/xmlmemory.h>\r
+#include <libxml/tree.h>\r
+#include <libxml/HTMLtree.h>\r
+#include <libxml/xmlerror.h>\r
+#include <libxml/xmlIO.h>\r
+#include "xsltutils.h"\r
+#include "templates.h"\r
+#include "xsltInternals.h"\r
+#include "imports.h"\r
+#include "transform.h"\r
+\r
+/* gettimeofday on Windows ??? */\r
+#if defined(WIN32) && !defined(__CYGWIN__)\r
+#ifdef _MSC_VER\r
+#include <winsock2.h>\r
+#pragma comment(lib, "ws2_32.lib")\r
+#define gettimeofday(p1,p2)\r
+#define HAVE_GETTIMEOFDAY\r
+#define XSLT_WIN32_PERFORMANCE_COUNTER\r
+#endif /* _MS_VER */\r
+#endif /* WIN32 */\r
+\r
+#ifdef XSLT_NEED_TRIO\r
+#include "trio.h"\r
+#define vsnprintf trio_vsnprintf\r
+#endif\r
+\r
+/************************************************************************\r
+ * *\r
+ * Convenience function *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltGetCNsProp:\r
+ * @style: the stylesheet\r
+ * @node: the node\r
+ * @name: the attribute name\r
+ * @nameSpace: the URI of the namespace\r
+ *\r
+ * Similar to xmlGetNsProp() but with a slightly different semantic\r
+ *\r
+ * Search and get the value of an attribute associated to a node\r
+ * This attribute has to be anchored in the namespace specified,\r
+ * or has no namespace and the element is in that namespace.\r
+ *\r
+ * This does the entity substitution.\r
+ * This function looks in DTD attribute declaration for #FIXED or\r
+ * default declaration values unless DTD use has been turned off.\r
+ *\r
+ * Returns the attribute value or NULL if not found. The string is allocated\r
+ * in the stylesheet dictionnary.\r
+ */\r
+const xmlChar *\r
+xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,\r
+ const xmlChar *name, const xmlChar *nameSpace) {\r
+ xmlAttrPtr prop;\r
+ xmlDocPtr doc;\r
+ xmlNsPtr ns;\r
+ xmlChar *tmp;\r
+ const xmlChar *ret;\r
+\r
+ if ((node == NULL) || (style == NULL) || (style->dict == NULL))\r
+ return(NULL);\r
+\r
+ prop = node->properties;\r
+ if (nameSpace == NULL) {\r
+ return xmlGetProp(node, name);\r
+ }\r
+ while (prop != NULL) {\r
+ /*\r
+ * One need to have\r
+ * - same attribute names\r
+ * - and the attribute carrying that namespace\r
+ */\r
+ if ((xmlStrEqual(prop->name, name)) &&\r
+ (((prop->ns == NULL) && (node->ns != NULL) &&\r
+ (xmlStrEqual(node->ns->href, nameSpace))) ||\r
+ ((prop->ns != NULL) &&\r
+ (xmlStrEqual(prop->ns->href, nameSpace))))) {\r
+\r
+ tmp = xmlNodeListGetString(node->doc, prop->children, 1);\r
+ if (tmp == NULL)\r
+ ret = xmlDictLookup(style->dict, BAD_CAST "", 0);\r
+ else {\r
+ ret = xmlDictLookup(style->dict, tmp, -1);\r
+ xmlFree(tmp);\r
+ }\r
+ return ret;\r
+ }\r
+ prop = prop->next;\r
+ }\r
+ tmp = NULL;\r
+ /*\r
+ * Check if there is a default declaration in the internal\r
+ * or external subsets\r
+ */\r
+ doc = node->doc;\r
+ if (doc != NULL) {\r
+ if (doc->intSubset != NULL) {\r
+ xmlAttributePtr attrDecl;\r
+\r
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);\r
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))\r
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);\r
+ \r
+ if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {\r
+ /*\r
+ * The DTD declaration only allows a prefix search\r
+ */\r
+ ns = xmlSearchNs(doc, node, attrDecl->prefix);\r
+ if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))\r
+ return(xmlDictLookup(style->dict,\r
+ attrDecl->defaultValue, -1));\r
+ }\r
+ }\r
+ }\r
+ return(NULL);\r
+}\r
+/**\r
+ * xsltGetNsProp:\r
+ * @node: the node\r
+ * @name: the attribute name\r
+ * @nameSpace: the URI of the namespace\r
+ *\r
+ * Similar to xmlGetNsProp() but with a slightly different semantic\r
+ *\r
+ * Search and get the value of an attribute associated to a node\r
+ * This attribute has to be anchored in the namespace specified,\r
+ * or has no namespace and the element is in that namespace.\r
+ *\r
+ * This does the entity substitution.\r
+ * This function looks in DTD attribute declaration for #FIXED or\r
+ * default declaration values unless DTD use has been turned off.\r
+ *\r
+ * Returns the attribute value or NULL if not found.\r
+ * It's up to the caller to free the memory.\r
+ */\r
+xmlChar *\r
+xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {\r
+ xmlAttrPtr prop;\r
+ xmlDocPtr doc;\r
+ xmlNsPtr ns;\r
+\r
+ if (node == NULL)\r
+ return(NULL);\r
+\r
+ prop = node->properties;\r
+ /*\r
+ * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former\r
+ * is not namespace-aware and will return an attribute with equal\r
+ * name regardless of its namespace.\r
+ * Example:\r
+ * <xsl:element foo:name="myName"/>\r
+ * So this would return "myName" even if an attribute @name\r
+ * in the XSLT was requested.\r
+ */\r
+ if (nameSpace == NULL)\r
+ return(xmlGetProp(node, name));\r
+ while (prop != NULL) {\r
+ /*\r
+ * One need to have\r
+ * - same attribute names\r
+ * - and the attribute carrying that namespace\r
+ */\r
+ if ((xmlStrEqual(prop->name, name)) &&\r
+ (((prop->ns == NULL) && (node->ns != NULL) &&\r
+ (xmlStrEqual(node->ns->href, nameSpace))) ||\r
+ ((prop->ns != NULL) &&\r
+ (xmlStrEqual(prop->ns->href, nameSpace))))) {\r
+ xmlChar *ret;\r
+\r
+ ret = xmlNodeListGetString(node->doc, prop->children, 1);\r
+ if (ret == NULL) return(xmlStrdup((xmlChar *)""));\r
+ return(ret);\r
+ }\r
+ prop = prop->next;\r
+ }\r
+\r
+ /*\r
+ * Check if there is a default declaration in the internal\r
+ * or external subsets\r
+ */\r
+ doc = node->doc;\r
+ if (doc != NULL) {\r
+ if (doc->intSubset != NULL) {\r
+ xmlAttributePtr attrDecl;\r
+\r
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);\r
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))\r
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);\r
+ \r
+ if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {\r
+ /*\r
+ * The DTD declaration only allows a prefix search\r
+ */\r
+ ns = xmlSearchNs(doc, node, attrDecl->prefix);\r
+ if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))\r
+ return(xmlStrdup(attrDecl->defaultValue));\r
+ }\r
+ }\r
+ }\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ * xsltGetUTF8Char:\r
+ * @utf: a sequence of UTF-8 encoded bytes\r
+ * @len: a pointer to @bytes len\r
+ *\r
+ * Read one UTF8 Char from @utf\r
+ * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately\r
+ * and use the original API\r
+ *\r
+ * Returns the char value or -1 in case of error and update @len with the\r
+ * number of bytes used\r
+ */\r
+int\r
+xsltGetUTF8Char(const unsigned char *utf, int *len) {\r
+ unsigned int c;\r
+\r
+ if (utf == NULL)\r
+ goto error;\r
+ if (len == NULL)\r
+ goto error;\r
+ if (*len < 1)\r
+ goto error;\r
+\r
+ c = utf[0];\r
+ if (c & 0x80) {\r
+ if (*len < 2)\r
+ goto error;\r
+ if ((utf[1] & 0xc0) != 0x80)\r
+ goto error;\r
+ if ((c & 0xe0) == 0xe0) {\r
+ if (*len < 3)\r
+ goto error;\r
+ if ((utf[2] & 0xc0) != 0x80)\r
+ goto error;\r
+ if ((c & 0xf0) == 0xf0) {\r
+ if (*len < 4)\r
+ goto error;\r
+ if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)\r
+ goto error;\r
+ *len = 4;\r
+ /* 4-byte code */\r
+ c = (utf[0] & 0x7) << 18;\r
+ c |= (utf[1] & 0x3f) << 12;\r
+ c |= (utf[2] & 0x3f) << 6;\r
+ c |= utf[3] & 0x3f;\r
+ } else {\r
+ /* 3-byte code */\r
+ *len = 3;\r
+ c = (utf[0] & 0xf) << 12;\r
+ c |= (utf[1] & 0x3f) << 6;\r
+ c |= utf[2] & 0x3f;\r
+ }\r
+ } else {\r
+ /* 2-byte code */\r
+ *len = 2;\r
+ c = (utf[0] & 0x1f) << 6;\r
+ c |= utf[1] & 0x3f;\r
+ }\r
+ } else {\r
+ /* 1-byte code */\r
+ *len = 1;\r
+ }\r
+ return(c);\r
+\r
+error:\r
+ if (len != NULL)\r
+ *len = 0;\r
+ return(-1);\r
+}\r
+\r
+#ifdef XSLT_REFACTORED\r
+\r
+/**\r
+ * xsltPointerListAddSize:\r
+ * @list: the pointer list structure\r
+ * @item: the item to be stored\r
+ * @initialSize: the initial size of the list\r
+ *\r
+ * Adds an item to the list.\r
+ *\r
+ * Returns the position of the added item in the list or\r
+ * -1 in case of an error.\r
+ */\r
+int\r
+xsltPointerListAddSize(xsltPointerListPtr list, \r
+ void *item,\r
+ int initialSize)\r
+{\r
+ if (list->items == NULL) {\r
+ if (initialSize <= 0)\r
+ initialSize = 1;\r
+ list->items = (void **) xmlMalloc(\r
+ initialSize * sizeof(void *));\r
+ if (list->items == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltPointerListAddSize: memory allocation failure.\n");\r
+ return(-1);\r
+ }\r
+ list->number = 0;\r
+ list->size = initialSize;\r
+ } else if (list->size <= list->number) {\r
+ list->size *= 2;\r
+ list->items = (void **) xmlRealloc(list->items,\r
+ list->size * sizeof(void *));\r
+ if (list->items == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltPointerListAddSize: memory re-allocation failure.\n");\r
+ list->size = 0;\r
+ return(-1);\r
+ }\r
+ }\r
+ list->items[list->number++] = item;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xsltPointerListCreate:\r
+ *\r
+ * Creates an xsltPointerList structure.\r
+ *\r
+ * Returns a xsltPointerList structure or NULL in case of an error.\r
+ */\r
+xsltPointerListPtr\r
+xsltPointerListCreate(int initialSize)\r
+{\r
+ xsltPointerListPtr ret;\r
+\r
+ ret = xmlMalloc(sizeof(xsltPointerList));\r
+ if (ret == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltPointerListCreate: memory allocation failure.\n");\r
+ return (NULL);\r
+ }\r
+ memset(ret, 0, sizeof(xsltPointerList));\r
+ if (initialSize > 0) {\r
+ xsltPointerListAddSize(ret, NULL, initialSize);\r
+ ret->number = 0;\r
+ }\r
+ return (ret);\r
+}\r
+\r
+/**\r
+ * xsltPointerListFree:\r
+ *\r
+ * Frees the xsltPointerList structure. This does not free\r
+ * the content of the list.\r
+ */\r
+void\r
+xsltPointerListFree(xsltPointerListPtr list)\r
+{\r
+ if (list == NULL)\r
+ return;\r
+ if (list->items != NULL)\r
+ xmlFree(list->items);\r
+ xmlFree(list);\r
+}\r
+\r
+/**\r
+ * xsltPointerListFree:\r
+ *\r
+ * Resets the list, but does not free the allocated array\r
+ * and does not free the content of the list.\r
+ */\r
+void\r
+xsltPointerListClear(xsltPointerListPtr list)\r
+{\r
+ if (list->items != NULL) {\r
+ xmlFree(list->items);\r
+ list->items = NULL;\r
+ }\r
+ list->number = 0;\r
+ list->size = 0;\r
+}\r
+\r
+#endif /* XSLT_REFACTORED */\r
+\r
+/************************************************************************\r
+ * *\r
+ * Handling of XSLT stylesheets messages *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltMessage:\r
+ * @ctxt: an XSLT processing context\r
+ * @node: The current node\r
+ * @inst: The node containing the message instruction\r
+ *\r
+ * Process and xsl:message construct\r
+ */\r
+void\r
+xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {\r
+ xmlChar *prop, *message;\r
+ int terminate = 0;\r
+\r
+ if ((ctxt == NULL) || (inst == NULL))\r
+ return;\r
+\r
+ prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);\r
+ if (prop != NULL) {\r
+ if (xmlStrEqual(prop, (const xmlChar *)"yes")) {\r
+ terminate = 1;\r
+ } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {\r
+ terminate = 0;\r
+ } else {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:message : terminate expecting 'yes' or 'no'\n");\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+ }\r
+ xmlFree(prop);\r
+ }\r
+ message = xsltEvalTemplateString(ctxt, node, inst);\r
+ if (message != NULL) {\r
+ int len = xmlStrlen(message);\r
+\r
+ xsltGenericError(xsltGenericErrorContext, "%s",\r
+ (const char *)message);\r
+ if ((len > 0) && (message[len - 1] != '\n'))\r
+ xsltGenericError(xsltGenericErrorContext, "\n");\r
+ xmlFree(message);\r
+ }\r
+ if (terminate)\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Handling of out of context errors *\r
+ * *\r
+ ************************************************************************/\r
+\r
+#define XSLT_GET_VAR_STR(msg, str) { \\r
+ int size; \\r
+ int chars; \\r
+ char *larger; \\r
+ va_list ap; \\r
+ \\r
+ str = (char *) xmlMalloc(150); \\r
+ if (str == NULL) \\r
+ return; \\r
+ \\r
+ size = 150; \\r
+ \\r
+ while (1) { \\r
+ va_start(ap, msg); \\r
+ chars = vsnprintf(str, size, msg, ap); \\r
+ va_end(ap); \\r
+ if ((chars > -1) && (chars < size)) \\r
+ break; \\r
+ if (chars > -1) \\r
+ size += chars + 1; \\r
+ else \\r
+ size += 100; \\r
+ if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\\r
+ xmlFree(str); \\r
+ return; \\r
+ } \\r
+ str = larger; \\r
+ } \\r
+}\r
+/**\r
+ * xsltGenericErrorDefaultFunc:\r
+ * @ctx: an error context\r
+ * @msg: the message to display/transmit\r
+ * @...: extra parameters for the message display\r
+ * \r
+ * Default handler for out of context error messages.\r
+ */\r
+static void\r
+xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {\r
+ va_list args;\r
+\r
+ if (xsltGenericErrorContext == NULL)\r
+ xsltGenericErrorContext = (void *) stderr;\r
+\r
+ va_start(args, msg);\r
+ vfprintf((FILE *)xsltGenericErrorContext, msg, args);\r
+ va_end(args);\r
+}\r
+\r
+xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;\r
+void *xsltGenericErrorContext = NULL;\r
+\r
+\r
+/**\r
+ * xsltSetGenericErrorFunc:\r
+ * @ctx: the new error handling context\r
+ * @handler: the new handler function\r
+ *\r
+ * Function to reset the handler and the error context for out of\r
+ * context error messages.\r
+ * This simply means that @handler will be called for subsequent\r
+ * error messages while not parsing nor validating. And @ctx will\r
+ * be passed as first argument to @handler\r
+ * One can simply force messages to be emitted to another FILE * than\r
+ * stderr by setting @ctx to this file handle and @handler to NULL.\r
+ */\r
+void\r
+xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {\r
+ xsltGenericErrorContext = ctx;\r
+ if (handler != NULL)\r
+ xsltGenericError = handler;\r
+ else\r
+ xsltGenericError = xsltGenericErrorDefaultFunc;\r
+}\r
+\r
+/**\r
+ * xsltGenericDebugDefaultFunc:\r
+ * @ctx: an error context\r
+ * @msg: the message to display/transmit\r
+ * @...: extra parameters for the message display\r
+ * \r
+ * Default handler for out of context error messages.\r
+ */\r
+static void\r
+xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {\r
+ va_list args;\r
+\r
+ if (xsltGenericDebugContext == NULL)\r
+ return;\r
+\r
+ va_start(args, msg);\r
+ vfprintf((FILE *)xsltGenericDebugContext, msg, args);\r
+ va_end(args);\r
+}\r
+\r
+xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;\r
+void *xsltGenericDebugContext = NULL;\r
+\r
+\r
+/**\r
+ * xsltSetGenericDebugFunc:\r
+ * @ctx: the new error handling context\r
+ * @handler: the new handler function\r
+ *\r
+ * Function to reset the handler and the error context for out of\r
+ * context error messages.\r
+ * This simply means that @handler will be called for subsequent\r
+ * error messages while not parsing or validating. And @ctx will\r
+ * be passed as first argument to @handler\r
+ * One can simply force messages to be emitted to another FILE * than\r
+ * stderr by setting @ctx to this file handle and @handler to NULL.\r
+ */\r
+void\r
+xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {\r
+ xsltGenericDebugContext = ctx;\r
+ if (handler != NULL)\r
+ xsltGenericDebug = handler;\r
+ else\r
+ xsltGenericDebug = xsltGenericDebugDefaultFunc;\r
+}\r
+\r
+/**\r
+ * xsltPrintErrorContext:\r
+ * @ctxt: the transformation context\r
+ * @style: the stylesheet\r
+ * @node: the current node being processed\r
+ *\r
+ * Display the context of an error.\r
+ */\r
+void\r
+xsltPrintErrorContext(xsltTransformContextPtr ctxt,\r
+ xsltStylesheetPtr style, xmlNodePtr node) {\r
+ int line = 0;\r
+ const xmlChar *file = NULL;\r
+ const xmlChar *name = NULL;\r
+ const char *type = "error";\r
+ xmlGenericErrorFunc error = xsltGenericError;\r
+ void *errctx = xsltGenericErrorContext;\r
+\r
+ if (ctxt != NULL) {\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+ if (ctxt->error != NULL) {\r
+ error = ctxt->error;\r
+ errctx = ctxt->errctx;\r
+ }\r
+ }\r
+ if ((node == NULL) && (ctxt != NULL))\r
+ node = ctxt->inst;\r
+\r
+ if (node != NULL) {\r
+ if ((node->type == XML_DOCUMENT_NODE) ||\r
+ (node->type == XML_HTML_DOCUMENT_NODE)) {\r
+ xmlDocPtr doc = (xmlDocPtr) node;\r
+\r
+ file = doc->URL;\r
+ } else {\r
+ line = xmlGetLineNo(node);\r
+ if ((node->doc != NULL) && (node->doc->URL != NULL))\r
+ file = node->doc->URL;\r
+ if (node->name != NULL)\r
+ name = node->name;\r
+ }\r
+ } \r
+ \r
+ if (ctxt != NULL)\r
+ type = "runtime error";\r
+ else if (style != NULL) {\r
+#ifdef XSLT_REFACTORED\r
+ if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)\r
+ type = "compilation warning";\r
+ else\r
+ type = "compilation error";\r
+#else\r
+ type = "compilation error";\r
+#endif\r
+ }\r
+\r
+ if ((file != NULL) && (line != 0) && (name != NULL))\r
+ error(errctx, "%s: file %s line %d element %s\n",\r
+ type, file, line, name);\r
+ else if ((file != NULL) && (name != NULL))\r
+ error(errctx, "%s: file %s element %s\n", type, file, name);\r
+ else if ((file != NULL) && (line != 0))\r
+ error(errctx, "%s: file %s line %d\n", type, file, line);\r
+ else if (file != NULL)\r
+ error(errctx, "%s: file %s\n", type, file);\r
+ else if (name != NULL)\r
+ error(errctx, "%s: element %s\n", type, name);\r
+ else\r
+ error(errctx, "%s\n", type);\r
+}\r
+\r
+/**\r
+ * xsltSetTransformErrorFunc:\r
+ * @ctxt: the XSLT transformation context\r
+ * @ctx: the new error handling context\r
+ * @handler: the new handler function\r
+ *\r
+ * Function to reset the handler and the error context for out of\r
+ * context error messages specific to a given XSLT transromation.\r
+ *\r
+ * This simply means that @handler will be called for subsequent\r
+ * error messages while running the transformation.\r
+ */\r
+void\r
+xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,\r
+ void *ctx, xmlGenericErrorFunc handler)\r
+{\r
+ ctxt->error = handler;\r
+ ctxt->errctx = ctx;\r
+}\r
+\r
+/**\r
+ * xsltTransformError:\r
+ * @ctxt: an XSLT transformation context\r
+ * @style: the XSLT stylesheet used\r
+ * @node: the current node in the stylesheet\r
+ * @msg: the message to display/transmit\r
+ * @...: extra parameters for the message display\r
+ *\r
+ * Display and format an error messages, gives file, line, position and\r
+ * extra parameters, will use the specific transformation context if available\r
+ */\r
+void\r
+xsltTransformError(xsltTransformContextPtr ctxt,\r
+ xsltStylesheetPtr style,\r
+ xmlNodePtr node,\r
+ const char *msg, ...) {\r
+ xmlGenericErrorFunc error = xsltGenericError;\r
+ void *errctx = xsltGenericErrorContext;\r
+ char * str;\r
+\r
+ if (ctxt != NULL) {\r
+ ctxt->state = XSLT_STATE_ERROR;\r
+ if (ctxt->error != NULL) {\r
+ error = ctxt->error;\r
+ errctx = ctxt->errctx;\r
+ }\r
+ }\r
+ if ((node == NULL) && (ctxt != NULL))\r
+ node = ctxt->inst;\r
+ xsltPrintErrorContext(ctxt, style, node);\r
+ XSLT_GET_VAR_STR(msg, str);\r
+ error(errctx, "%s", str);\r
+ if (str != NULL)\r
+ xmlFree(str);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * QNames *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltSplitQName:\r
+ * @dict: a dictionnary\r
+ * @name: the full QName\r
+ * @prefix: the return value\r
+ *\r
+ * Split QNames into prefix and local names, both allocated from a dictionnary.\r
+ *\r
+ * Returns: the localname or NULL in case of error.\r
+ */\r
+const xmlChar *\r
+xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {\r
+ int len = 0;\r
+ const xmlChar *ret = NULL;\r
+\r
+ *prefix = NULL;\r
+ if ((name == NULL) || (dict == NULL)) return(NULL);\r
+ if (name[0] == ':')\r
+ return(xmlDictLookup(dict, name, -1));\r
+ while ((name[len] != 0) && (name[len] != ':')) len++;\r
+ if (name[len] == 0) return(xmlDictLookup(dict, name, -1));\r
+ *prefix = xmlDictLookup(dict, name, len);\r
+ ret = xmlDictLookup(dict, &name[len + 1], -1);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltGetQNameURI:\r
+ * @node: the node holding the QName\r
+ * @name: pointer to the initial QName value\r
+ *\r
+ * This function analyzes @name, if the name contains a prefix,\r
+ * the function seaches the associated namespace in scope for it.\r
+ * It will also replace @name value with the NCName, the old value being\r
+ * freed.\r
+ * Errors in the prefix lookup are signalled by setting @name to NULL.\r
+ *\r
+ * NOTE: the namespace returned is a pointer to the place where it is\r
+ * defined and hence has the same lifespan as the document holding it.\r
+ *\r
+ * Returns the namespace URI if there is a prefix, or NULL if @name is\r
+ * not prefixed.\r
+ */\r
+const xmlChar *\r
+xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)\r
+{\r
+ int len = 0;\r
+ xmlChar *qname;\r
+ xmlNsPtr ns;\r
+\r
+ if (name == NULL)\r
+ return(NULL);\r
+ qname = *name;\r
+ if ((qname == NULL) || (*qname == 0))\r
+ return(NULL);\r
+ if (node == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "QName: no element for namespace lookup %s\n",\r
+ qname);\r
+ xmlFree(qname);\r
+ *name = NULL;\r
+ return(NULL);\r
+ }\r
+\r
+ /* nasty but valid */\r
+ if (qname[0] == ':')\r
+ return(NULL);\r
+\r
+ /*\r
+ * we are not trying to validate but just to cut, and yes it will\r
+ * work even if this is a set of UTF-8 encoded chars\r
+ */\r
+ while ((qname[len] != 0) && (qname[len] != ':')) \r
+ len++;\r
+ \r
+ if (qname[len] == 0)\r
+ return(NULL);\r
+\r
+ /*\r
+ * handle xml: separately, this one is magical\r
+ */\r
+ if ((qname[0] == 'x') && (qname[1] == 'm') &&\r
+ (qname[2] == 'l') && (qname[3] == ':')) {\r
+ if (qname[4] == 0)\r
+ return(NULL);\r
+ *name = xmlStrdup(&qname[4]);\r
+ xmlFree(qname);\r
+ return(XML_XML_NAMESPACE);\r
+ }\r
+\r
+ qname[len] = 0;\r
+ ns = xmlSearchNs(node->doc, node, qname);\r
+ if (ns == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "%s:%s : no namespace bound to prefix %s\n",\r
+ qname, &qname[len + 1], qname);\r
+ *name = NULL;\r
+ xmlFree(qname);\r
+ return(NULL);\r
+ }\r
+ *name = xmlStrdup(&qname[len + 1]);\r
+ xmlFree(qname);\r
+ return(ns->href);\r
+}\r
+\r
+/**\r
+ * xsltGetQNameURI2:\r
+ * @style: stylesheet pointer\r
+ * @node: the node holding the QName\r
+ * @name: pointer to the initial QName value\r
+ *\r
+ * This function is similar to xsltGetQNameURI, but is used when\r
+ * @name is a dictionary entry.\r
+ *\r
+ * Returns the namespace URI if there is a prefix, or NULL if @name is\r
+ * not prefixed.\r
+ */\r
+const xmlChar *\r
+xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,\r
+ const xmlChar **name) {\r
+ int len = 0;\r
+ xmlChar *qname;\r
+ xmlNsPtr ns;\r
+\r
+ if (name == NULL)\r
+ return(NULL);\r
+ qname = (xmlChar *)*name;\r
+ if ((qname == NULL) || (*qname == 0))\r
+ return(NULL);\r
+ if (node == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "QName: no element for namespace lookup %s\n",\r
+ qname);\r
+ *name = NULL;\r
+ return(NULL);\r
+ }\r
+\r
+ /*\r
+ * we are not trying to validate but just to cut, and yes it will\r
+ * work even if this is a set of UTF-8 encoded chars\r
+ */\r
+ while ((qname[len] != 0) && (qname[len] != ':'))\r
+ len++;\r
+\r
+ if (qname[len] == 0)\r
+ return(NULL);\r
+\r
+ /*\r
+ * handle xml: separately, this one is magical\r
+ */\r
+ if ((qname[0] == 'x') && (qname[1] == 'm') &&\r
+ (qname[2] == 'l') && (qname[3] == ':')) {\r
+ if (qname[4] == 0)\r
+ return(NULL);\r
+ *name = xmlDictLookup(style->dict, &qname[4], -1);\r
+ return(XML_XML_NAMESPACE);\r
+ }\r
+\r
+ qname = xmlStrndup(*name, len);\r
+ ns = xmlSearchNs(node->doc, node, qname);\r
+ if (ns == NULL) {\r
+ if (style) {\r
+ xsltTransformError(NULL, style, node,\r
+ "No namespace bound to prefix '%s'.\n",\r
+ qname);\r
+ style->errors++;\r
+ } else {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "%s : no namespace bound to prefix %s\n",\r
+ *name, qname);\r
+ }\r
+ *name = NULL;\r
+ xmlFree(qname);\r
+ return(NULL);\r
+ }\r
+ *name = xmlDictLookup(style->dict, (*name)+len+1, -1);\r
+ xmlFree(qname);\r
+ return(ns->href);\r
+}\r
+ \r
+/************************************************************************\r
+ * *\r
+ * Sorting *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltDocumentSortFunction:\r
+ * @list: the node set\r
+ *\r
+ * reorder the current node list @list accordingly to the document order\r
+ * This function is slow, obsolete and should not be used anymore.\r
+ */\r
+void\r
+xsltDocumentSortFunction(xmlNodeSetPtr list) {\r
+ int i, j;\r
+ int len, tst;\r
+ xmlNodePtr node;\r
+\r
+ if (list == NULL)\r
+ return;\r
+ len = list->nodeNr;\r
+ if (len <= 1)\r
+ return;\r
+ /* TODO: sort is really not optimized, does it needs to ? */\r
+ for (i = 0;i < len -1;i++) {\r
+ for (j = i + 1; j < len; j++) {\r
+ tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);\r
+ if (tst == -1) {\r
+ node = list->nodeTab[i];\r
+ list->nodeTab[i] = list->nodeTab[j];\r
+ list->nodeTab[j] = node;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * xsltComputeSortResult:\r
+ * @ctxt: a XSLT process context\r
+ * @sort: node list\r
+ *\r
+ * reorder the current node list accordingly to the set of sorting\r
+ * requirement provided by the array of nodes.\r
+ *\r
+ * Returns a ordered XPath nodeset or NULL in case of error.\r
+ */\r
+xmlXPathObjectPtr *\r
+xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemSortPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ xmlXPathObjectPtr *results = NULL;\r
+ xmlNodeSetPtr list = NULL;\r
+ xmlXPathObjectPtr res;\r
+ int len = 0;\r
+ int i; \r
+ xmlNodePtr oldNode;\r
+ xmlNodePtr oldInst;\r
+ int oldPos, oldSize ;\r
+ int oldNsNr;\r
+ xmlNsPtr *oldNamespaces;\r
+\r
+ comp = sort->psvi;\r
+ if (comp == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsl:sort : compilation failed\n");\r
+ return(NULL);\r
+ }\r
+\r
+ if ((comp->select == NULL) || (comp->comp == NULL))\r
+ return(NULL);\r
+\r
+ list = ctxt->nodeList;\r
+ if ((list == NULL) || (list->nodeNr <= 1))\r
+ return(NULL);\r
+\r
+ len = list->nodeNr;\r
+\r
+ /* TODO: xsl:sort lang attribute */\r
+ /* TODO: xsl:sort case-order attribute */\r
+\r
+\r
+ results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));\r
+ if (results == NULL) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltComputeSortResult: memory allocation failure\n");\r
+ return(NULL);\r
+ }\r
+\r
+ oldNode = ctxt->node;\r
+ oldInst = ctxt->inst;\r
+ oldPos = ctxt->xpathCtxt->proximityPosition;\r
+ oldSize = ctxt->xpathCtxt->contextSize;\r
+ oldNsNr = ctxt->xpathCtxt->nsNr;\r
+ oldNamespaces = ctxt->xpathCtxt->namespaces;\r
+ for (i = 0;i < len;i++) {\r
+ ctxt->inst = sort;\r
+ ctxt->xpathCtxt->contextSize = len;\r
+ ctxt->xpathCtxt->proximityPosition = i + 1;\r
+ ctxt->node = list->nodeTab[i];\r
+ ctxt->xpathCtxt->node = ctxt->node;\r
+#ifdef XSLT_REFACTORED\r
+ if (comp->inScopeNs != NULL) {\r
+ ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;\r
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;\r
+ } else {\r
+ ctxt->xpathCtxt->namespaces = NULL;\r
+ ctxt->xpathCtxt->nsNr = 0;\r
+ }\r
+#else\r
+ ctxt->xpathCtxt->namespaces = comp->nsList;\r
+ ctxt->xpathCtxt->nsNr = comp->nsNr;\r
+#endif\r
+ res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);\r
+ if (res != NULL) {\r
+ if (res->type != XPATH_STRING)\r
+ res = xmlXPathConvertString(res);\r
+ if (comp->number)\r
+ res = xmlXPathConvertNumber(res);\r
+ res->index = i; /* Save original pos for dupl resolv */\r
+ if (comp->number) {\r
+ if (res->type == XPATH_NUMBER) {\r
+ results[i] = res;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltComputeSortResult: select didn't evaluate to a number\n");\r
+#endif\r
+ results[i] = NULL;\r
+ }\r
+ } else {\r
+ if (res->type == XPATH_STRING) {\r
+ results[i] = res;\r
+ } else {\r
+#ifdef WITH_XSLT_DEBUG_PROCESS\r
+ xsltGenericDebug(xsltGenericDebugContext,\r
+ "xsltComputeSortResult: select didn't evaluate to a string\n");\r
+#endif\r
+ results[i] = NULL;\r
+ }\r
+ }\r
+ } else {\r
+ ctxt->state = XSLT_STATE_STOPPED;\r
+ results[i] = NULL;\r
+ }\r
+ }\r
+ ctxt->node = oldNode;\r
+ ctxt->inst = oldInst;\r
+ ctxt->xpathCtxt->contextSize = oldSize;\r
+ ctxt->xpathCtxt->proximityPosition = oldPos;\r
+ ctxt->xpathCtxt->nsNr = oldNsNr;\r
+ ctxt->xpathCtxt->namespaces = oldNamespaces;\r
+\r
+ return(results);\r
+}\r
+\r
+/**\r
+ * xsltDefaultSortFunction:\r
+ * @ctxt: a XSLT process context\r
+ * @sorts: array of sort nodes\r
+ * @nbsorts: the number of sorts in the array\r
+ *\r
+ * reorder the current node list accordingly to the set of sorting\r
+ * requirement provided by the arry of nodes.\r
+ */\r
+void \r
+xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,\r
+ int nbsorts) {\r
+#ifdef XSLT_REFACTORED\r
+ xsltStyleItemSortPtr comp;\r
+#else\r
+ xsltStylePreCompPtr comp;\r
+#endif\r
+ xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];\r
+ xmlXPathObjectPtr *results = NULL, *res;\r
+ xmlNodeSetPtr list = NULL;\r
+ int descending, number, desc, numb;\r
+ int len = 0;\r
+ int i, j, incr;\r
+ int tst;\r
+ int depth;\r
+ xmlNodePtr node;\r
+ xmlXPathObjectPtr tmp; \r
+ int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];\r
+\r
+ if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||\r
+ (nbsorts >= XSLT_MAX_SORT))\r
+ return;\r
+ if (sorts[0] == NULL)\r
+ return;\r
+ comp = sorts[0]->psvi;\r
+ if (comp == NULL)\r
+ return;\r
+\r
+ list = ctxt->nodeList;\r
+ if ((list == NULL) || (list->nodeNr <= 1))\r
+ return; /* nothing to do */\r
+\r
+ for (j = 0; j < nbsorts; j++) {\r
+ comp = sorts[j]->psvi;\r
+ tempstype[j] = 0;\r
+ if ((comp->stype == NULL) && (comp->has_stype != 0)) {\r
+ comp->stype =\r
+ xsltEvalAttrValueTemplate(ctxt, sorts[j],\r
+ (const xmlChar *) "data-type",\r
+ XSLT_NAMESPACE);\r
+ if (comp->stype != NULL) {\r
+ tempstype[j] = 1;\r
+ if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))\r
+ comp->number = 0;\r
+ else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))\r
+ comp->number = 1;\r
+ else {\r
+ xsltTransformError(ctxt, NULL, sorts[j],\r
+ "xsltDoSortFunction: no support for data-type = %s\n",\r
+ comp->stype);\r
+ comp->number = 0; /* use default */\r
+ }\r
+ }\r
+ }\r
+ temporder[j] = 0;\r
+ if ((comp->order == NULL) && (comp->has_order != 0)) {\r
+ comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],\r
+ (const xmlChar *) "order",\r
+ XSLT_NAMESPACE);\r
+ if (comp->order != NULL) {\r
+ temporder[j] = 1;\r
+ if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))\r
+ comp->descending = 0;\r
+ else if (xmlStrEqual(comp->order,\r
+ (const xmlChar *) "descending"))\r
+ comp->descending = 1;\r
+ else {\r
+ xsltTransformError(ctxt, NULL, sorts[j],\r
+ "xsltDoSortFunction: invalid value %s for order\n",\r
+ comp->order);\r
+ comp->descending = 0; /* use default */\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ len = list->nodeNr;\r
+\r
+ resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);\r
+ for (i = 1;i < XSLT_MAX_SORT;i++)\r
+ resultsTab[i] = NULL;\r
+\r
+ results = resultsTab[0];\r
+\r
+ comp = sorts[0]->psvi;\r
+ descending = comp->descending;\r
+ number = comp->number;\r
+ if (results == NULL)\r
+ return;\r
+\r
+ /* Shell's sort of node-set */\r
+ for (incr = len / 2; incr > 0; incr /= 2) {\r
+ for (i = incr; i < len; i++) {\r
+ j = i - incr;\r
+ if (results[i] == NULL)\r
+ continue;\r
+ \r
+ while (j >= 0) {\r
+ if (results[j] == NULL)\r
+ tst = 1;\r
+ else {\r
+ if (number) {\r
+ /* We make NaN smaller than number in accordance\r
+ with XSLT spec */\r
+ if (xmlXPathIsNaN(results[j]->floatval)) {\r
+ if (xmlXPathIsNaN(results[j + incr]->floatval))\r
+ tst = 0;\r
+ else\r
+ tst = -1;\r
+ } else if (xmlXPathIsNaN(results[j + incr]->floatval))\r
+ tst = 1;\r
+ else if (results[j]->floatval ==\r
+ results[j + incr]->floatval)\r
+ tst = 0;\r
+ else if (results[j]->floatval > \r
+ results[j + incr]->floatval)\r
+ tst = 1;\r
+ else tst = -1;\r
+ } else {\r
+ tst = xmlStrcmp(results[j]->stringval,\r
+ results[j + incr]->stringval); \r
+ }\r
+ if (descending)\r
+ tst = -tst;\r
+ }\r
+ if (tst == 0) {\r
+ /*\r
+ * Okay we need to use multi level sorts\r
+ */\r
+ depth = 1;\r
+ while (depth < nbsorts) {\r
+ if (sorts[depth] == NULL)\r
+ break;\r
+ comp = sorts[depth]->psvi;\r
+ if (comp == NULL)\r
+ break;\r
+ desc = comp->descending;\r
+ numb = comp->number;\r
+\r
+ /*\r
+ * Compute the result of the next level for the\r
+ * full set, this might be optimized ... or not\r
+ */\r
+ if (resultsTab[depth] == NULL) \r
+ resultsTab[depth] = xsltComputeSortResult(ctxt,\r
+ sorts[depth]);\r
+ res = resultsTab[depth];\r
+ if (res == NULL) \r
+ break;\r
+ if (res[j] == NULL) {\r
+ if (res[j+incr] != NULL)\r
+ tst = 1;\r
+ } else {\r
+ if (numb) {\r
+ /* We make NaN smaller than number in\r
+ accordance with XSLT spec */\r
+ if (xmlXPathIsNaN(res[j]->floatval)) {\r
+ if (xmlXPathIsNaN(res[j +\r
+ incr]->floatval))\r
+ tst = 0;\r
+ else\r
+ tst = -1;\r
+ } else if (xmlXPathIsNaN(res[j + incr]->\r
+ floatval))\r
+ tst = 1;\r
+ else if (res[j]->floatval == res[j + incr]->\r
+ floatval)\r
+ tst = 0;\r
+ else if (res[j]->floatval > \r
+ res[j + incr]->floatval)\r
+ tst = 1;\r
+ else tst = -1;\r
+ } else {\r
+ tst = xmlStrcmp(res[j]->stringval,\r
+ res[j + incr]->stringval); \r
+ }\r
+ if (desc)\r
+ tst = -tst;\r
+ }\r
+\r
+ /*\r
+ * if we still can't differenciate at this level\r
+ * try one level deeper.\r
+ */\r
+ if (tst != 0)\r
+ break;\r
+ depth++;\r
+ }\r
+ }\r
+ if (tst == 0) {\r
+ tst = results[j]->index > results[j + incr]->index;\r
+ }\r
+ if (tst > 0) {\r
+ tmp = results[j];\r
+ results[j] = results[j + incr];\r
+ results[j + incr] = tmp;\r
+ node = list->nodeTab[j];\r
+ list->nodeTab[j] = list->nodeTab[j + incr];\r
+ list->nodeTab[j + incr] = node;\r
+ depth = 1;\r
+ while (depth < nbsorts) {\r
+ if (sorts[depth] == NULL)\r
+ break;\r
+ if (resultsTab[depth] == NULL)\r
+ break;\r
+ res = resultsTab[depth];\r
+ tmp = res[j];\r
+ res[j] = res[j + incr];\r
+ res[j + incr] = tmp;\r
+ depth++;\r
+ }\r
+ j -= incr;\r
+ } else\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (j = 0; j < nbsorts; j++) {\r
+ comp = sorts[j]->psvi;\r
+ if (tempstype[j] == 1) {\r
+ /* The data-type needs to be recomputed each time */\r
+ xmlFree((void *)(comp->stype));\r
+ comp->stype = NULL;\r
+ }\r
+ if (temporder[j] == 1) {\r
+ /* The order needs to be recomputed each time */\r
+ xmlFree((void *)(comp->order));\r
+ comp->order = NULL;\r
+ }\r
+ if (resultsTab[j] != NULL) {\r
+ for (i = 0;i < len;i++)\r
+ xmlXPathFreeObject(resultsTab[j][i]);\r
+ xmlFree(resultsTab[j]);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;\r
+\r
+/**\r
+ * xsltDoSortFunction:\r
+ * @ctxt: a XSLT process context\r
+ * @sorts: array of sort nodes\r
+ * @nbsorts: the number of sorts in the array\r
+ *\r
+ * reorder the current node list accordingly to the set of sorting\r
+ * requirement provided by the arry of nodes.\r
+ * This is a wrapper function, the actual function used is specified\r
+ * using xsltSetCtxtSortFunc() to set the context specific sort function,\r
+ * or xsltSetSortFunc() to set the global sort function.\r
+ * If a sort function is set on the context, this will get called.\r
+ * Otherwise the global sort function is called.\r
+ */\r
+void\r
+xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,\r
+ int nbsorts)\r
+{\r
+ if (ctxt->sortfunc != NULL)\r
+ (ctxt->sortfunc)(ctxt, sorts, nbsorts);\r
+ else if (xsltSortFunction != NULL)\r
+ xsltSortFunction(ctxt, sorts, nbsorts);\r
+}\r
+\r
+/**\r
+ * xsltSetSortFunc:\r
+ * @handler: the new handler function\r
+ *\r
+ * Function to reset the global handler for XSLT sorting.\r
+ * If the handler is NULL, the default sort function will be used.\r
+ */\r
+void\r
+xsltSetSortFunc(xsltSortFunc handler) {\r
+ if (handler != NULL)\r
+ xsltSortFunction = handler;\r
+ else\r
+ xsltSortFunction = xsltDefaultSortFunction;\r
+}\r
+\r
+/**\r
+ * xsltSetCtxtSortFunc:\r
+ * @ctxt: a XSLT process context\r
+ * @handler: the new handler function\r
+ *\r
+ * Function to set the handler for XSLT sorting\r
+ * for the specified context. \r
+ * If the handler is NULL, then the global\r
+ * sort function will be called\r
+ */\r
+void \r
+xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {\r
+ ctxt->sortfunc = handler;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Parsing options *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltSetCtxtParseOptions:\r
+ * @ctxt: a XSLT process context\r
+ * @options: a combination of libxml2 xmlParserOption\r
+ * \r
+ * Change the default parser option passed by the XSLT engine to the \r
+ * parser when using document() loading.\r
+ *\r
+ * Returns the previous options or -1 in case of error\r
+ */\r
+int \r
+xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)\r
+{\r
+ int oldopts;\r
+\r
+ if (ctxt == NULL)\r
+ return(-1);\r
+ oldopts = ctxt->parserOptions;\r
+ ctxt->parserOptions = options;\r
+ return(oldopts);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Output *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltSaveResultTo:\r
+ * @buf: an output buffer\r
+ * @result: the result xmlDocPtr\r
+ * @style: the stylesheet\r
+ *\r
+ * Save the result @result obtained by applying the @style stylesheet\r
+ * to an I/O output channel @buf\r
+ *\r
+ * Returns the number of byte written or -1 in case of failure.\r
+ */\r
+int\r
+xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,\r
+ xsltStylesheetPtr style) {\r
+ const xmlChar *encoding;\r
+ int base;\r
+ const xmlChar *method;\r
+ int indent;\r
+\r
+ if ((buf == NULL) || (result == NULL) || (style == NULL))\r
+ return(-1);\r
+ if ((result->children == NULL) ||\r
+ ((result->children->type == XML_DTD_NODE) &&\r
+ (result->children->next == NULL)))\r
+ return(0);\r
+\r
+ if ((style->methodURI != NULL) &&\r
+ ((style->method == NULL) ||\r
+ (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {\r
+ xsltGenericError(xsltGenericErrorContext,\r
+ "xsltSaveResultTo : unknown ouput method\n");\r
+ return(-1);\r
+ }\r
+\r
+ base = buf->written;\r
+\r
+ XSLT_GET_IMPORT_PTR(method, style, method)\r
+ XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ XSLT_GET_IMPORT_INT(indent, style, indent);\r
+\r
+ if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))\r
+ method = (const xmlChar *) "html";\r
+\r
+ if ((method != NULL) &&\r
+ (xmlStrEqual(method, (const xmlChar *) "html"))) {\r
+ if (encoding != NULL) {\r
+ htmlSetMetaEncoding(result, (const xmlChar *) encoding);\r
+ } else {\r
+ htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");\r
+ }\r
+ if (indent == -1)\r
+ indent = 1;\r
+ htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,\r
+ indent);\r
+ xmlOutputBufferFlush(buf);\r
+ } else if ((method != NULL) &&\r
+ (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {\r
+ if (encoding != NULL) {\r
+ htmlSetMetaEncoding(result, (const xmlChar *) encoding);\r
+ } else {\r
+ htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");\r
+ }\r
+ htmlDocContentDumpOutput(buf, result, (const char *) encoding);\r
+ xmlOutputBufferFlush(buf);\r
+ } else if ((method != NULL) &&\r
+ (xmlStrEqual(method, (const xmlChar *) "text"))) {\r
+ xmlNodePtr cur;\r
+\r
+ cur = result->children;\r
+ while (cur != NULL) {\r
+ if (cur->type == XML_TEXT_NODE)\r
+ xmlOutputBufferWriteString(buf, (const char *) cur->content);\r
+\r
+ /*\r
+ * Skip to next node\r
+ */\r
+ if (cur->children != NULL) {\r
+ if ((cur->children->type != XML_ENTITY_DECL) &&\r
+ (cur->children->type != XML_ENTITY_REF_NODE) &&\r
+ (cur->children->type != XML_ENTITY_NODE)) {\r
+ cur = cur->children;\r
+ continue;\r
+ }\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ continue;\r
+ }\r
+ \r
+ do {\r
+ cur = cur->parent;\r
+ if (cur == NULL)\r
+ break;\r
+ if (cur == (xmlNodePtr) style->doc) {\r
+ cur = NULL;\r
+ break;\r
+ }\r
+ if (cur->next != NULL) {\r
+ cur = cur->next;\r
+ break;\r
+ }\r
+ } while (cur != NULL);\r
+ }\r
+ xmlOutputBufferFlush(buf);\r
+ } else {\r
+ int omitXmlDecl;\r
+ int standalone;\r
+\r
+ XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);\r
+ XSLT_GET_IMPORT_INT(standalone, style, standalone);\r
+\r
+ if (omitXmlDecl != 1) {\r
+ xmlOutputBufferWriteString(buf, "<?xml version=");\r
+ if (result->version != NULL) \r
+ xmlBufferWriteQuotedString(buf->buffer, result->version);\r
+ else\r
+ xmlOutputBufferWriteString(buf, "\"1.0\"");\r
+ if (encoding == NULL) {\r
+ if (result->encoding != NULL)\r
+ encoding = result->encoding;\r
+ else if (result->charset != XML_CHAR_ENCODING_UTF8)\r
+ encoding = (const xmlChar *)\r
+ xmlGetCharEncodingName((xmlCharEncoding)\r
+ result->charset);\r
+ }\r
+ if (encoding != NULL) {\r
+ xmlOutputBufferWriteString(buf, " encoding=");\r
+ xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);\r
+ }\r
+ switch (standalone) {\r
+ case 0:\r
+ xmlOutputBufferWriteString(buf, " standalone=\"no\"");\r
+ break;\r
+ case 1:\r
+ xmlOutputBufferWriteString(buf, " standalone=\"yes\"");\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ xmlOutputBufferWriteString(buf, "?>\n");\r
+ }\r
+ if (result->children != NULL) {\r
+ xmlNodePtr child = result->children;\r
+\r
+ while (child != NULL) {\r
+ xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),\r
+ (const char *) encoding);\r
+ if ((child->type == XML_DTD_NODE) ||\r
+ ((child->type == XML_COMMENT_NODE) &&\r
+ (child->next != NULL)))\r
+ xmlOutputBufferWriteString(buf, "\n");\r
+ child = child->next;\r
+ }\r
+ xmlOutputBufferWriteString(buf, "\n");\r
+ }\r
+ xmlOutputBufferFlush(buf);\r
+ }\r
+ return(buf->written - base);\r
+}\r
+\r
+/**\r
+ * xsltSaveResultToFilename:\r
+ * @URL: a filename or URL\r
+ * @result: the result xmlDocPtr\r
+ * @style: the stylesheet\r
+ * @compression: the compression factor (0 - 9 included)\r
+ *\r
+ * Save the result @result obtained by applying the @style stylesheet\r
+ * to a file or @URL\r
+ *\r
+ * Returns the number of byte written or -1 in case of failure.\r
+ */\r
+int\r
+xsltSaveResultToFilename(const char *URL, xmlDocPtr result,\r
+ xsltStylesheetPtr style, int compression) {\r
+ xmlOutputBufferPtr buf;\r
+ const xmlChar *encoding;\r
+ int ret;\r
+\r
+ if ((URL == NULL) || (result == NULL) || (style == NULL))\r
+ return(-1);\r
+ if (result->children == NULL)\r
+ return(0);\r
+\r
+ XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ if (encoding != NULL) {\r
+ xmlCharEncodingHandlerPtr encoder;\r
+\r
+ encoder = xmlFindCharEncodingHandler((char *)encoding);\r
+ if ((encoder != NULL) &&\r
+ (xmlStrEqual((const xmlChar *)encoder->name,\r
+ (const xmlChar *) "UTF-8")))\r
+ encoder = NULL;\r
+ buf = xmlOutputBufferCreateFilename(URL, encoder, compression);\r
+ } else {\r
+ buf = xmlOutputBufferCreateFilename(URL, NULL, compression);\r
+ }\r
+ if (buf == NULL)\r
+ return(-1);\r
+ xsltSaveResultTo(buf, result, style);\r
+ ret = xmlOutputBufferClose(buf);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltSaveResultToFile:\r
+ * @file: a FILE * I/O\r
+ * @result: the result xmlDocPtr\r
+ * @style: the stylesheet\r
+ *\r
+ * Save the result @result obtained by applying the @style stylesheet\r
+ * to an open FILE * I/O.\r
+ * This does not close the FILE @file\r
+ *\r
+ * Returns the number of bytes written or -1 in case of failure.\r
+ */\r
+int\r
+xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {\r
+ xmlOutputBufferPtr buf;\r
+ const xmlChar *encoding;\r
+ int ret;\r
+\r
+ if ((file == NULL) || (result == NULL) || (style == NULL))\r
+ return(-1);\r
+ if (result->children == NULL)\r
+ return(0);\r
+\r
+ XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ if (encoding != NULL) {\r
+ xmlCharEncodingHandlerPtr encoder;\r
+\r
+ encoder = xmlFindCharEncodingHandler((char *)encoding);\r
+ if ((encoder != NULL) &&\r
+ (xmlStrEqual((const xmlChar *)encoder->name,\r
+ (const xmlChar *) "UTF-8")))\r
+ encoder = NULL;\r
+ buf = xmlOutputBufferCreateFile(file, encoder);\r
+ } else {\r
+ buf = xmlOutputBufferCreateFile(file, NULL);\r
+ }\r
+\r
+ if (buf == NULL)\r
+ return(-1);\r
+ xsltSaveResultTo(buf, result, style);\r
+ ret = xmlOutputBufferClose(buf);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltSaveResultToFd:\r
+ * @fd: a file descriptor\r
+ * @result: the result xmlDocPtr\r
+ * @style: the stylesheet\r
+ *\r
+ * Save the result @result obtained by applying the @style stylesheet\r
+ * to an open file descriptor\r
+ * This does not close the descriptor.\r
+ *\r
+ * Returns the number of bytes written or -1 in case of failure.\r
+ */\r
+int\r
+xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {\r
+ xmlOutputBufferPtr buf;\r
+ const xmlChar *encoding;\r
+ int ret;\r
+\r
+ if ((fd < 0) || (result == NULL) || (style == NULL))\r
+ return(-1);\r
+ if (result->children == NULL)\r
+ return(0);\r
+\r
+ XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ if (encoding != NULL) {\r
+ xmlCharEncodingHandlerPtr encoder;\r
+\r
+ encoder = xmlFindCharEncodingHandler((char *)encoding);\r
+ if ((encoder != NULL) &&\r
+ (xmlStrEqual((const xmlChar *)encoder->name,\r
+ (const xmlChar *) "UTF-8")))\r
+ encoder = NULL;\r
+ buf = xmlOutputBufferCreateFd(fd, encoder);\r
+ } else {\r
+ buf = xmlOutputBufferCreateFd(fd, NULL);\r
+ }\r
+ if (buf == NULL)\r
+ return(-1);\r
+ xsltSaveResultTo(buf, result, style);\r
+ ret = xmlOutputBufferClose(buf);\r
+ return(ret);\r
+}\r
+\r
+/**\r
+ * xsltSaveResultToString:\r
+ * @doc_txt_ptr: Memory pointer for allocated XML text\r
+ * @doc_txt_len: Length of the generated XML text\r
+ * @result: the result xmlDocPtr\r
+ * @style: the stylesheet\r
+ *\r
+ * Save the result @result obtained by applying the @style stylesheet\r
+ * to a new allocated string.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of error\r
+ */\r
+int\r
+xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, \r
+ xmlDocPtr result, xsltStylesheetPtr style) {\r
+ xmlOutputBufferPtr buf;\r
+ const xmlChar *encoding;\r
+\r
+ *doc_txt_ptr = NULL;\r
+ *doc_txt_len = 0;\r
+ if (result->children == NULL)\r
+ return(0);\r
+\r
+ XSLT_GET_IMPORT_PTR(encoding, style, encoding)\r
+ if (encoding != NULL) {\r
+ xmlCharEncodingHandlerPtr encoder;\r
+\r
+ encoder = xmlFindCharEncodingHandler((char *)encoding);\r
+ if ((encoder != NULL) &&\r
+ (xmlStrEqual((const xmlChar *)encoder->name,\r
+ (const xmlChar *) "UTF-8")))\r
+ encoder = NULL;\r
+ buf = xmlAllocOutputBuffer(encoder);\r
+ } else {\r
+ buf = xmlAllocOutputBuffer(NULL);\r
+ }\r
+ if (buf == NULL)\r
+ return(-1);\r
+ xsltSaveResultTo(buf, result, style);\r
+ if (buf->conv != NULL) {\r
+ *doc_txt_len = buf->conv->use;\r
+ *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);\r
+ } else {\r
+ *doc_txt_len = buf->buffer->use;\r
+ *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);\r
+ }\r
+ (void)xmlOutputBufferClose(buf);\r
+ return 0;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Generating profiling informations *\r
+ * *\r
+ ************************************************************************/\r
+\r
+static long calibration = -1;\r
+\r
+/**\r
+ * xsltCalibrateTimestamps:\r
+ *\r
+ * Used for to calibrate the xsltTimestamp() function\r
+ * Should work if launched at startup and we don't loose our quantum :-)\r
+ *\r
+ * Returns the number of milliseconds used by xsltTimestamp()\r
+ */\r
+static long\r
+xsltCalibrateTimestamps(void) {\r
+ register int i;\r
+\r
+ for (i = 0;i < 999;i++)\r
+ xsltTimestamp();\r
+ return(xsltTimestamp() / 1000);\r
+}\r
+\r
+/**\r
+ * xsltCalibrateAdjust:\r
+ * @delta: a negative dealy value found\r
+ *\r
+ * Used for to correct the calibration for xsltTimestamp()\r
+ */\r
+void\r
+xsltCalibrateAdjust(long delta) {\r
+ calibration += delta;\r
+}\r
+\r
+/**\r
+ * xsltTimestamp:\r
+ *\r
+ * Used for gathering profiling data\r
+ *\r
+ * Returns the number of tenth of milliseconds since the beginning of the\r
+ * profiling\r
+ */\r
+long\r
+xsltTimestamp(void)\r
+{\r
+#ifdef XSLT_WIN32_PERFORMANCE_COUNTER\r
+ BOOL ok;\r
+ LARGE_INTEGER performanceCount;\r
+ LARGE_INTEGER performanceFrequency;\r
+ LONGLONG quadCount;\r
+ double seconds;\r
+ static LONGLONG startupQuadCount = 0;\r
+ static LONGLONG startupQuadFreq = 0;\r
+\r
+ ok = QueryPerformanceCounter(&performanceCount);\r
+ if (!ok)\r
+ return 0;\r
+ quadCount = performanceCount.QuadPart;\r
+ if (calibration < 0) {\r
+ calibration = 0;\r
+ ok = QueryPerformanceFrequency(&performanceFrequency);\r
+ if (!ok)\r
+ return 0;\r
+ startupQuadFreq = performanceFrequency.QuadPart;\r
+ startupQuadCount = quadCount;\r
+ return (0);\r
+ }\r
+ if (startupQuadFreq == 0)\r
+ return 0;\r
+ seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;\r
+ return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);\r
+\r
+#else /* XSLT_WIN32_PERFORMANCE_COUNTER */\r
+#ifdef HAVE_GETTIMEOFDAY\r
+ static struct timeval startup;\r
+ struct timeval cur;\r
+ long tics;\r
+\r
+ if (calibration < 0) {\r
+ gettimeofday(&startup, NULL);\r
+ calibration = 0;\r
+ calibration = xsltCalibrateTimestamps();\r
+ gettimeofday(&startup, NULL);\r
+ return (0);\r
+ }\r
+\r
+ gettimeofday(&cur, NULL);\r
+ tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;\r
+ tics += (cur.tv_usec - startup.tv_usec) /\r
+ (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);\r
+ \r
+ tics -= calibration;\r
+ return(tics);\r
+#else\r
+\r
+ /* Neither gettimeofday() nor Win32 performance counter available */\r
+\r
+ return (0);\r
+\r
+#endif /* HAVE_GETTIMEOFDAY */\r
+#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */\r
+}\r
+\r
+#define MAX_TEMPLATES 10000\r
+\r
+/**\r
+ * xsltSaveProfiling:\r
+ * @ctxt: an XSLT context\r
+ * @output: a FILE * for saving the informations\r
+ *\r
+ * Save the profiling informations on @output\r
+ */\r
+void\r
+xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {\r
+ int nb, i,j;\r
+ int max;\r
+ int total;\r
+ long totalt;\r
+ xsltTemplatePtr *templates;\r
+ xsltStylesheetPtr style;\r
+ xsltTemplatePtr template;\r
+\r
+ if ((output == NULL) || (ctxt == NULL))\r
+ return;\r
+ if (ctxt->profile == 0)\r
+ return;\r
+\r
+ nb = 0;\r
+ max = MAX_TEMPLATES;\r
+ templates = xmlMalloc(max * sizeof(xsltTemplatePtr));\r
+ if (templates == NULL)\r
+ return;\r
+\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ template = style->templates;\r
+ while (template != NULL) {\r
+ if (nb >= max)\r
+ break;\r
+\r
+ if (template->nbCalls > 0)\r
+ templates[nb++] = template;\r
+ template = template->next;\r
+ }\r
+\r
+ style = xsltNextImport(style);\r
+ }\r
+\r
+ for (i = 0;i < nb -1;i++) {\r
+ for (j = i + 1; j < nb; j++) {\r
+ if ((templates[i]->time <= templates[j]->time) ||\r
+ ((templates[i]->time == templates[j]->time) &&\r
+ (templates[i]->nbCalls <= templates[j]->nbCalls))) {\r
+ template = templates[j];\r
+ templates[j] = templates[i];\r
+ templates[i] = template;\r
+ }\r
+ }\r
+ }\r
+\r
+ fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n",\r
+ "number", "match", "name", "mode");\r
+ total = 0;\r
+ totalt = 0;\r
+ for (i = 0;i < nb;i++) {\r
+ fprintf(output, "%5d ", i);\r
+ if (templates[i]->match != NULL) {\r
+ if (xmlStrlen(templates[i]->match) > 20)\r
+ fprintf(output, "%s\n%26s", templates[i]->match, "");\r
+ else\r
+ fprintf(output, "%20s", templates[i]->match);\r
+ } else {\r
+ fprintf(output, "%20s", "");\r
+ }\r
+ if (templates[i]->name != NULL) {\r
+ if (xmlStrlen(templates[i]->name) > 20)\r
+ fprintf(output, "%s\n%46s", templates[i]->name, "");\r
+ else\r
+ fprintf(output, "%20s", templates[i]->name);\r
+ } else {\r
+ fprintf(output, "%20s", "");\r
+ }\r
+ if (templates[i]->mode != NULL) {\r
+ if (xmlStrlen(templates[i]->mode) > 10)\r
+ fprintf(output, "%s\n%56s", templates[i]->mode, "");\r
+ else\r
+ fprintf(output, "%10s", templates[i]->mode);\r
+ } else {\r
+ fprintf(output, "%10s", "");\r
+ }\r
+ fprintf(output, " %6d", templates[i]->nbCalls);\r
+ fprintf(output, " %6ld %6ld\n", templates[i]->time,\r
+ templates[i]->time / templates[i]->nbCalls);\r
+ total += templates[i]->nbCalls;\r
+ totalt += templates[i]->time;\r
+ }\r
+ fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);\r
+\r
+ xmlFree(templates);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Fetching profiling informations *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltGetProfileInformation:\r
+ * @ctxt: a transformation context\r
+ *\r
+ * This function should be called after the transformation completed\r
+ * to extract template processing profiling informations if availble.\r
+ * The informations are returned as an XML document tree like\r
+ * <?xml version="1.0"?>\r
+ * <profile>\r
+ * <template rank="1" match="*" name=""\r
+ * mode="" calls="6" time="48" average="8"/>\r
+ * <template rank="2" match="item2|item3" name=""\r
+ * mode="" calls="10" time="30" average="3"/>\r
+ * <template rank="3" match="item1" name=""\r
+ * mode="" calls="5" time="17" average="3"/>\r
+ * </profile>\r
+ * The caller will need to free up the returned tree with xmlFreeDoc()\r
+ *\r
+ * Returns the xmlDocPtr corresponding to the result or NULL if not available.\r
+ */\r
+\r
+xmlDocPtr\r
+xsltGetProfileInformation(xsltTransformContextPtr ctxt)\r
+{\r
+ xmlDocPtr ret = NULL;\r
+ xmlNodePtr root, child;\r
+ char buf[100];\r
+\r
+ xsltStylesheetPtr style;\r
+ xsltTemplatePtr *templates;\r
+ xsltTemplatePtr templ;\r
+ int nb = 0, max = 0, i, j;\r
+\r
+ if (!ctxt)\r
+ return NULL;\r
+\r
+ if (!ctxt->profile)\r
+ return NULL;\r
+\r
+ nb = 0;\r
+ max = 10000;\r
+ templates =\r
+ (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));\r
+ if (templates == NULL)\r
+ return NULL;\r
+\r
+ /*\r
+ * collect all the templates in an array\r
+ */\r
+ style = ctxt->style;\r
+ while (style != NULL) {\r
+ templ = style->templates;\r
+ while (templ != NULL) {\r
+ if (nb >= max)\r
+ break;\r
+\r
+ if (templ->nbCalls > 0)\r
+ templates[nb++] = templ;\r
+ templ = templ->next;\r
+ }\r
+\r
+ style = (xsltStylesheetPtr) xsltNextImport(style);\r
+ }\r
+\r
+ /*\r
+ * Sort the array by time spent\r
+ */\r
+ for (i = 0; i < nb - 1; i++) {\r
+ for (j = i + 1; j < nb; j++) {\r
+ if ((templates[i]->time <= templates[j]->time) ||\r
+ ((templates[i]->time == templates[j]->time) &&\r
+ (templates[i]->nbCalls <= templates[j]->nbCalls))) {\r
+ templ = templates[j];\r
+ templates[j] = templates[i];\r
+ templates[i] = templ;\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Generate a document corresponding to the results.\r
+ */\r
+ ret = xmlNewDoc(BAD_CAST "1.0");\r
+ root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);\r
+ xmlDocSetRootElement(ret, root);\r
+\r
+ for (i = 0; i < nb; i++) {\r
+ child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);\r
+ sprintf(buf, "%d", i + 1);\r
+ xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);\r
+ xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);\r
+ xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);\r
+ xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);\r
+\r
+ sprintf(buf, "%d", templates[i]->nbCalls);\r
+ xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);\r
+\r
+ sprintf(buf, "%ld", templates[i]->time);\r
+ xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);\r
+\r
+ sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);\r
+ xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);\r
+ };\r
+\r
+ xmlFree(templates);\r
+\r
+ return ret;\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Hooks for libxml2 XPath *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/**\r
+ * xsltXPathCompile:\r
+ * @style: the stylesheet\r
+ * @str: the XPath expression\r
+ *\r
+ * Compile an XPath expression\r
+ *\r
+ * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.\r
+ * the caller has to free the object.\r
+ */\r
+xmlXPathCompExprPtr\r
+xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {\r
+ xmlXPathContextPtr xpathCtxt;\r
+ xmlXPathCompExprPtr ret;\r
+\r
+ if (style != NULL) {\r
+#ifdef XSLT_REFACTORED_XPATHCOMP\r
+ if (XSLT_CCTXT(style)) {\r
+ /*\r
+ * Proposed by Jerome Pesenti\r
+ * --------------------------\r
+ * For better efficiency we'll reuse the compilation\r
+ * context's XPath context. For the common stylesheet using\r
+ * XPath expressions this will reduce compilation time to\r
+ * about 50%.\r
+ *\r
+ * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html\r
+ */\r
+ xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;\r
+ xpathCtxt->doc = style->doc;\r
+ } else\r
+ xpathCtxt = xmlXPathNewContext(style->doc); \r
+#else\r
+ xpathCtxt = xmlXPathNewContext(style->doc);\r
+#endif\r
+ xpathCtxt->dict = style->dict;\r
+ } else {\r
+ xpathCtxt = xmlXPathNewContext(NULL);\r
+ }\r
+ /*\r
+ * Compile the expression.\r
+ */\r
+ ret = xmlXPathCtxtCompile(xpathCtxt, str);\r
+\r
+#ifdef XSLT_REFACTORED_XPATHCOMP\r
+ if ((style == NULL) || (! XSLT_CCTXT(style))) {\r
+ xmlXPathFreeContext(xpathCtxt);\r
+ }\r
+#else\r
+ xmlXPathFreeContext(xpathCtxt);\r
+#endif\r
+ /*\r
+ * TODO: there is a lot of optimizations which should be possible\r
+ * like variable slot precomputations, function precomputations, etc.\r
+ */\r
+\r
+ return(ret);\r
+}\r
+\r
+/************************************************************************\r
+ * *\r
+ * Hooks for the debugger *\r
+ * *\r
+ ************************************************************************/\r
+\r
+/*\r
+ * There is currently only 3 debugging callback defined\r
+ * Debugger callbacks are disabled by default\r
+ */\r
+#define XSLT_CALLBACK_NUMBER 3\r
+\r
+typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;\r
+typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;\r
+struct _xsltDebuggerCallbacks {\r
+ xsltHandleDebuggerCallback handler;\r
+ xsltAddCallCallback add;\r
+ xsltDropCallCallback drop;\r
+};\r
+\r
+static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {\r
+ NULL, /* handler */\r
+ NULL, /* add */\r
+ NULL /* drop */\r
+};\r
+\r
+int xslDebugStatus;\r
+\r
+/**\r
+ * xsltSetDebuggerStatus:\r
+ * @value : the value to be set\r
+ * \r
+ * This function sets the value of xslDebugStatus.\r
+ */\r
+void\r
+xsltSetDebuggerStatus(int value)\r
+{\r
+ xslDebugStatus = value; \r
+}\r
+\r
+/**\r
+ * xsltGetDebuggerStatus: \r
+ * \r
+ * Get xslDebugStatus.\r
+ *\r
+ * Returns the value of xslDebugStatus.\r
+ */\r
+int\r
+xsltGetDebuggerStatus(void)\r
+{\r
+ return(xslDebugStatus); \r
+}\r
+\r
+/**\r
+ * xsltSetDebuggerCallbacks:\r
+ * @no : number of callbacks\r
+ * @block : the block of callbacks\r
+ * \r
+ * This function allow to plug a debugger into the XSLT library\r
+ * @block points to a block of memory containing the address of @no \r
+ * callback routines.\r
+ *\r
+ * Returns 0 in case of success and -1 in case of error\r
+ */\r
+int\r
+xsltSetDebuggerCallbacks(int no, void *block)\r
+{\r
+ xsltDebuggerCallbacksPtr callbacks;\r
+\r
+ if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))\r
+ return(-1);\r
+\r
+ callbacks = (xsltDebuggerCallbacksPtr) block;\r
+ xsltDebuggerCurrentCallbacks.handler = callbacks->handler;\r
+ xsltDebuggerCurrentCallbacks.add = callbacks->add;\r
+ xsltDebuggerCurrentCallbacks.drop = callbacks->drop;\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xslHandleDebugger:\r
+ * @cur : source node being executed\r
+ * @node : data node being processed\r
+ * @templ : temlate that applies to node\r
+ * @ctxt : the xslt transform context \r
+ * \r
+ * If either cur or node are a breakpoint, or xslDebugStatus in state \r
+ * where debugging must occcur at this time then transfer control\r
+ * to the xslDebugBreak function\r
+ */\r
+void\r
+xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,\r
+ xsltTransformContextPtr ctxt)\r
+{\r
+ if (xsltDebuggerCurrentCallbacks.handler != NULL)\r
+ xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);\r
+}\r
+\r
+/**\r
+ * xslAddCall:\r
+ * @templ : current template being applied\r
+ * @source : the source node being processed\r
+ *\r
+ * Add template "call" to call stack\r
+ * Returns : 1 on sucess 0 otherwise an error may be printed if \r
+ * WITH_XSLT_DEBUG_BREAKPOINTS is defined\r
+ */\r
+int\r
+xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)\r
+{\r
+ if (xsltDebuggerCurrentCallbacks.add != NULL)\r
+ return(xsltDebuggerCurrentCallbacks.add(templ, source));\r
+ return(0);\r
+}\r
+\r
+/**\r
+ * xslDropCall:\r
+ *\r
+ * Drop the topmost item off the call stack\r
+ */\r
+void\r
+xslDropCall(void)\r
+{\r
+ if (xsltDebuggerCurrentCallbacks.drop != NULL)\r
+ xsltDebuggerCurrentCallbacks.drop();\r
+}\r
+\r
-/*
- * Summary: set of utilities for the XSLT engine
- * Description: interfaces for the utilities module of the XSLT engine.
- * things like message handling, profiling, and other
- * generally useful routines.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Daniel Veillard
- */
-
-#ifndef __XML_XSLTUTILS_H__
-#define __XML_XSLTUTILS_H__
-
-#include <libxslt/xsltconfig.h>
-#ifdef HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#include <libxml/xpath.h>
-#include <libxml/dict.h>
-#include <libxml/xmlerror.h>
-#include "xsltexports.h"
-#include "xsltInternals.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * XSLT_TODO:
- *
- * Macro to flag unimplemented blocks.
- */
-#define XSLT_TODO \
- xsltGenericError(xsltGenericErrorContext, \
- "Unimplemented block at %s:%d\n", \
- __FILE__, __LINE__);
-
-/**
- * XSLT_STRANGE:
- *
- * Macro to flag that a problem was detected internally.
- */
-#define XSLT_STRANGE \
- xsltGenericError(xsltGenericErrorContext, \
- "Internal error at %s:%d\n", \
- __FILE__, __LINE__);
-
-/**
- * IS_XSLT_ELEM:
- *
- * Checks that the element pertains to XSLT namespace.
- */
-#define IS_XSLT_ELEM(n) \
- (((n) != NULL) && ((n)->ns != NULL) && \
- (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
-
-/**
- * IS_XSLT_NAME:
- *
- * Checks the value of an element in XSLT namespace.
- */
-#define IS_XSLT_NAME(n, val) \
- (xmlStrEqual((n)->name, (const xmlChar *) (val)))
-
-/**
- * IS_XSLT_REAL_NODE:
- *
- * Check that a node is a 'real' one: document, element, text or attribute.
- */
-#define IS_XSLT_REAL_NODE(n) \
- (((n) != NULL) && \
- (((n)->type == XML_ELEMENT_NODE) || \
- ((n)->type == XML_TEXT_NODE) || \
- ((n)->type == XML_ATTRIBUTE_NODE) || \
- ((n)->type == XML_DOCUMENT_NODE) || \
- ((n)->type == XML_HTML_DOCUMENT_NODE) || \
- ((n)->type == XML_PI_NODE)))
-
-/*
- * Our own version of namespaced atributes lookup.
- */
-XSLTPUBFUN xmlChar * XSLTCALL
- xsltGetNsProp (xmlNodePtr node,
- const xmlChar *name,
- const xmlChar *nameSpace);
-XSLTPUBFUN const xmlChar * XSLTCALL
- xsltGetCNsProp (xsltStylesheetPtr style,
- xmlNodePtr node,
- const xmlChar *name,
- const xmlChar *nameSpace);
-XSLTPUBFUN int XSLTCALL
- xsltGetUTF8Char (const unsigned char *utf,
- int *len);
-
-/*
- * XSLT Debug Tracing Tracing Types
- */
-typedef enum {
- XSLT_TRACE_ALL = -1,
- XSLT_TRACE_NONE = 0,
- XSLT_TRACE_COPY_TEXT = 1<<0,
- XSLT_TRACE_PROCESS_NODE = 1<<1,
- XSLT_TRACE_APPLY_TEMPLATE = 1<<2,
- XSLT_TRACE_COPY = 1<<3,
- XSLT_TRACE_COMMENT = 1<<4,
- XSLT_TRACE_PI = 1<<5,
- XSLT_TRACE_COPY_OF = 1<<6,
- XSLT_TRACE_VALUE_OF = 1<<7,
- XSLT_TRACE_CALL_TEMPLATE = 1<<8,
- XSLT_TRACE_APPLY_TEMPLATES = 1<<9,
- XSLT_TRACE_CHOOSE = 1<<10,
- XSLT_TRACE_IF = 1<<11,
- XSLT_TRACE_FOR_EACH = 1<<12,
- XSLT_TRACE_STRIP_SPACES = 1<<13,
- XSLT_TRACE_TEMPLATES = 1<<14,
- XSLT_TRACE_KEYS = 1<<15,
- XSLT_TRACE_VARIABLES = 1<<16
-} xsltDebugTraceCodes;
-
-/**
- * XSLT_TRACE:
- *
- * Control the type of xsl debugtrace messages emitted.
- */
-#define XSLT_TRACE(ctxt,code,call) \
- if (ctxt->traceCode && (*(ctxt->traceCode) & code)) \
- call
-
-XSLTPUBFUN void XSLTCALL
- xsltDebugSetDefaultTrace(xsltDebugTraceCodes val);
-XSLTPUBFUN xsltDebugTraceCodes XSLTCALL
- xsltDebugGetDefaultTrace(void);
-
-/*
- * XSLT specific error and debug reporting functions.
- */
-XSLTPUBVAR xmlGenericErrorFunc xsltGenericError;
-XSLTPUBVAR void *xsltGenericErrorContext;
-XSLTPUBVAR xmlGenericErrorFunc xsltGenericDebug;
-XSLTPUBVAR void *xsltGenericDebugContext;
-
-XSLTPUBFUN void XSLTCALL
- xsltPrintErrorContext (xsltTransformContextPtr ctxt,
- xsltStylesheetPtr style,
- xmlNodePtr node);
-XSLTPUBFUN void XSLTCALL
- xsltMessage (xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- xmlNodePtr inst);
-XSLTPUBFUN void XSLTCALL
- xsltSetGenericErrorFunc (void *ctx,
- xmlGenericErrorFunc handler);
-XSLTPUBFUN void XSLTCALL
- xsltSetGenericDebugFunc (void *ctx,
- xmlGenericErrorFunc handler);
-XSLTPUBFUN void XSLTCALL
- xsltSetTransformErrorFunc (xsltTransformContextPtr ctxt,
- void *ctx,
- xmlGenericErrorFunc handler);
-XSLTPUBFUN void XSLTCALL
- xsltTransformError (xsltTransformContextPtr ctxt,
- xsltStylesheetPtr style,
- xmlNodePtr node,
- const char *msg,
- ...);
-
-XSLTPUBFUN int XSLTCALL
- xsltSetCtxtParseOptions (xsltTransformContextPtr ctxt,
- int options);
-/*
- * Sorting.
- */
-
-XSLTPUBFUN void XSLTCALL
- xsltDocumentSortFunction (xmlNodeSetPtr list);
-XSLTPUBFUN void XSLTCALL
- xsltSetSortFunc (xsltSortFunc handler);
-XSLTPUBFUN void XSLTCALL
- xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt,
- xsltSortFunc handler);
-XSLTPUBFUN void XSLTCALL
- xsltDefaultSortFunction (xsltTransformContextPtr ctxt,
- xmlNodePtr *sorts,
- int nbsorts);
-XSLTPUBFUN void XSLTCALL
- xsltDoSortFunction (xsltTransformContextPtr ctxt,
- xmlNodePtr * sorts,
- int nbsorts);
-XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL
- xsltComputeSortResult (xsltTransformContextPtr ctxt,
- xmlNodePtr sort);
-
-/*
- * QNames handling.
- */
-
-XSLTPUBFUN const xmlChar * XSLTCALL
- xsltSplitQName (xmlDictPtr dict,
- const xmlChar *name,
- const xmlChar **prefix);
-XSLTPUBFUN const xmlChar * XSLTCALL
- xsltGetQNameURI (xmlNodePtr node,
- xmlChar **name);
-
-XSLTPUBFUN const xmlChar * XSLTCALL
- xsltGetQNameURI2 (xsltStylesheetPtr style,
- xmlNodePtr node,
- const xmlChar **name);
-
-/*
- * Output, reuse libxml I/O buffers.
- */
-XSLTPUBFUN int XSLTCALL
- xsltSaveResultTo (xmlOutputBufferPtr buf,
- xmlDocPtr result,
- xsltStylesheetPtr style);
-XSLTPUBFUN int XSLTCALL
- xsltSaveResultToFilename (const char *URI,
- xmlDocPtr result,
- xsltStylesheetPtr style,
- int compression);
-XSLTPUBFUN int XSLTCALL
- xsltSaveResultToFile (FILE *file,
- xmlDocPtr result,
- xsltStylesheetPtr style);
-XSLTPUBFUN int XSLTCALL
- xsltSaveResultToFd (int fd,
- xmlDocPtr result,
- xsltStylesheetPtr style);
-XSLTPUBFUN int XSLTCALL
- xsltSaveResultToString (xmlChar **doc_txt_ptr,
- int * doc_txt_len,
- xmlDocPtr result,
- xsltStylesheetPtr style);
-
-/*
- * XPath interface
- */
-XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL
- xsltXPathCompile (xsltStylesheetPtr style,
- const xmlChar *str);
-
-/*
- * Profiling.
- */
-XSLTPUBFUN void XSLTCALL
- xsltSaveProfiling (xsltTransformContextPtr ctxt,
- FILE *output);
-XSLTPUBFUN xmlDocPtr XSLTCALL
- xsltGetProfileInformation (xsltTransformContextPtr ctxt);
-
-XSLTPUBFUN long XSLTCALL
- xsltTimestamp (void);
-XSLTPUBFUN void XSLTCALL
- xsltCalibrateAdjust (long delta);
-
-/**
- * XSLT_TIMESTAMP_TICS_PER_SEC:
- *
- * Sampling precision for profiling
- */
-#define XSLT_TIMESTAMP_TICS_PER_SEC 100000l
-
-/*
- * Hooks for the debugger.
- */
-
-typedef enum {
- XSLT_DEBUG_NONE = 0, /* no debugging allowed */
- XSLT_DEBUG_INIT,
- XSLT_DEBUG_STEP,
- XSLT_DEBUG_STEPOUT,
- XSLT_DEBUG_NEXT,
- XSLT_DEBUG_STOP,
- XSLT_DEBUG_CONT,
- XSLT_DEBUG_RUN,
- XSLT_DEBUG_RUN_RESTART,
- XSLT_DEBUG_QUIT
-} xsltDebugStatusCodes;
-
-XSLTPUBVAR int xslDebugStatus;
-
-typedef void (*xsltHandleDebuggerCallback) (xmlNodePtr cur, xmlNodePtr node,
- xsltTemplatePtr templ, xsltTransformContextPtr ctxt);
-typedef int (*xsltAddCallCallback) (xsltTemplatePtr templ, xmlNodePtr source);
-typedef void (*xsltDropCallCallback) (void);
-
-XSLTPUBFUN void XSLTCALL
- xsltSetDebuggerStatus (int value);
-XSLTPUBFUN int XSLTCALL
- xsltGetDebuggerStatus (void);
-XSLTPUBFUN int XSLTCALL
- xsltSetDebuggerCallbacks (int no, void *block);
-XSLTPUBFUN int XSLTCALL
- xslAddCall (xsltTemplatePtr templ,
- xmlNodePtr source);
-XSLTPUBFUN void XSLTCALL
- xslDropCall (void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XML_XSLTUTILS_H__ */
-
-
+/*\r
+ * Summary: set of utilities for the XSLT engine\r
+ * Description: interfaces for the utilities module of the XSLT engine.\r
+ * things like message handling, profiling, and other\r
+ * generally useful routines.\r
+ *\r
+ * Copy: See Copyright for the status of this software.\r
+ *\r
+ * Author: Daniel Veillard\r
+ */\r
+\r
+#ifndef __XML_XSLTUTILS_H__\r
+#define __XML_XSLTUTILS_H__\r
+\r
+#include <libxslt/xsltconfig.h>\r
+#ifdef HAVE_STDARG_H\r
+#include <stdarg.h>\r
+#endif\r
+#include <libxml/xpath.h>\r
+#include <libxml/dict.h>\r
+#include <libxml/xmlerror.h>\r
+#include "xsltexports.h"\r
+#include "xsltInternals.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * XSLT_TODO:\r
+ *\r
+ * Macro to flag unimplemented blocks.\r
+ */\r
+#define XSLT_TODO \\r
+ xsltGenericError(xsltGenericErrorContext, \\r
+ "Unimplemented block at %s:%d\n", \\r
+ __FILE__, __LINE__);\r
+\r
+/**\r
+ * XSLT_STRANGE:\r
+ *\r
+ * Macro to flag that a problem was detected internally.\r
+ */\r
+#define XSLT_STRANGE \\r
+ xsltGenericError(xsltGenericErrorContext, \\r
+ "Internal error at %s:%d\n", \\r
+ __FILE__, __LINE__);\r
+\r
+/**\r
+ * IS_XSLT_ELEM:\r
+ *\r
+ * Checks that the element pertains to XSLT namespace.\r
+ */\r
+#define IS_XSLT_ELEM(n) \\r
+ (((n) != NULL) && ((n)->ns != NULL) && \\r
+ (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))\r
+\r
+/**\r
+ * IS_XSLT_NAME:\r
+ *\r
+ * Checks the value of an element in XSLT namespace.\r
+ */\r
+#define IS_XSLT_NAME(n, val) \\r
+ (xmlStrEqual((n)->name, (const xmlChar *) (val)))\r
+\r
+/**\r
+ * IS_XSLT_REAL_NODE:\r
+ *\r
+ * Check that a node is a 'real' one: document, element, text or attribute.\r
+ */\r
+#define IS_XSLT_REAL_NODE(n) \\r
+ (((n) != NULL) && \\r
+ (((n)->type == XML_ELEMENT_NODE) || \\r
+ ((n)->type == XML_TEXT_NODE) || \\r
+ ((n)->type == XML_CDATA_SECTION_NODE) || \\r
+ ((n)->type == XML_ATTRIBUTE_NODE) || \\r
+ ((n)->type == XML_DOCUMENT_NODE) || \\r
+ ((n)->type == XML_HTML_DOCUMENT_NODE) || \\r
+ ((n)->type == XML_COMMENT_NODE) || \\r
+ ((n)->type == XML_PI_NODE))) \r
+\r
+/*\r
+ * Our own version of namespaced atributes lookup.\r
+ */\r
+XSLTPUBFUN xmlChar * XSLTCALL\r
+ xsltGetNsProp (xmlNodePtr node,\r
+ const xmlChar *name,\r
+ const xmlChar *nameSpace);\r
+XSLTPUBFUN const xmlChar * XSLTCALL\r
+ xsltGetCNsProp (xsltStylesheetPtr style,\r
+ xmlNodePtr node,\r
+ const xmlChar *name,\r
+ const xmlChar *nameSpace);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltGetUTF8Char (const unsigned char *utf,\r
+ int *len);\r
+\r
+/*\r
+ * XSLT Debug Tracing Tracing Types\r
+ */\r
+typedef enum {\r
+ XSLT_TRACE_ALL = -1,\r
+ XSLT_TRACE_NONE = 0,\r
+ XSLT_TRACE_COPY_TEXT = 1<<0,\r
+ XSLT_TRACE_PROCESS_NODE = 1<<1,\r
+ XSLT_TRACE_APPLY_TEMPLATE = 1<<2,\r
+ XSLT_TRACE_COPY = 1<<3,\r
+ XSLT_TRACE_COMMENT = 1<<4,\r
+ XSLT_TRACE_PI = 1<<5,\r
+ XSLT_TRACE_COPY_OF = 1<<6,\r
+ XSLT_TRACE_VALUE_OF = 1<<7,\r
+ XSLT_TRACE_CALL_TEMPLATE = 1<<8,\r
+ XSLT_TRACE_APPLY_TEMPLATES = 1<<9,\r
+ XSLT_TRACE_CHOOSE = 1<<10,\r
+ XSLT_TRACE_IF = 1<<11,\r
+ XSLT_TRACE_FOR_EACH = 1<<12,\r
+ XSLT_TRACE_STRIP_SPACES = 1<<13,\r
+ XSLT_TRACE_TEMPLATES = 1<<14,\r
+ XSLT_TRACE_KEYS = 1<<15,\r
+ XSLT_TRACE_VARIABLES = 1<<16\r
+} xsltDebugTraceCodes;\r
+\r
+/**\r
+ * XSLT_TRACE:\r
+ *\r
+ * Control the type of xsl debugtrace messages emitted.\r
+ */\r
+#define XSLT_TRACE(ctxt,code,call) \\r
+ if (ctxt->traceCode && (*(ctxt->traceCode) & code)) \\r
+ call\r
+\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltDebugSetDefaultTrace(xsltDebugTraceCodes val);\r
+XSLTPUBFUN xsltDebugTraceCodes XSLTCALL\r
+ xsltDebugGetDefaultTrace(void);\r
+\r
+/*\r
+ * XSLT specific error and debug reporting functions.\r
+ */\r
+XSLTPUBVAR xmlGenericErrorFunc xsltGenericError;\r
+XSLTPUBVAR void *xsltGenericErrorContext;\r
+XSLTPUBVAR xmlGenericErrorFunc xsltGenericDebug;\r
+XSLTPUBVAR void *xsltGenericDebugContext;\r
+\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltPrintErrorContext (xsltTransformContextPtr ctxt,\r
+ xsltStylesheetPtr style,\r
+ xmlNodePtr node);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltMessage (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr node,\r
+ xmlNodePtr inst);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSetGenericErrorFunc (void *ctx,\r
+ xmlGenericErrorFunc handler);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSetGenericDebugFunc (void *ctx,\r
+ xmlGenericErrorFunc handler);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSetTransformErrorFunc (xsltTransformContextPtr ctxt,\r
+ void *ctx,\r
+ xmlGenericErrorFunc handler);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltTransformError (xsltTransformContextPtr ctxt,\r
+ xsltStylesheetPtr style,\r
+ xmlNodePtr node,\r
+ const char *msg,\r
+ ...);\r
+\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltSetCtxtParseOptions (xsltTransformContextPtr ctxt,\r
+ int options);\r
+/*\r
+ * Sorting.\r
+ */\r
+\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltDocumentSortFunction (xmlNodeSetPtr list);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSetSortFunc (xsltSortFunc handler);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt,\r
+ xsltSortFunc handler);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltDefaultSortFunction (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr *sorts,\r
+ int nbsorts);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltDoSortFunction (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr * sorts,\r
+ int nbsorts);\r
+XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL \r
+ xsltComputeSortResult (xsltTransformContextPtr ctxt,\r
+ xmlNodePtr sort);\r
+\r
+/*\r
+ * QNames handling.\r
+ */\r
+\r
+XSLTPUBFUN const xmlChar * XSLTCALL\r
+ xsltSplitQName (xmlDictPtr dict,\r
+ const xmlChar *name,\r
+ const xmlChar **prefix);\r
+XSLTPUBFUN const xmlChar * XSLTCALL \r
+ xsltGetQNameURI (xmlNodePtr node,\r
+ xmlChar **name);\r
+\r
+XSLTPUBFUN const xmlChar * XSLTCALL\r
+ xsltGetQNameURI2 (xsltStylesheetPtr style,\r
+ xmlNodePtr node,\r
+ const xmlChar **name);\r
+\r
+/*\r
+ * Output, reuse libxml I/O buffers.\r
+ */\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSaveResultTo (xmlOutputBufferPtr buf,\r
+ xmlDocPtr result,\r
+ xsltStylesheetPtr style);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSaveResultToFilename (const char *URI,\r
+ xmlDocPtr result,\r
+ xsltStylesheetPtr style,\r
+ int compression);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSaveResultToFile (FILE *file,\r
+ xmlDocPtr result,\r
+ xsltStylesheetPtr style);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSaveResultToFd (int fd,\r
+ xmlDocPtr result,\r
+ xsltStylesheetPtr style);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSaveResultToString (xmlChar **doc_txt_ptr, \r
+ int * doc_txt_len, \r
+ xmlDocPtr result, \r
+ xsltStylesheetPtr style);\r
+\r
+/*\r
+ * XPath interface\r
+ */\r
+XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL\r
+ xsltXPathCompile (xsltStylesheetPtr style,\r
+ const xmlChar *str);\r
+\r
+/*\r
+ * Profiling.\r
+ */\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltSaveProfiling (xsltTransformContextPtr ctxt,\r
+ FILE *output);\r
+XSLTPUBFUN xmlDocPtr XSLTCALL \r
+ xsltGetProfileInformation (xsltTransformContextPtr ctxt);\r
+\r
+XSLTPUBFUN long XSLTCALL \r
+ xsltTimestamp (void);\r
+XSLTPUBFUN void XSLTCALL \r
+ xsltCalibrateAdjust (long delta);\r
+\r
+/**\r
+ * XSLT_TIMESTAMP_TICS_PER_SEC:\r
+ *\r
+ * Sampling precision for profiling\r
+ */\r
+#define XSLT_TIMESTAMP_TICS_PER_SEC 100000l\r
+\r
+/*\r
+ * Hooks for the debugger.\r
+ */\r
+\r
+typedef enum {\r
+ XSLT_DEBUG_NONE = 0, /* no debugging allowed */\r
+ XSLT_DEBUG_INIT,\r
+ XSLT_DEBUG_STEP,\r
+ XSLT_DEBUG_STEPOUT,\r
+ XSLT_DEBUG_NEXT,\r
+ XSLT_DEBUG_STOP,\r
+ XSLT_DEBUG_CONT,\r
+ XSLT_DEBUG_RUN,\r
+ XSLT_DEBUG_RUN_RESTART,\r
+ XSLT_DEBUG_QUIT\r
+} xsltDebugStatusCodes;\r
+\r
+XSLTPUBVAR int xslDebugStatus;\r
+\r
+typedef void (*xsltHandleDebuggerCallback) (xmlNodePtr cur, xmlNodePtr node,\r
+ xsltTemplatePtr templ, xsltTransformContextPtr ctxt);\r
+typedef int (*xsltAddCallCallback) (xsltTemplatePtr templ, xmlNodePtr source);\r
+typedef void (*xsltDropCallCallback) (void);\r
+\r
+XSLTPUBFUN void XSLTCALL\r
+ xsltSetDebuggerStatus (int value);\r
+XSLTPUBFUN int XSLTCALL\r
+ xsltGetDebuggerStatus (void);\r
+XSLTPUBFUN int XSLTCALL \r
+ xsltSetDebuggerCallbacks (int no, void *block);\r
+XSLTPUBFUN int XSLTCALL \r
+ xslAddCall (xsltTemplatePtr templ,\r
+ xmlNodePtr source);\r
+XSLTPUBFUN void XSLTCALL \r
+ xslDropCall (void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __XML_XSLTUTILS_H__ */\r
+\r
+\r