1 /* 2 * variables.c: Implementation of the variable storage and lookup 3 * 4 * Reference: 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 6 * 7 * See Copyright for the status of this software. 8 * 9 * daniel (at) veillard.com 10 */ 11 12 #define IN_LIBXSLT 13 #include "libxslt.h" 14 15 #include <string.h> 16 17 #include <libxml/xmlmemory.h> 18 #include <libxml/tree.h> 19 #include <libxml/valid.h> 20 #include <libxml/hash.h> 21 #include <libxml/xmlerror.h> 22 #include <libxml/xpath.h> 23 #include <libxml/xpathInternals.h> 24 #include <libxml/parserInternals.h> 25 #include <libxml/dict.h> 26 #include "xslt.h" 27 #include "xsltInternals.h" 28 #include "xsltutils.h" 29 #include "variables.h" 30 #include "transform.h" 31 #include "imports.h" 32 #include "preproc.h" 33 #include "keys.h" 34 35 #ifdef WITH_XSLT_DEBUG 36 #define WITH_XSLT_DEBUG_VARIABLE 37 #endif 38 39 #ifdef XSLT_REFACTORED 40 const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; 41 #endif 42 43 const xmlChar *xsltComputingGlobalVarMarker = 44 (const xmlChar *) " var/param being computed"; 45 46 #define XSLT_VAR_GLOBAL 1<<0 47 #define XSLT_VAR_IN_SELECT 1<<1 48 #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) 49 50 /************************************************************************ 51 * * 52 * Result Value Tree (Result Tree Fragment) interfaces * 53 * * 54 ************************************************************************/ 55 /** 56 * xsltCreateRVT: 57 * @ctxt: an XSLT transformation context 58 * 59 * Creates a Result Value Tree 60 * (the XSLT 1.0 term for this is "Result Tree Fragment") 61 * 62 * Returns the result value tree or NULL in case of API or internal errors. 63 */ 64 xmlDocPtr 65 xsltCreateRVT(xsltTransformContextPtr ctxt) 66 { 67 xmlDocPtr container; 68 69 /* 70 * Question: Why is this function public? 71 * Answer: It is called by the EXSLT module. 72 */ 73 if (ctxt == NULL) 74 return(NULL); 75 76 /* 77 * Reuse a RTF from the cache if available. 78 */ 79 if (ctxt->cache->RVT) { 80 container = ctxt->cache->RVT; 81 ctxt->cache->RVT = (xmlDocPtr) container->next; 82 /* clear the internal pointers */ 83 container->next = NULL; 84 container->prev = NULL; 85 if (ctxt->cache->nbRVT > 0) 86 ctxt->cache->nbRVT--; 87 #ifdef XSLT_DEBUG_PROFILE_CACHE 88 ctxt->cache->dbgReusedRVTs++; 89 #endif 90 return(container); 91 } 92 93 container = xmlNewDoc(NULL); 94 if (container == NULL) 95 return(NULL); 96 container->dict = ctxt->dict; 97 xmlDictReference(container->dict); 98 XSLT_MARK_RES_TREE_FRAG(container); 99 container->doc = container; 100 container->parent = NULL; 101 return(container); 102 } 103 104 /** 105 * xsltRegisterTmpRVT: 106 * @ctxt: an XSLT transformation context 107 * @RVT: a result value tree (Result Tree Fragment) 108 * 109 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment) 110 * in the garbage collector. 111 * The fragment will be freed at the exit of the currently 112 * instantiated xsl:template. 113 * Obsolete; this function might produce massive memory overhead, 114 * since the fragment is only freed when the current xsl:template 115 * exits. Use xsltRegisterLocalRVT() instead. 116 * 117 * Returns 0 in case of success and -1 in case of API or internal errors. 118 */ 119 int 120 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 121 { 122 if ((ctxt == NULL) || (RVT == NULL)) 123 return(-1); 124 125 /* 126 * We'll restrict the lifetime of user-created fragments 127 * insinde an xsl:variable and xsl:param to the lifetime of the 128 * var/param itself. 129 */ 130 if (ctxt->contextVariable != NULL) { 131 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; 132 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; 133 return(0); 134 } 135 136 RVT->next = (xmlNodePtr) ctxt->tmpRVT; 137 if (ctxt->tmpRVT != NULL) 138 ctxt->tmpRVT->prev = (xmlNodePtr) RVT; 139 ctxt->tmpRVT = RVT; 140 return(0); 141 } 142 143 /** 144 * xsltRegisterLocalRVT: 145 * @ctxt: an XSLT transformation context 146 * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr) 147 * 148 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment) 149 * in the RVT garbage collector. 150 * The fragment will be freed when the instruction which created the 151 * fragment exits. 152 * 153 * Returns 0 in case of success and -1 in case of API or internal errors. 154 */ 155 int 156 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, 157 xmlDocPtr RVT) 158 { 159 if ((ctxt == NULL) || (RVT == NULL)) 160 return(-1); 161 162 /* 163 * When evaluating "select" expressions of xsl:variable 164 * and xsl:param, we need to bind newly created tree fragments 165 * to the variable itself; otherwise the tragment will be 166 * freed before we leave the scope of a var. 167 */ 168 if ((ctxt->contextVariable != NULL) && 169 (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) 170 { 171 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; 172 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; 173 return(0); 174 } 175 /* 176 * Store the fragment in the scope of the current instruction. 177 * If not reference by a returning instruction (like EXSLT's function), 178 * then this fragment will be freed, when the instruction exits. 179 */ 180 RVT->next = (xmlNodePtr) ctxt->localRVT; 181 if (ctxt->localRVT != NULL) 182 ctxt->localRVT->prev = (xmlNodePtr) RVT; 183 ctxt->localRVT = RVT; 184 /* 185 * We need to keep track of the first registered fragment 186 * for extension instructions which return fragments 187 * (e.g. EXSLT'S function), in order to let 188 * xsltExtensionInstructionResultFinalize() clear the 189 * preserving flag on the fragments. 190 */ 191 if (ctxt->localRVTBase == NULL) 192 ctxt->localRVTBase = RVT; 193 return(0); 194 } 195 196 /** 197 * xsltExtensionInstructionResultFinalize: 198 * @ctxt: an XSLT transformation context 199 * 200 * Finalizes the data (e.g. result tree fragments) created 201 * within a value-returning process (e.g. EXSLT's function). 202 * Tree fragments marked as being returned by a function are 203 * set to normal state, which means that the fragment garbage 204 * collector will free them after the function-calling process exits. 205 * 206 * Returns 0 in case of success and -1 in case of API or internal errors. 207 */ 208 int 209 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) 210 { 211 xmlDocPtr cur; 212 213 if (ctxt == NULL) 214 return(-1); 215 if (ctxt->localRVTBase == NULL) 216 return(0); 217 /* 218 * Enable remaining local tree fragments to be freed 219 * by the fragment garbage collector. 220 */ 221 cur = ctxt->localRVTBase; 222 do { 223 cur->psvi = NULL; 224 cur = (xmlDocPtr) cur->next; 225 } while (cur != NULL); 226 return(0); 227 } 228 229 /** 230 * xsltExtensionInstructionResultRegister: 231 * @ctxt: an XSLT transformation context 232 * @obj: an XPath object to be inspected for result tree fragments 233 * 234 * Marks the result of a value-returning extension instruction 235 * in order to avoid it being garbage collected before the 236 * extension instruction exits. 237 * Note that one still has to additionally register any newly created 238 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). 239 * 240 * Returns 0 in case of success and -1 in case of error. 241 */ 242 int 243 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, 244 xmlXPathObjectPtr obj) 245 { 246 int i; 247 xmlNodePtr cur; 248 xmlDocPtr doc; 249 250 if ((ctxt == NULL) || (obj == NULL)) 251 return(-1); 252 253 /* 254 * OPTIMIZE TODO: If no local variables/params and no local tree 255 * fragments were created, then we don't need to analyse the XPath 256 * objects for tree fragments. 257 */ 258 259 if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE)) 260 return(0); 261 if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) 262 return(0); 263 264 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 265 cur = obj->nodesetval->nodeTab[i]; 266 if (cur->type == XML_NAMESPACE_DECL) { 267 /* 268 * The XPath module sets the owner element of a ns-node on 269 * the ns->next field. 270 */ 271 if ((((xmlNsPtr) cur)->next != NULL) && 272 (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE)) 273 { 274 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; 275 doc = cur->doc; 276 } else { 277 xsltTransformError(ctxt, NULL, ctxt->inst, 278 "Internal error in " 279 "xsltExtensionInstructionResultRegister(): " 280 "Cannot retrieve the doc of a namespace node.\n"); 281 goto error; 282 } 283 } else { 284 doc = cur->doc; 285 } 286 if (doc == NULL) { 287 xsltTransformError(ctxt, NULL, ctxt->inst, 288 "Internal error in " 289 "xsltExtensionInstructionResultRegister(): " 290 "Cannot retrieve the doc of a node.\n"); 291 goto error; 292 } 293 if (doc->name && (doc->name[0] == ' ')) { 294 /* 295 * This is a result tree fragment. 296 * We'll use the @psvi field for reference counting. 297 * TODO: How do we know if this is a value of a 298 * global variable or a doc acquired via the 299 * document() function? 300 */ 301 doc->psvi = (void *) ((long) 1); 302 } 303 } 304 305 return(0); 306 error: 307 return(-1); 308 } 309 310 /** 311 * xsltReleaseRVT: 312 * @ctxt: an XSLT transformation context 313 * @RVT: a result value tree (Result Tree Fragment) 314 * 315 * Either frees the RVT (which is an xmlDoc) or stores 316 * it in the context's cache for later reuse. 317 */ 318 void 319 xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 320 { 321 if (RVT == NULL) 322 return; 323 324 if (ctxt && (ctxt->cache->nbRVT < 40)) { 325 /* 326 * Store the Result Tree Fragment. 327 * Free the document info. 328 */ 329 if (RVT->_private != NULL) { 330 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); 331 xmlFree(RVT->_private); 332 RVT->_private = NULL; 333 } 334 /* 335 * Clear the document tree. 336 * REVISIT TODO: Do we expect ID/IDREF tables to be existent? 337 */ 338 if (RVT->children != NULL) { 339 xmlFreeNodeList(RVT->children); 340 RVT->children = NULL; 341 RVT->last = NULL; 342 } 343 if (RVT->ids != NULL) { 344 xmlFreeIDTable((xmlIDTablePtr) RVT->ids); 345 RVT->ids = NULL; 346 } 347 if (RVT->refs != NULL) { 348 xmlFreeRefTable((xmlRefTablePtr) RVT->refs); 349 RVT->refs = NULL; 350 } 351 352 /* 353 * Reset the reference counter. 354 */ 355 RVT->psvi = 0; 356 357 RVT->next = (xmlNodePtr) ctxt->cache->RVT; 358 ctxt->cache->RVT = RVT; 359 360 ctxt->cache->nbRVT++; 361 362 #ifdef XSLT_DEBUG_PROFILE_CACHE 363 ctxt->cache->dbgCachedRVTs++; 364 #endif 365 return; 366 } 367 /* 368 * Free it. 369 */ 370 if (RVT->_private != NULL) { 371 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); 372 xmlFree(RVT->_private); 373 } 374 xmlFreeDoc(RVT); 375 } 376 377 /** 378 * xsltRegisterPersistRVT: 379 * @ctxt: an XSLT transformation context 380 * @RVT: a result value tree (Result Tree Fragment) 381 * 382 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment) 383 * in the fragment garbage collector. 384 * The fragment will be freed when the transformation context is 385 * freed. 386 * 387 * Returns 0 in case of success and -1 in case of error. 388 */ 389 int 390 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 391 { 392 if ((ctxt == NULL) || (RVT == NULL)) return(-1); 393 394 RVT->next = (xmlNodePtr) ctxt->persistRVT; 395 if (ctxt->persistRVT != NULL) 396 ctxt->persistRVT->prev = (xmlNodePtr) RVT; 397 ctxt->persistRVT = RVT; 398 return(0); 399 } 400 401 /** 402 * xsltFreeRVTs: 403 * @ctxt: an XSLT transformation context 404 * 405 * Frees all registered result value trees (Result Tree Fragments) 406 * of the transformation. Internal function; should not be called 407 * by user-code. 408 */ 409 void 410 xsltFreeRVTs(xsltTransformContextPtr ctxt) 411 { 412 xmlDocPtr cur, next; 413 414 if (ctxt == NULL) 415 return; 416 /* 417 * Local fragments. 418 */ 419 cur = ctxt->localRVT; 420 while (cur != NULL) { 421 next = (xmlDocPtr) cur->next; 422 if (cur->_private != NULL) { 423 xsltFreeDocumentKeys(cur->_private); 424 xmlFree(cur->_private); 425 } 426 xmlFreeDoc(cur); 427 cur = next; 428 } 429 ctxt->localRVT = NULL; 430 /* 431 * User-created per-template fragments. 432 */ 433 cur = ctxt->tmpRVT; 434 while (cur != NULL) { 435 next = (xmlDocPtr) cur->next; 436 if (cur->_private != NULL) { 437 xsltFreeDocumentKeys(cur->_private); 438 xmlFree(cur->_private); 439 } 440 xmlFreeDoc(cur); 441 cur = next; 442 } 443 ctxt->tmpRVT = NULL; 444 /* 445 * Global fragments. 446 */ 447 cur = ctxt->persistRVT; 448 while (cur != NULL) { 449 next = (xmlDocPtr) cur->next; 450 if (cur->_private != NULL) { 451 xsltFreeDocumentKeys(cur->_private); 452 xmlFree(cur->_private); 453 } 454 xmlFreeDoc(cur); 455 cur = next; 456 } 457 ctxt->persistRVT = NULL; 458 } 459 460 /************************************************************************ 461 * * 462 * Module interfaces * 463 * * 464 ************************************************************************/ 465 466 /** 467 * xsltNewStackElem: 468 * 469 * Create a new XSLT ParserContext 470 * 471 * Returns the newly allocated xsltParserStackElem or NULL in case of error 472 */ 473 static xsltStackElemPtr 474 xsltNewStackElem(xsltTransformContextPtr ctxt) 475 { 476 xsltStackElemPtr ret; 477 /* 478 * Reuse a stack item from the cache if available. 479 */ 480 if (ctxt && ctxt->cache->stackItems) { 481 ret = ctxt->cache->stackItems; 482 ctxt->cache->stackItems = ret->next; 483 ret->next = NULL; 484 ctxt->cache->nbStackItems--; 485 #ifdef XSLT_DEBUG_PROFILE_CACHE 486 ctxt->cache->dbgReusedVars++; 487 #endif 488 return(ret); 489 } 490 ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); 491 if (ret == NULL) { 492 xsltTransformError(NULL, NULL, NULL, 493 "xsltNewStackElem : malloc failed\n"); 494 return(NULL); 495 } 496 memset(ret, 0, sizeof(xsltStackElem)); 497 ret->context = ctxt; 498 return(ret); 499 } 500 501 /** 502 * xsltCopyStackElem: 503 * @elem: an XSLT stack element 504 * 505 * Makes a copy of the stack element 506 * 507 * Returns the copy of NULL 508 */ 509 static xsltStackElemPtr 510 xsltCopyStackElem(xsltStackElemPtr elem) { 511 xsltStackElemPtr cur; 512 513 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); 514 if (cur == NULL) { 515 xsltTransformError(NULL, NULL, NULL, 516 "xsltCopyStackElem : malloc failed\n"); 517 return(NULL); 518 } 519 memset(cur, 0, sizeof(xsltStackElem)); 520 cur->context = elem->context; 521 cur->name = elem->name; 522 cur->nameURI = elem->nameURI; 523 cur->select = elem->select; 524 cur->tree = elem->tree; 525 cur->comp = elem->comp; 526 return(cur); 527 } 528 529 /** 530 * xsltFreeStackElem: 531 * @elem: an XSLT stack element 532 * 533 * Free up the memory allocated by @elem 534 */ 535 static void 536 xsltFreeStackElem(xsltStackElemPtr elem) { 537 if (elem == NULL) 538 return; 539 if (elem->value != NULL) 540 xmlXPathFreeObject(elem->value); 541 /* 542 * Release the list of temporary Result Tree Fragments. 543 */ 544 if (elem->fragment) { 545 xmlDocPtr cur; 546 547 while (elem->fragment != NULL) { 548 cur = elem->fragment; 549 elem->fragment = (xmlDocPtr) cur->next; 550 551 if (elem->context && 552 (cur->psvi == (void *) ((long) 1))) 553 { 554 /* 555 * This fragment is a result of an extension instruction 556 * (e.g. XSLT's function) and needs to be preserved until 557 * the instruction exits. 558 * Example: The fragment of the variable must not be freed 559 * since it is returned by the EXSLT function: 560 * <f:function name="foo"> 561 * <xsl:variable name="bar"> 562 * <bar/> 563 * </xsl:variable> 564 * <f:result select="$bar"/> 565 * </f:function> 566 * 567 */ 568 xsltRegisterLocalRVT(elem->context, cur); 569 } else { 570 xsltReleaseRVT((xsltTransformContextPtr) elem->context, 571 cur); 572 } 573 } 574 } 575 /* 576 * Cache or free the variable structure. 577 */ 578 if (elem->context && (elem->context->cache->nbStackItems < 50)) { 579 /* 580 * Store the item in the cache. 581 */ 582 xsltTransformContextPtr ctxt = elem->context; 583 memset(elem, 0, sizeof(xsltStackElem)); 584 elem->context = ctxt; 585 elem->next = ctxt->cache->stackItems; 586 ctxt->cache->stackItems = elem; 587 ctxt->cache->nbStackItems++; 588 #ifdef XSLT_DEBUG_PROFILE_CACHE 589 ctxt->cache->dbgCachedVars++; 590 #endif 591 return; 592 } 593 xmlFree(elem); 594 } 595 596 /** 597 * xsltFreeStackElemList: 598 * @elem: an XSLT stack element 599 * 600 * Free up the memory allocated by @elem 601 */ 602 void 603 xsltFreeStackElemList(xsltStackElemPtr elem) { 604 xsltStackElemPtr next; 605 606 while (elem != NULL) { 607 next = elem->next; 608 xsltFreeStackElem(elem); 609 elem = next; 610 } 611 } 612 613 /** 614 * xsltStackLookup: 615 * @ctxt: an XSLT transformation context 616 * @name: the local part of the name 617 * @nameURI: the URI part of the name 618 * 619 * Locate an element in the stack based on its name. 620 */ 621 #if 0 /* TODO: Those seem to have been used for debugging. */ 622 static int stack_addr = 0; 623 static int stack_cmp = 0; 624 #endif 625 626 static xsltStackElemPtr 627 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 628 const xmlChar *nameURI) { 629 int i; 630 xsltStackElemPtr cur; 631 632 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0)) 633 return(NULL); 634 635 /* 636 * Do the lookup from the top of the stack, but 637 * don't use params being computed in a call-param 638 * First lookup expects the variable name and URI to 639 * come from the disctionnary and hence pointer comparison. 640 */ 641 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { 642 cur = ctxt->varsTab[i-1]; 643 while (cur != NULL) { 644 if ((cur->name == name) && (cur->nameURI == nameURI)) { 645 #if 0 646 stack_addr++; 647 #endif 648 return(cur); 649 } 650 cur = cur->next; 651 } 652 } 653 654 /* 655 * Redo the lookup with interned string compares 656 * to avoid string compares. 657 */ 658 name = xmlDictLookup(ctxt->dict, name, -1); 659 if (nameURI != NULL) 660 nameURI = xmlDictLookup(ctxt->dict, nameURI, -1); 661 662 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { 663 cur = ctxt->varsTab[i-1]; 664 while (cur != NULL) { 665 if ((cur->name == name) && (cur->nameURI == nameURI)) { 666 #if 0 667 stack_cmp++; 668 #endif 669 return(cur); 670 } 671 cur = cur->next; 672 } 673 } 674 675 return(NULL); 676 } 677 678 /** 679 * xsltCheckStackElem: 680 * @ctxt: xn XSLT transformation context 681 * @name: the variable name 682 * @nameURI: the variable namespace URI 683 * 684 * Checks whether a variable or param is already defined. 685 * 686 * URGENT TODO: Checks for redefinition of vars/params should be 687 * done only at compilation time. 688 * 689 * Returns 1 if variable is present, 2 if param is present, 3 if this 690 * is an inherited param, 0 if not found, -1 in case of failure. 691 */ 692 static int 693 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name, 694 const xmlChar *nameURI) { 695 xsltStackElemPtr cur; 696 697 if ((ctxt == NULL) || (name == NULL)) 698 return(-1); 699 700 cur = xsltStackLookup(ctxt, name, nameURI); 701 if (cur == NULL) 702 return(0); 703 if (cur->comp != NULL) { 704 if (cur->comp->type == XSLT_FUNC_WITHPARAM) 705 return(3); 706 else if (cur->comp->type == XSLT_FUNC_PARAM) 707 return(2); 708 } 709 710 return(1); 711 } 712 713 /** 714 * xsltAddStackElem: 715 * @ctxt: xn XSLT transformation context 716 * @elem: a stack element 717 * 718 * Push an element (or list) onto the stack. 719 * In case of a list, each member will be pushed into 720 * a seperate slot; i.e. there's always 1 stack entry for 721 * 1 stack element. 722 * 723 * Returns 0 in case of success, -1 in case of failure. 724 */ 725 static int 726 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) 727 { 728 if ((ctxt == NULL) || (elem == NULL)) 729 return(-1); 730 731 do { 732 if (ctxt->varsMax == 0) { 733 ctxt->varsMax = 10; 734 ctxt->varsTab = 735 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * 736 sizeof(ctxt->varsTab[0])); 737 if (ctxt->varsTab == NULL) { 738 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 739 return (-1); 740 } 741 } 742 if (ctxt->varsNr >= ctxt->varsMax) { 743 ctxt->varsMax *= 2; 744 ctxt->varsTab = 745 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, 746 ctxt->varsMax * 747 sizeof(ctxt->varsTab[0])); 748 if (ctxt->varsTab == NULL) { 749 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 750 return (-1); 751 } 752 } 753 ctxt->varsTab[ctxt->varsNr++] = elem; 754 ctxt->vars = elem; 755 756 elem = elem->next; 757 } while (elem != NULL); 758 759 return(0); 760 } 761 762 /** 763 * xsltAddStackElemList: 764 * @ctxt: xn XSLT transformation context 765 * @elems: a stack element list 766 * 767 * Push an element list onto the stack. 768 * 769 * Returns 0 in case of success, -1 in case of failure. 770 */ 771 int 772 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) 773 { 774 return(xsltAddStackElem(ctxt, elems)); 775 } 776 777 /************************************************************************ 778 * * 779 * Module interfaces * 780 * * 781 ************************************************************************/ 782 783 /** 784 * xsltEvalVariable: 785 * @ctxt: the XSLT transformation context 786 * @variable: the variable or parameter item 787 * @comp: the compiled XSLT instruction 788 * 789 * Evaluate a variable value. 790 * 791 * Returns the XPath Object value or NULL in case of error 792 */ 793 static xmlXPathObjectPtr 794 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, 795 xsltStylePreCompPtr castedComp) 796 { 797 #ifdef XSLT_REFACTORED 798 xsltStyleItemVariablePtr comp = 799 (xsltStyleItemVariablePtr) castedComp; 800 #else 801 xsltStylePreCompPtr comp = castedComp; 802 #endif 803 xmlXPathObjectPtr result = NULL; 804 xmlNodePtr oldInst; 805 806 if ((ctxt == NULL) || (variable == NULL)) 807 return(NULL); 808 809 /* 810 * A variable or parameter are evaluated on demand; thus the 811 * context (of XSLT and XPath) need to be temporarily adjusted and 812 * restored on exit. 813 */ 814 oldInst = ctxt->inst; 815 816 #ifdef WITH_XSLT_DEBUG_VARIABLE 817 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 818 "Evaluating variable '%s'\n", variable->name)); 819 #endif 820 if (variable->select != NULL) { 821 xmlXPathCompExprPtr xpExpr = NULL; 822 xmlDocPtr oldXPDoc; 823 xmlNodePtr oldXPContextNode; 824 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 825 xmlNsPtr *oldXPNamespaces; 826 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 827 xsltStackElemPtr oldVar = ctxt->contextVariable; 828 829 if ((comp != NULL) && (comp->comp != NULL)) { 830 xpExpr = comp->comp; 831 } else { 832 xpExpr = xmlXPathCompile(variable->select); 833 } 834 if (xpExpr == NULL) 835 return(NULL); 836 /* 837 * Save context states. 838 */ 839 oldXPDoc = xpctxt->doc; 840 oldXPContextNode = xpctxt->node; 841 oldXPProximityPosition = xpctxt->proximityPosition; 842 oldXPContextSize = xpctxt->contextSize; 843 oldXPNamespaces = xpctxt->namespaces; 844 oldXPNsNr = xpctxt->nsNr; 845 846 xpctxt->node = ctxt->node; 847 /* 848 * OPTIMIZE TODO: Lame try to set the context doc. 849 * Get rid of this somehow in xpath.c. 850 */ 851 if ((ctxt->node->type != XML_NAMESPACE_DECL) && 852 ctxt->node->doc) 853 xpctxt->doc = ctxt->node->doc; 854 /* 855 * BUG TODO: The proximity position and the context size will 856 * potentially be wrong. 857 * Example: 858 * <xsl:template select="foo"> 859 * <xsl:variable name="pos" select="position()"/> 860 * <xsl:for-each select="bar"> 861 * <xsl:value-of select="$pos"/> 862 * </xsl:for-each> 863 * </xsl:template> 864 * Here the proximity position and context size are changed 865 * to the context of <xsl:for-each select="bar">, but 866 * the variable needs to be evaluated in the context of 867 * <xsl:template select="foo">. 868 */ 869 if (comp != NULL) { 870 871 #ifdef XSLT_REFACTORED 872 if (comp->inScopeNs != NULL) { 873 xpctxt->namespaces = comp->inScopeNs->list; 874 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 875 } else { 876 xpctxt->namespaces = NULL; 877 xpctxt->nsNr = 0; 878 } 879 #else 880 xpctxt->namespaces = comp->nsList; 881 xpctxt->nsNr = comp->nsNr; 882 #endif 883 } else { 884 xpctxt->namespaces = NULL; 885 xpctxt->nsNr = 0; 886 } 887 888 /* 889 * We need to mark that we are "selecting" a var's value; 890 * if any tree fragments are created inside the expression, 891 * then those need to be stored inside the variable; otherwise 892 * we'll eventually free still referenced fragments, before 893 * we leave the scope of the variable. 894 */ 895 ctxt->contextVariable = variable; 896 variable->flags |= XSLT_VAR_IN_SELECT; 897 898 result = xmlXPathCompiledEval(xpExpr, xpctxt); 899 900 variable->flags ^= XSLT_VAR_IN_SELECT; 901 /* 902 * Restore Context states. 903 */ 904 ctxt->contextVariable = oldVar; 905 906 xpctxt->doc = oldXPDoc; 907 xpctxt->node = oldXPContextNode; 908 xpctxt->contextSize = oldXPContextSize; 909 xpctxt->proximityPosition = oldXPProximityPosition; 910 xpctxt->namespaces = oldXPNamespaces; 911 xpctxt->nsNr = oldXPNsNr; 912 913 if ((comp == NULL) || (comp->comp == NULL)) 914 xmlXPathFreeCompExpr(xpExpr); 915 if (result == NULL) { 916 xsltTransformError(ctxt, NULL, 917 (comp != NULL) ? comp->inst : NULL, 918 "Failed to evaluate the expression of variable '%s'.\n", 919 variable->name); 920 ctxt->state = XSLT_STATE_STOPPED; 921 922 #ifdef WITH_XSLT_DEBUG_VARIABLE 923 #ifdef LIBXML_DEBUG_ENABLED 924 } else { 925 if ((xsltGenericDebugContext == stdout) || 926 (xsltGenericDebugContext == stderr)) 927 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 928 result, 0); 929 #endif 930 #endif 931 } 932 } else { 933 if (variable->tree == NULL) { 934 result = xmlXPathNewCString(""); 935 } else { 936 if (variable->tree) { 937 xmlDocPtr container; 938 xmlNodePtr oldInsert; 939 xmlDocPtr oldOutput; 940 xsltStackElemPtr oldVar = ctxt->contextVariable; 941 942 /* 943 * Generate a result tree fragment. 944 */ 945 container = xsltCreateRVT(ctxt); 946 if (container == NULL) 947 goto error; 948 /* 949 * NOTE: Local Result Tree Fragments of params/variables 950 * are not registered globally anymore; the life-time 951 * is not directly dependant of the param/variable itself. 952 * 953 * OLD: xsltRegisterTmpRVT(ctxt, container); 954 */ 955 /* 956 * Attach the Result Tree Fragment to the variable; 957 * when the variable is freed, it will also free 958 * the Result Tree Fragment. 959 */ 960 variable->fragment = container; 961 962 oldOutput = ctxt->output; 963 oldInsert = ctxt->insert; 964 965 ctxt->output = container; 966 ctxt->insert = (xmlNodePtr) container; 967 ctxt->contextVariable = variable; 968 /* 969 * Process the sequence constructor (variable->tree). 970 * The resulting tree will be held by @container. 971 */ 972 xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree, 973 NULL, NULL); 974 975 ctxt->contextVariable = oldVar; 976 ctxt->insert = oldInsert; 977 ctxt->output = oldOutput; 978 979 result = xmlXPathNewValueTree((xmlNodePtr) container); 980 } 981 if (result == NULL) { 982 result = xmlXPathNewCString(""); 983 } else { 984 /* 985 * Freeing is not handled there anymore. 986 * QUESTION TODO: What does the above comment mean? 987 */ 988 result->boolval = 0; 989 } 990 #ifdef WITH_XSLT_DEBUG_VARIABLE 991 #ifdef LIBXML_DEBUG_ENABLED 992 993 if ((xsltGenericDebugContext == stdout) || 994 (xsltGenericDebugContext == stderr)) 995 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 996 result, 0); 997 #endif 998 #endif 999 } 1000 } 1001 1002 error: 1003 ctxt->inst = oldInst; 1004 return(result); 1005 } 1006 1007 /** 1008 * xsltEvalGlobalVariable: 1009 * @elem: the variable or parameter 1010 * @ctxt: the XSLT transformation context 1011 * 1012 * Evaluates a the value of a global xsl:variable or 1013 * xsl:param declaration. 1014 * 1015 * Returns the XPath Object value or NULL in case of error 1016 */ 1017 static xmlXPathObjectPtr 1018 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) 1019 { 1020 xmlXPathObjectPtr result = NULL; 1021 xmlNodePtr oldInst; 1022 const xmlChar* oldVarName; 1023 1024 #ifdef XSLT_REFACTORED 1025 xsltStyleBasicItemVariablePtr comp; 1026 #else 1027 xsltStylePreCompPtr comp; 1028 #endif 1029 1030 if ((ctxt == NULL) || (elem == NULL)) 1031 return(NULL); 1032 if (elem->computed) 1033 return(elem->value); 1034 1035 1036 #ifdef WITH_XSLT_DEBUG_VARIABLE 1037 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1038 "Evaluating global variable %s\n", elem->name)); 1039 #endif 1040 1041 #ifdef WITH_DEBUGGER 1042 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && 1043 elem->comp && elem->comp->inst) 1044 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt); 1045 #endif 1046 1047 oldInst = ctxt->inst; 1048 comp = elem->comp; 1049 oldVarName = elem->name; 1050 elem->name = xsltComputingGlobalVarMarker; 1051 /* 1052 * OPTIMIZE TODO: We should consider instantiating global vars/params 1053 * on-demand. The vars/params don't need to be evaluated if never 1054 * called; and in the case of global params, if values for such params 1055 * are provided by the user. 1056 */ 1057 if (elem->select != NULL) { 1058 xmlXPathCompExprPtr xpExpr = NULL; 1059 xmlDocPtr oldXPDoc; 1060 xmlNodePtr oldXPContextNode; 1061 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 1062 xmlNsPtr *oldXPNamespaces; 1063 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 1064 1065 if ((comp != NULL) && (comp->comp != NULL)) { 1066 xpExpr = comp->comp; 1067 } else { 1068 xpExpr = xmlXPathCompile(elem->select); 1069 } 1070 if (xpExpr == NULL) 1071 goto error; 1072 1073 1074 if (comp != NULL) 1075 ctxt->inst = comp->inst; 1076 else 1077 ctxt->inst = NULL; 1078 /* 1079 * SPEC XSLT 1.0: 1080 * "At top-level, the expression or template specifying the 1081 * variable value is evaluated with the same context as that used 1082 * to process the root node of the source document: the current 1083 * node is the root node of the source document and the current 1084 * node list is a list containing just the root node of the source 1085 * document." 1086 */ 1087 /* 1088 * Save context states. 1089 */ 1090 oldXPDoc = xpctxt->doc; 1091 oldXPContextNode = xpctxt->node; 1092 oldXPProximityPosition = xpctxt->proximityPosition; 1093 oldXPContextSize = xpctxt->contextSize; 1094 oldXPNamespaces = xpctxt->namespaces; 1095 oldXPNsNr = xpctxt->nsNr; 1096 1097 xpctxt->node = ctxt->initialContextNode; 1098 xpctxt->doc = ctxt->initialContextDoc; 1099 xpctxt->contextSize = 1; 1100 xpctxt->proximityPosition = 1; 1101 1102 if (comp != NULL) { 1103 1104 #ifdef XSLT_REFACTORED 1105 if (comp->inScopeNs != NULL) { 1106 xpctxt->namespaces = comp->inScopeNs->list; 1107 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 1108 } else { 1109 xpctxt->namespaces = NULL; 1110 xpctxt->nsNr = 0; 1111 } 1112 #else 1113 xpctxt->namespaces = comp->nsList; 1114 xpctxt->nsNr = comp->nsNr; 1115 #endif 1116 } else { 1117 xpctxt->namespaces = NULL; 1118 xpctxt->nsNr = 0; 1119 } 1120 1121 result = xmlXPathCompiledEval(xpExpr, xpctxt); 1122 1123 /* 1124 * Restore Context states. 1125 */ 1126 xpctxt->doc = oldXPDoc; 1127 xpctxt->node = oldXPContextNode; 1128 xpctxt->contextSize = oldXPContextSize; 1129 xpctxt->proximityPosition = oldXPProximityPosition; 1130 xpctxt->namespaces = oldXPNamespaces; 1131 xpctxt->nsNr = oldXPNsNr; 1132 1133 if ((comp == NULL) || (comp->comp == NULL)) 1134 xmlXPathFreeCompExpr(xpExpr); 1135 if (result == NULL) { 1136 if (comp == NULL) 1137 xsltTransformError(ctxt, NULL, NULL, 1138 "Evaluating global variable %s failed\n", elem->name); 1139 else 1140 xsltTransformError(ctxt, NULL, comp->inst, 1141 "Evaluating global variable %s failed\n", elem->name); 1142 ctxt->state = XSLT_STATE_STOPPED; 1143 #ifdef WITH_XSLT_DEBUG_VARIABLE 1144 #ifdef LIBXML_DEBUG_ENABLED 1145 } else { 1146 if ((xsltGenericDebugContext == stdout) || 1147 (xsltGenericDebugContext == stderr)) 1148 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 1149 result, 0); 1150 #endif 1151 #endif 1152 } 1153 } else { 1154 if (elem->tree == NULL) { 1155 result = xmlXPathNewCString(""); 1156 } else { 1157 xmlDocPtr container; 1158 xmlNodePtr oldInsert; 1159 xmlDocPtr oldOutput, oldXPDoc; 1160 /* 1161 * Generate a result tree fragment. 1162 */ 1163 container = xsltCreateRVT(ctxt); 1164 if (container == NULL) 1165 goto error; 1166 /* 1167 * Let the lifetime of the tree fragment be handled by 1168 * the Libxslt's garbage collector. 1169 */ 1170 xsltRegisterPersistRVT(ctxt, container); 1171 1172 oldOutput = ctxt->output; 1173 oldInsert = ctxt->insert; 1174 1175 oldXPDoc = ctxt->xpathCtxt->doc; 1176 1177 ctxt->output = container; 1178 ctxt->insert = (xmlNodePtr) container; 1179 1180 ctxt->xpathCtxt->doc = ctxt->initialContextDoc; 1181 /* 1182 * Process the sequence constructor. 1183 */ 1184 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL); 1185 1186 ctxt->xpathCtxt->doc = oldXPDoc; 1187 1188 ctxt->insert = oldInsert; 1189 ctxt->output = oldOutput; 1190 1191 result = xmlXPathNewValueTree((xmlNodePtr) container); 1192 if (result == NULL) { 1193 result = xmlXPathNewCString(""); 1194 } else { 1195 result->boolval = 0; /* Freeing is not handled there anymore */ 1196 } 1197 #ifdef WITH_XSLT_DEBUG_VARIABLE 1198 #ifdef LIBXML_DEBUG_ENABLED 1199 if ((xsltGenericDebugContext == stdout) || 1200 (xsltGenericDebugContext == stderr)) 1201 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 1202 result, 0); 1203 #endif 1204 #endif 1205 } 1206 } 1207 1208 error: 1209 elem->name = oldVarName; 1210 ctxt->inst = oldInst; 1211 if (result != NULL) { 1212 elem->value = result; 1213 elem->computed = 1; 1214 } 1215 return(result); 1216 } 1217 1218 /** 1219 * xsltEvalGlobalVariables: 1220 * @ctxt: the XSLT transformation context 1221 * 1222 * Evaluates all global variables and parameters of a stylesheet. 1223 * For internal use only. This is called at start of a transformation. 1224 * 1225 * Returns 0 in case of success, -1 in case of error 1226 */ 1227 int 1228 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) { 1229 xsltStackElemPtr elem; 1230 xsltStylesheetPtr style; 1231 1232 if ((ctxt == NULL) || (ctxt->document == NULL)) 1233 return(-1); 1234 1235 #ifdef WITH_XSLT_DEBUG_VARIABLE 1236 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1237 "Registering global variables\n")); 1238 #endif 1239 /* 1240 * Walk the list from the stylesheets and populate the hash table 1241 */ 1242 style = ctxt->style; 1243 while (style != NULL) { 1244 elem = style->variables; 1245 1246 #ifdef WITH_XSLT_DEBUG_VARIABLE 1247 if ((style->doc != NULL) && (style->doc->URL != NULL)) { 1248 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1249 "Registering global variables from %s\n", 1250 style->doc->URL)); 1251 } 1252 #endif 1253 1254 while (elem != NULL) { 1255 xsltStackElemPtr def; 1256 1257 /* 1258 * Global variables are stored in the variables pool. 1259 */ 1260 def = (xsltStackElemPtr) 1261 xmlHashLookup2(ctxt->globalVars, 1262 elem->name, elem->nameURI); 1263 if (def == NULL) { 1264 1265 def = xsltCopyStackElem(elem); 1266 xmlHashAddEntry2(ctxt->globalVars, 1267 elem->name, elem->nameURI, def); 1268 } else if ((elem->comp != NULL) && 1269 (elem->comp->type == XSLT_FUNC_VARIABLE)) { 1270 /* 1271 * Redefinition of variables from a different stylesheet 1272 * should not generate a message. 1273 */ 1274 if ((elem->comp->inst != NULL) && 1275 (def->comp != NULL) && (def->comp->inst != NULL) && 1276 (elem->comp->inst->doc == def->comp->inst->doc)) 1277 { 1278 xsltTransformError(ctxt, style, elem->comp->inst, 1279 "Global variable %s already defined\n", elem->name); 1280 if (style != NULL) style->errors++; 1281 } 1282 } 1283 elem = elem->next; 1284 } 1285 1286 style = xsltNextImport(style); 1287 } 1288 1289 /* 1290 * This part does the actual evaluation 1291 */ 1292 xmlHashScan(ctxt->globalVars, 1293 (xmlHashScanner) xsltEvalGlobalVariable, ctxt); 1294 1295 return(0); 1296 } 1297 1298 /** 1299 * xsltRegisterGlobalVariable: 1300 * @style: the XSLT transformation context 1301 * @name: the variable name 1302 * @ns_uri: the variable namespace URI 1303 * @sel: the expression which need to be evaluated to generate a value 1304 * @tree: the subtree if sel is NULL 1305 * @comp: the precompiled value 1306 * @value: the string value if available 1307 * 1308 * Register a new variable value. If @value is NULL it unregisters 1309 * the variable 1310 * 1311 * Returns 0 in case of success, -1 in case of error 1312 */ 1313 static int 1314 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, 1315 const xmlChar *ns_uri, const xmlChar *sel, 1316 xmlNodePtr tree, xsltStylePreCompPtr comp, 1317 const xmlChar *value) { 1318 xsltStackElemPtr elem, tmp; 1319 if (style == NULL) 1320 return(-1); 1321 if (name == NULL) 1322 return(-1); 1323 if (comp == NULL) 1324 return(-1); 1325 1326 #ifdef WITH_XSLT_DEBUG_VARIABLE 1327 if (comp->type == XSLT_FUNC_PARAM) 1328 xsltGenericDebug(xsltGenericDebugContext, 1329 "Defining global param %s\n", name); 1330 else 1331 xsltGenericDebug(xsltGenericDebugContext, 1332 "Defining global variable %s\n", name); 1333 #endif 1334 1335 elem = xsltNewStackElem(NULL); 1336 if (elem == NULL) 1337 return(-1); 1338 elem->comp = comp; 1339 elem->name = xmlDictLookup(style->dict, name, -1); 1340 elem->select = xmlDictLookup(style->dict, sel, -1); 1341 if (ns_uri) 1342 elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1); 1343 elem->tree = tree; 1344 tmp = style->variables; 1345 if (tmp == NULL) { 1346 elem->next = NULL; 1347 style->variables = elem; 1348 } else { 1349 while (tmp != NULL) { 1350 if ((elem->comp->type == XSLT_FUNC_VARIABLE) && 1351 (tmp->comp->type == XSLT_FUNC_VARIABLE) && 1352 (xmlStrEqual(elem->name, tmp->name)) && 1353 ((elem->nameURI == tmp->nameURI) || 1354 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) 1355 { 1356 xsltTransformError(NULL, style, comp->inst, 1357 "redefinition of global variable %s\n", elem->name); 1358 style->errors++; 1359 } 1360 if (tmp->next == NULL) 1361 break; 1362 tmp = tmp->next; 1363 } 1364 elem->next = NULL; 1365 tmp->next = elem; 1366 } 1367 if (value != NULL) { 1368 elem->computed = 1; 1369 elem->value = xmlXPathNewString(value); 1370 } 1371 return(0); 1372 } 1373 1374 /** 1375 * xsltProcessUserParamInternal 1376 * 1377 * @ctxt: the XSLT transformation context 1378 * @name: a null terminated parameter name 1379 * @value: a null terminated value (may be an XPath expression) 1380 * @eval: 0 to treat the value literally, else evaluate as XPath expression 1381 * 1382 * If @eval is 0 then @value is treated literally and is stored in the global 1383 * parameter/variable table without any change. 1384 * 1385 * Uf @eval is 1 then @value is treated as an XPath expression and is 1386 * evaluated. In this case, if you want to pass a string which will be 1387 * interpreted literally then it must be enclosed in single or double quotes. 1388 * If the string contains single quotes (double quotes) then it cannot be 1389 * enclosed single quotes (double quotes). If the string which you want to 1390 * be treated literally contains both single and double quotes (e.g. Meet 1391 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable 1392 * quoting character. You cannot use ' or " inside the string 1393 * because the replacement of character entities with their equivalents is 1394 * done at a different stage of processing. The solution is to call 1395 * xsltQuoteUserParams or xsltQuoteOneUserParam. 1396 * 1397 * This needs to be done on parsed stylesheets before starting to apply 1398 * transformations. Normally this will be called (directly or indirectly) 1399 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams, 1400 * or xsltQuoteOneUserParam. 1401 * 1402 * Returns 0 in case of success, -1 in case of error 1403 */ 1404 1405 static 1406 int 1407 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, 1408 const xmlChar * name, 1409 const xmlChar * value, 1410 int eval) { 1411 1412 xsltStylesheetPtr style; 1413 const xmlChar *prefix; 1414 const xmlChar *href; 1415 xmlXPathCompExprPtr xpExpr; 1416 xmlXPathObjectPtr result; 1417 1418 xsltStackElemPtr elem; 1419 int res; 1420 void *res_ptr; 1421 1422 if (ctxt == NULL) 1423 return(-1); 1424 if (name == NULL) 1425 return(0); 1426 if (value == NULL) 1427 return(0); 1428 1429 style = ctxt->style; 1430 1431 #ifdef WITH_XSLT_DEBUG_VARIABLE 1432 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1433 "Evaluating user parameter %s=%s\n", name, value)); 1434 #endif 1435 1436 /* 1437 * Name lookup 1438 */ 1439 1440 name = xsltSplitQName(ctxt->dict, name, &prefix); 1441 href = NULL; 1442 if (prefix != NULL) { 1443 xmlNsPtr ns; 1444 1445 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), 1446 prefix); 1447 if (ns == NULL) { 1448 xsltTransformError(ctxt, style, NULL, 1449 "user param : no namespace bound to prefix %s\n", prefix); 1450 href = NULL; 1451 } else { 1452 href = ns->href; 1453 } 1454 } 1455 1456 if (name == NULL) 1457 return (-1); 1458 1459 res_ptr = xmlHashLookup2(ctxt->globalVars, name, href); 1460 if (res_ptr != 0) { 1461 xsltTransformError(ctxt, style, NULL, 1462 "Global parameter %s already defined\n", name); 1463 } 1464 if (ctxt->globalVars == NULL) 1465 ctxt->globalVars = xmlHashCreate(20); 1466 1467 /* 1468 * do not overwrite variables with parameters from the command line 1469 */ 1470 while (style != NULL) { 1471 elem = ctxt->style->variables; 1472 while (elem != NULL) { 1473 if ((elem->comp != NULL) && 1474 (elem->comp->type == XSLT_FUNC_VARIABLE) && 1475 (xmlStrEqual(elem->name, name)) && 1476 (xmlStrEqual(elem->nameURI, href))) { 1477 return(0); 1478 } 1479 elem = elem->next; 1480 } 1481 style = xsltNextImport(style); 1482 } 1483 style = ctxt->style; 1484 elem = NULL; 1485 1486 /* 1487 * Do the evaluation if @eval is non-zero. 1488 */ 1489 1490 result = NULL; 1491 if (eval != 0) { 1492 xpExpr = xmlXPathCompile(value); 1493 if (xpExpr != NULL) { 1494 xmlDocPtr oldXPDoc; 1495 xmlNodePtr oldXPContextNode; 1496 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 1497 xmlNsPtr *oldXPNamespaces; 1498 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 1499 1500 /* 1501 * Save context states. 1502 */ 1503 oldXPDoc = xpctxt->doc; 1504 oldXPContextNode = xpctxt->node; 1505 oldXPProximityPosition = xpctxt->proximityPosition; 1506 oldXPContextSize = xpctxt->contextSize; 1507 oldXPNamespaces = xpctxt->namespaces; 1508 oldXPNsNr = xpctxt->nsNr; 1509 1510 /* 1511 * SPEC XSLT 1.0: 1512 * "At top-level, the expression or template specifying the 1513 * variable value is evaluated with the same context as that used 1514 * to process the root node of the source document: the current 1515 * node is the root node of the source document and the current 1516 * node list is a list containing just the root node of the source 1517 * document." 1518 */ 1519 xpctxt->doc = ctxt->initialContextDoc; 1520 xpctxt->node = ctxt->initialContextNode; 1521 xpctxt->contextSize = 1; 1522 xpctxt->proximityPosition = 1; 1523 /* 1524 * There is really no in scope namespace for parameters on the 1525 * command line. 1526 */ 1527 xpctxt->namespaces = NULL; 1528 xpctxt->nsNr = 0; 1529 1530 result = xmlXPathCompiledEval(xpExpr, xpctxt); 1531 1532 /* 1533 * Restore Context states. 1534 */ 1535 xpctxt->doc = oldXPDoc; 1536 xpctxt->node = oldXPContextNode; 1537 xpctxt->contextSize = oldXPContextSize; 1538 xpctxt->proximityPosition = oldXPProximityPosition; 1539 xpctxt->namespaces = oldXPNamespaces; 1540 xpctxt->nsNr = oldXPNsNr; 1541 1542 xmlXPathFreeCompExpr(xpExpr); 1543 } 1544 if (result == NULL) { 1545 xsltTransformError(ctxt, style, NULL, 1546 "Evaluating user parameter %s failed\n", name); 1547 ctxt->state = XSLT_STATE_STOPPED; 1548 return(-1); 1549 } 1550 } 1551 1552 /* 1553 * If @eval is 0 then @value is to be taken literally and result is NULL 1554 * 1555 * If @eval is not 0, then @value is an XPath expression and has been 1556 * successfully evaluated and result contains the resulting value and 1557 * is not NULL. 1558 * 1559 * Now create an xsltStackElemPtr for insertion into the context's 1560 * global variable/parameter hash table. 1561 */ 1562 1563 #ifdef WITH_XSLT_DEBUG_VARIABLE 1564 #ifdef LIBXML_DEBUG_ENABLED 1565 if ((xsltGenericDebugContext == stdout) || 1566 (xsltGenericDebugContext == stderr)) 1567 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 1568 result, 0); 1569 #endif 1570 #endif 1571 1572 elem = xsltNewStackElem(NULL); 1573 if (elem != NULL) { 1574 elem->name = name; 1575 elem->select = xmlDictLookup(ctxt->dict, value, -1); 1576 if (href != NULL) 1577 elem->nameURI = xmlDictLookup(ctxt->dict, href, -1); 1578 elem->tree = NULL; 1579 elem->computed = 1; 1580 if (eval == 0) { 1581 elem->value = xmlXPathNewString(value); 1582 } 1583 else { 1584 elem->value = result; 1585 } 1586 } 1587 1588 /* 1589 * Global parameters are stored in the XPath context variables pool. 1590 */ 1591 1592 res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem); 1593 if (res != 0) { 1594 xsltFreeStackElem(elem); 1595 xsltTransformError(ctxt, style, NULL, 1596 "Global parameter %s already defined\n", name); 1597 } 1598 return(0); 1599 } 1600 1601 /** 1602 * xsltEvalUserParams: 1603 * 1604 * @ctxt: the XSLT transformation context 1605 * @params: a NULL terminated array of parameters name/value tuples 1606 * 1607 * Evaluate the global variables of a stylesheet. This needs to be 1608 * done on parsed stylesheets before starting to apply transformations. 1609 * Each of the parameters is evaluated as an XPath expression and stored 1610 * in the global variables/parameter hash table. If you want your 1611 * parameter used literally, use xsltQuoteUserParams. 1612 * 1613 * Returns 0 in case of success, -1 in case of error 1614 */ 1615 1616 int 1617 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) { 1618 int indx = 0; 1619 const xmlChar *name; 1620 const xmlChar *value; 1621 1622 if (params == NULL) 1623 return(0); 1624 while (params[indx] != NULL) { 1625 name = (const xmlChar *) params[indx++]; 1626 value = (const xmlChar *) params[indx++]; 1627 if (xsltEvalOneUserParam(ctxt, name, value) != 0) 1628 return(-1); 1629 } 1630 return 0; 1631 } 1632 1633 /** 1634 * xsltQuoteUserParams: 1635 * 1636 * @ctxt: the XSLT transformation context 1637 * @params: a NULL terminated arry of parameters names/values tuples 1638 * 1639 * Similar to xsltEvalUserParams, but the values are treated literally and 1640 * are * *not* evaluated as XPath expressions. This should be done on parsed 1641 * stylesheets before starting to apply transformations. 1642 * 1643 * Returns 0 in case of success, -1 in case of error. 1644 */ 1645 1646 int 1647 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) { 1648 int indx = 0; 1649 const xmlChar *name; 1650 const xmlChar *value; 1651 1652 if (params == NULL) 1653 return(0); 1654 while (params[indx] != NULL) { 1655 name = (const xmlChar *) params[indx++]; 1656 value = (const xmlChar *) params[indx++]; 1657 if (xsltQuoteOneUserParam(ctxt, name, value) != 0) 1658 return(-1); 1659 } 1660 return 0; 1661 } 1662 1663 /** 1664 * xsltEvalOneUserParam: 1665 * @ctxt: the XSLT transformation context 1666 * @name: a null terminated string giving the name of the parameter 1667 * @value: a null terminated string giving the XPath expression to be evaluated 1668 * 1669 * This is normally called from xsltEvalUserParams to process a single 1670 * parameter from a list of parameters. The @value is evaluated as an 1671 * XPath expression and the result is stored in the context's global 1672 * variable/parameter hash table. 1673 * 1674 * To have a parameter treated literally (not as an XPath expression) 1675 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more 1676 * details see description of xsltProcessOneUserParamInternal. 1677 * 1678 * Returns 0 in case of success, -1 in case of error. 1679 */ 1680 1681 int 1682 xsltEvalOneUserParam(xsltTransformContextPtr ctxt, 1683 const xmlChar * name, 1684 const xmlChar * value) { 1685 return xsltProcessUserParamInternal(ctxt, name, value, 1686 1 /* xpath eval ? */); 1687 } 1688 1689 /** 1690 * xsltQuoteOneUserParam: 1691 * @ctxt: the XSLT transformation context 1692 * @name: a null terminated string giving the name of the parameter 1693 * @value: a null terminated string giving the parameter value 1694 * 1695 * This is normally called from xsltQuoteUserParams to process a single 1696 * parameter from a list of parameters. The @value is stored in the 1697 * context's global variable/parameter hash table. 1698 * 1699 * Returns 0 in case of success, -1 in case of error. 1700 */ 1701 1702 int 1703 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt, 1704 const xmlChar * name, 1705 const xmlChar * value) { 1706 return xsltProcessUserParamInternal(ctxt, name, value, 1707 0 /* xpath eval ? */); 1708 } 1709 1710 /** 1711 * xsltBuildVariable: 1712 * @ctxt: the XSLT transformation context 1713 * @comp: the precompiled form 1714 * @tree: the tree if select is NULL 1715 * 1716 * Computes a new variable value. 1717 * 1718 * Returns the xsltStackElemPtr or NULL in case of error 1719 */ 1720 static xsltStackElemPtr 1721 xsltBuildVariable(xsltTransformContextPtr ctxt, 1722 xsltStylePreCompPtr castedComp, 1723 xmlNodePtr tree) 1724 { 1725 #ifdef XSLT_REFACTORED 1726 xsltStyleBasicItemVariablePtr comp = 1727 (xsltStyleBasicItemVariablePtr) castedComp; 1728 #else 1729 xsltStylePreCompPtr comp = castedComp; 1730 #endif 1731 xsltStackElemPtr elem; 1732 1733 #ifdef WITH_XSLT_DEBUG_VARIABLE 1734 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1735 "Building variable %s", comp->name)); 1736 if (comp->select != NULL) 1737 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1738 " select %s", comp->select)); 1739 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n")); 1740 #endif 1741 1742 elem = xsltNewStackElem(ctxt); 1743 if (elem == NULL) 1744 return(NULL); 1745 elem->comp = (xsltStylePreCompPtr) comp; 1746 elem->name = comp->name; 1747 elem->select = comp->select; 1748 elem->nameURI = comp->ns; 1749 elem->tree = tree; 1750 elem->value = xsltEvalVariable(ctxt, elem, 1751 (xsltStylePreCompPtr) comp); 1752 if (elem->value != NULL) 1753 elem->computed = 1; 1754 return(elem); 1755 } 1756 1757 /** 1758 * xsltRegisterVariable: 1759 * @ctxt: the XSLT transformation context 1760 * @comp: the compiled XSLT-variable (or param) instruction 1761 * @tree: the tree if select is NULL 1762 * @isParam: indicates if this is a parameter 1763 * 1764 * Computes and registers a new variable. 1765 * 1766 * Returns 0 in case of success, -1 in case of error 1767 */ 1768 static int 1769 xsltRegisterVariable(xsltTransformContextPtr ctxt, 1770 xsltStylePreCompPtr castedComp, 1771 xmlNodePtr tree, int isParam) 1772 { 1773 #ifdef XSLT_REFACTORED 1774 xsltStyleBasicItemVariablePtr comp = 1775 (xsltStyleBasicItemVariablePtr) castedComp; 1776 #else 1777 xsltStylePreCompPtr comp = castedComp; 1778 int present; 1779 #endif 1780 xsltStackElemPtr variable; 1781 1782 #ifdef XSLT_REFACTORED 1783 /* 1784 * REFACTORED NOTE: Redefinitions of vars/params are checked 1785 * at compilation time in the refactored code. 1786 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate(). 1787 */ 1788 #else 1789 present = xsltCheckStackElem(ctxt, comp->name, comp->ns); 1790 if (isParam == 0) { 1791 if ((present != 0) && (present != 3)) { 1792 /* TODO: report QName. */ 1793 xsltTransformError(ctxt, NULL, comp->inst, 1794 "XSLT-variable: Redefinition of variable '%s'.\n", comp->name); 1795 return(0); 1796 } 1797 } else if (present != 0) { 1798 if ((present == 1) || (present == 2)) { 1799 /* TODO: report QName. */ 1800 xsltTransformError(ctxt, NULL, comp->inst, 1801 "XSLT-param: Redefinition of parameter '%s'.\n", comp->name); 1802 return(0); 1803 } 1804 #ifdef WITH_XSLT_DEBUG_VARIABLE 1805 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1806 "param %s defined by caller\n", comp->name)); 1807 #endif 1808 return(0); 1809 } 1810 #endif /* else of XSLT_REFACTORED */ 1811 1812 variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); 1813 xsltAddStackElem(ctxt, variable); 1814 return(0); 1815 } 1816 1817 /** 1818 * xsltGlobalVariableLookup: 1819 * @ctxt: the XSLT transformation context 1820 * @name: the variable name 1821 * @ns_uri: the variable namespace URI 1822 * 1823 * Search in the Variable array of the context for the given 1824 * variable value. 1825 * 1826 * Returns the value or NULL if not found 1827 */ 1828 static xmlXPathObjectPtr 1829 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 1830 const xmlChar *ns_uri) { 1831 xsltStackElemPtr elem; 1832 xmlXPathObjectPtr ret = NULL; 1833 1834 /* 1835 * Lookup the global variables in XPath global variable hash table 1836 */ 1837 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL)) 1838 return(NULL); 1839 elem = (xsltStackElemPtr) 1840 xmlHashLookup2(ctxt->globalVars, name, ns_uri); 1841 if (elem == NULL) { 1842 #ifdef WITH_XSLT_DEBUG_VARIABLE 1843 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1844 "global variable not found %s\n", name)); 1845 #endif 1846 return(NULL); 1847 } 1848 /* 1849 * URGENT TODO: Move the detection of recursive definitions 1850 * to compile-time. 1851 */ 1852 if (elem->computed == 0) { 1853 if (elem->name == xsltComputingGlobalVarMarker) { 1854 xsltTransformError(ctxt, NULL, elem->comp->inst, 1855 "Recursive definition of %s\n", name); 1856 return(NULL); 1857 } 1858 ret = xsltEvalGlobalVariable(elem, ctxt); 1859 } else 1860 ret = elem->value; 1861 return(xmlXPathObjectCopy(ret)); 1862 } 1863 1864 /** 1865 * xsltVariableLookup: 1866 * @ctxt: the XSLT transformation context 1867 * @name: the variable name 1868 * @ns_uri: the variable namespace URI 1869 * 1870 * Search in the Variable array of the context for the given 1871 * variable value. 1872 * 1873 * Returns the value or NULL if not found 1874 */ 1875 xmlXPathObjectPtr 1876 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 1877 const xmlChar *ns_uri) { 1878 xsltStackElemPtr elem; 1879 1880 if (ctxt == NULL) 1881 return(NULL); 1882 1883 elem = xsltStackLookup(ctxt, name, ns_uri); 1884 if (elem == NULL) { 1885 return(xsltGlobalVariableLookup(ctxt, name, ns_uri)); 1886 } 1887 if (elem->computed == 0) { 1888 #ifdef WITH_XSLT_DEBUG_VARIABLE 1889 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1890 "uncomputed variable %s\n", name)); 1891 #endif 1892 elem->value = xsltEvalVariable(ctxt, elem, NULL); 1893 elem->computed = 1; 1894 } 1895 if (elem->value != NULL) 1896 return(xmlXPathObjectCopy(elem->value)); 1897 #ifdef WITH_XSLT_DEBUG_VARIABLE 1898 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1899 "variable not found %s\n", name)); 1900 #endif 1901 return(NULL); 1902 } 1903 1904 /** 1905 * xsltParseStylesheetCallerParam: 1906 * @ctxt: the XSLT transformation context 1907 * @inst: the xsl:with-param instruction element 1908 * 1909 * Processes an xsl:with-param instruction at transformation time. 1910 * The value is compute, but not recorded. 1911 * NOTE that this is also called with an *xsl:param* element 1912 * from exsltFuncFunctionFunction(). 1913 * 1914 * Returns the new xsltStackElemPtr or NULL 1915 */ 1916 1917 xsltStackElemPtr 1918 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst) 1919 { 1920 #ifdef XSLT_REFACTORED 1921 xsltStyleBasicItemVariablePtr comp; 1922 #else 1923 xsltStylePreCompPtr comp; 1924 #endif 1925 xmlNodePtr tree = NULL; /* The first child node of the instruction or 1926 the instruction itself. */ 1927 xsltStackElemPtr param = NULL; 1928 1929 if ((ctxt == NULL) || (inst == NULL)) 1930 return(NULL); 1931 1932 #ifdef XSLT_REFACTORED 1933 comp = (xsltStyleBasicItemVariablePtr) inst->psvi; 1934 #else 1935 comp = (xsltStylePreCompPtr) inst->psvi; 1936 #endif 1937 1938 if (comp == NULL) { 1939 xsltTransformError(ctxt, NULL, inst, 1940 "Internal error in xsltParseStylesheetCallerParam(): " 1941 "The XSLT 'with-param' instruction was not compiled.\n"); 1942 return(NULL); 1943 } 1944 if (comp->name == NULL) { 1945 xsltTransformError(ctxt, NULL, inst, 1946 "Internal error in xsltParseStylesheetCallerParam(): " 1947 "XSLT 'with-param': The attribute 'name' was not compiled.\n"); 1948 return(NULL); 1949 } 1950 1951 #ifdef WITH_XSLT_DEBUG_VARIABLE 1952 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1953 "Handling xsl:with-param %s\n", comp->name)); 1954 #endif 1955 1956 if (comp->select == NULL) { 1957 tree = inst->children; 1958 } else { 1959 #ifdef WITH_XSLT_DEBUG_VARIABLE 1960 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 1961 " select %s\n", comp->select)); 1962 #endif 1963 tree = inst; 1964 } 1965 1966 param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); 1967 1968 return(param); 1969 } 1970 1971 /** 1972 * xsltParseGlobalVariable: 1973 * @style: the XSLT stylesheet 1974 * @cur: the "variable" element 1975 * 1976 * Parses a global XSLT 'variable' declaration at compilation time 1977 * and registers it 1978 */ 1979 void 1980 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) 1981 { 1982 #ifdef XSLT_REFACTORED 1983 xsltStyleItemVariablePtr comp; 1984 #else 1985 xsltStylePreCompPtr comp; 1986 #endif 1987 1988 if ((cur == NULL) || (style == NULL)) 1989 return; 1990 1991 #ifdef XSLT_REFACTORED 1992 /* 1993 * Note that xsltStylePreCompute() will be called from 1994 * xslt.c only. 1995 */ 1996 comp = (xsltStyleItemVariablePtr) cur->psvi; 1997 #else 1998 xsltStylePreCompute(style, cur); 1999 comp = (xsltStylePreCompPtr) cur->psvi; 2000 #endif 2001 if (comp == NULL) { 2002 xsltTransformError(NULL, style, cur, 2003 "xsl:variable : compilation failed\n"); 2004 return; 2005 } 2006 2007 if (comp->name == NULL) { 2008 xsltTransformError(NULL, style, cur, 2009 "xsl:variable : missing name attribute\n"); 2010 return; 2011 } 2012 2013 /* 2014 * Parse the content (a sequence constructor) of xsl:variable. 2015 */ 2016 if (cur->children != NULL) { 2017 #ifdef XSLT_REFACTORED 2018 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); 2019 #else 2020 xsltParseTemplateContent(style, cur); 2021 #endif 2022 } 2023 #ifdef WITH_XSLT_DEBUG_VARIABLE 2024 xsltGenericDebug(xsltGenericDebugContext, 2025 "Registering global variable %s\n", comp->name); 2026 #endif 2027 2028 xsltRegisterGlobalVariable(style, comp->name, comp->ns, 2029 comp->select, cur->children, (xsltStylePreCompPtr) comp, 2030 NULL); 2031 } 2032 2033 /** 2034 * xsltParseGlobalParam: 2035 * @style: the XSLT stylesheet 2036 * @cur: the "param" element 2037 * 2038 * parse an XSLT transformation param declaration and record 2039 * its value. 2040 */ 2041 2042 void 2043 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { 2044 #ifdef XSLT_REFACTORED 2045 xsltStyleItemParamPtr comp; 2046 #else 2047 xsltStylePreCompPtr comp; 2048 #endif 2049 2050 if ((cur == NULL) || (style == NULL)) 2051 return; 2052 2053 #ifdef XSLT_REFACTORED 2054 /* 2055 * Note that xsltStylePreCompute() will be called from 2056 * xslt.c only. 2057 */ 2058 comp = (xsltStyleItemParamPtr) cur->psvi; 2059 #else 2060 xsltStylePreCompute(style, cur); 2061 comp = (xsltStylePreCompPtr) cur->psvi; 2062 #endif 2063 if (comp == NULL) { 2064 xsltTransformError(NULL, style, cur, 2065 "xsl:param : compilation failed\n"); 2066 return; 2067 } 2068 2069 if (comp->name == NULL) { 2070 xsltTransformError(NULL, style, cur, 2071 "xsl:param : missing name attribute\n"); 2072 return; 2073 } 2074 2075 /* 2076 * Parse the content (a sequence constructor) of xsl:param. 2077 */ 2078 if (cur->children != NULL) { 2079 #ifdef XSLT_REFACTORED 2080 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); 2081 #else 2082 xsltParseTemplateContent(style, cur); 2083 #endif 2084 } 2085 2086 #ifdef WITH_XSLT_DEBUG_VARIABLE 2087 xsltGenericDebug(xsltGenericDebugContext, 2088 "Registering global param %s\n", comp->name); 2089 #endif 2090 2091 xsltRegisterGlobalVariable(style, comp->name, comp->ns, 2092 comp->select, cur->children, (xsltStylePreCompPtr) comp, 2093 NULL); 2094 } 2095 2096 /** 2097 * xsltParseStylesheetVariable: 2098 * @ctxt: the XSLT transformation context 2099 * @inst: the xsl:variable instruction element 2100 * 2101 * Registers a local XSLT 'variable' instruction at transformation time 2102 * and evaluates its value. 2103 */ 2104 void 2105 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst) 2106 { 2107 #ifdef XSLT_REFACTORED 2108 xsltStyleItemVariablePtr comp; 2109 #else 2110 xsltStylePreCompPtr comp; 2111 #endif 2112 2113 if ((inst == NULL) || (ctxt == NULL)) 2114 return; 2115 2116 comp = inst->psvi; 2117 if (comp == NULL) { 2118 xsltTransformError(ctxt, NULL, inst, 2119 "Internal error in xsltParseStylesheetVariable(): " 2120 "The XSLT 'variable' instruction was not compiled.\n"); 2121 return; 2122 } 2123 if (comp->name == NULL) { 2124 xsltTransformError(ctxt, NULL, inst, 2125 "Internal error in xsltParseStylesheetVariable(): " 2126 "The attribute 'name' was not compiled.\n"); 2127 return; 2128 } 2129 2130 #ifdef WITH_XSLT_DEBUG_VARIABLE 2131 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2132 "Registering variable '%s'\n", comp->name)); 2133 #endif 2134 2135 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0); 2136 } 2137 2138 /** 2139 * xsltParseStylesheetParam: 2140 * @ctxt: the XSLT transformation context 2141 * @cur: the XSLT 'param' element 2142 * 2143 * Registers a local XSLT 'param' declaration at transformation time and 2144 * evaluates its value. 2145 */ 2146 void 2147 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) 2148 { 2149 #ifdef XSLT_REFACTORED 2150 xsltStyleItemParamPtr comp; 2151 #else 2152 xsltStylePreCompPtr comp; 2153 #endif 2154 2155 if ((cur == NULL) || (ctxt == NULL)) 2156 return; 2157 2158 comp = cur->psvi; 2159 if ((comp == NULL) || (comp->name == NULL)) { 2160 xsltTransformError(ctxt, NULL, cur, 2161 "Internal error in xsltParseStylesheetParam(): " 2162 "The XSLT 'param' declaration was not compiled correctly.\n"); 2163 return; 2164 } 2165 2166 #ifdef WITH_XSLT_DEBUG_VARIABLE 2167 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2168 "Registering param %s\n", comp->name)); 2169 #endif 2170 2171 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1); 2172 } 2173 2174 /** 2175 * xsltFreeGlobalVariables: 2176 * @ctxt: the XSLT transformation context 2177 * 2178 * Free up the data associated to the global variables 2179 * its value. 2180 */ 2181 2182 void 2183 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) { 2184 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem); 2185 } 2186 2187 /** 2188 * xsltXPathVariableLookup: 2189 * @ctxt: a void * but the the XSLT transformation context actually 2190 * @name: the variable name 2191 * @ns_uri: the variable namespace URI 2192 * 2193 * This is the entry point when a varibale is needed by the XPath 2194 * interpretor. 2195 * 2196 * Returns the value or NULL if not found 2197 */ 2198 xmlXPathObjectPtr 2199 xsltXPathVariableLookup(void *ctxt, const xmlChar *name, 2200 const xmlChar *ns_uri) { 2201 xsltTransformContextPtr tctxt; 2202 xmlXPathObjectPtr valueObj = NULL; 2203 2204 if ((ctxt == NULL) || (name == NULL)) 2205 return(NULL); 2206 2207 #ifdef WITH_XSLT_DEBUG_VARIABLE 2208 XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2209 "Lookup variable '%s'\n", name)); 2210 #endif 2211 2212 tctxt = (xsltTransformContextPtr) ctxt; 2213 /* 2214 * Local variables/params --------------------------------------------- 2215 * 2216 * Do the lookup from the top of the stack, but 2217 * don't use params being computed in a call-param 2218 * First lookup expects the variable name and URI to 2219 * come from the disctionnary and hence pointer comparison. 2220 */ 2221 if (tctxt->varsNr != 0) { 2222 int i; 2223 xsltStackElemPtr variable = NULL, cur; 2224 2225 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { 2226 cur = tctxt->varsTab[i-1]; 2227 if ((cur->name == name) && (cur->nameURI == ns_uri)) { 2228 #if 0 2229 stack_addr++; 2230 #endif 2231 variable = cur; 2232 goto local_variable_found; 2233 } 2234 cur = cur->next; 2235 } 2236 /* 2237 * Redo the lookup with interned strings to avoid string comparison. 2238 * 2239 * OPTIMIZE TODO: The problem here is, that if we request a 2240 * global variable, then this will be also executed. 2241 */ 2242 { 2243 const xmlChar *tmpName = name, *tmpNsName = ns_uri; 2244 2245 name = xmlDictLookup(tctxt->dict, name, -1); 2246 if (ns_uri) 2247 ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1); 2248 if ((tmpName != name) || (tmpNsName != ns_uri)) { 2249 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { 2250 cur = tctxt->varsTab[i-1]; 2251 if ((cur->name == name) && (cur->nameURI == ns_uri)) { 2252 #if 0 2253 stack_cmp++; 2254 #endif 2255 variable = cur; 2256 goto local_variable_found; 2257 } 2258 } 2259 } 2260 } 2261 2262 local_variable_found: 2263 2264 if (variable) { 2265 if (variable->computed == 0) { 2266 2267 #ifdef WITH_XSLT_DEBUG_VARIABLE 2268 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2269 "uncomputed variable '%s'\n", name)); 2270 #endif 2271 variable->value = xsltEvalVariable(tctxt, variable, NULL); 2272 variable->computed = 1; 2273 } 2274 if (variable->value != NULL) { 2275 valueObj = xmlXPathObjectCopy(variable->value); 2276 } 2277 return(valueObj); 2278 } 2279 } 2280 /* 2281 * Global variables/params -------------------------------------------- 2282 */ 2283 if (tctxt->globalVars) { 2284 valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri); 2285 } 2286 2287 if (valueObj == NULL) { 2288 2289 #ifdef WITH_XSLT_DEBUG_VARIABLE 2290 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2291 "variable not found '%s'\n", name)); 2292 #endif 2293 2294 if (ns_uri) { 2295 xsltTransformError(tctxt, NULL, tctxt->inst, 2296 "Variable '{%s}%s' has not been declared.\n", ns_uri, name); 2297 } else { 2298 xsltTransformError(tctxt, NULL, tctxt->inst, 2299 "Variable '%s' has not been declared.\n", name); 2300 } 2301 } else { 2302 2303 #ifdef WITH_XSLT_DEBUG_VARIABLE 2304 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 2305 "found variable '%s'\n", name)); 2306 #endif 2307 } 2308 2309 return(valueObj); 2310 } 2311 2312 2313