| OLD | NEW |
| (Empty) |
| 1 #define IN_LIBEXSLT | |
| 2 #include "libexslt/libexslt.h" | |
| 3 | |
| 4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) | |
| 5 #include <win32config.h> | |
| 6 #else | |
| 7 #include "config.h" | |
| 8 #endif | |
| 9 | |
| 10 #include <string.h> | |
| 11 | |
| 12 #include <libxml/tree.h> | |
| 13 #include <libxml/xpath.h> | |
| 14 #include <libxml/xpathInternals.h> | |
| 15 #include <libxml/hash.h> | |
| 16 #include <libxml/debugXML.h> | |
| 17 | |
| 18 #include <libxslt/xsltutils.h> | |
| 19 #include <libxslt/variables.h> | |
| 20 #include <libxslt/xsltInternals.h> | |
| 21 #include <libxslt/extensions.h> | |
| 22 #include <libxslt/transform.h> | |
| 23 #include <libxslt/imports.h> | |
| 24 | |
| 25 #include "exslt.h" | |
| 26 | |
| 27 typedef struct _exsltFuncFunctionData exsltFuncFunctionData; | |
| 28 struct _exsltFuncFunctionData { | |
| 29 int nargs; /* number of arguments to the function */ | |
| 30 xmlNodePtr content; /* the func:fuction template content */ | |
| 31 }; | |
| 32 | |
| 33 typedef struct _exsltFuncData exsltFuncData; | |
| 34 struct _exsltFuncData { | |
| 35 xmlHashTablePtr funcs; /* pointer to the stylesheet module data */ | |
| 36 xmlXPathObjectPtr result; /* returned by func:result */ | |
| 37 int error; /* did an error occur? */ | |
| 38 }; | |
| 39 | |
| 40 typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; | |
| 41 struct _exsltFuncResultPreComp { | |
| 42 xsltElemPreComp comp; | |
| 43 xmlXPathCompExprPtr select; | |
| 44 xmlNsPtr *nsList; | |
| 45 int nsNr; | |
| 46 }; | |
| 47 | |
| 48 /* Used for callback function in exsltInitFunc */ | |
| 49 typedef struct _exsltFuncImportRegData exsltFuncImportRegData; | |
| 50 struct _exsltFuncImportRegData { | |
| 51 xsltTransformContextPtr ctxt; | |
| 52 xmlHashTablePtr hash; | |
| 53 }; | |
| 54 | |
| 55 static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, | |
| 56 int nargs); | |
| 57 static exsltFuncFunctionData *exsltFuncNewFunctionData(void); | |
| 58 | |
| 59 /*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/ | |
| 60 | |
| 61 /** | |
| 62 * exsltFuncRegisterFunc: | |
| 63 * @func: the #exsltFuncFunctionData for the function | |
| 64 * @ctxt: an XSLT transformation context | |
| 65 * @URI: the function namespace URI | |
| 66 * @name: the function name | |
| 67 * | |
| 68 * Registers a function declared by a func:function element | |
| 69 */ | |
| 70 static void | |
| 71 exsltFuncRegisterFunc (exsltFuncFunctionData *data, | |
| 72 xsltTransformContextPtr ctxt, | |
| 73 const xmlChar *URI, const xmlChar *name, | |
| 74 ATTRIBUTE_UNUSED const xmlChar *ignored) { | |
| 75 if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL)) | |
| 76 return; | |
| 77 | |
| 78 xsltGenericDebug(xsltGenericDebugContext, | |
| 79 "exsltFuncRegisterFunc: register {%s}%s\n", | |
| 80 URI, name); | |
| 81 xsltRegisterExtFunction(ctxt, name, URI, | |
| 82 exsltFuncFunctionFunction); | |
| 83 } | |
| 84 | |
| 85 /* | |
| 86 * exsltFuncRegisterImportFunc | |
| 87 * @data: the exsltFuncFunctionData for the function | |
| 88 * @ch: structure containing context and hash table | |
| 89 * @URI: the function namespace URI | |
| 90 * @name: the function name | |
| 91 * | |
| 92 * Checks if imported function is already registered in top-level | |
| 93 * stylesheet. If not, copies function data and registers function | |
| 94 */ | |
| 95 static void | |
| 96 exsltFuncRegisterImportFunc (exsltFuncFunctionData *data, | |
| 97 exsltFuncImportRegData *ch, | |
| 98 const xmlChar *URI, const xmlChar *name, | |
| 99 ATTRIBUTE_UNUSED const xmlChar *ignored) { | |
| 100 exsltFuncFunctionData *func=NULL; | |
| 101 | |
| 102 if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL)) | |
| 103 return; | |
| 104 | |
| 105 if (ch->ctxt == NULL || ch->hash == NULL) | |
| 106 return; | |
| 107 | |
| 108 /* Check if already present */ | |
| 109 func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name); | |
| 110 if (func == NULL) { /* Not yet present - copy it in */ | |
| 111 func = exsltFuncNewFunctionData(); | |
| 112 if (func == NULL) | |
| 113 return; | |
| 114 memcpy(func, data, sizeof(exsltFuncFunctionData)); | |
| 115 if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) { | |
| 116 xsltGenericError(xsltGenericErrorContext, | |
| 117 "Failed to register function {%s}%s\n", | |
| 118 URI, name); | |
| 119 } else { /* Do the registration */ | |
| 120 xsltGenericDebug(xsltGenericDebugContext, | |
| 121 "exsltFuncRegisterImportFunc: register {%s}%s\n", | |
| 122 URI, name); | |
| 123 xsltRegisterExtFunction(ch->ctxt, name, URI, | |
| 124 exsltFuncFunctionFunction); | |
| 125 } | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * exsltFuncInit: | |
| 131 * @ctxt: an XSLT transformation context | |
| 132 * @URI: the namespace URI for the extension | |
| 133 * | |
| 134 * Initializes the EXSLT - Functions module. | |
| 135 * Called at transformation-time; merges all | |
| 136 * functions declared in the import tree taking | |
| 137 * import precedence into account, i.e. overriding | |
| 138 * functions with lower import precedence. | |
| 139 * | |
| 140 * Returns the data for this transformation | |
| 141 */ | |
| 142 static exsltFuncData * | |
| 143 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { | |
| 144 exsltFuncData *ret; | |
| 145 xsltStylesheetPtr tmp; | |
| 146 exsltFuncImportRegData ch; | |
| 147 xmlHashTablePtr hash; | |
| 148 | |
| 149 ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData)); | |
| 150 if (ret == NULL) { | |
| 151 xsltGenericError(xsltGenericErrorContext, | |
| 152 "exsltFuncInit: not enough memory\n"); | |
| 153 return(NULL); | |
| 154 } | |
| 155 memset(ret, 0, sizeof(exsltFuncData)); | |
| 156 | |
| 157 ret->result = NULL; | |
| 158 ret->error = 0; | |
| 159 | |
| 160 ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI); | |
| 161 ret->funcs = ch.hash; | |
| 162 xmlHashScanFull(ch.hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt); | |
| 163 tmp = ctxt->style; | |
| 164 ch.ctxt = ctxt; | |
| 165 while ((tmp=xsltNextImport(tmp))!=NULL) { | |
| 166 hash = xsltGetExtInfo(tmp, URI); | |
| 167 if (hash != NULL) { | |
| 168 xmlHashScanFull(hash, | |
| 169 (xmlHashScannerFull) exsltFuncRegisterImportFunc, &ch); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 return(ret); | |
| 174 } | |
| 175 | |
| 176 /** | |
| 177 * exsltFuncShutdown: | |
| 178 * @ctxt: an XSLT transformation context | |
| 179 * @URI: the namespace URI for the extension | |
| 180 * @data: the module data to free up | |
| 181 * | |
| 182 * Shutdown the EXSLT - Functions module | |
| 183 * Called at transformation-time. | |
| 184 */ | |
| 185 static void | |
| 186 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, | |
| 187 const xmlChar *URI ATTRIBUTE_UNUSED, | |
| 188 exsltFuncData *data) { | |
| 189 if (data->result != NULL) | |
| 190 xmlXPathFreeObject(data->result); | |
| 191 xmlFree(data); | |
| 192 } | |
| 193 | |
| 194 /** | |
| 195 * exsltFuncStyleInit: | |
| 196 * @style: an XSLT stylesheet | |
| 197 * @URI: the namespace URI for the extension | |
| 198 * | |
| 199 * Allocates the stylesheet data for EXSLT - Function | |
| 200 * Called at compile-time. | |
| 201 * | |
| 202 * Returns the allocated data | |
| 203 */ | |
| 204 static xmlHashTablePtr | |
| 205 exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, | |
| 206 const xmlChar *URI ATTRIBUTE_UNUSED) { | |
| 207 return xmlHashCreate(1); | |
| 208 } | |
| 209 | |
| 210 /** | |
| 211 * exsltFuncStyleShutdown: | |
| 212 * @style: an XSLT stylesheet | |
| 213 * @URI: the namespace URI for the extension | |
| 214 * @data: the stylesheet data to free up | |
| 215 * | |
| 216 * Shutdown the EXSLT - Function module | |
| 217 * Called at compile-time. | |
| 218 */ | |
| 219 static void | |
| 220 exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, | |
| 221 const xmlChar *URI ATTRIBUTE_UNUSED, | |
| 222 xmlHashTablePtr data) { | |
| 223 xmlHashFree(data, (xmlHashDeallocator) xmlFree); | |
| 224 } | |
| 225 | |
| 226 /** | |
| 227 * exsltFuncNewFunctionData: | |
| 228 * | |
| 229 * Allocates an #exslFuncFunctionData object | |
| 230 * | |
| 231 * Returns the new structure | |
| 232 */ | |
| 233 static exsltFuncFunctionData * | |
| 234 exsltFuncNewFunctionData (void) { | |
| 235 exsltFuncFunctionData *ret; | |
| 236 | |
| 237 ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData)); | |
| 238 if (ret == NULL) { | |
| 239 xsltGenericError(xsltGenericErrorContext, | |
| 240 "exsltFuncNewFunctionData: not enough memory\n"); | |
| 241 return (NULL); | |
| 242 } | |
| 243 memset(ret, 0, sizeof(exsltFuncFunctionData)); | |
| 244 | |
| 245 ret->nargs = 0; | |
| 246 ret->content = NULL; | |
| 247 | |
| 248 return(ret); | |
| 249 } | |
| 250 | |
| 251 /** | |
| 252 * exsltFreeFuncResultPreComp: | |
| 253 * @comp: the #exsltFuncResultPreComp to free up | |
| 254 * | |
| 255 * Deallocates an #exsltFuncResultPreComp | |
| 256 */ | |
| 257 static void | |
| 258 exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) { | |
| 259 if (comp == NULL) | |
| 260 return; | |
| 261 | |
| 262 if (comp->select != NULL) | |
| 263 xmlXPathFreeCompExpr (comp->select); | |
| 264 if (comp->nsList != NULL) | |
| 265 xmlFree(comp->nsList); | |
| 266 xmlFree(comp); | |
| 267 } | |
| 268 | |
| 269 /** | |
| 270 * exsltFuncFunctionFunction: | |
| 271 * @ctxt: an XPath parser context | |
| 272 * @nargs: the number of arguments | |
| 273 * | |
| 274 * Evaluates the func:function element that defines the called function. | |
| 275 */ | |
| 276 static void | |
| 277 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
| 278 xmlXPathObjectPtr oldResult, ret; | |
| 279 exsltFuncData *data; | |
| 280 exsltFuncFunctionData *func; | |
| 281 xmlNodePtr paramNode, oldInsert, fake; | |
| 282 int oldBase; | |
| 283 xsltStackElemPtr params = NULL, param; | |
| 284 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); | |
| 285 int i, notSet; | |
| 286 struct objChain { | |
| 287 struct objChain *next; | |
| 288 xmlXPathObjectPtr obj; | |
| 289 }; | |
| 290 struct objChain *savedObjChain = NULL, *savedObj; | |
| 291 | |
| 292 /* | |
| 293 * retrieve func:function template | |
| 294 */ | |
| 295 data = (exsltFuncData *) xsltGetExtData (tctxt, | |
| 296 EXSLT_FUNCTIONS_NAMESPACE); | |
| 297 oldResult = data->result; | |
| 298 data->result = NULL; | |
| 299 | |
| 300 func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs, | |
| 301 ctxt->context->functionURI, | |
| 302 ctxt->context->function); | |
| 303 if (func == NULL) { | |
| 304 /* Should never happen */ | |
| 305 xsltGenericError(xsltGenericErrorContext, | |
| 306 "{%s}%s: not found\n", | |
| 307 ctxt->context->functionURI, ctxt->context->function); | |
| 308 ctxt->error = XPATH_UNKNOWN_FUNC_ERROR; | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 /* | |
| 313 * params handling | |
| 314 */ | |
| 315 if (nargs > func->nargs) { | |
| 316 xsltGenericError(xsltGenericErrorContext, | |
| 317 "{%s}%s: called with too many arguments\n", | |
| 318 ctxt->context->functionURI, ctxt->context->function); | |
| 319 ctxt->error = XPATH_INVALID_ARITY; | |
| 320 return; | |
| 321 } | |
| 322 if (func->content != NULL) { | |
| 323 paramNode = func->content->prev; | |
| 324 } | |
| 325 else | |
| 326 paramNode = NULL; | |
| 327 if ((paramNode == NULL) && (func->nargs != 0)) { | |
| 328 xsltGenericError(xsltGenericErrorContext, | |
| 329 "exsltFuncFunctionFunction: nargs != 0 and " | |
| 330 "param == NULL\n"); | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 /* | |
| 335 * When a function is called recursively during evaluation of its | |
| 336 * arguments, the recursion check in xsltApplySequenceConstructor | |
| 337 * isn't reached. | |
| 338 */ | |
| 339 if (tctxt->depth >= tctxt->maxTemplateDepth) { | |
| 340 xsltTransformError(tctxt, NULL, NULL, | |
| 341 "exsltFuncFunctionFunction: Potentially infinite recursion " | |
| 342 "detected in function {%s}%s.\n", | |
| 343 ctxt->context->functionURI, ctxt->context->function); | |
| 344 tctxt->state = XSLT_STATE_STOPPED; | |
| 345 return; | |
| 346 } | |
| 347 tctxt->depth++; | |
| 348 | |
| 349 /* | |
| 350 * We have a problem with the evaluation of function parameters. | |
| 351 * The original library code did not evaluate XPath expressions until | |
| 352 * the last moment. After version 1.1.17 of the libxslt, the logic | |
| 353 * of other parts of the library was changed, and the evaluation of | |
| 354 * XPath expressions within parameters now takes place as soon as the | |
| 355 * parameter is parsed/evaluated (xsltParseStylesheetCallerParam). | |
| 356 * This means that the parameters need to be evaluated in lexical | |
| 357 * order (since a variable is "in scope" as soon as it is declared). | |
| 358 * However, on entry to this routine, the values (from the caller) are | |
| 359 * in reverse order (held on the XPath context variable stack). To | |
| 360 * accomplish what is required, I have added code to pop the XPath | |
| 361 * objects off of the stack at the beginning and save them, then use | |
| 362 * them (in the reverse order) as the params are evaluated. This | |
| 363 * requires an xmlMalloc/xmlFree for each param set by the caller, | |
| 364 * which is not very nice. There is probably a much better solution | |
| 365 * (like change other code to delay the evaluation). | |
| 366 */ | |
| 367 /* | |
| 368 * In order to give the function params and variables a new 'scope' | |
| 369 * we change varsBase in the context. | |
| 370 */ | |
| 371 oldBase = tctxt->varsBase; | |
| 372 tctxt->varsBase = tctxt->varsNr; | |
| 373 /* If there are any parameters */ | |
| 374 if (paramNode != NULL) { | |
| 375 /* Fetch the stored argument values from the caller */ | |
| 376 for (i = 0; i < nargs; i++) { | |
| 377 savedObj = xmlMalloc(sizeof(struct objChain)); | |
| 378 savedObj->next = savedObjChain; | |
| 379 savedObj->obj = valuePop(ctxt); | |
| 380 savedObjChain = savedObj; | |
| 381 } | |
| 382 | |
| 383 /* | |
| 384 * Prepare to process params in reverse order. First, go to | |
| 385 * the beginning of the param chain. | |
| 386 */ | |
| 387 for (i = 1; i <= func->nargs; i++) { | |
| 388 if (paramNode->prev == NULL) | |
| 389 break; | |
| 390 paramNode = paramNode->prev; | |
| 391 } | |
| 392 /* | |
| 393 * i has total # params found, nargs is number which are present | |
| 394 * as arguments from the caller | |
| 395 * Calculate the number of un-set parameters | |
| 396 */ | |
| 397 notSet = func->nargs - nargs; | |
| 398 for (; i > 0; i--) { | |
| 399 param = xsltParseStylesheetCallerParam (tctxt, paramNode); | |
| 400 if (i > notSet) { /* if parameter value set */ | |
| 401 param->computed = 1; | |
| 402 if (param->value != NULL) | |
| 403 xmlXPathFreeObject(param->value); | |
| 404 savedObj = savedObjChain; /* get next val from chain */ | |
| 405 param->value = savedObj->obj; | |
| 406 savedObjChain = savedObjChain->next; | |
| 407 xmlFree(savedObj); | |
| 408 } | |
| 409 xsltLocalVariablePush(tctxt, param, -1); | |
| 410 param->next = params; | |
| 411 params = param; | |
| 412 paramNode = paramNode->next; | |
| 413 } | |
| 414 } | |
| 415 /* | |
| 416 * actual processing | |
| 417 */ | |
| 418 fake = xmlNewDocNode(tctxt->output, NULL, | |
| 419 (const xmlChar *)"fake", NULL); | |
| 420 oldInsert = tctxt->insert; | |
| 421 tctxt->insert = fake; | |
| 422 xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt), | |
| 423 func->content, NULL, NULL); | |
| 424 xsltLocalVariablePop(tctxt, tctxt->varsBase, -2); | |
| 425 tctxt->insert = oldInsert; | |
| 426 tctxt->varsBase = oldBase; /* restore original scope */ | |
| 427 if (params != NULL) | |
| 428 xsltFreeStackElemList(params); | |
| 429 | |
| 430 if (data->error != 0) | |
| 431 goto error; | |
| 432 | |
| 433 if (data->result != NULL) { | |
| 434 ret = data->result; | |
| 435 /* | |
| 436 * IMPORTANT: This enables previously tree fragments marked as | |
| 437 * being results of a function, to be garbage-collected after | |
| 438 * the calling process exits. | |
| 439 */ | |
| 440 xsltFlagRVTs(tctxt, ret, XSLT_RVT_LOCAL); | |
| 441 } else | |
| 442 ret = xmlXPathNewCString(""); | |
| 443 | |
| 444 data->result = oldResult; | |
| 445 | |
| 446 /* | |
| 447 * It is an error if the instantiation of the template results in | |
| 448 * the generation of result nodes. | |
| 449 */ | |
| 450 if (fake->children != NULL) { | |
| 451 #ifdef LIBXML_DEBUG_ENABLED | |
| 452 xmlDebugDumpNode (stderr, fake, 1); | |
| 453 #endif | |
| 454 xsltGenericError(xsltGenericErrorContext, | |
| 455 "{%s}%s: cannot write to result tree while " | |
| 456 "executing a function\n", | |
| 457 ctxt->context->functionURI, ctxt->context->function); | |
| 458 xmlFreeNode(fake); | |
| 459 goto error; | |
| 460 } | |
| 461 xmlFreeNode(fake); | |
| 462 valuePush(ctxt, ret); | |
| 463 | |
| 464 error: | |
| 465 tctxt->depth--; | |
| 466 } | |
| 467 | |
| 468 | |
| 469 static void | |
| 470 exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { | |
| 471 xmlChar *name, *prefix; | |
| 472 xmlNsPtr ns; | |
| 473 xmlHashTablePtr data; | |
| 474 exsltFuncFunctionData *func; | |
| 475 | |
| 476 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) | |
| 477 return; | |
| 478 | |
| 479 { | |
| 480 xmlChar *qname; | |
| 481 | |
| 482 qname = xmlGetProp(inst, (const xmlChar *) "name"); | |
| 483 name = xmlSplitQName2 (qname, &prefix); | |
| 484 xmlFree(qname); | |
| 485 } | |
| 486 if ((name == NULL) || (prefix == NULL)) { | |
| 487 xsltGenericError(xsltGenericErrorContext, | |
| 488 "func:function: not a QName\n"); | |
| 489 if (name != NULL) | |
| 490 xmlFree(name); | |
| 491 return; | |
| 492 } | |
| 493 /* namespace lookup */ | |
| 494 ns = xmlSearchNs (inst->doc, inst, prefix); | |
| 495 if (ns == NULL) { | |
| 496 xsltGenericError(xsltGenericErrorContext, | |
| 497 "func:function: undeclared prefix %s\n", | |
| 498 prefix); | |
| 499 xmlFree(name); | |
| 500 xmlFree(prefix); | |
| 501 return; | |
| 502 } | |
| 503 xmlFree(prefix); | |
| 504 | |
| 505 xsltParseTemplateContent(style, inst); | |
| 506 | |
| 507 /* | |
| 508 * Create function data | |
| 509 */ | |
| 510 func = exsltFuncNewFunctionData(); | |
| 511 if (func == NULL) { | |
| 512 xmlFree(name); | |
| 513 return; | |
| 514 } | |
| 515 func->content = inst->children; | |
| 516 while (IS_XSLT_ELEM(func->content) && | |
| 517 IS_XSLT_NAME(func->content, "param")) { | |
| 518 func->content = func->content->next; | |
| 519 func->nargs++; | |
| 520 } | |
| 521 | |
| 522 /* | |
| 523 * Register the function data such that it can be retrieved | |
| 524 * by exslFuncFunctionFunction | |
| 525 */ | |
| 526 #ifdef XSLT_REFACTORED | |
| 527 /* | |
| 528 * Ensure that the hash table will be stored in the *current* | |
| 529 * stylesheet level in order to correctly evaluate the | |
| 530 * import precedence. | |
| 531 */ | |
| 532 data = (xmlHashTablePtr) | |
| 533 xsltStyleStylesheetLevelGetExtData(style, | |
| 534 EXSLT_FUNCTIONS_NAMESPACE); | |
| 535 #else | |
| 536 data = (xmlHashTablePtr) | |
| 537 xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); | |
| 538 #endif | |
| 539 if (data == NULL) { | |
| 540 xsltGenericError(xsltGenericErrorContext, | |
| 541 "exsltFuncFunctionComp: no stylesheet data\n"); | |
| 542 xmlFree(name); | |
| 543 return; | |
| 544 } | |
| 545 | |
| 546 if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { | |
| 547 xsltTransformError(NULL, style, inst, | |
| 548 "Failed to register function {%s}%s\n", | |
| 549 ns->href, name); | |
| 550 style->errors++; | |
| 551 } else { | |
| 552 xsltGenericDebug(xsltGenericDebugContext, | |
| 553 "exsltFuncFunctionComp: register {%s}%s\n", | |
| 554 ns->href, name); | |
| 555 } | |
| 556 xmlFree(name); | |
| 557 } | |
| 558 | |
| 559 static xsltElemPreCompPtr | |
| 560 exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, | |
| 561 xsltTransformFunction function) { | |
| 562 xmlNodePtr test; | |
| 563 xmlChar *sel; | |
| 564 exsltFuncResultPreComp *ret; | |
| 565 | |
| 566 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) | |
| 567 return (NULL); | |
| 568 | |
| 569 /* | |
| 570 * "Validity" checking | |
| 571 */ | |
| 572 /* it is an error to have any following sibling elements aside | |
| 573 * from the xsl:fallback element. | |
| 574 */ | |
| 575 for (test = inst->next; test != NULL; test = test->next) { | |
| 576 if (test->type != XML_ELEMENT_NODE) | |
| 577 continue; | |
| 578 if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback")) | |
| 579 continue; | |
| 580 xsltGenericError(xsltGenericErrorContext, | |
| 581 "exsltFuncResultElem: only xsl:fallback is " | |
| 582 "allowed to follow func:result\n"); | |
| 583 style->errors++; | |
| 584 return (NULL); | |
| 585 } | |
| 586 /* it is an error for a func:result element to not be a descendant | |
| 587 * of func:function. | |
| 588 * it is an error if a func:result occurs within a func:result | |
| 589 * element. | |
| 590 * it is an error if instanciating the content of a variable | |
| 591 * binding element (i.e. xsl:variable, xsl:param) results in the | |
| 592 * instanciation of a func:result element. | |
| 593 */ | |
| 594 for (test = inst->parent; test != NULL; test = test->parent) { | |
| 595 if (IS_XSLT_ELEM(test) && | |
| 596 IS_XSLT_NAME(test, "stylesheet")) { | |
| 597 xsltGenericError(xsltGenericErrorContext, | |
| 598 "func:result element not a descendant " | |
| 599 "of a func:function\n"); | |
| 600 style->errors++; | |
| 601 return (NULL); | |
| 602 } | |
| 603 if ((test->ns != NULL) && | |
| 604 (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) { | |
| 605 if (xmlStrEqual(test->name, (const xmlChar *) "function")) { | |
| 606 break; | |
| 607 } | |
| 608 if (xmlStrEqual(test->name, (const xmlChar *) "result")) { | |
| 609 xsltGenericError(xsltGenericErrorContext, | |
| 610 "func:result element not allowed within" | |
| 611 " another func:result element\n"); | |
| 612 style->errors++; | |
| 613 return (NULL); | |
| 614 } | |
| 615 } | |
| 616 if (IS_XSLT_ELEM(test) && | |
| 617 (IS_XSLT_NAME(test, "variable") || | |
| 618 IS_XSLT_NAME(test, "param"))) { | |
| 619 xsltGenericError(xsltGenericErrorContext, | |
| 620 "func:result element not allowed within" | |
| 621 " a variable binding element\n"); | |
| 622 style->errors++; | |
| 623 return (NULL); | |
| 624 } | |
| 625 } | |
| 626 | |
| 627 /* | |
| 628 * Precomputation | |
| 629 */ | |
| 630 ret = (exsltFuncResultPreComp *) | |
| 631 xmlMalloc (sizeof(exsltFuncResultPreComp)); | |
| 632 if (ret == NULL) { | |
| 633 xsltPrintErrorContext(NULL, NULL, NULL); | |
| 634 xsltGenericError(xsltGenericErrorContext, | |
| 635 "exsltFuncResultComp : malloc failed\n"); | |
| 636 style->errors++; | |
| 637 return (NULL); | |
| 638 } | |
| 639 memset(ret, 0, sizeof(exsltFuncResultPreComp)); | |
| 640 | |
| 641 xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, | |
| 642 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp); | |
| 643 ret->select = NULL; | |
| 644 | |
| 645 /* | |
| 646 * Precompute the select attribute | |
| 647 */ | |
| 648 sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); | |
| 649 if (sel != NULL) { | |
| 650 ret->select = xmlXPathCompile (sel); | |
| 651 xmlFree(sel); | |
| 652 } | |
| 653 /* | |
| 654 * Precompute the namespace list | |
| 655 */ | |
| 656 ret->nsList = xmlGetNsList(inst->doc, inst); | |
| 657 if (ret->nsList != NULL) { | |
| 658 int i = 0; | |
| 659 while (ret->nsList[i] != NULL) | |
| 660 i++; | |
| 661 ret->nsNr = i; | |
| 662 } | |
| 663 return ((xsltElemPreCompPtr) ret); | |
| 664 } | |
| 665 | |
| 666 static void | |
| 667 exsltFuncResultElem (xsltTransformContextPtr ctxt, | |
| 668 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, | |
| 669 exsltFuncResultPreComp *comp) { | |
| 670 exsltFuncData *data; | |
| 671 xmlXPathObjectPtr ret; | |
| 672 | |
| 673 | |
| 674 /* It is an error if instantiating the content of the | |
| 675 * func:function element results in the instantiation of more than | |
| 676 * one func:result elements. | |
| 677 */ | |
| 678 data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); | |
| 679 if (data == NULL) { | |
| 680 xsltGenericError(xsltGenericErrorContext, | |
| 681 "exsltFuncReturnElem: data == NULL\n"); | |
| 682 return; | |
| 683 } | |
| 684 if (data->result != NULL) { | |
| 685 xsltGenericError(xsltGenericErrorContext, | |
| 686 "func:result already instanciated\n"); | |
| 687 data->error = 1; | |
| 688 return; | |
| 689 } | |
| 690 /* | |
| 691 * Processing | |
| 692 */ | |
| 693 if (comp->select != NULL) { | |
| 694 xmlNsPtr *oldXPNsList; | |
| 695 int oldXPNsNr; | |
| 696 xmlNodePtr oldXPContextNode; | |
| 697 /* If the func:result element has a select attribute, then the | |
| 698 * value of the attribute must be an expression and the | |
| 699 * returned value is the object that results from evaluating | |
| 700 * the expression. In this case, the content must be empty. | |
| 701 */ | |
| 702 if (inst->children != NULL) { | |
| 703 xsltGenericError(xsltGenericErrorContext, | |
| 704 "func:result content must be empty if" | |
| 705 " the function has a select attribute\n"); | |
| 706 data->error = 1; | |
| 707 return; | |
| 708 } | |
| 709 oldXPNsList = ctxt->xpathCtxt->namespaces; | |
| 710 oldXPNsNr = ctxt->xpathCtxt->nsNr; | |
| 711 oldXPContextNode = ctxt->xpathCtxt->node; | |
| 712 | |
| 713 ctxt->xpathCtxt->namespaces = comp->nsList; | |
| 714 ctxt->xpathCtxt->nsNr = comp->nsNr; | |
| 715 | |
| 716 ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); | |
| 717 | |
| 718 ctxt->xpathCtxt->node = oldXPContextNode; | |
| 719 ctxt->xpathCtxt->nsNr = oldXPNsNr; | |
| 720 ctxt->xpathCtxt->namespaces = oldXPNsList; | |
| 721 | |
| 722 if (ret == NULL) { | |
| 723 xsltGenericError(xsltGenericErrorContext, | |
| 724 "exsltFuncResultElem: ret == NULL\n"); | |
| 725 return; | |
| 726 } | |
| 727 /* | |
| 728 * Mark it as a function result in order to avoid garbage | |
| 729 * collecting of tree fragments before the function exits. | |
| 730 */ | |
| 731 xsltFlagRVTs(ctxt, ret, XSLT_RVT_FUNC_RESULT); | |
| 732 } else if (inst->children != NULL) { | |
| 733 /* If the func:result element does not have a select attribute | |
| 734 * and has non-empty content (i.e. the func:result element has | |
| 735 * one or more child nodes), then the content of the | |
| 736 * func:result element specifies the value. | |
| 737 */ | |
| 738 xmlNodePtr oldInsert; | |
| 739 xmlDocPtr container; | |
| 740 | |
| 741 container = xsltCreateRVT(ctxt); | |
| 742 if (container == NULL) { | |
| 743 xsltGenericError(xsltGenericErrorContext, | |
| 744 "exsltFuncResultElem: out of memory\n"); | |
| 745 data->error = 1; | |
| 746 return; | |
| 747 } | |
| 748 /* Mark as function result. */ | |
| 749 container->psvi = XSLT_RVT_FUNC_RESULT; | |
| 750 | |
| 751 oldInsert = ctxt->insert; | |
| 752 ctxt->insert = (xmlNodePtr) container; | |
| 753 xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node, | |
| 754 inst->children, NULL, NULL); | |
| 755 ctxt->insert = oldInsert; | |
| 756 | |
| 757 ret = xmlXPathNewValueTree((xmlNodePtr) container); | |
| 758 if (ret == NULL) { | |
| 759 xsltGenericError(xsltGenericErrorContext, | |
| 760 "exsltFuncResultElem: ret == NULL\n"); | |
| 761 data->error = 1; | |
| 762 } else { | |
| 763 ret->boolval = 0; /* Freeing is not handled there anymore */ | |
| 764 } | |
| 765 } else { | |
| 766 /* If the func:result element has empty content and does not | |
| 767 * have a select attribute, then the returned value is an | |
| 768 * empty string. | |
| 769 */ | |
| 770 ret = xmlXPathNewCString(""); | |
| 771 } | |
| 772 data->result = ret; | |
| 773 } | |
| 774 | |
| 775 /** | |
| 776 * exsltFuncRegister: | |
| 777 * | |
| 778 * Registers the EXSLT - Functions module | |
| 779 */ | |
| 780 void | |
| 781 exsltFuncRegister (void) { | |
| 782 xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, | |
| 783 (xsltExtInitFunction) exsltFuncInit, | |
| 784 (xsltExtShutdownFunction) exsltFuncShutdown, | |
| 785 (xsltStyleExtInitFunction) exsltFuncStyleInit, | |
| 786 (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown); | |
| 787 | |
| 788 xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", | |
| 789 EXSLT_FUNCTIONS_NAMESPACE, | |
| 790 exsltFuncFunctionComp); | |
| 791 xsltRegisterExtModuleElement ((const xmlChar *) "result", | |
| 792 EXSLT_FUNCTIONS_NAMESPACE, | |
| 793 (xsltPreComputeFunction)exsltFuncResultComp, | |
| 794 (xsltTransformFunction) exsltFuncResultElem); | |
| 795 } | |
| OLD | NEW |