summaryrefslogtreecommitdiffstats
path: root/libxslt/libexslt/saxon.c
diff options
context:
space:
mode:
Diffstat (limited to 'libxslt/libexslt/saxon.c')
-rw-r--r--libxslt/libexslt/saxon.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/libxslt/libexslt/saxon.c b/libxslt/libexslt/saxon.c
new file mode 100644
index 0000000..7a2f63b
--- /dev/null
+++ b/libxslt/libexslt/saxon.c
@@ -0,0 +1,313 @@
+#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/hash.h>
+
+#include <libxslt/xsltconfig.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/extensions.h>
+
+#include "exslt.h"
+
+/**
+ * exsltSaxonInit:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ *
+ * Initializes the SAXON module.
+ *
+ * Returns the data for this transformation
+ */
+static xmlHashTablePtr
+exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *URI ATTRIBUTE_UNUSED) {
+ return xmlHashCreate(1);
+}
+
+/**
+ * exsltSaxonShutdown:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ * @data: the module data to free up
+ *
+ * Shutdown the SAXON extension module
+ */
+static void
+exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *URI ATTRIBUTE_UNUSED,
+ xmlHashTablePtr data) {
+ xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr);
+}
+
+
+/**
+ * exsltSaxonExpressionFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * The supplied string must contain an XPath expression. The result of
+ * the function is a stored expression, which may be supplied as an
+ * argument to other extension functions such as saxon:eval(),
+ * saxon:sum() and saxon:distinct(). The result of the expression will
+ * usually depend on the current node. The expression may contain
+ * references to variables that are in scope at the point where
+ * saxon:expression() is called: these variables will be replaced in
+ * the stored expression with the values they take at the time
+ * saxon:expression() is called, not the values of the variables at
+ * the time the stored expression is evaluated. Similarly, if the
+ * expression contains namespace prefixes, these are interpreted in
+ * terms of the namespace declarations in scope at the point where the
+ * saxon:expression() function is called, not those in scope where the
+ * stored expression is evaluated.
+ *
+ * TODO: current implementation doesn't conform to SAXON behaviour
+ * regarding context and namespaces.
+ */
+static void
+exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlChar *arg;
+ xmlXPathCompExprPtr ret;
+ xmlHashTablePtr hash;
+ xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
+
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ arg = xmlXPathPopString(ctxt);
+ if (xmlXPathCheckError(ctxt) || (arg == NULL)) {
+ xmlXPathSetTypeError(ctxt);
+ return;
+ }
+
+ hash = (xmlHashTablePtr) xsltGetExtData(tctxt,
+ ctxt->context->functionURI);
+
+ ret = xmlHashLookup(hash, arg);
+
+ if (ret == NULL) {
+ ret = xmlXPathCompile(arg);
+ if (ret == NULL) {
+ xmlFree(arg);
+ xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
+ return;
+ }
+ xmlHashAddEntry(hash, arg, (void *) ret);
+ }
+
+ xmlFree(arg);
+
+ xmlXPathReturnExternal(ctxt, ret);
+}
+
+/**
+ * exsltSaxonEvalFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: number of arguments
+ *
+ * Implements de SAXON eval() function:
+ * object saxon:eval (saxon:stored-expression)
+ * Returns the result of evaluating the supplied stored expression.
+ * A stored expression may be obtained as the result of calling
+ * the saxon:expression() function.
+ * The stored expression is evaluated in the current context, that
+ * is, the context node is the current node, and the context position
+ * and context size are the same as the result of calling position()
+ * or last() respectively.
+ */
+static void
+exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlXPathCompExprPtr expr;
+ xmlXPathObjectPtr ret;
+
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if (!xmlXPathStackIsExternal(ctxt)) {
+ xmlXPathSetTypeError(ctxt);
+ return;
+ }
+
+ expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt);
+
+ ret = xmlXPathCompiledEval(expr, ctxt->context);
+ if (ret == NULL) {
+ xmlXPathSetError(ctxt, XPATH_EXPR_ERROR);
+ return;
+ }
+
+ valuePush(ctxt, ret);
+}
+
+/**
+ * exsltSaxonEvaluateFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: number of arguments
+ *
+ * Implements the SAXON evaluate() function
+ * object saxon:evaluate (string)
+ * The supplied string must contain an XPath expression. The result of
+ * the function is the result of evaluating the XPath expression. This
+ * is useful where an expression needs to be constructed at run-time or
+ * passed to the stylesheet as a parameter, for example where the sort
+ * key is determined dynamically. The context for the expression (e.g.
+ * which variables and namespaces are available) is exactly the same as
+ * if the expression were written explicitly at this point in the
+ * stylesheet. The function saxon:evaluate(string) is shorthand for
+ * saxon:eval(saxon:expression(string)).
+ */
+static void
+exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+ if (nargs != 1) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ exsltSaxonExpressionFunction(ctxt, 1);
+ exsltSaxonEvalFunction(ctxt, 1);
+}
+
+/**
+ * exsltSaxonSystemIdFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: number of arguments
+ *
+ * Implements the SAXON systemId() function
+ * string saxon:systemId ()
+ * This function returns the system ID of the document being styled.
+ */
+static void
+exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ if (ctxt == NULL)
+ return;
+ if (nargs != 0) {
+ xmlXPathSetArityError(ctxt);
+ return;
+ }
+
+ if ((ctxt->context) && (ctxt->context->doc) &&
+ (ctxt->context->doc->URL))
+ valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL));
+ else
+ valuePush(ctxt, xmlXPathNewString(BAD_CAST ""));
+}
+
+/**
+ * exsltSaxonLineNumberFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: number of arguments
+ *
+ * Implements the SAXON line-number() function
+ * integer saxon:line-number()
+ *
+ * This returns the line number of the context node in the source document
+ * within the entity that contains it. There are no arguments. If line numbers
+ * are not maintained for the current document, the function returns -1. (To
+ * ensure that line numbers are maintained, use the -l option on the command
+ * line)
+ *
+ * The extension has been extended to have the following form:
+ * integer saxon:line-number([node-set-1])
+ * If a node-set is given, this extension will return the line number of the
+ * node in the argument node-set that is first in document order.
+ */
+static void
+exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+ xmlNodePtr cur = NULL;
+ xmlXPathObjectPtr obj = NULL;
+ long lineNo = -1;
+
+ if (nargs == 0) {
+ cur = ctxt->context->node;
+ } else if (nargs == 1) {
+ xmlNodeSetPtr nodelist;
+ int i;
+
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+ "saxon:line-number() : invalid arg expecting a node-set\n");
+ ctxt->error = XPATH_INVALID_TYPE;
+ return;
+ }
+
+ obj = valuePop(ctxt);
+ nodelist = obj->nodesetval;
+ if ((nodelist != NULL) && (nodelist->nodeNr > 0)) {
+ cur = nodelist->nodeTab[0];
+ for (i = 1;i < nodelist->nodeNr;i++) {
+ int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
+ if (ret == -1)
+ cur = nodelist->nodeTab[i];
+ }
+ }
+ } else {
+ xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+ "saxon:line-number() : invalid number of args %d\n",
+ nargs);
+ ctxt->error = XPATH_INVALID_ARITY;
+ return;
+ }
+
+ if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) {
+ /*
+ * The XPath module sets the owner element of a ns-node on
+ * the ns->next field.
+ */
+ cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
+ if (cur == NULL || cur->type != XML_ELEMENT_NODE) {
+ xsltGenericError(xsltGenericErrorContext,
+ "Internal error in exsltSaxonLineNumberFunction: "
+ "Cannot retrieve the doc of a namespace node.\n");
+ cur = NULL;
+ }
+ }
+
+ if (cur != NULL)
+ lineNo = xmlGetLineNo(cur);
+
+ valuePush(ctxt, xmlXPathNewFloat(lineNo));
+
+ xmlXPathFreeObject(obj);
+}
+
+/**
+ * exsltSaxonRegister:
+ *
+ * Registers the SAXON extension module
+ */
+void
+exsltSaxonRegister (void) {
+ xsltRegisterExtModule (SAXON_NAMESPACE,
+ (xsltExtInitFunction) exsltSaxonInit,
+ (xsltExtShutdownFunction) exsltSaxonShutdown);
+ xsltRegisterExtModuleFunction((const xmlChar *) "expression",
+ SAXON_NAMESPACE,
+ exsltSaxonExpressionFunction);
+ xsltRegisterExtModuleFunction((const xmlChar *) "eval",
+ SAXON_NAMESPACE,
+ exsltSaxonEvalFunction);
+ xsltRegisterExtModuleFunction((const xmlChar *) "evaluate",
+ SAXON_NAMESPACE,
+ exsltSaxonEvaluateFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "line-number",
+ SAXON_NAMESPACE,
+ exsltSaxonLineNumberFunction);
+ xsltRegisterExtModuleFunction ((const xmlChar *) "systemId",
+ SAXON_NAMESPACE,
+ exsltSaxonSystemIdFunction);
+}