Home | History | Annotate | Download | only in libexslt
      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