OLD | NEW |
| (Empty) |
1 /* | |
2 * dynamic.c: Implementation of the EXSLT -- Dynamic module | |
3 * | |
4 * References: | |
5 * http://www.exslt.org/dyn/dyn.html | |
6 * | |
7 * See Copyright for the status of this software. | |
8 * | |
9 * Authors: | |
10 * Mark Vakoc <mark_vakoc@jdedwards.com> | |
11 * Thomas Broyer <tbroyer@ltgt.net> | |
12 * | |
13 * TODO: | |
14 * elements: | |
15 * functions: | |
16 * min | |
17 * max | |
18 * sum | |
19 * map | |
20 * closure | |
21 */ | |
22 | |
23 #define IN_LIBEXSLT | |
24 #include "libexslt/libexslt.h" | |
25 | |
26 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) | |
27 #include <win32config.h> | |
28 #else | |
29 #include "config.h" | |
30 #endif | |
31 | |
32 #include <libxml/tree.h> | |
33 #include <libxml/xpath.h> | |
34 #include <libxml/xpathInternals.h> | |
35 | |
36 #include <libxslt/xsltconfig.h> | |
37 #include <libxslt/xsltutils.h> | |
38 #include <libxslt/xsltInternals.h> | |
39 #include <libxslt/extensions.h> | |
40 | |
41 #include "exslt.h" | |
42 | |
43 /** | |
44 * exsltDynEvaluateFunction: | |
45 * @ctxt: an XPath parser context | |
46 * @nargs: the number of arguments | |
47 * | |
48 * Evaluates the string as an XPath expression and returns the result | |
49 * value, which may be a boolean, number, string, node set, result tree | |
50 * fragment or external object. | |
51 */ | |
52 | |
53 static void | |
54 exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { | |
55 xmlChar *str = NULL; | |
56 xmlXPathObjectPtr ret = NULL; | |
57 | |
58 if (ctxt == NULL) | |
59 return; | |
60 if (nargs != 1) { | |
61 xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL,
NULL); | |
62 xsltGenericError(xsltGenericErrorContext, | |
63 "dyn:evalute() : invalid number of args %d\n", nargs); | |
64 ctxt->error = XPATH_INVALID_ARITY; | |
65 return; | |
66 } | |
67 str = xmlXPathPopString(ctxt); | |
68 /* return an empty node-set if an empty string is passed in */ | |
69 if (!str||!xmlStrlen(str)) { | |
70 if (str) xmlFree(str); | |
71 valuePush(ctxt,xmlXPathNewNodeSet(NULL)); | |
72 return; | |
73 } | |
74 ret = xmlXPathEval(str,ctxt->context); | |
75 if (ret) | |
76 valuePush(ctxt,ret); | |
77 else { | |
78 xsltGenericError(xsltGenericErrorContext, | |
79 "dyn:evaluate() : unable to evaluate expression '%s'\n",
str); | |
80 valuePush(ctxt,xmlXPathNewNodeSet(NULL)); | |
81 } | |
82 xmlFree(str); | |
83 return; | |
84 } | |
85 | |
86 /** | |
87 * exsltDynMapFunction: | |
88 * @ctxt: an XPath parser context | |
89 * @nargs: the number of arguments | |
90 * | |
91 * Evaluates the string as an XPath expression and returns the result | |
92 * value, which may be a boolean, number, string, node set, result tree | |
93 * fragment or external object. | |
94 */ | |
95 | |
96 static void | |
97 exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) | |
98 { | |
99 xmlChar *str = NULL; | |
100 xmlNodeSetPtr nodeset = NULL; | |
101 xsltTransformContextPtr tctxt; | |
102 xmlXPathCompExprPtr comp = NULL; | |
103 xmlXPathObjectPtr ret = NULL; | |
104 xmlDocPtr oldDoc, container = NULL; | |
105 xmlNodePtr oldNode; | |
106 int oldContextSize; | |
107 int oldProximityPosition; | |
108 int i, j; | |
109 | |
110 | |
111 if (nargs != 2) { | |
112 xmlXPathSetArityError(ctxt); | |
113 return; | |
114 } | |
115 str = xmlXPathPopString(ctxt); | |
116 if (xmlXPathCheckError(ctxt)) { | |
117 xmlXPathSetTypeError(ctxt); | |
118 return; | |
119 } | |
120 | |
121 nodeset = xmlXPathPopNodeSet(ctxt); | |
122 if (xmlXPathCheckError(ctxt)) { | |
123 xmlXPathSetTypeError(ctxt); | |
124 return; | |
125 } | |
126 if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { | |
127 if (nodeset != NULL) | |
128 xmlXPathFreeNodeSet(nodeset); | |
129 if (str != NULL) | |
130 xmlFree(str); | |
131 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | |
132 return; | |
133 } | |
134 | |
135 ret = xmlXPathNewNodeSet(NULL); | |
136 if (ret == NULL) { | |
137 xsltGenericError(xsltGenericErrorContext, | |
138 "exsltDynMapFunction: ret == NULL\n"); | |
139 goto cleanup; | |
140 } | |
141 | |
142 oldDoc = ctxt->context->doc; | |
143 oldNode = ctxt->context->node; | |
144 oldContextSize = ctxt->context->contextSize; | |
145 oldProximityPosition = ctxt->context->proximityPosition; | |
146 | |
147 /** | |
148 * since we really don't know we're going to be adding node(s) | |
149 * down the road we create the RVT regardless | |
150 */ | |
151 tctxt = xsltXPathGetTransformContext(ctxt); | |
152 if (tctxt == NULL) { | |
153 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
154 "dyn:map : internal error tctxt == NULL\n"); | |
155 goto cleanup; | |
156 } | |
157 container = xsltCreateRVT(tctxt); | |
158 if (container == NULL) { | |
159 xsltTransformError(tctxt, NULL, NULL, | |
160 "dyn:map : internal error container == NULL\n"); | |
161 goto cleanup; | |
162 } | |
163 xsltRegisterLocalRVT(tctxt, container); | |
164 if (nodeset && nodeset->nodeNr > 0) { | |
165 xmlXPathNodeSetSort(nodeset); | |
166 ctxt->context->contextSize = nodeset->nodeNr; | |
167 ctxt->context->proximityPosition = 0; | |
168 for (i = 0; i < nodeset->nodeNr; i++) { | |
169 xmlXPathObjectPtr subResult = NULL; | |
170 xmlNodePtr cur = nodeset->nodeTab[i]; | |
171 | |
172 ctxt->context->proximityPosition++; | |
173 ctxt->context->node = cur; | |
174 | |
175 if (cur->type == XML_NAMESPACE_DECL) { | |
176 /* | |
177 * The XPath module sets the owner element of a ns-node on | |
178 * the ns->next field. | |
179 */ | |
180 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; | |
181 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { | |
182 xsltGenericError(xsltGenericErrorContext, | |
183 "Internal error in exsltDynMapFunction: " | |
184 "Cannot retrieve the doc of a namespace node.\n"); | |
185 continue; | |
186 } | |
187 ctxt->context->doc = cur->doc; | |
188 } else { | |
189 ctxt->context->doc = cur->doc; | |
190 } | |
191 | |
192 subResult = xmlXPathCompiledEval(comp, ctxt->context); | |
193 if (subResult != NULL) { | |
194 switch (subResult->type) { | |
195 case XPATH_NODESET: | |
196 if (subResult->nodesetval != NULL) | |
197 for (j = 0; j < subResult->nodesetval->nodeNr; | |
198 j++) | |
199 xmlXPathNodeSetAdd(ret->nodesetval, | |
200 subResult->nodesetval-> | |
201 nodeTab[j]); | |
202 break; | |
203 case XPATH_BOOLEAN: | |
204 if (container != NULL) { | |
205 xmlNodePtr cur = | |
206 xmlNewChild((xmlNodePtr) container, NULL, | |
207 BAD_CAST "boolean", | |
208 BAD_CAST (subResult-> | |
209 boolval ? "true" : "")); | |
210 if (cur != NULL) { | |
211 cur->ns = | |
212 xmlNewNs(cur, | |
213 BAD_CAST | |
214 "http://exslt.org/common", | |
215 BAD_CAST "exsl"); | |
216 xmlXPathNodeSetAddUnique(ret->nodesetval, | |
217 cur); | |
218 } | |
219 } | |
220 break; | |
221 case XPATH_NUMBER: | |
222 if (container != NULL) { | |
223 xmlChar *val = | |
224 xmlXPathCastNumberToString(subResult-> | |
225 floatval); | |
226 xmlNodePtr cur = | |
227 xmlNewChild((xmlNodePtr) container, NULL, | |
228 BAD_CAST "number", val); | |
229 if (val != NULL) | |
230 xmlFree(val); | |
231 | |
232 if (cur != NULL) { | |
233 cur->ns = | |
234 xmlNewNs(cur, | |
235 BAD_CAST | |
236 "http://exslt.org/common", | |
237 BAD_CAST "exsl"); | |
238 xmlXPathNodeSetAddUnique(ret->nodesetval, | |
239 cur); | |
240 } | |
241 } | |
242 break; | |
243 case XPATH_STRING: | |
244 if (container != NULL) { | |
245 xmlNodePtr cur = | |
246 xmlNewChild((xmlNodePtr) container, NULL, | |
247 BAD_CAST "string", | |
248 subResult->stringval); | |
249 if (cur != NULL) { | |
250 cur->ns = | |
251 xmlNewNs(cur, | |
252 BAD_CAST | |
253 "http://exslt.org/common", | |
254 BAD_CAST "exsl"); | |
255 xmlXPathNodeSetAddUnique(ret->nodesetval, | |
256 cur); | |
257 } | |
258 } | |
259 break; | |
260 default: | |
261 break; | |
262 } | |
263 xmlXPathFreeObject(subResult); | |
264 } | |
265 } | |
266 } | |
267 ctxt->context->doc = oldDoc; | |
268 ctxt->context->node = oldNode; | |
269 ctxt->context->contextSize = oldContextSize; | |
270 ctxt->context->proximityPosition = oldProximityPosition; | |
271 | |
272 | |
273 cleanup: | |
274 /* restore the xpath context */ | |
275 if (comp != NULL) | |
276 xmlXPathFreeCompExpr(comp); | |
277 if (nodeset != NULL) | |
278 xmlXPathFreeNodeSet(nodeset); | |
279 if (str != NULL) | |
280 xmlFree(str); | |
281 valuePush(ctxt, ret); | |
282 return; | |
283 } | |
284 | |
285 | |
286 /** | |
287 * exsltDynRegister: | |
288 * | |
289 * Registers the EXSLT - Dynamic module | |
290 */ | |
291 | |
292 void | |
293 exsltDynRegister (void) { | |
294 xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate", | |
295 EXSLT_DYNAMIC_NAMESPACE, | |
296 exsltDynEvaluateFunction); | |
297 xsltRegisterExtModuleFunction ((const xmlChar *) "map", | |
298 EXSLT_DYNAMIC_NAMESPACE, | |
299 exsltDynMapFunction); | |
300 | |
301 } | |
OLD | NEW |