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 27typedef struct _exsltFuncFunctionData exsltFuncFunctionData; 28struct _exsltFuncFunctionData { 29 int nargs; /* number of arguments to the function */ 30 xmlNodePtr content; /* the func:fuction template content */ 31}; 32 33typedef struct _exsltFuncData exsltFuncData; 34struct _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 41typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; 42struct _exsltFuncResultPreComp { 43 xsltElemPreComp comp; 44 xmlXPathCompExprPtr select; 45 xmlNsPtr *nsList; 46 int nsNr; 47}; 48 49/* Used for callback function in exsltInitFunc */ 50typedef struct _exsltFuncImportRegData exsltFuncImportRegData; 51struct _exsltFuncImportRegData { 52 xsltTransformContextPtr ctxt; 53 xmlHashTablePtr hash; 54}; 55 56static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, 57 int nargs); 58static 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 */ 73static void 74exsltFuncRegisterFunc (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 */ 98static void 99exsltFuncRegisterImportFunc (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 */ 143static exsltFuncData * 144exsltFuncInit (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 */ 186static void 187exsltFuncShutdown (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 */ 205static xmlHashTablePtr 206exsltFuncStyleInit (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 */ 220static void 221exsltFuncStyleShutdown (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 */ 234static exsltFuncFunctionData * 235exsltFuncNewFunctionData (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 */ 258static void 259exsltFreeFuncResultPreComp (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 */ 277static void 278exsltFuncFunctionFunction (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 444error: 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 455static void 456exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { 457 xmlChar *name, *prefix; 458 xmlNsPtr ns; 459 xmlHashTablePtr data; 460 exsltFuncFunctionData *func; 461 462 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 463 return; 464 465 { 466 xmlChar *qname; 467 468 qname = xmlGetProp(inst, (const xmlChar *) "name"); 469 name = xmlSplitQName2 (qname, &prefix); 470 xmlFree(qname); 471 } 472 if ((name == NULL) || (prefix == NULL)) { 473 xsltGenericError(xsltGenericErrorContext, 474 "func:function: not a QName\n"); 475 if (name != NULL) 476 xmlFree(name); 477 return; 478 } 479 /* namespace lookup */ 480 ns = xmlSearchNs (inst->doc, inst, prefix); 481 if (ns == NULL) { 482 xsltGenericError(xsltGenericErrorContext, 483 "func:function: undeclared prefix %s\n", 484 prefix); 485 xmlFree(name); 486 xmlFree(prefix); 487 return; 488 } 489 xmlFree(prefix); 490 491 xsltParseTemplateContent(style, inst); 492 493 /* 494 * Create function data 495 */ 496 func = exsltFuncNewFunctionData(); 497 func->content = inst->children; 498 while (IS_XSLT_ELEM(func->content) && 499 IS_XSLT_NAME(func->content, "param")) { 500 func->content = func->content->next; 501 func->nargs++; 502 } 503 504 /* 505 * Register the function data such that it can be retrieved 506 * by exslFuncFunctionFunction 507 */ 508#ifdef XSLT_REFACTORED 509 /* 510 * Ensure that the hash table will be stored in the *current* 511 * stylesheet level in order to correctly evaluate the 512 * import precedence. 513 */ 514 data = (xmlHashTablePtr) 515 xsltStyleStylesheetLevelGetExtData(style, 516 EXSLT_FUNCTIONS_NAMESPACE); 517#else 518 data = (xmlHashTablePtr) 519 xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); 520#endif 521 if (data == NULL) { 522 xsltGenericError(xsltGenericErrorContext, 523 "exsltFuncFunctionComp: no stylesheet data\n"); 524 xmlFree(name); 525 return; 526 } 527 528 if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { 529 xsltTransformError(NULL, style, inst, 530 "Failed to register function {%s}%s\n", 531 ns->href, name); 532 style->errors++; 533 } else { 534 xsltGenericDebug(xsltGenericDebugContext, 535 "exsltFuncFunctionComp: register {%s}%s\n", 536 ns->href, name); 537 } 538 xmlFree(name); 539} 540 541static xsltElemPreCompPtr 542exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, 543 xsltTransformFunction function) { 544 xmlNodePtr test; 545 xmlChar *sel; 546 exsltFuncResultPreComp *ret; 547 548 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 549 return (NULL); 550 551 /* 552 * "Validity" checking 553 */ 554 /* it is an error to have any following sibling elements aside 555 * from the xsl:fallback element. 556 */ 557 for (test = inst->next; test != NULL; test = test->next) { 558 if (test->type != XML_ELEMENT_NODE) 559 continue; 560 if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback")) 561 continue; 562 xsltGenericError(xsltGenericErrorContext, 563 "exsltFuncResultElem: only xsl:fallback is " 564 "allowed to follow func:result\n"); 565 style->errors++; 566 return (NULL); 567 } 568 /* it is an error for a func:result element to not be a descendant 569 * of func:function. 570 * it is an error if a func:result occurs within a func:result 571 * element. 572 * it is an error if instanciating the content of a variable 573 * binding element (i.e. xsl:variable, xsl:param) results in the 574 * instanciation of a func:result element. 575 */ 576 for (test = inst->parent; test != NULL; test = test->parent) { 577 if (IS_XSLT_ELEM(test) && 578 IS_XSLT_NAME(test, "stylesheet")) { 579 xsltGenericError(xsltGenericErrorContext, 580 "func:result element not a descendant " 581 "of a func:function\n"); 582 style->errors++; 583 return (NULL); 584 } 585 if ((test->ns != NULL) && 586 (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) { 587 if (xmlStrEqual(test->name, (const xmlChar *) "function")) { 588 break; 589 } 590 if (xmlStrEqual(test->name, (const xmlChar *) "result")) { 591 xsltGenericError(xsltGenericErrorContext, 592 "func:result element not allowed within" 593 " another func:result element\n"); 594 style->errors++; 595 return (NULL); 596 } 597 } 598 if (IS_XSLT_ELEM(test) && 599 (IS_XSLT_NAME(test, "variable") || 600 IS_XSLT_NAME(test, "param"))) { 601 xsltGenericError(xsltGenericErrorContext, 602 "func:result element not allowed within" 603 " a variable binding element\n"); 604 style->errors++; 605 return (NULL); 606 } 607 } 608 609 /* 610 * Precomputation 611 */ 612 ret = (exsltFuncResultPreComp *) 613 xmlMalloc (sizeof(exsltFuncResultPreComp)); 614 if (ret == NULL) { 615 xsltPrintErrorContext(NULL, NULL, NULL); 616 xsltGenericError(xsltGenericErrorContext, 617 "exsltFuncResultComp : malloc failed\n"); 618 style->errors++; 619 return (NULL); 620 } 621 memset(ret, 0, sizeof(exsltFuncResultPreComp)); 622 623 xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, 624 (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp); 625 ret->select = NULL; 626 627 /* 628 * Precompute the select attribute 629 */ 630 sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); 631 if (sel != NULL) { 632 ret->select = xmlXPathCompile (sel); 633 xmlFree(sel); 634 } 635 /* 636 * Precompute the namespace list 637 */ 638 ret->nsList = xmlGetNsList(inst->doc, inst); 639 if (ret->nsList != NULL) { 640 int i = 0; 641 while (ret->nsList[i] != NULL) 642 i++; 643 ret->nsNr = i; 644 } 645 return ((xsltElemPreCompPtr) ret); 646} 647 648static void 649exsltFuncResultElem (xsltTransformContextPtr ctxt, 650 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, 651 exsltFuncResultPreComp *comp) { 652 exsltFuncData *data; 653 xmlXPathObjectPtr ret; 654 655 656 /* It is an error if instantiating the content of the 657 * func:function element results in the instantiation of more than 658 * one func:result elements. 659 */ 660 data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); 661 if (data == NULL) { 662 xsltGenericError(xsltGenericErrorContext, 663 "exsltFuncReturnElem: data == NULL\n"); 664 return; 665 } 666 if (data->result != NULL) { 667 xsltGenericError(xsltGenericErrorContext, 668 "func:result already instanciated\n"); 669 data->error = 1; 670 return; 671 } 672 /* 673 * Processing 674 */ 675 if (comp->select != NULL) { 676 xmlNsPtr *oldXPNsList; 677 int oldXPNsNr; 678 xmlNodePtr oldXPContextNode; 679 /* If the func:result element has a select attribute, then the 680 * value of the attribute must be an expression and the 681 * returned value is the object that results from evaluating 682 * the expression. In this case, the content must be empty. 683 */ 684 if (inst->children != NULL) { 685 xsltGenericError(xsltGenericErrorContext, 686 "func:result content must be empty if" 687 " the function has a select attribute\n"); 688 data->error = 1; 689 return; 690 } 691 oldXPNsList = ctxt->xpathCtxt->namespaces; 692 oldXPNsNr = ctxt->xpathCtxt->nsNr; 693 oldXPContextNode = ctxt->xpathCtxt->node; 694 695 ctxt->xpathCtxt->namespaces = comp->nsList; 696 ctxt->xpathCtxt->nsNr = comp->nsNr; 697 698 ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); 699 700 ctxt->xpathCtxt->node = oldXPContextNode; 701 ctxt->xpathCtxt->nsNr = oldXPNsNr; 702 ctxt->xpathCtxt->namespaces = oldXPNsList; 703 704 if (ret == NULL) { 705 xsltGenericError(xsltGenericErrorContext, 706 "exsltFuncResultElem: ret == NULL\n"); 707 return; 708 } 709 /* 710 * Mark it as a function result in order to avoid garbage 711 * collecting of tree fragments before the function exits. 712 */ 713 xsltExtensionInstructionResultRegister(ctxt, ret); 714 } else if (inst->children != NULL) { 715 /* If the func:result element does not have a select attribute 716 * and has non-empty content (i.e. the func:result element has 717 * one or more child nodes), then the content of the 718 * func:result element specifies the value. 719 */ 720 xmlNodePtr oldInsert; 721 xmlDocPtr container; 722 723 container = xsltCreateRVT(ctxt); 724 if (container == NULL) { 725 xsltGenericError(xsltGenericErrorContext, 726 "exsltFuncResultElem: out of memory\n"); 727 data->error = 1; 728 return; 729 } 730 xsltRegisterLocalRVT(ctxt, container); 731 732 oldInsert = ctxt->insert; 733 ctxt->insert = (xmlNodePtr) container; 734 xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node, 735 inst->children, NULL, NULL); 736 ctxt->insert = oldInsert; 737 738 ret = xmlXPathNewValueTree((xmlNodePtr) container); 739 if (ret == NULL) { 740 xsltGenericError(xsltGenericErrorContext, 741 "exsltFuncResultElem: ret == NULL\n"); 742 data->error = 1; 743 } else { 744 ret->boolval = 0; /* Freeing is not handled there anymore */ 745 /* 746 * Mark it as a function result in order to avoid garbage 747 * collecting of tree fragments before the function exits. 748 */ 749 xsltExtensionInstructionResultRegister(ctxt, ret); 750 } 751 } else { 752 /* If the func:result element has empty content and does not 753 * have a select attribute, then the returned value is an 754 * empty string. 755 */ 756 ret = xmlXPathNewCString(""); 757 } 758 data->result = ret; 759} 760 761/** 762 * exsltFuncRegister: 763 * 764 * Registers the EXSLT - Functions module 765 */ 766void 767exsltFuncRegister (void) { 768 xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, 769 (xsltExtInitFunction) exsltFuncInit, 770 (xsltExtShutdownFunction) exsltFuncShutdown, 771 (xsltStyleExtInitFunction) exsltFuncStyleInit, 772 (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown); 773 774 xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", 775 EXSLT_FUNCTIONS_NAMESPACE, 776 exsltFuncFunctionComp); 777 xsltRegisterExtModuleElement ((const xmlChar *) "result", 778 EXSLT_FUNCTIONS_NAMESPACE, 779 (xsltPreComputeFunction)exsltFuncResultComp, 780 (xsltTransformFunction) exsltFuncResultElem); 781} 782