Imported Upstream version 1.1.30_rc1
[platform/upstream/libxslt.git] / libexslt / dynamic.c
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         goto cleanup;
118
119     nodeset = xmlXPathPopNodeSet(ctxt);
120     if (xmlXPathCheckError(ctxt))
121         goto cleanup;
122
123     ret = xmlXPathNewNodeSet(NULL);
124     if (ret == NULL) {
125         xsltGenericError(xsltGenericErrorContext,
126                          "exsltDynMapFunction: ret == NULL\n");
127         goto cleanup;
128     }
129
130     if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str)))
131         goto cleanup;
132
133     oldDoc = ctxt->context->doc;
134     oldNode = ctxt->context->node;
135     oldContextSize = ctxt->context->contextSize;
136     oldProximityPosition = ctxt->context->proximityPosition;
137
138         /**
139          * since we really don't know we're going to be adding node(s)
140          * down the road we create the RVT regardless
141          */
142     tctxt = xsltXPathGetTransformContext(ctxt);
143     if (tctxt == NULL) {
144         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
145               "dyn:map : internal error tctxt == NULL\n");
146         goto cleanup;
147     }
148     container = xsltCreateRVT(tctxt);
149     if (container == NULL) {
150         xsltTransformError(tctxt, NULL, NULL,
151               "dyn:map : internal error container == NULL\n");
152         goto cleanup;
153     }
154     xsltRegisterLocalRVT(tctxt, container);
155     if (nodeset && nodeset->nodeNr > 0) {
156         xmlXPathNodeSetSort(nodeset);
157         ctxt->context->contextSize = nodeset->nodeNr;
158         ctxt->context->proximityPosition = 0;
159         for (i = 0; i < nodeset->nodeNr; i++) {
160             xmlXPathObjectPtr subResult = NULL;
161             xmlNodePtr cur = nodeset->nodeTab[i];
162
163             ctxt->context->proximityPosition++;
164             ctxt->context->node = cur;
165
166             if (cur->type == XML_NAMESPACE_DECL) {
167                 /*
168                 * The XPath module sets the owner element of a ns-node on
169                 * the ns->next field.
170                 */
171                 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
172                 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
173                     xsltGenericError(xsltGenericErrorContext,
174                         "Internal error in exsltDynMapFunction: "
175                         "Cannot retrieve the doc of a namespace node.\n");
176                     continue;
177                 }
178                 ctxt->context->doc = cur->doc;
179             } else {
180                 ctxt->context->doc = cur->doc;
181             }
182
183             subResult = xmlXPathCompiledEval(comp, ctxt->context);
184             if (subResult != NULL) {
185                 switch (subResult->type) {
186                     case XPATH_NODESET:
187                         if (subResult->nodesetval != NULL)
188                             for (j = 0; j < subResult->nodesetval->nodeNr;
189                                  j++)
190                                 xmlXPathNodeSetAdd(ret->nodesetval,
191                                                    subResult->nodesetval->
192                                                    nodeTab[j]);
193                         break;
194                     case XPATH_BOOLEAN:
195                         if (container != NULL) {
196                             xmlNodePtr cur =
197                                 xmlNewChild((xmlNodePtr) container, NULL,
198                                             BAD_CAST "boolean",
199                                             BAD_CAST (subResult->
200                                             boolval ? "true" : ""));
201                             if (cur != NULL) {
202                                 cur->ns =
203                                     xmlNewNs(cur,
204                                              BAD_CAST
205                                              "http://exslt.org/common",
206                                              BAD_CAST "exsl");
207                                 xmlXPathNodeSetAddUnique(ret->nodesetval,
208                                                          cur);
209                             }
210                         }
211                         break;
212                     case XPATH_NUMBER:
213                         if (container != NULL) {
214                             xmlChar *val =
215                                 xmlXPathCastNumberToString(subResult->
216                                                            floatval);
217                             xmlNodePtr cur =
218                                 xmlNewChild((xmlNodePtr) container, NULL,
219                                             BAD_CAST "number", val);
220                             if (val != NULL)
221                                 xmlFree(val);
222
223                             if (cur != NULL) {
224                                 cur->ns =
225                                     xmlNewNs(cur,
226                                              BAD_CAST
227                                              "http://exslt.org/common",
228                                              BAD_CAST "exsl");
229                                 xmlXPathNodeSetAddUnique(ret->nodesetval,
230                                                          cur);
231                             }
232                         }
233                         break;
234                     case XPATH_STRING:
235                         if (container != NULL) {
236                             xmlNodePtr cur =
237                                 xmlNewChild((xmlNodePtr) container, NULL,
238                                             BAD_CAST "string",
239                                             subResult->stringval);
240                             if (cur != NULL) {
241                                 cur->ns =
242                                     xmlNewNs(cur,
243                                              BAD_CAST
244                                              "http://exslt.org/common",
245                                              BAD_CAST "exsl");
246                                 xmlXPathNodeSetAddUnique(ret->nodesetval,
247                                                          cur);
248                             }
249                         }
250                         break;
251                     default:
252                         break;
253                 }
254                 xmlXPathFreeObject(subResult);
255             }
256         }
257     }
258     ctxt->context->doc = oldDoc;
259     ctxt->context->node = oldNode;
260     ctxt->context->contextSize = oldContextSize;
261     ctxt->context->proximityPosition = oldProximityPosition;
262
263
264   cleanup:
265     /* restore the xpath context */
266     if (comp != NULL)
267         xmlXPathFreeCompExpr(comp);
268     if (nodeset != NULL)
269         xmlXPathFreeNodeSet(nodeset);
270     if (str != NULL)
271         xmlFree(str);
272     valuePush(ctxt, ret);
273     return;
274 }
275
276
277 /**
278  * exsltDynRegister:
279  *
280  * Registers the EXSLT - Dynamic module
281  */
282
283 void
284 exsltDynRegister (void) {
285     xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
286                                    EXSLT_DYNAMIC_NAMESPACE,
287                                    exsltDynEvaluateFunction);
288   xsltRegisterExtModuleFunction ((const xmlChar *) "map",
289                                    EXSLT_DYNAMIC_NAMESPACE,
290                                    exsltDynMapFunction);
291
292 }