summaryrefslogtreecommitdiff
path: root/libexslt/saxon.c
blob: 30ec5144bcae47290c1d1c2100f28e2c8aed6083 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#define IN_LIBEXSLT
#include "libexslt/libexslt.h"

#if defined(WIN32) && !defined (__CYGWIN__)
#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);
	      xsltGenericError(xsltGenericErrorContext,
			"{%s}:%s: argument is not an XPath expression\n",
			ctxt->context->functionURI, ctxt->context->function);
	      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);

     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);
}

/**
 * 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);
}