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