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 (at) jdedwards.com> 11 * Thomas Broyer <tbroyer (at) 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 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 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