OLD | NEW |
| (Empty) |
1 #define IN_LIBEXSLT | |
2 #include "libexslt/libexslt.h" | |
3 | |
4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) | |
5 #include <win32config.h> | |
6 #else | |
7 #include "config.h" | |
8 #endif | |
9 | |
10 #include <libxml/tree.h> | |
11 #include <libxml/xpath.h> | |
12 #include <libxml/xpathInternals.h> | |
13 #include <libxml/parser.h> | |
14 #include <libxml/hash.h> | |
15 | |
16 #include <libxslt/xsltconfig.h> | |
17 #include <libxslt/xsltutils.h> | |
18 #include <libxslt/xsltInternals.h> | |
19 #include <libxslt/extensions.h> | |
20 | |
21 #include "exslt.h" | |
22 | |
23 /** | |
24 * exsltSaxonInit: | |
25 * @ctxt: an XSLT transformation context | |
26 * @URI: the namespace URI for the extension | |
27 * | |
28 * Initializes the SAXON module. | |
29 * | |
30 * Returns the data for this transformation | |
31 */ | |
32 static xmlHashTablePtr | |
33 exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, | |
34 const xmlChar *URI ATTRIBUTE_UNUSED) { | |
35 return xmlHashCreate(1); | |
36 } | |
37 | |
38 /** | |
39 * exsltSaxonShutdown: | |
40 * @ctxt: an XSLT transformation context | |
41 * @URI: the namespace URI for the extension | |
42 * @data: the module data to free up | |
43 * | |
44 * Shutdown the SAXON extension module | |
45 */ | |
46 static void | |
47 exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, | |
48 const xmlChar *URI ATTRIBUTE_UNUSED, | |
49 xmlHashTablePtr data) { | |
50 xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr); | |
51 } | |
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 exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
79 xmlChar *arg; | |
80 xmlXPathCompExprPtr ret; | |
81 xmlHashTablePtr hash; | |
82 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); | |
83 | |
84 if (nargs != 1) { | |
85 xmlXPathSetArityError(ctxt); | |
86 return; | |
87 } | |
88 | |
89 arg = xmlXPathPopString(ctxt); | |
90 if (xmlXPathCheckError(ctxt) || (arg == NULL)) { | |
91 xmlXPathSetTypeError(ctxt); | |
92 return; | |
93 } | |
94 | |
95 hash = (xmlHashTablePtr) xsltGetExtData(tctxt, | |
96 ctxt->context->functionURI); | |
97 | |
98 ret = xmlHashLookup(hash, arg); | |
99 | |
100 if (ret == NULL) { | |
101 ret = xmlXPathCompile(arg); | |
102 if (ret == NULL) { | |
103 xmlFree(arg); | |
104 xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); | |
105 return; | |
106 } | |
107 xmlHashAddEntry(hash, arg, (void *) ret); | |
108 } | |
109 | |
110 xmlFree(arg); | |
111 | |
112 xmlXPathReturnExternal(ctxt, ret); | |
113 } | |
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 exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
132 xmlXPathCompExprPtr expr; | |
133 xmlXPathObjectPtr ret; | |
134 | |
135 if (nargs != 1) { | |
136 xmlXPathSetArityError(ctxt); | |
137 return; | |
138 } | |
139 | |
140 if (!xmlXPathStackIsExternal(ctxt)) { | |
141 xmlXPathSetTypeError(ctxt); | |
142 return; | |
143 } | |
144 | |
145 expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); | |
146 | |
147 ret = xmlXPathCompiledEval(expr, ctxt->context); | |
148 if (ret == NULL) { | |
149 xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); | |
150 return; | |
151 } | |
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 * 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 { | |
196 if (ctxt == NULL) | |
197 return; | |
198 if (nargs != 0) { | |
199 xmlXPathSetArityError(ctxt); | |
200 return; | |
201 } | |
202 | |
203 if ((ctxt->context) && (ctxt->context->doc) && | |
204 (ctxt->context->doc->URL)) | |
205 valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); | |
206 else | |
207 valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); | |
208 } | |
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 exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { | |
231 xmlNodePtr cur = NULL; | |
232 xmlXPathObjectPtr obj = NULL; | |
233 long lineNo = -1; | |
234 | |
235 if (nargs == 0) { | |
236 cur = ctxt->context->node; | |
237 } else if (nargs == 1) { | |
238 xmlNodeSetPtr nodelist; | |
239 int i; | |
240 | |
241 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { | |
242 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
243 "saxon:line-number() : invalid arg expecting a node-set\n"); | |
244 ctxt->error = XPATH_INVALID_TYPE; | |
245 return; | |
246 } | |
247 | |
248 obj = valuePop(ctxt); | |
249 nodelist = obj->nodesetval; | |
250 if ((nodelist != NULL) && (nodelist->nodeNr > 0)) { | |
251 cur = nodelist->nodeTab[0]; | |
252 for (i = 1;i < nodelist->nodeNr;i++) { | |
253 int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); | |
254 if (ret == -1) | |
255 cur = nodelist->nodeTab[i]; | |
256 } | |
257 } | |
258 } else { | |
259 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
260 "saxon:line-number() : invalid number of args %d\n", | |
261 nargs); | |
262 ctxt->error = XPATH_INVALID_ARITY; | |
263 return; | |
264 } | |
265 | |
266 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 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; | |
272 if (cur == NULL || cur->type != XML_ELEMENT_NODE) { | |
273 xsltGenericError(xsltGenericErrorContext, | |
274 "Internal error in exsltSaxonLineNumberFunction: " | |
275 "Cannot retrieve the doc of a namespace node.\n"); | |
276 cur = NULL; | |
277 } | |
278 } | |
279 | |
280 if (cur != NULL) | |
281 lineNo = xmlGetLineNo(cur); | |
282 | |
283 valuePush(ctxt, xmlXPathNewFloat(lineNo)); | |
284 | |
285 xmlXPathFreeObject(obj); | |
286 } | |
287 | |
288 /** | |
289 * exsltSaxonRegister: | |
290 * | |
291 * Registers the SAXON extension module | |
292 */ | |
293 void | |
294 exsltSaxonRegister (void) { | |
295 xsltRegisterExtModule (SAXON_NAMESPACE, | |
296 (xsltExtInitFunction) exsltSaxonInit, | |
297 (xsltExtShutdownFunction) exsltSaxonShutdown); | |
298 xsltRegisterExtModuleFunction((const xmlChar *) "expression", | |
299 SAXON_NAMESPACE, | |
300 exsltSaxonExpressionFunction); | |
301 xsltRegisterExtModuleFunction((const xmlChar *) "eval", | |
302 SAXON_NAMESPACE, | |
303 exsltSaxonEvalFunction); | |
304 xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", | |
305 SAXON_NAMESPACE, | |
306 exsltSaxonEvaluateFunction); | |
307 xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", | |
308 SAXON_NAMESPACE, | |
309 exsltSaxonLineNumberFunction); | |
310 xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", | |
311 SAXON_NAMESPACE, | |
312 exsltSaxonSystemIdFunction); | |
313 } | |
OLD | NEW |