/src/libxslt/libexslt/saxon.c
Line | Count | Source (jump to first uncovered line) |
1 | | #define IN_LIBEXSLT |
2 | | #include "libexslt/libexslt.h" |
3 | | |
4 | | #include <libxml/tree.h> |
5 | | #include <libxml/xpath.h> |
6 | | #include <libxml/xpathInternals.h> |
7 | | #include <libxml/parser.h> |
8 | | #include <libxml/hash.h> |
9 | | |
10 | | #include <libxslt/xsltutils.h> |
11 | | #include <libxslt/xsltInternals.h> |
12 | | #include <libxslt/extensions.h> |
13 | | |
14 | | #include "exslt.h" |
15 | | |
16 | | /** |
17 | | * exsltSaxonInit: |
18 | | * @ctxt: an XSLT transformation context |
19 | | * @URI: the namespace URI for the extension |
20 | | * |
21 | | * Initializes the SAXON module. |
22 | | * |
23 | | * Returns the data for this transformation |
24 | | */ |
25 | | static void * |
26 | | exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, |
27 | 381 | const xmlChar *URI ATTRIBUTE_UNUSED) { |
28 | 381 | return xmlHashCreate(1); |
29 | 381 | } |
30 | | |
31 | | static void |
32 | | exsltSaxonFreeCompExprEntry(void *payload, |
33 | 0 | const xmlChar *name ATTRIBUTE_UNUSED) { |
34 | 0 | xmlXPathFreeCompExpr((xmlXPathCompExprPtr) payload); |
35 | 0 | } |
36 | | |
37 | | /** |
38 | | * exsltSaxonShutdown: |
39 | | * @ctxt: an XSLT transformation context |
40 | | * @URI: the namespace URI for the extension |
41 | | * @data: the module data to free up |
42 | | * |
43 | | * Shutdown the SAXON extension module |
44 | | */ |
45 | | static void |
46 | | exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, |
47 | | const xmlChar *URI ATTRIBUTE_UNUSED, |
48 | 0 | void *vdata) { |
49 | 0 | xmlHashTablePtr data = (xmlHashTablePtr) vdata; |
50 | 0 | xmlHashFree(data, exsltSaxonFreeCompExprEntry); |
51 | 0 | } |
52 | | |
53 | | |
54 | | /** |
55 | | * exsltSaxonExpressionFunction: |
56 | | * @ctxt: an XPath parser context |
57 | | * @nargs: the number of arguments |
58 | | * |
59 | | * The supplied string must contain an XPath expression. The result of |
60 | | * the function is a stored expression, which may be supplied as an |
61 | | * argument to other extension functions such as saxon:eval(), |
62 | | * saxon:sum() and saxon:distinct(). The result of the expression will |
63 | | * usually depend on the current node. The expression may contain |
64 | | * references to variables that are in scope at the point where |
65 | | * saxon:expression() is called: these variables will be replaced in |
66 | | * the stored expression with the values they take at the time |
67 | | * saxon:expression() is called, not the values of the variables at |
68 | | * the time the stored expression is evaluated. Similarly, if the |
69 | | * expression contains namespace prefixes, these are interpreted in |
70 | | * terms of the namespace declarations in scope at the point where the |
71 | | * saxon:expression() function is called, not those in scope where the |
72 | | * stored expression is evaluated. |
73 | | * |
74 | | * TODO: current implementation doesn't conform to SAXON behaviour |
75 | | * regarding context and namespaces. |
76 | | */ |
77 | | static void |
78 | 7.18k | exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
79 | 7.18k | xmlChar *arg; |
80 | 7.18k | xmlXPathCompExprPtr ret; |
81 | 7.18k | xmlHashTablePtr hash; |
82 | 7.18k | xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); |
83 | | |
84 | 7.18k | if (nargs != 1) { |
85 | 16 | xmlXPathSetArityError(ctxt); |
86 | 16 | return; |
87 | 16 | } |
88 | | |
89 | 7.17k | arg = xmlXPathPopString(ctxt); |
90 | 7.17k | if (xmlXPathCheckError(ctxt) || (arg == NULL)) { |
91 | 0 | xmlXPathSetTypeError(ctxt); |
92 | 0 | return; |
93 | 0 | } |
94 | | |
95 | 7.17k | hash = (xmlHashTablePtr) xsltGetExtData(tctxt, |
96 | 7.17k | ctxt->context->functionURI); |
97 | | |
98 | 7.17k | ret = xmlHashLookup(hash, arg); |
99 | | |
100 | 7.17k | if (ret == NULL) { |
101 | 2.72k | ret = xmlXPathCtxtCompile(tctxt->xpathCtxt, arg); |
102 | 2.72k | if (ret == NULL) { |
103 | 204 | xmlFree(arg); |
104 | 204 | xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); |
105 | 204 | return; |
106 | 204 | } |
107 | 2.52k | xmlHashAddEntry(hash, arg, (void *) ret); |
108 | 2.52k | } |
109 | | |
110 | 6.96k | xmlFree(arg); |
111 | | |
112 | 6.96k | xmlXPathReturnExternal(ctxt, ret); |
113 | 6.96k | } |
114 | | |
115 | | /** |
116 | | * exsltSaxonEvalFunction: |
117 | | * @ctxt: an XPath parser context |
118 | | * @nargs: number of arguments |
119 | | * |
120 | | * Implements de SAXON eval() function: |
121 | | * object saxon:eval (saxon:stored-expression) |
122 | | * Returns the result of evaluating the supplied stored expression. |
123 | | * A stored expression may be obtained as the result of calling |
124 | | * the saxon:expression() function. |
125 | | * The stored expression is evaluated in the current context, that |
126 | | * is, the context node is the current node, and the context position |
127 | | * and context size are the same as the result of calling position() |
128 | | * or last() respectively. |
129 | | */ |
130 | | static void |
131 | 1.95k | exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
132 | 1.95k | xmlXPathCompExprPtr expr; |
133 | 1.95k | xmlXPathObjectPtr ret; |
134 | | |
135 | 1.95k | if (nargs != 1) { |
136 | 16 | xmlXPathSetArityError(ctxt); |
137 | 16 | return; |
138 | 16 | } |
139 | | |
140 | 1.93k | if (!xmlXPathStackIsExternal(ctxt)) { |
141 | 162 | xmlXPathSetTypeError(ctxt); |
142 | 162 | return; |
143 | 162 | } |
144 | | |
145 | 1.77k | expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); |
146 | | |
147 | 1.77k | ret = xmlXPathCompiledEval(expr, ctxt->context); |
148 | 1.77k | if (ret == NULL) { |
149 | 1.02k | xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); |
150 | 1.02k | return; |
151 | 1.02k | } |
152 | | |
153 | 754 | valuePush(ctxt, ret); |
154 | 754 | } |
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 | 1.83k | exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
175 | 1.83k | if (nargs != 1) { |
176 | 17 | xmlXPathSetArityError(ctxt); |
177 | 17 | return; |
178 | 17 | } |
179 | | |
180 | 1.81k | exsltSaxonExpressionFunction(ctxt, 1); |
181 | 1.81k | exsltSaxonEvalFunction(ctxt, 1); |
182 | 1.81k | } |
183 | | |
184 | | /** |
185 | | * exsltSaxonSystemIdFunction: |
186 | | * @ctxt: an XPath parser context |
187 | | * @nargs: number of arguments |
188 | | * |
189 | | * Implements the SAXON systemId() function |
190 | | * string saxon:systemId () |
191 | | * This function returns the system ID of the document being styled. |
192 | | */ |
193 | | static void |
194 | | exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs) |
195 | 70 | { |
196 | 70 | if (ctxt == NULL) |
197 | 0 | return; |
198 | 70 | if (nargs != 0) { |
199 | 17 | xmlXPathSetArityError(ctxt); |
200 | 17 | return; |
201 | 17 | } |
202 | | |
203 | 53 | if ((ctxt->context) && (ctxt->context->doc) && |
204 | 53 | (ctxt->context->doc->URL)) |
205 | 53 | valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); |
206 | 0 | else |
207 | 0 | valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); |
208 | 53 | } |
209 | | |
210 | | /** |
211 | | * exsltSaxonLineNumberFunction: |
212 | | * @ctxt: an XPath parser context |
213 | | * @nargs: number of arguments |
214 | | * |
215 | | * Implements the SAXON line-number() function |
216 | | * integer saxon:line-number() |
217 | | * |
218 | | * This returns the line number of the context node in the source document |
219 | | * within the entity that contains it. There are no arguments. If line numbers |
220 | | * are not maintained for the current document, the function returns -1. (To |
221 | | * ensure that line numbers are maintained, use the -l option on the command |
222 | | * line) |
223 | | * |
224 | | * The extension has been extended to have the following form: |
225 | | * integer saxon:line-number([node-set-1]) |
226 | | * If a node-set is given, this extension will return the line number of the |
227 | | * node in the argument node-set that is first in document order. |
228 | | */ |
229 | | static void |
230 | 316 | exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
231 | 316 | xmlNodePtr cur = NULL; |
232 | 316 | xmlXPathObjectPtr obj = NULL; |
233 | 316 | long lineNo = -1; |
234 | | |
235 | 316 | if (nargs == 0) { |
236 | 33 | cur = ctxt->context->node; |
237 | 283 | } else if (nargs == 1) { |
238 | 267 | xmlNodeSetPtr nodelist; |
239 | 267 | int i; |
240 | | |
241 | 267 | if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { |
242 | 55 | xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
243 | 55 | "saxon:line-number() : invalid arg expecting a node-set\n"); |
244 | 55 | ctxt->error = XPATH_INVALID_TYPE; |
245 | 55 | return; |
246 | 55 | } |
247 | | |
248 | 212 | obj = valuePop(ctxt); |
249 | 212 | nodelist = obj->nodesetval; |
250 | 212 | if ((nodelist != NULL) && (nodelist->nodeNr > 0)) { |
251 | 180 | cur = nodelist->nodeTab[0]; |
252 | 2.90k | for (i = 1;i < nodelist->nodeNr;i++) { |
253 | 2.72k | int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); |
254 | 2.72k | if (ret == -1) |
255 | 18 | cur = nodelist->nodeTab[i]; |
256 | 2.72k | } |
257 | 180 | } |
258 | 212 | } else { |
259 | 16 | xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
260 | 16 | "saxon:line-number() : invalid number of args %d\n", |
261 | 16 | nargs); |
262 | 16 | ctxt->error = XPATH_INVALID_ARITY; |
263 | 16 | return; |
264 | 16 | } |
265 | | |
266 | 245 | if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) { |
267 | | /* |
268 | | * The XPath module sets the owner element of a ns-node on |
269 | | * the ns->next field. |
270 | | */ |
271 | 7 | cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; |
272 | 7 | if (cur == NULL || cur->type != XML_ELEMENT_NODE) { |
273 | 0 | xsltGenericError(xsltGenericErrorContext, |
274 | 0 | "Internal error in exsltSaxonLineNumberFunction: " |
275 | 0 | "Cannot retrieve the doc of a namespace node.\n"); |
276 | 0 | cur = NULL; |
277 | 0 | } |
278 | 7 | } |
279 | | |
280 | 245 | if (cur != NULL) |
281 | 213 | lineNo = xmlGetLineNo(cur); |
282 | | |
283 | 245 | valuePush(ctxt, xmlXPathNewFloat(lineNo)); |
284 | | |
285 | 245 | xmlXPathFreeObject(obj); |
286 | 245 | } |
287 | | |
288 | | /** |
289 | | * exsltSaxonRegister: |
290 | | * |
291 | | * Registers the SAXON extension module |
292 | | */ |
293 | | void |
294 | 2.94k | exsltSaxonRegister (void) { |
295 | 2.94k | xsltRegisterExtModule (SAXON_NAMESPACE, |
296 | 2.94k | exsltSaxonInit, |
297 | 2.94k | exsltSaxonShutdown); |
298 | 2.94k | xsltRegisterExtModuleFunction((const xmlChar *) "expression", |
299 | 2.94k | SAXON_NAMESPACE, |
300 | 2.94k | exsltSaxonExpressionFunction); |
301 | 2.94k | xsltRegisterExtModuleFunction((const xmlChar *) "eval", |
302 | 2.94k | SAXON_NAMESPACE, |
303 | 2.94k | exsltSaxonEvalFunction); |
304 | 2.94k | xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", |
305 | 2.94k | SAXON_NAMESPACE, |
306 | 2.94k | exsltSaxonEvaluateFunction); |
307 | 2.94k | xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", |
308 | 2.94k | SAXON_NAMESPACE, |
309 | 2.94k | exsltSaxonLineNumberFunction); |
310 | 2.94k | xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", |
311 | 2.94k | SAXON_NAMESPACE, |
312 | 2.94k | exsltSaxonSystemIdFunction); |
313 | 2.94k | } |