• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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