| /* |
| * dynamic.c: Implementation of the EXSLT -- Dynamic module |
| * |
| * References: |
| * http://www.exslt.org/dyn/dyn.html |
| * |
| * See Copyright for the status of this software. |
| * |
| * Authors: |
| * Mark Vakoc <mark_vakoc@jdedwards.com> |
| * Thomas Broyer <tbroyer@ltgt.net> |
| * |
| * TODO: |
| * elements: |
| * functions: |
| * min |
| * max |
| * sum |
| * map |
| * closure |
| */ |
| |
| #define IN_LIBEXSLT |
| #include "libexslt/libexslt.h" |
| |
| #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) |
| #include <win32config.h> |
| #else |
| #include "config.h" |
| #endif |
| |
| #include <libxml/tree.h> |
| #include <libxml/xpath.h> |
| #include <libxml/xpathInternals.h> |
| |
| #include <libxslt/xsltconfig.h> |
| #include <libxslt/xsltutils.h> |
| #include <libxslt/xsltInternals.h> |
| #include <libxslt/extensions.h> |
| |
| #include "exslt.h" |
| |
| /** |
| * exsltDynEvaluateFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Evaluates the string as an XPath expression and returns the result |
| * value, which may be a boolean, number, string, node set, result tree |
| * fragment or external object. |
| */ |
| |
| static void |
| exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlChar *str = NULL; |
| xmlXPathObjectPtr ret = NULL; |
| |
| if (ctxt == NULL) |
| return; |
| if (nargs != 1) { |
| xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); |
| xsltGenericError(xsltGenericErrorContext, |
| "dyn:evalute() : invalid number of args %d\n", nargs); |
| ctxt->error = XPATH_INVALID_ARITY; |
| return; |
| } |
| str = xmlXPathPopString(ctxt); |
| /* return an empty node-set if an empty string is passed in */ |
| if (!str||!xmlStrlen(str)) { |
| if (str) xmlFree(str); |
| valuePush(ctxt,xmlXPathNewNodeSet(NULL)); |
| return; |
| } |
| ret = xmlXPathEval(str,ctxt->context); |
| if (ret) |
| valuePush(ctxt,ret); |
| else { |
| xsltGenericError(xsltGenericErrorContext, |
| "dyn:evaluate() : unable to evaluate expression '%s'\n",str); |
| valuePush(ctxt,xmlXPathNewNodeSet(NULL)); |
| } |
| xmlFree(str); |
| return; |
| } |
| |
| /** |
| * exsltDynMapFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * Evaluates the string as an XPath expression and returns the result |
| * value, which may be a boolean, number, string, node set, result tree |
| * fragment or external object. |
| */ |
| |
| static void |
| exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) |
| { |
| xmlChar *str = NULL; |
| xmlNodeSetPtr nodeset = NULL; |
| xsltTransformContextPtr tctxt; |
| xmlXPathCompExprPtr comp = NULL; |
| xmlXPathObjectPtr ret = NULL; |
| xmlDocPtr oldDoc, container = NULL; |
| xmlNodePtr oldNode; |
| int oldContextSize; |
| int oldProximityPosition; |
| int i, j; |
| |
| |
| if (nargs != 2) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| str = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt)) { |
| xmlXPathSetTypeError(ctxt); |
| return; |
| } |
| |
| nodeset = xmlXPathPopNodeSet(ctxt); |
| if (xmlXPathCheckError(ctxt)) { |
| xmlXPathSetTypeError(ctxt); |
| return; |
| } |
| if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { |
| if (nodeset != NULL) |
| xmlXPathFreeNodeSet(nodeset); |
| if (str != NULL) |
| xmlFree(str); |
| valuePush(ctxt, xmlXPathNewNodeSet(NULL)); |
| return; |
| } |
| |
| ret = xmlXPathNewNodeSet(NULL); |
| if (ret == NULL) { |
| xsltGenericError(xsltGenericErrorContext, |
| "exsltDynMapFunction: ret == NULL\n"); |
| goto cleanup; |
| } |
| |
| oldDoc = ctxt->context->doc; |
| oldNode = ctxt->context->node; |
| oldContextSize = ctxt->context->contextSize; |
| oldProximityPosition = ctxt->context->proximityPosition; |
| |
| /** |
| * since we really don't know we're going to be adding node(s) |
| * down the road we create the RVT regardless |
| */ |
| tctxt = xsltXPathGetTransformContext(ctxt); |
| if (tctxt == NULL) { |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
| "dyn:map : internal error tctxt == NULL\n"); |
| goto cleanup; |
| } |
| container = xsltCreateRVT(tctxt); |
| if (container == NULL) { |
| xsltTransformError(tctxt, NULL, NULL, |
| "dyn:map : internal error container == NULL\n"); |
| goto cleanup; |
| } |
| xsltRegisterLocalRVT(tctxt, container); |
| if (nodeset && nodeset->nodeNr > 0) { |
| xmlXPathNodeSetSort(nodeset); |
| ctxt->context->contextSize = nodeset->nodeNr; |
| ctxt->context->proximityPosition = 0; |
| for (i = 0; i < nodeset->nodeNr; i++) { |
| xmlXPathObjectPtr subResult = NULL; |
| |
| ctxt->context->proximityPosition++; |
| ctxt->context->node = nodeset->nodeTab[i]; |
| ctxt->context->doc = nodeset->nodeTab[i]->doc; |
| |
| subResult = xmlXPathCompiledEval(comp, ctxt->context); |
| if (subResult != NULL) { |
| switch (subResult->type) { |
| case XPATH_NODESET: |
| if (subResult->nodesetval != NULL) |
| for (j = 0; j < subResult->nodesetval->nodeNr; |
| j++) |
| xmlXPathNodeSetAdd(ret->nodesetval, |
| subResult->nodesetval-> |
| nodeTab[j]); |
| break; |
| case XPATH_BOOLEAN: |
| if (container != NULL) { |
| xmlNodePtr cur = |
| xmlNewChild((xmlNodePtr) container, NULL, |
| BAD_CAST "boolean", |
| BAD_CAST (subResult-> |
| boolval ? "true" : "")); |
| if (cur != NULL) { |
| cur->ns = |
| xmlNewNs(cur, |
| BAD_CAST |
| "http://exslt.org/common", |
| BAD_CAST "exsl"); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, |
| cur); |
| } |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| } |
| break; |
| case XPATH_NUMBER: |
| if (container != NULL) { |
| xmlChar *val = |
| xmlXPathCastNumberToString(subResult-> |
| floatval); |
| xmlNodePtr cur = |
| xmlNewChild((xmlNodePtr) container, NULL, |
| BAD_CAST "number", val); |
| if (val != NULL) |
| xmlFree(val); |
| |
| if (cur != NULL) { |
| cur->ns = |
| xmlNewNs(cur, |
| BAD_CAST |
| "http://exslt.org/common", |
| BAD_CAST "exsl"); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, |
| cur); |
| } |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| } |
| break; |
| case XPATH_STRING: |
| if (container != NULL) { |
| xmlNodePtr cur = |
| xmlNewChild((xmlNodePtr) container, NULL, |
| BAD_CAST "string", |
| subResult->stringval); |
| if (cur != NULL) { |
| cur->ns = |
| xmlNewNs(cur, |
| BAD_CAST |
| "http://exslt.org/common", |
| BAD_CAST "exsl"); |
| xmlXPathNodeSetAddUnique(ret->nodesetval, |
| cur); |
| } |
| xsltExtensionInstructionResultRegister(tctxt, ret); |
| } |
| break; |
| default: |
| break; |
| } |
| xmlXPathFreeObject(subResult); |
| } |
| } |
| } |
| ctxt->context->doc = oldDoc; |
| ctxt->context->node = oldNode; |
| ctxt->context->contextSize = oldContextSize; |
| ctxt->context->proximityPosition = oldProximityPosition; |
| |
| |
| cleanup: |
| /* restore the xpath context */ |
| if (comp != NULL) |
| xmlXPathFreeCompExpr(comp); |
| if (nodeset != NULL) |
| xmlXPathFreeNodeSet(nodeset); |
| if (str != NULL) |
| xmlFree(str); |
| valuePush(ctxt, ret); |
| return; |
| } |
| |
| |
| /** |
| * exsltDynRegister: |
| * |
| * Registers the EXSLT - Dynamic module |
| */ |
| |
| void |
| exsltDynRegister (void) { |
| xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate", |
| EXSLT_DYNAMIC_NAMESPACE, |
| exsltDynEvaluateFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "map", |
| EXSLT_DYNAMIC_NAMESPACE, |
| exsltDynMapFunction); |
| |
| } |