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
exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltDynMapFunction(xmlXPathParserContextPtr ctxt,int nargs)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
171 ctxt->context->proximityPosition++;
172 ctxt->context->node = nodeset->nodeTab[i];
173 ctxt->context->doc = nodeset->nodeTab[i]->doc;
174
175 subResult = xmlXPathCompiledEval(comp, ctxt->context);
176 if (subResult != NULL) {
177 switch (subResult->type) {
178 case XPATH_NODESET:
179 if (subResult->nodesetval != NULL)
180 for (j = 0; j < subResult->nodesetval->nodeNr;
181 j++)
182 xmlXPathNodeSetAdd(ret->nodesetval,
183 subResult->nodesetval->
184 nodeTab[j]);
185 break;
186 case XPATH_BOOLEAN:
187 if (container != NULL) {
188 xmlNodePtr cur =
189 xmlNewChild((xmlNodePtr) container, NULL,
190 BAD_CAST "boolean",
191 BAD_CAST (subResult->
192 boolval ? "true" : ""));
193 if (cur != NULL) {
194 cur->ns =
195 xmlNewNs(cur,
196 BAD_CAST
197 "http://exslt.org/common",
198 BAD_CAST "exsl");
199 xmlXPathNodeSetAddUnique(ret->nodesetval,
200 cur);
201 }
202 xsltExtensionInstructionResultRegister(tctxt, ret);
203 }
204 break;
205 case XPATH_NUMBER:
206 if (container != NULL) {
207 xmlChar *val =
208 xmlXPathCastNumberToString(subResult->
209 floatval);
210 xmlNodePtr cur =
211 xmlNewChild((xmlNodePtr) container, NULL,
212 BAD_CAST "number", val);
213 if (val != NULL)
214 xmlFree(val);
215
216 if (cur != NULL) {
217 cur->ns =
218 xmlNewNs(cur,
219 BAD_CAST
220 "http://exslt.org/common",
221 BAD_CAST "exsl");
222 xmlXPathNodeSetAddUnique(ret->nodesetval,
223 cur);
224 }
225 xsltExtensionInstructionResultRegister(tctxt, ret);
226 }
227 break;
228 case XPATH_STRING:
229 if (container != NULL) {
230 xmlNodePtr cur =
231 xmlNewChild((xmlNodePtr) container, NULL,
232 BAD_CAST "string",
233 subResult->stringval);
234 if (cur != NULL) {
235 cur->ns =
236 xmlNewNs(cur,
237 BAD_CAST
238 "http://exslt.org/common",
239 BAD_CAST "exsl");
240 xmlXPathNodeSetAddUnique(ret->nodesetval,
241 cur);
242 }
243 xsltExtensionInstructionResultRegister(tctxt, ret);
244 }
245 break;
246 default:
247 break;
248 }
249 xmlXPathFreeObject(subResult);
250 }
251 }
252 }
253 ctxt->context->doc = oldDoc;
254 ctxt->context->node = oldNode;
255 ctxt->context->contextSize = oldContextSize;
256 ctxt->context->proximityPosition = oldProximityPosition;
257
258
259 cleanup:
260 /* restore the xpath context */
261 if (comp != NULL)
262 xmlXPathFreeCompExpr(comp);
263 if (nodeset != NULL)
264 xmlXPathFreeNodeSet(nodeset);
265 if (str != NULL)
266 xmlFree(str);
267 valuePush(ctxt, ret);
268 return;
269 }
270
271
272 /**
273 * exsltDynRegister:
274 *
275 * Registers the EXSLT - Dynamic module
276 */
277
278 void
exsltDynRegister(void)279 exsltDynRegister (void) {
280 xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
281 EXSLT_DYNAMIC_NAMESPACE,
282 exsltDynEvaluateFunction);
283 xsltRegisterExtModuleFunction ((const xmlChar *) "map",
284 EXSLT_DYNAMIC_NAMESPACE,
285 exsltDynMapFunction);
286
287 }
288