1 | #define IN_LIBEXSLT
|
---|
2 | #include "libexslt/libexslt.h"
|
---|
3 |
|
---|
4 | #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
|
---|
5 | #include <win32config.h>
|
---|
6 | #elif defined(VBOX)
|
---|
7 | #include "vboxconfig.h"
|
---|
8 | #else
|
---|
9 | #include "config.h"
|
---|
10 | #endif
|
---|
11 |
|
---|
12 | #include <libxml/tree.h>
|
---|
13 | #include <libxml/xpath.h>
|
---|
14 | #include <libxml/xpathInternals.h>
|
---|
15 | #include <libxml/parser.h>
|
---|
16 | #include <libxml/hash.h>
|
---|
17 |
|
---|
18 | #include <libxslt/xsltconfig.h>
|
---|
19 | #include <libxslt/xsltutils.h>
|
---|
20 | #include <libxslt/xsltInternals.h>
|
---|
21 | #include <libxslt/extensions.h>
|
---|
22 |
|
---|
23 | #include "exslt.h"
|
---|
24 |
|
---|
25 | /**
|
---|
26 | * exsltSaxonInit:
|
---|
27 | * @ctxt: an XSLT transformation context
|
---|
28 | * @URI: the namespace URI for the extension
|
---|
29 | *
|
---|
30 | * Initializes the SAXON module.
|
---|
31 | *
|
---|
32 | * Returns the data for this transformation
|
---|
33 | */
|
---|
34 | static xmlHashTablePtr
|
---|
35 | exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
|
---|
36 | const xmlChar *URI ATTRIBUTE_UNUSED) {
|
---|
37 | return xmlHashCreate(1);
|
---|
38 | }
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * exsltSaxonShutdown:
|
---|
42 | * @ctxt: an XSLT transformation context
|
---|
43 | * @URI: the namespace URI for the extension
|
---|
44 | * @data: the module data to free up
|
---|
45 | *
|
---|
46 | * Shutdown the SAXON extension module
|
---|
47 | */
|
---|
48 | static void
|
---|
49 | exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
|
---|
50 | const xmlChar *URI ATTRIBUTE_UNUSED,
|
---|
51 | xmlHashTablePtr data) {
|
---|
52 | xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr);
|
---|
53 | }
|
---|
54 |
|
---|
55 |
|
---|
56 | /**
|
---|
57 | * exsltSaxonExpressionFunction:
|
---|
58 | * @ctxt: an XPath parser context
|
---|
59 | * @nargs: the number of arguments
|
---|
60 | *
|
---|
61 | * The supplied string must contain an XPath expression. The result of
|
---|
62 | * the function is a stored expression, which may be supplied as an
|
---|
63 | * argument to other extension functions such as saxon:eval(),
|
---|
64 | * saxon:sum() and saxon:distinct(). The result of the expression will
|
---|
65 | * usually depend on the current node. The expression may contain
|
---|
66 | * references to variables that are in scope at the point where
|
---|
67 | * saxon:expression() is called: these variables will be replaced in
|
---|
68 | * the stored expression with the values they take at the time
|
---|
69 | * saxon:expression() is called, not the values of the variables at
|
---|
70 | * the time the stored expression is evaluated. Similarly, if the
|
---|
71 | * expression contains namespace prefixes, these are interpreted in
|
---|
72 | * terms of the namespace declarations in scope at the point where the
|
---|
73 | * saxon:expression() function is called, not those in scope where the
|
---|
74 | * stored expression is evaluated.
|
---|
75 | *
|
---|
76 | * TODO: current implementation doesn't conform to SAXON behaviour
|
---|
77 | * regarding context and namespaces.
|
---|
78 | */
|
---|
79 | static void
|
---|
80 | exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
---|
81 | xmlChar *arg;
|
---|
82 | xmlXPathCompExprPtr ret;
|
---|
83 | xmlHashTablePtr hash;
|
---|
84 | xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
|
---|
85 |
|
---|
86 | if (nargs != 1) {
|
---|
87 | xmlXPathSetArityError(ctxt);
|
---|
88 | return;
|
---|
89 | }
|
---|
90 |
|
---|
91 | arg = xmlXPathPopString(ctxt);
|
---|
92 | if (xmlXPathCheckError(ctxt) || (arg == NULL)) {
|
---|
93 | xmlXPathSetTypeError(ctxt);
|
---|
94 | return;
|
---|
95 | }
|
---|
96 |
|
---|
97 | hash = (xmlHashTablePtr) xsltGetExtData(tctxt,
|
---|
98 | ctxt->context->functionURI);
|
---|
99 |
|
---|
100 | ret = xmlHashLookup(hash, arg);
|
---|
101 |
|
---|
102 | if (ret == NULL) {
|
---|
103 | ret = xmlXPathCompile(arg);
|
---|
104 | if (ret == NULL) {
|
---|
105 | xmlFree(arg);
|
---|
106 | xsltGenericError(xsltGenericErrorContext,
|
---|
107 | "{%s}:%s: argument is not an XPath expression\n",
|
---|
108 | ctxt->context->functionURI, ctxt->context->function);
|
---|
109 | return;
|
---|
110 | }
|
---|
111 | xmlHashAddEntry(hash, arg, (void *) ret);
|
---|
112 | }
|
---|
113 |
|
---|
114 | xmlFree(arg);
|
---|
115 |
|
---|
116 | xmlXPathReturnExternal(ctxt, ret);
|
---|
117 | }
|
---|
118 |
|
---|
119 | /**
|
---|
120 | * exsltSaxonEvalFunction:
|
---|
121 | * @ctxt: an XPath parser context
|
---|
122 | * @nargs: number of arguments
|
---|
123 | *
|
---|
124 | * Implements de SAXON eval() function:
|
---|
125 | * object saxon:eval (saxon:stored-expression)
|
---|
126 | * Returns the result of evaluating the supplied stored expression.
|
---|
127 | * A stored expression may be obtained as the result of calling
|
---|
128 | * the saxon:expression() function.
|
---|
129 | * The stored expression is evaluated in the current context, that
|
---|
130 | * is, the context node is the current node, and the context position
|
---|
131 | * and context size are the same as the result of calling position()
|
---|
132 | * or last() respectively.
|
---|
133 | */
|
---|
134 | static void
|
---|
135 | exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
---|
136 | xmlXPathCompExprPtr expr;
|
---|
137 | xmlXPathObjectPtr ret;
|
---|
138 |
|
---|
139 | if (nargs != 1) {
|
---|
140 | xmlXPathSetArityError(ctxt);
|
---|
141 | return;
|
---|
142 | }
|
---|
143 |
|
---|
144 | if (!xmlXPathStackIsExternal(ctxt)) {
|
---|
145 | xmlXPathSetTypeError(ctxt);
|
---|
146 | return;
|
---|
147 | }
|
---|
148 |
|
---|
149 | expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt);
|
---|
150 |
|
---|
151 | ret = xmlXPathCompiledEval(expr, ctxt->context);
|
---|
152 |
|
---|
153 | valuePush(ctxt, ret);
|
---|
154 | }
|
---|
155 |
|
---|
156 | /**
|
---|
157 | * exsltSaxonEvaluateFunction:
|
---|
158 | * @ctxt: an XPath parser context
|
---|
159 | * @nargs: number of arguments
|
---|
160 | *
|
---|
161 | * Implements the SAXON evaluate() function
|
---|
162 | * object saxon:evaluate (string)
|
---|
163 | * The supplied string must contain an XPath expression. The result of
|
---|
164 | * the function is the result of evaluating the XPath expression. This
|
---|
165 | * is useful where an expression needs to be constructed at run-time or
|
---|
166 | * passed to the stylesheet as a parameter, for example where the sort
|
---|
167 | * key is determined dynamically. The context for the expression (e.g.
|
---|
168 | * which variables and namespaces are available) is exactly the same as
|
---|
169 | * if the expression were written explicitly at this point in the
|
---|
170 | * stylesheet. The function saxon:evaluate(string) is shorthand for
|
---|
171 | * saxon:eval(saxon:expression(string)).
|
---|
172 | */
|
---|
173 | static void
|
---|
174 | exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
---|
175 | if (nargs != 1) {
|
---|
176 | xmlXPathSetArityError(ctxt);
|
---|
177 | return;
|
---|
178 | }
|
---|
179 |
|
---|
180 | exsltSaxonExpressionFunction(ctxt, 1);
|
---|
181 | exsltSaxonEvalFunction(ctxt, 1);
|
---|
182 | }
|
---|
183 |
|
---|
184 | /**
|
---|
185 | * exsltSaxonLineNumberFunction:
|
---|
186 | * @ctxt: an XPath parser context
|
---|
187 | * @nargs: number of arguments
|
---|
188 | *
|
---|
189 | * Implements the SAXON line-number() function
|
---|
190 | * integer saxon:line-number()
|
---|
191 | *
|
---|
192 | * This returns the line number of the context node in the source document
|
---|
193 | * within the entity that contains it. There are no arguments. If line numbers
|
---|
194 | * are not maintained for the current document, the function returns -1. (To
|
---|
195 | * ensure that line numbers are maintained, use the -l option on the command
|
---|
196 | * line)
|
---|
197 | *
|
---|
198 | * The extension has been extended to have the following form:
|
---|
199 | * integer saxon:line-number([node-set-1])
|
---|
200 | * If a node-set is given, this extension will return the line number of the
|
---|
201 | * node in the argument node-set that is first in document order.
|
---|
202 | */
|
---|
203 | static void
|
---|
204 | exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
---|
205 | xmlNodePtr cur = NULL;
|
---|
206 |
|
---|
207 | if (nargs == 0) {
|
---|
208 | cur = ctxt->context->node;
|
---|
209 | } else if (nargs == 1) {
|
---|
210 | xmlXPathObjectPtr obj;
|
---|
211 | xmlNodeSetPtr nodelist;
|
---|
212 | int i;
|
---|
213 |
|
---|
214 | if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
|
---|
215 | xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
---|
216 | "saxon:line-number() : invalid arg expecting a node-set\n");
|
---|
217 | ctxt->error = XPATH_INVALID_TYPE;
|
---|
218 | return;
|
---|
219 | }
|
---|
220 |
|
---|
221 | obj = valuePop(ctxt);
|
---|
222 | nodelist = obj->nodesetval;
|
---|
223 | if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
|
---|
224 | xmlXPathFreeObject(obj);
|
---|
225 | valuePush(ctxt, xmlXPathNewFloat(-1));
|
---|
226 | return;
|
---|
227 | }
|
---|
228 | cur = nodelist->nodeTab[0];
|
---|
229 | for (i = 1;i < nodelist->nodeNr;i++) {
|
---|
230 | int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
|
---|
231 | if (ret == -1)
|
---|
232 | cur = nodelist->nodeTab[i];
|
---|
233 | }
|
---|
234 | xmlXPathFreeObject(obj);
|
---|
235 | } else {
|
---|
236 | xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
---|
237 | "saxon:line-number() : invalid number of args %d\n",
|
---|
238 | nargs);
|
---|
239 | ctxt->error = XPATH_INVALID_ARITY;
|
---|
240 | return;
|
---|
241 | }
|
---|
242 |
|
---|
243 | valuePush(ctxt, xmlXPathNewFloat(xmlGetLineNo(cur)));
|
---|
244 | return;
|
---|
245 | }
|
---|
246 |
|
---|
247 | /**
|
---|
248 | * exsltSaxonRegister:
|
---|
249 | *
|
---|
250 | * Registers the SAXON extension module
|
---|
251 | */
|
---|
252 | void
|
---|
253 | exsltSaxonRegister (void) {
|
---|
254 | xsltRegisterExtModule (SAXON_NAMESPACE,
|
---|
255 | (xsltExtInitFunction) exsltSaxonInit,
|
---|
256 | (xsltExtShutdownFunction) exsltSaxonShutdown);
|
---|
257 | xsltRegisterExtModuleFunction((const xmlChar *) "expression",
|
---|
258 | SAXON_NAMESPACE,
|
---|
259 | exsltSaxonExpressionFunction);
|
---|
260 | xsltRegisterExtModuleFunction((const xmlChar *) "eval",
|
---|
261 | SAXON_NAMESPACE,
|
---|
262 | exsltSaxonEvalFunction);
|
---|
263 | xsltRegisterExtModuleFunction((const xmlChar *) "evaluate",
|
---|
264 | SAXON_NAMESPACE,
|
---|
265 | exsltSaxonEvaluateFunction);
|
---|
266 | xsltRegisterExtModuleFunction ((const xmlChar *) "line-number",
|
---|
267 | SAXON_NAMESPACE,
|
---|
268 | exsltSaxonLineNumberFunction);
|
---|
269 | }
|
---|