| 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 |