1 /* 2 * transform.c: Implementation of the XSL Transformation 1.0 engine 3 * transform part, i.e. applying a Stylesheet to a document 4 * 5 * References: 6 * http://www.w3.org/TR/1999/REC-xslt-19991116 7 * 8 * Michael Kay "XSLT Programmer's Reference" pp 637-643 9 * Writing Multiple Output Files 10 * 11 * XSLT-1.1 Working Draft 12 * http://www.w3.org/TR/xslt11#multiple-output 13 * 14 * See Copyright for the status of this software. 15 * 16 * daniel (at) veillard.com 17 */ 18 19 #define IN_LIBXSLT 20 #include "libxslt.h" 21 22 #include <string.h> 23 24 #include <libxml/xmlmemory.h> 25 #include <libxml/parser.h> 26 #include <libxml/tree.h> 27 #include <libxml/valid.h> 28 #include <libxml/hash.h> 29 #include <libxml/encoding.h> 30 #include <libxml/xmlerror.h> 31 #include <libxml/xpath.h> 32 #include <libxml/parserInternals.h> 33 #include <libxml/xpathInternals.h> 34 #include <libxml/HTMLtree.h> 35 #include <libxml/debugXML.h> 36 #include <libxml/uri.h> 37 #include "xslt.h" 38 #include "xsltInternals.h" 39 #include "xsltutils.h" 40 #include "pattern.h" 41 #include "transform.h" 42 #include "variables.h" 43 #include "numbersInternals.h" 44 #include "namespaces.h" 45 #include "attributes.h" 46 #include "templates.h" 47 #include "imports.h" 48 #include "keys.h" 49 #include "documents.h" 50 #include "extensions.h" 51 #include "extra.h" 52 #include "preproc.h" 53 #include "security.h" 54 55 #ifdef WITH_XSLT_DEBUG 56 #define WITH_XSLT_DEBUG_EXTRA 57 #define WITH_XSLT_DEBUG_PROCESS 58 #endif 59 60 #define XSLT_GENERATE_HTML_DOCTYPE 61 #ifdef XSLT_GENERATE_HTML_DOCTYPE 62 static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, 63 const xmlChar **systemID); 64 #endif 65 66 int xsltMaxDepth = 3000; 67 68 /* 69 * Useful macros 70 */ 71 72 #ifndef FALSE 73 # define FALSE (0 == 1) 74 # define TRUE (!FALSE) 75 #endif 76 77 #define IS_BLANK_NODE(n) \ 78 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) 79 80 81 /* 82 * Forward declarations 83 */ 84 85 static xmlNsPtr 86 xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); 87 88 static xmlNodePtr 89 xsltCopyTreeInternal(xsltTransformContextPtr ctxt, 90 xmlNodePtr invocNode, 91 xmlNodePtr node, 92 xmlNodePtr insert, int isLRE, int topElemVisited); 93 94 static void 95 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, 96 xmlNodePtr contextNode, xmlNodePtr list, 97 xsltTemplatePtr templ); 98 99 static void 100 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, 101 xmlNodePtr contextNode, 102 xmlNodePtr list, 103 xsltTemplatePtr templ, 104 xsltStackElemPtr withParams); 105 106 /** 107 * templPush: 108 * @ctxt: the transformation context 109 * @value: the template to push on the stack 110 * 111 * Push a template on the stack 112 * 113 * Returns the new index in the stack or 0 in case of error 114 */ 115 static int 116 templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) 117 { 118 if (ctxt->templMax == 0) { 119 ctxt->templMax = 4; 120 ctxt->templTab = 121 (xsltTemplatePtr *) xmlMalloc(ctxt->templMax * 122 sizeof(ctxt->templTab[0])); 123 if (ctxt->templTab == NULL) { 124 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 125 return (0); 126 } 127 } 128 if (ctxt->templNr >= ctxt->templMax) { 129 ctxt->templMax *= 2; 130 ctxt->templTab = 131 (xsltTemplatePtr *) xmlRealloc(ctxt->templTab, 132 ctxt->templMax * 133 sizeof(ctxt->templTab[0])); 134 if (ctxt->templTab == NULL) { 135 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 136 return (0); 137 } 138 } 139 ctxt->templTab[ctxt->templNr] = value; 140 ctxt->templ = value; 141 return (ctxt->templNr++); 142 } 143 /** 144 * templPop: 145 * @ctxt: the transformation context 146 * 147 * Pop a template value from the stack 148 * 149 * Returns the stored template value 150 */ 151 static xsltTemplatePtr 152 templPop(xsltTransformContextPtr ctxt) 153 { 154 xsltTemplatePtr ret; 155 156 if (ctxt->templNr <= 0) 157 return (0); 158 ctxt->templNr--; 159 if (ctxt->templNr > 0) 160 ctxt->templ = ctxt->templTab[ctxt->templNr - 1]; 161 else 162 ctxt->templ = (xsltTemplatePtr) 0; 163 ret = ctxt->templTab[ctxt->templNr]; 164 ctxt->templTab[ctxt->templNr] = 0; 165 return (ret); 166 } 167 168 /** 169 * xsltLocalVariablePop: 170 * @ctxt: the transformation context 171 * @limitNr: number of variables which should remain 172 * @level: the depth in the xsl:template's tree 173 * 174 * Pops all variable values at the given @depth from the stack. 175 * 176 * Returns the stored variable value 177 * **NOTE:** 178 * This is an internal routine and should not be called by users! 179 */ 180 void 181 xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level) 182 { 183 xsltStackElemPtr variable; 184 185 if (ctxt->varsNr <= 0) 186 return; 187 188 do { 189 if (ctxt->varsNr <= limitNr) 190 break; 191 variable = ctxt->varsTab[ctxt->varsNr - 1]; 192 if (variable->level <= level) 193 break; 194 if (variable->level >= 0) 195 xsltFreeStackElemList(variable); 196 ctxt->varsNr--; 197 } while (ctxt->varsNr != 0); 198 if (ctxt->varsNr > 0) 199 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; 200 else 201 ctxt->vars = NULL; 202 } 203 204 /** 205 * xsltTemplateParamsCleanup: 206 * 207 * Removes xsl:param and xsl:with-param items from the 208 * variable-stack. Only xsl:with-param items are not freed. 209 */ 210 static void 211 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt) 212 { 213 xsltStackElemPtr param; 214 215 for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) { 216 param = ctxt->varsTab[ctxt->varsNr -1]; 217 /* 218 * Free xsl:param items. 219 * xsl:with-param items will have a level of -1 or -2. 220 */ 221 if (param->level >= 0) { 222 xsltFreeStackElemList(param); 223 } 224 } 225 if (ctxt->varsNr > 0) 226 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; 227 else 228 ctxt->vars = NULL; 229 } 230 231 /** 232 * profPush: 233 * @ctxt: the transformation context 234 * @value: the profiling value to push on the stack 235 * 236 * Push a profiling value on the stack 237 * 238 * Returns the new index in the stack or 0 in case of error 239 */ 240 static int 241 profPush(xsltTransformContextPtr ctxt, long value) 242 { 243 if (ctxt->profMax == 0) { 244 ctxt->profMax = 4; 245 ctxt->profTab = 246 (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0])); 247 if (ctxt->profTab == NULL) { 248 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 249 return (0); 250 } 251 } 252 if (ctxt->profNr >= ctxt->profMax) { 253 ctxt->profMax *= 2; 254 ctxt->profTab = 255 (long *) xmlRealloc(ctxt->profTab, 256 ctxt->profMax * sizeof(ctxt->profTab[0])); 257 if (ctxt->profTab == NULL) { 258 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 259 return (0); 260 } 261 } 262 ctxt->profTab[ctxt->profNr] = value; 263 ctxt->prof = value; 264 return (ctxt->profNr++); 265 } 266 /** 267 * profPop: 268 * @ctxt: the transformation context 269 * 270 * Pop a profiling value from the stack 271 * 272 * Returns the stored profiling value 273 */ 274 static long 275 profPop(xsltTransformContextPtr ctxt) 276 { 277 long ret; 278 279 if (ctxt->profNr <= 0) 280 return (0); 281 ctxt->profNr--; 282 if (ctxt->profNr > 0) 283 ctxt->prof = ctxt->profTab[ctxt->profNr - 1]; 284 else 285 ctxt->prof = (long) 0; 286 ret = ctxt->profTab[ctxt->profNr]; 287 ctxt->profTab[ctxt->profNr] = 0; 288 return (ret); 289 } 290 291 /************************************************************************ 292 * * 293 * XInclude default settings * 294 * * 295 ************************************************************************/ 296 297 static int xsltDoXIncludeDefault = 0; 298 299 /** 300 * xsltSetXIncludeDefault: 301 * @xinclude: whether to do XInclude processing 302 * 303 * Set whether XInclude should be processed on document being loaded by default 304 */ 305 void 306 xsltSetXIncludeDefault(int xinclude) { 307 xsltDoXIncludeDefault = (xinclude != 0); 308 } 309 310 /** 311 * xsltGetXIncludeDefault: 312 * 313 * Provides the default state for XInclude processing 314 * 315 * Returns 0 if there is no processing 1 otherwise 316 */ 317 int 318 xsltGetXIncludeDefault(void) { 319 return(xsltDoXIncludeDefault); 320 } 321 322 unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; 323 324 /** 325 * xsltDebugSetDefaultTrace: 326 * @val: tracing level mask 327 * 328 * Set the default debug tracing level mask 329 */ 330 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) { 331 xsltDefaultTrace = val; 332 } 333 334 /** 335 * xsltDebugGetDefaultTrace: 336 * 337 * Get the current default debug tracing level mask 338 * 339 * Returns the current default debug tracing level mask 340 */ 341 xsltDebugTraceCodes xsltDebugGetDefaultTrace() { 342 return xsltDefaultTrace; 343 } 344 345 /************************************************************************ 346 * * 347 * Handling of Transformation Contexts * 348 * * 349 ************************************************************************/ 350 351 static xsltTransformCachePtr 352 xsltTransformCacheCreate(void) 353 { 354 xsltTransformCachePtr ret; 355 356 ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache)); 357 if (ret == NULL) { 358 xsltTransformError(NULL, NULL, NULL, 359 "xsltTransformCacheCreate : malloc failed\n"); 360 return(NULL); 361 } 362 memset(ret, 0, sizeof(xsltTransformCache)); 363 return(ret); 364 } 365 366 static void 367 xsltTransformCacheFree(xsltTransformCachePtr cache) 368 { 369 if (cache == NULL) 370 return; 371 /* 372 * Free tree fragments. 373 */ 374 if (cache->RVT) { 375 xmlDocPtr tmp, cur = cache->RVT; 376 while (cur) { 377 tmp = cur; 378 cur = (xmlDocPtr) cur->next; 379 if (tmp->_private != NULL) { 380 /* 381 * Tree the document info. 382 */ 383 xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); 384 xmlFree(tmp->_private); 385 } 386 xmlFreeDoc(tmp); 387 } 388 } 389 /* 390 * Free vars/params. 391 */ 392 if (cache->stackItems) { 393 xsltStackElemPtr tmp, cur = cache->stackItems; 394 while (cur) { 395 tmp = cur; 396 cur = cur->next; 397 /* 398 * REVISIT TODO: Should be call a destruction-function 399 * instead? 400 */ 401 xmlFree(tmp); 402 } 403 } 404 xmlFree(cache); 405 } 406 407 /** 408 * xsltNewTransformContext: 409 * @style: a parsed XSLT stylesheet 410 * @doc: the input document 411 * 412 * Create a new XSLT TransformContext 413 * 414 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error 415 */ 416 xsltTransformContextPtr 417 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { 418 xsltTransformContextPtr cur; 419 xsltDocumentPtr docu; 420 int i; 421 422 xsltInitGlobals(); 423 424 cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext)); 425 if (cur == NULL) { 426 xsltTransformError(NULL, NULL, (xmlNodePtr)doc, 427 "xsltNewTransformContext : malloc failed\n"); 428 return(NULL); 429 } 430 memset(cur, 0, sizeof(xsltTransformContext)); 431 432 cur->cache = xsltTransformCacheCreate(); 433 if (cur->cache == NULL) 434 goto internal_err; 435 /* 436 * setup of the dictionary must be done early as some of the 437 * processing later like key handling may need it. 438 */ 439 cur->dict = xmlDictCreateSub(style->dict); 440 cur->internalized = ((style->internalized) && (cur->dict != NULL)); 441 #ifdef WITH_XSLT_DEBUG 442 xsltGenericDebug(xsltGenericDebugContext, 443 "Creating sub-dictionary from stylesheet for transformation\n"); 444 #endif 445 446 /* 447 * initialize the template stack 448 */ 449 cur->templTab = (xsltTemplatePtr *) 450 xmlMalloc(10 * sizeof(xsltTemplatePtr)); 451 if (cur->templTab == NULL) { 452 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 453 "xsltNewTransformContext: out of memory\n"); 454 goto internal_err; 455 } 456 cur->templNr = 0; 457 cur->templMax = 5; 458 cur->templ = NULL; 459 460 /* 461 * initialize the variables stack 462 */ 463 cur->varsTab = (xsltStackElemPtr *) 464 xmlMalloc(10 * sizeof(xsltStackElemPtr)); 465 if (cur->varsTab == NULL) { 466 xmlGenericError(xmlGenericErrorContext, 467 "xsltNewTransformContext: out of memory\n"); 468 goto internal_err; 469 } 470 cur->varsNr = 0; 471 cur->varsMax = 10; 472 cur->vars = NULL; 473 cur->varsBase = 0; 474 475 /* 476 * the profiling stack is not initialized by default 477 */ 478 cur->profTab = NULL; 479 cur->profNr = 0; 480 cur->profMax = 0; 481 cur->prof = 0; 482 483 cur->style = style; 484 xmlXPathInit(); 485 cur->xpathCtxt = xmlXPathNewContext(doc); 486 if (cur->xpathCtxt == NULL) { 487 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 488 "xsltNewTransformContext : xmlXPathNewContext failed\n"); 489 goto internal_err; 490 } 491 /* 492 * Create an XPath cache. 493 */ 494 if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1) 495 goto internal_err; 496 /* 497 * Initialize the extras array 498 */ 499 if (style->extrasNr != 0) { 500 cur->extrasMax = style->extrasNr + 20; 501 cur->extras = (xsltRuntimeExtraPtr) 502 xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra)); 503 if (cur->extras == NULL) { 504 xmlGenericError(xmlGenericErrorContext, 505 "xsltNewTransformContext: out of memory\n"); 506 goto internal_err; 507 } 508 cur->extrasNr = style->extrasNr; 509 for (i = 0;i < cur->extrasMax;i++) { 510 cur->extras[i].info = NULL; 511 cur->extras[i].deallocate = NULL; 512 cur->extras[i].val.ptr = NULL; 513 } 514 } else { 515 cur->extras = NULL; 516 cur->extrasNr = 0; 517 cur->extrasMax = 0; 518 } 519 520 XSLT_REGISTER_VARIABLE_LOOKUP(cur); 521 XSLT_REGISTER_FUNCTION_LOOKUP(cur); 522 cur->xpathCtxt->nsHash = style->nsHash; 523 /* 524 * Initialize the registered external modules 525 */ 526 xsltInitCtxtExts(cur); 527 /* 528 * Setup document element ordering for later efficiencies 529 * (bug 133289) 530 */ 531 if (xslDebugStatus == XSLT_DEBUG_NONE) 532 xmlXPathOrderDocElems(doc); 533 /* 534 * Must set parserOptions before calling xsltNewDocument 535 * (bug 164530) 536 */ 537 cur->parserOptions = XSLT_PARSE_OPTIONS; 538 docu = xsltNewDocument(cur, doc); 539 if (docu == NULL) { 540 xsltTransformError(cur, NULL, (xmlNodePtr)doc, 541 "xsltNewTransformContext : xsltNewDocument failed\n"); 542 goto internal_err; 543 } 544 docu->main = 1; 545 cur->document = docu; 546 cur->inst = NULL; 547 cur->outputFile = NULL; 548 cur->sec = xsltGetDefaultSecurityPrefs(); 549 cur->debugStatus = xslDebugStatus; 550 cur->traceCode = (unsigned long*) &xsltDefaultTrace; 551 cur->xinclude = xsltGetXIncludeDefault(); 552 cur->keyInitLevel = 0; 553 554 return(cur); 555 556 internal_err: 557 if (cur != NULL) 558 xsltFreeTransformContext(cur); 559 return(NULL); 560 } 561 562 /** 563 * xsltFreeTransformContext: 564 * @ctxt: an XSLT parser context 565 * 566 * Free up the memory allocated by @ctxt 567 */ 568 void 569 xsltFreeTransformContext(xsltTransformContextPtr ctxt) { 570 if (ctxt == NULL) 571 return; 572 573 /* 574 * Shutdown the extension modules associated to the stylesheet 575 * used if needed. 576 */ 577 xsltShutdownCtxtExts(ctxt); 578 579 if (ctxt->xpathCtxt != NULL) { 580 ctxt->xpathCtxt->nsHash = NULL; 581 xmlXPathFreeContext(ctxt->xpathCtxt); 582 } 583 if (ctxt->templTab != NULL) 584 xmlFree(ctxt->templTab); 585 if (ctxt->varsTab != NULL) 586 xmlFree(ctxt->varsTab); 587 if (ctxt->profTab != NULL) 588 xmlFree(ctxt->profTab); 589 if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) { 590 int i; 591 592 for (i = 0;i < ctxt->extrasNr;i++) { 593 if ((ctxt->extras[i].deallocate != NULL) && 594 (ctxt->extras[i].info != NULL)) 595 ctxt->extras[i].deallocate(ctxt->extras[i].info); 596 } 597 xmlFree(ctxt->extras); 598 } 599 xsltFreeGlobalVariables(ctxt); 600 xsltFreeDocuments(ctxt); 601 xsltFreeCtxtExts(ctxt); 602 xsltFreeRVTs(ctxt); 603 xsltTransformCacheFree(ctxt->cache); 604 xmlDictFree(ctxt->dict); 605 #ifdef WITH_XSLT_DEBUG 606 xsltGenericDebug(xsltGenericDebugContext, 607 "freeing transformation dictionary\n"); 608 #endif 609 memset(ctxt, -1, sizeof(xsltTransformContext)); 610 xmlFree(ctxt); 611 } 612 613 /************************************************************************ 614 * * 615 * Copy of Nodes in an XSLT fashion * 616 * * 617 ************************************************************************/ 618 619 xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, 620 xmlNodePtr node, xmlNodePtr insert, int literal); 621 622 /** 623 * xsltAddChild: 624 * @parent: the parent node 625 * @cur: the child node 626 * 627 * Wrapper version of xmlAddChild with a more consistent behaviour on 628 * error. One expect the use to be child = xsltAddChild(parent, child); 629 * and the routine will take care of not leaking on errors or node merge 630 * 631 * Returns the child is successfully attached or NULL if merged or freed 632 */ 633 static xmlNodePtr 634 xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { 635 xmlNodePtr ret; 636 637 if ((cur == NULL) || (parent == NULL)) 638 return(NULL); 639 if (parent == NULL) { 640 xmlFreeNode(cur); 641 return(NULL); 642 } 643 ret = xmlAddChild(parent, cur); 644 645 return(ret); 646 } 647 648 /** 649 * xsltAddTextString: 650 * @ctxt: a XSLT process context 651 * @target: the text node where the text will be attached 652 * @string: the text string 653 * @len: the string length in byte 654 * 655 * Extend the current text node with the new string, it handles coalescing 656 * 657 * Returns: the text node 658 */ 659 static xmlNodePtr 660 xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, 661 const xmlChar *string, int len) { 662 /* 663 * optimization 664 */ 665 if ((len <= 0) || (string == NULL) || (target == NULL)) 666 return(target); 667 668 if (ctxt->lasttext == target->content) { 669 670 if (ctxt->lasttuse + len >= ctxt->lasttsize) { 671 xmlChar *newbuf; 672 int size; 673 674 size = ctxt->lasttsize + len + 100; 675 size *= 2; 676 newbuf = (xmlChar *) xmlRealloc(target->content,size); 677 if (newbuf == NULL) { 678 xsltTransformError(ctxt, NULL, target, 679 "xsltCopyText: text allocation failed\n"); 680 return(NULL); 681 } 682 ctxt->lasttsize = size; 683 ctxt->lasttext = newbuf; 684 target->content = newbuf; 685 } 686 memcpy(&(target->content[ctxt->lasttuse]), string, len); 687 ctxt->lasttuse += len; 688 target->content[ctxt->lasttuse] = 0; 689 } else { 690 xmlNodeAddContent(target, string); 691 ctxt->lasttext = target->content; 692 len = xmlStrlen(target->content); 693 ctxt->lasttsize = len; 694 ctxt->lasttuse = len; 695 } 696 return(target); 697 } 698 699 /** 700 * xsltCopyTextString: 701 * @ctxt: a XSLT process context 702 * @target: the element where the text will be attached 703 * @string: the text string 704 * @noescape: should disable-escaping be activated for this text node. 705 * 706 * Adds @string to a newly created or an existent text node child of 707 * @target. 708 * 709 * Returns: the text node, where the text content of @cur is copied to. 710 * NULL in case of API or internal errors. 711 */ 712 xmlNodePtr 713 xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, 714 const xmlChar *string, int noescape) 715 { 716 xmlNodePtr copy; 717 int len; 718 719 if (string == NULL) 720 return(NULL); 721 722 #ifdef WITH_XSLT_DEBUG_PROCESS 723 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 724 "xsltCopyTextString: copy text %s\n", 725 string)); 726 #endif 727 728 /* 729 * Play save and reset the merging mechanism for every new 730 * target node. 731 */ 732 if ((target == NULL) || (target->children == NULL)) { 733 ctxt->lasttext = NULL; 734 } 735 736 /* handle coalescing of text nodes here */ 737 len = xmlStrlen(string); 738 if ((ctxt->type == XSLT_OUTPUT_XML) && 739 (ctxt->style->cdataSection != NULL) && 740 (target != NULL) && 741 (target->type == XML_ELEMENT_NODE) && 742 (((target->ns == NULL) && 743 (xmlHashLookup2(ctxt->style->cdataSection, 744 target->name, NULL) != NULL)) || 745 ((target->ns != NULL) && 746 (xmlHashLookup2(ctxt->style->cdataSection, 747 target->name, target->ns->href) != NULL)))) 748 { 749 /* 750 * Process "cdata-section-elements". 751 */ 752 if ((target->last != NULL) && 753 (target->last->type == XML_CDATA_SECTION_NODE)) 754 { 755 return(xsltAddTextString(ctxt, target->last, string, len)); 756 } 757 copy = xmlNewCDataBlock(ctxt->output, string, len); 758 } else if (noescape) { 759 /* 760 * Process "disable-output-escaping". 761 */ 762 if ((target != NULL) && (target->last != NULL) && 763 (target->last->type == XML_TEXT_NODE) && 764 (target->last->name == xmlStringTextNoenc)) 765 { 766 return(xsltAddTextString(ctxt, target->last, string, len)); 767 } 768 copy = xmlNewTextLen(string, len); 769 if (copy != NULL) 770 copy->name = xmlStringTextNoenc; 771 } else { 772 /* 773 * Default processing. 774 */ 775 if ((target != NULL) && (target->last != NULL) && 776 (target->last->type == XML_TEXT_NODE) && 777 (target->last->name == xmlStringText)) { 778 return(xsltAddTextString(ctxt, target->last, string, len)); 779 } 780 copy = xmlNewTextLen(string, len); 781 } 782 if (copy != NULL) { 783 if (target != NULL) 784 copy = xsltAddChild(target, copy); 785 ctxt->lasttext = copy->content; 786 ctxt->lasttsize = len; 787 ctxt->lasttuse = len; 788 } else { 789 xsltTransformError(ctxt, NULL, target, 790 "xsltCopyTextString: text copy failed\n"); 791 ctxt->lasttext = NULL; 792 } 793 return(copy); 794 } 795 796 /** 797 * xsltCopyText: 798 * @ctxt: a XSLT process context 799 * @target: the element where the text will be attached 800 * @cur: the text or CDATA node 801 * @interned: the string is in the target doc dictionary 802 * 803 * Copy the text content of @cur and append it to @target's children. 804 * 805 * Returns: the text node, where the text content of @cur is copied to. 806 * NULL in case of API or internal errors. 807 */ 808 static xmlNodePtr 809 xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target, 810 xmlNodePtr cur, int interned) 811 { 812 xmlNodePtr copy; 813 814 if ((cur->type != XML_TEXT_NODE) && 815 (cur->type != XML_CDATA_SECTION_NODE)) 816 return(NULL); 817 if (cur->content == NULL) 818 return(NULL); 819 820 #ifdef WITH_XSLT_DEBUG_PROCESS 821 if (cur->type == XML_CDATA_SECTION_NODE) { 822 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 823 "xsltCopyText: copy CDATA text %s\n", 824 cur->content)); 825 } else if (cur->name == xmlStringTextNoenc) { 826 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 827 "xsltCopyText: copy unescaped text %s\n", 828 cur->content)); 829 } else { 830 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 831 "xsltCopyText: copy text %s\n", 832 cur->content)); 833 } 834 #endif 835 836 /* 837 * Play save and reset the merging mechanism for every new 838 * target node. 839 */ 840 if ((target == NULL) || (target->children == NULL)) { 841 ctxt->lasttext = NULL; 842 } 843 844 if ((ctxt->style->cdataSection != NULL) && 845 (ctxt->type == XSLT_OUTPUT_XML) && 846 (target != NULL) && 847 (target->type == XML_ELEMENT_NODE) && 848 (((target->ns == NULL) && 849 (xmlHashLookup2(ctxt->style->cdataSection, 850 target->name, NULL) != NULL)) || 851 ((target->ns != NULL) && 852 (xmlHashLookup2(ctxt->style->cdataSection, 853 target->name, target->ns->href) != NULL)))) 854 { 855 /* 856 * Process "cdata-section-elements". 857 */ 858 /* 859 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. 860 */ 861 /* 862 * TODO: Since this doesn't merge adjacent CDATA-section nodes, 863 * we'll get: <![CDATA[x]]><!CDATA[y]]>. 864 * TODO: Reported in #321505. 865 */ 866 if ((target->last != NULL) && 867 (target->last->type == XML_CDATA_SECTION_NODE)) 868 { 869 /* 870 * Append to existing CDATA-section node. 871 */ 872 copy = xsltAddTextString(ctxt, target->last, cur->content, 873 xmlStrlen(cur->content)); 874 goto exit; 875 } else { 876 unsigned int len; 877 878 len = xmlStrlen(cur->content); 879 copy = xmlNewCDataBlock(ctxt->output, cur->content, len); 880 if (copy == NULL) 881 goto exit; 882 ctxt->lasttext = copy->content; 883 ctxt->lasttsize = len; 884 ctxt->lasttuse = len; 885 } 886 } else if ((target != NULL) && 887 (target->last != NULL) && 888 /* both escaped or both non-escaped text-nodes */ 889 (((target->last->type == XML_TEXT_NODE) && 890 (target->last->name == cur->name)) || 891 /* non-escaped text nodes and CDATA-section nodes */ 892 (((target->last->type == XML_CDATA_SECTION_NODE) && 893 (cur->name == xmlStringTextNoenc))))) 894 { 895 /* 896 * we are appending to an existing text node 897 */ 898 copy = xsltAddTextString(ctxt, target->last, cur->content, 899 xmlStrlen(cur->content)); 900 goto exit; 901 } else if ((interned) && (target != NULL) && 902 (target->doc != NULL) && 903 (target->doc->dict == ctxt->dict)) 904 { 905 /* 906 * TODO: DO we want to use this also for "text" output? 907 */ 908 copy = xmlNewTextLen(NULL, 0); 909 if (copy == NULL) 910 goto exit; 911 if (cur->name == xmlStringTextNoenc) 912 copy->name = xmlStringTextNoenc; 913 914 /* 915 * Must confirm that content is in dict (bug 302821) 916 * TODO: This check should be not needed for text coming 917 * from the stylesheets 918 */ 919 if (xmlDictOwns(ctxt->dict, cur->content)) 920 copy->content = cur->content; 921 else { 922 if ((copy->content = xmlStrdup(cur->content)) == NULL) 923 return NULL; 924 } 925 } else { 926 /* 927 * normal processing. keep counters to extend the text node 928 * in xsltAddTextString if needed. 929 */ 930 unsigned int len; 931 932 len = xmlStrlen(cur->content); 933 copy = xmlNewTextLen(cur->content, len); 934 if (copy == NULL) 935 goto exit; 936 if (cur->name == xmlStringTextNoenc) 937 copy->name = xmlStringTextNoenc; 938 ctxt->lasttext = copy->content; 939 ctxt->lasttsize = len; 940 ctxt->lasttuse = len; 941 } 942 if (copy != NULL) { 943 if (target != NULL) { 944 copy->doc = target->doc; 945 /* 946 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here 947 * to ensure that the optimized text-merging mechanism 948 * won't interfere with normal node-merging in any case. 949 */ 950 copy = xsltAddChild(target, copy); 951 } 952 } else { 953 xsltTransformError(ctxt, NULL, target, 954 "xsltCopyText: text copy failed\n"); 955 } 956 957 exit: 958 if ((copy == NULL) || (copy->content == NULL)) { 959 xsltTransformError(ctxt, NULL, target, 960 "Internal error in xsltCopyText(): " 961 "Failed to copy the string.\n"); 962 ctxt->state = XSLT_STATE_STOPPED; 963 } 964 return(copy); 965 } 966 967 /** 968 * xsltShallowCopyAttr: 969 * @ctxt: a XSLT process context 970 * @invocNode: responsible node in the stylesheet; used for error reports 971 * @target: the element where the attribute will be grafted 972 * @attr: the attribute to be copied 973 * 974 * Do a copy of an attribute. 975 * Called by: 976 * - xsltCopyTreeInternal() 977 * - xsltCopyOf() 978 * - xsltCopy() 979 * 980 * Returns: a new xmlAttrPtr, or NULL in case of error. 981 */ 982 static xmlAttrPtr 983 xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, 984 xmlNodePtr target, xmlAttrPtr attr) 985 { 986 xmlAttrPtr copy; 987 xmlChar *value; 988 989 if (attr == NULL) 990 return(NULL); 991 992 if (target->type != XML_ELEMENT_NODE) { 993 xsltTransformError(ctxt, NULL, invocNode, 994 "Cannot add an attribute node to a non-element node.\n"); 995 return(NULL); 996 } 997 998 if (target->children != NULL) { 999 xsltTransformError(ctxt, NULL, invocNode, 1000 "Attribute nodes must be added before " 1001 "any child nodes to an element.\n"); 1002 return(NULL); 1003 } 1004 1005 value = xmlNodeListGetString(attr->doc, attr->children, 1); 1006 if (attr->ns != NULL) { 1007 xmlNsPtr ns; 1008 1009 ns = xsltGetSpecialNamespace(ctxt, invocNode, 1010 attr->ns->href, attr->ns->prefix, target); 1011 if (ns == NULL) { 1012 xsltTransformError(ctxt, NULL, invocNode, 1013 "Namespace fixup error: Failed to acquire an in-scope " 1014 "namespace binding of the copied attribute '{%s}%s'.\n", 1015 attr->ns->href, attr->name); 1016 /* 1017 * TODO: Should we just stop here? 1018 */ 1019 } 1020 /* 1021 * Note that xmlSetNsProp() will take care of duplicates 1022 * and assigns the new namespace even to a duplicate. 1023 */ 1024 copy = xmlSetNsProp(target, ns, attr->name, value); 1025 } else { 1026 copy = xmlSetNsProp(target, NULL, attr->name, value); 1027 } 1028 if (value != NULL) 1029 xmlFree(value); 1030 1031 if (copy == NULL) 1032 return(NULL); 1033 1034 #if 0 1035 /* 1036 * NOTE: This was optimized according to bug #342695. 1037 * TODO: Can this further be optimized, if source and target 1038 * share the same dict and attr->children is just 1 text node 1039 * which is in the dict? How probable is such a case? 1040 */ 1041 /* 1042 * TODO: Do we need to create an empty text node if the value 1043 * is the empty string? 1044 */ 1045 value = xmlNodeListGetString(attr->doc, attr->children, 1); 1046 if (value != NULL) { 1047 txtNode = xmlNewDocText(target->doc, NULL); 1048 if (txtNode == NULL) 1049 return(NULL); 1050 if ((target->doc != NULL) && 1051 (target->doc->dict != NULL)) 1052 { 1053 txtNode->content = 1054 (xmlChar *) xmlDictLookup(target->doc->dict, 1055 BAD_CAST value, -1); 1056 xmlFree(value); 1057 } else 1058 txtNode->content = value; 1059 copy->children = txtNode; 1060 } 1061 #endif 1062 1063 return(copy); 1064 } 1065 1066 /** 1067 * xsltCopyAttrListNoOverwrite: 1068 * @ctxt: a XSLT process context 1069 * @invocNode: responsible node in the stylesheet; used for error reports 1070 * @target: the element where the new attributes will be grafted 1071 * @attr: the first attribute in the list to be copied 1072 * 1073 * Copies a list of attribute nodes, starting with @attr, over to the 1074 * @target element node. 1075 * 1076 * Called by: 1077 * - xsltCopyTreeInternal() 1078 * 1079 * Returns 0 on success and -1 on errors and internal errors. 1080 */ 1081 static int 1082 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt, 1083 xmlNodePtr invocNode, 1084 xmlNodePtr target, xmlAttrPtr attr) 1085 { 1086 xmlAttrPtr copy; 1087 xmlNsPtr origNs = NULL, copyNs = NULL; 1088 xmlChar *value; 1089 1090 /* 1091 * Don't use xmlCopyProp() here, since it will try to 1092 * reconciliate namespaces. 1093 */ 1094 while (attr != NULL) { 1095 /* 1096 * Find a namespace node in the tree of @target. 1097 * Avoid searching for the same ns. 1098 */ 1099 if (attr->ns != origNs) { 1100 origNs = attr->ns; 1101 if (attr->ns != NULL) { 1102 copyNs = xsltGetSpecialNamespace(ctxt, invocNode, 1103 attr->ns->href, attr->ns->prefix, target); 1104 if (copyNs == NULL) 1105 return(-1); 1106 } else 1107 copyNs = NULL; 1108 } 1109 /* 1110 * If attribute has a value, we need to copy it (watching out 1111 * for possible entities) 1112 */ 1113 if ((attr->children) && (attr->children->type == XML_TEXT_NODE) && 1114 (attr->children->next == NULL)) { 1115 copy = xmlNewNsProp(target, copyNs, attr->name, 1116 attr->children->content); 1117 } else if (attr->children != NULL) { 1118 value = xmlNodeListGetString(attr->doc, attr->children, 1); 1119 copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value); 1120 xmlFree(value); 1121 } else { 1122 copy = xmlNewNsProp(target, copyNs, attr->name, NULL); 1123 } 1124 1125 if (copy == NULL) 1126 return(-1); 1127 1128 attr = attr->next; 1129 } 1130 return(0); 1131 } 1132 1133 /** 1134 * xsltShallowCopyElem: 1135 * @ctxt: the XSLT process context 1136 * @node: the element node in the source tree 1137 * or the Literal Result Element 1138 * @insert: the parent in the result tree 1139 * @isLRE: if @node is a Literal Result Element 1140 * 1141 * Make a copy of the element node @node 1142 * and insert it as last child of @insert. 1143 * 1144 * URGENT TODO: The problem with this one (for the non-refactored code) 1145 * is that it is used for both, Literal Result Elements *and* 1146 * copying input nodes. 1147 * 1148 * BIG NOTE: This is only called for XML_ELEMENT_NODEs. 1149 * 1150 * Called from: 1151 * xsltApplySequenceConstructor() 1152 * (for Literal Result Elements - which is a problem) 1153 * xsltCopy() (for shallow-copying elements via xsl:copy) 1154 * 1155 * Returns a pointer to the new node, or NULL in case of error 1156 */ 1157 static xmlNodePtr 1158 xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node, 1159 xmlNodePtr insert, int isLRE) 1160 { 1161 xmlNodePtr copy; 1162 1163 if ((node->type == XML_DTD_NODE) || (insert == NULL)) 1164 return(NULL); 1165 if ((node->type == XML_TEXT_NODE) || 1166 (node->type == XML_CDATA_SECTION_NODE)) 1167 return(xsltCopyText(ctxt, insert, node, 0)); 1168 1169 copy = xmlDocCopyNode(node, insert->doc, 0); 1170 if (copy != NULL) { 1171 copy->doc = ctxt->output; 1172 copy = xsltAddChild(insert, copy); 1173 1174 if (node->type == XML_ELEMENT_NODE) { 1175 /* 1176 * Add namespaces as they are needed 1177 */ 1178 if (node->nsDef != NULL) { 1179 /* 1180 * TODO: Remove the LRE case in the refactored code 1181 * gets enabled. 1182 */ 1183 if (isLRE) 1184 xsltCopyNamespaceList(ctxt, copy, node->nsDef); 1185 else 1186 xsltCopyNamespaceListInternal(copy, node->nsDef); 1187 } 1188 1189 /* 1190 * URGENT TODO: The problem with this is that it does not 1191 * copy over all namespace nodes in scope. 1192 * The damn thing about this is, that we would need to 1193 * use the xmlGetNsList(), for every single node; this is 1194 * also done in xsltCopyTreeInternal(), but only for the top node. 1195 */ 1196 if (node->ns != NULL) { 1197 if (isLRE) { 1198 /* 1199 * REVISIT TODO: Since the non-refactored code still does 1200 * ns-aliasing, we need to call xsltGetNamespace() here. 1201 * Remove this when ready. 1202 */ 1203 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy); 1204 } else { 1205 copy->ns = xsltGetSpecialNamespace(ctxt, 1206 node, node->ns->href, node->ns->prefix, copy); 1207 1208 } 1209 } else if ((insert->type == XML_ELEMENT_NODE) && 1210 (insert->ns != NULL)) 1211 { 1212 /* 1213 * "Undeclare" the default namespace. 1214 */ 1215 xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy); 1216 } 1217 } 1218 } else { 1219 xsltTransformError(ctxt, NULL, node, 1220 "xsltShallowCopyElem: copy %s failed\n", node->name); 1221 } 1222 return(copy); 1223 } 1224 1225 /** 1226 * xsltCopyTreeList: 1227 * @ctxt: a XSLT process context 1228 * @invocNode: responsible node in the stylesheet; used for error reports 1229 * @list: the list of element nodes in the source tree. 1230 * @insert: the parent in the result tree. 1231 * @isLRE: is this a literal result element list 1232 * @topElemVisited: indicates if a top-most element was already processed 1233 * 1234 * Make a copy of the full list of tree @list 1235 * and insert it as last children of @insert 1236 * 1237 * NOTE: Not to be used for Literal Result Elements. 1238 * 1239 * Used by: 1240 * - xsltCopyOf() 1241 * 1242 * Returns a pointer to the new list, or NULL in case of error 1243 */ 1244 static xmlNodePtr 1245 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, 1246 xmlNodePtr list, 1247 xmlNodePtr insert, int isLRE, int topElemVisited) 1248 { 1249 xmlNodePtr copy, ret = NULL; 1250 1251 while (list != NULL) { 1252 copy = xsltCopyTreeInternal(ctxt, invocNode, 1253 list, insert, isLRE, topElemVisited); 1254 if (copy != NULL) { 1255 if (ret == NULL) { 1256 ret = copy; 1257 } 1258 } 1259 list = list->next; 1260 } 1261 return(ret); 1262 } 1263 1264 /** 1265 * xsltCopyNamespaceListInternal: 1266 * @node: the target node 1267 * @cur: the first namespace 1268 * 1269 * Do a copy of a namespace list. If @node is non-NULL the 1270 * new namespaces are added automatically. 1271 * Called by: 1272 * xsltCopyTreeInternal() 1273 * 1274 * QUESTION: What is the exact difference between this function 1275 * and xsltCopyNamespaceList() in "namespaces.c"? 1276 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases. 1277 * 1278 * Returns: a new xmlNsPtr, or NULL in case of error. 1279 */ 1280 static xmlNsPtr 1281 xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) { 1282 xmlNsPtr ret = NULL; 1283 xmlNsPtr p = NULL, q, luNs; 1284 1285 if (ns == NULL) 1286 return(NULL); 1287 /* 1288 * One can add namespaces only on element nodes 1289 */ 1290 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) 1291 elem = NULL; 1292 1293 do { 1294 if (ns->type != XML_NAMESPACE_DECL) 1295 break; 1296 /* 1297 * Avoid duplicating namespace declarations on the tree. 1298 */ 1299 if (elem != NULL) { 1300 if ((elem->ns != NULL) && 1301 xmlStrEqual(elem->ns->prefix, ns->prefix) && 1302 xmlStrEqual(elem->ns->href, ns->href)) 1303 { 1304 ns = ns->next; 1305 continue; 1306 } 1307 luNs = xmlSearchNs(elem->doc, elem, ns->prefix); 1308 if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href))) 1309 { 1310 ns = ns->next; 1311 continue; 1312 } 1313 } 1314 q = xmlNewNs(elem, ns->href, ns->prefix); 1315 if (p == NULL) { 1316 ret = p = q; 1317 } else if (q != NULL) { 1318 p->next = q; 1319 p = q; 1320 } 1321 ns = ns->next; 1322 } while (ns != NULL); 1323 return(ret); 1324 } 1325 1326 /** 1327 * xsltShallowCopyNsNode: 1328 * @ctxt: the XSLT transformation context 1329 * @invocNode: responsible node in the stylesheet; used for error reports 1330 * @insert: the target element node in the result tree 1331 * @ns: the namespace node 1332 * 1333 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy. 1334 * 1335 * Returns a new/existing ns-node, or NULL. 1336 */ 1337 static xmlNsPtr 1338 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt, 1339 xmlNodePtr invocNode, 1340 xmlNodePtr insert, 1341 xmlNsPtr ns) 1342 { 1343 /* 1344 * TODO: Contrary to header comments, this is declared as int. 1345 * be modified to return a node pointer, or NULL if any error 1346 */ 1347 xmlNsPtr tmpns; 1348 1349 if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE)) 1350 return(NULL); 1351 1352 if (insert->children != NULL) { 1353 xsltTransformError(ctxt, NULL, invocNode, 1354 "Namespace nodes must be added before " 1355 "any child nodes are added to an element.\n"); 1356 return(NULL); 1357 } 1358 /* 1359 * BIG NOTE: Xalan-J simply overwrites any ns-decls with 1360 * an equal prefix. We definitively won't do that. 1361 * 1362 * MSXML 4.0 and the .NET ignores ns-decls for which an 1363 * equal prefix is already in use. 1364 * 1365 * Saxon raises an error like: 1366 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace 1367 * nodes with the same name". 1368 * 1369 * NOTE: We'll currently follow MSXML here. 1370 * REVISIT TODO: Check if it's better to follow Saxon here. 1371 */ 1372 if (ns->prefix == NULL) { 1373 /* 1374 * If we are adding ns-nodes to an element using e.g. 1375 * <xsl:copy-of select="/foo/namespace::*">, then we need 1376 * to ensure that we don't incorrectly declare a default 1377 * namespace on an element in no namespace, which otherwise 1378 * would move the element incorrectly into a namespace, if 1379 * the node tree is serialized. 1380 */ 1381 if (insert->ns == NULL) 1382 goto occupied; 1383 } else if ((ns->prefix[0] == 'x') && 1384 xmlStrEqual(ns->prefix, BAD_CAST "xml")) 1385 { 1386 /* 1387 * The XML namespace is built in. 1388 */ 1389 return(NULL); 1390 } 1391 1392 if (insert->nsDef != NULL) { 1393 tmpns = insert->nsDef; 1394 do { 1395 if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { 1396 if ((tmpns->prefix == ns->prefix) || 1397 xmlStrEqual(tmpns->prefix, ns->prefix)) 1398 { 1399 /* 1400 * Same prefix. 1401 */ 1402 if (xmlStrEqual(tmpns->href, ns->href)) 1403 return(NULL); 1404 goto occupied; 1405 } 1406 } 1407 tmpns = tmpns->next; 1408 } while (tmpns != NULL); 1409 } 1410 tmpns = xmlSearchNs(insert->doc, insert, ns->prefix); 1411 if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href)) 1412 return(NULL); 1413 /* 1414 * Declare a new namespace. 1415 * TODO: The problem (wrt efficiency) with this xmlNewNs() is 1416 * that it will again search the already declared namespaces 1417 * for a duplicate :-/ 1418 */ 1419 return(xmlNewNs(insert, ns->href, ns->prefix)); 1420 1421 occupied: 1422 /* 1423 * TODO: We could as well raise an error here (like Saxon does), 1424 * or at least generate a warning. 1425 */ 1426 return(NULL); 1427 } 1428 1429 /** 1430 * xsltCopyTreeInternal: 1431 * @ctxt: the XSLT transformation context 1432 * @invocNode: responsible node in the stylesheet; used for error reports 1433 * @node: the element node in the source tree 1434 * @insert: the parent in the result tree 1435 * @isLRE: indicates if @node is a Literal Result Element 1436 * @topElemVisited: indicates if a top-most element was already processed 1437 * 1438 * Make a copy of the full tree under the element node @node 1439 * and insert it as last child of @insert 1440 * 1441 * NOTE: Not to be used for Literal Result Elements. 1442 * 1443 * Used by: 1444 * - xsltCopyOf() 1445 * 1446 * Returns a pointer to the new tree, or NULL in case of error 1447 */ 1448 static xmlNodePtr 1449 xsltCopyTreeInternal(xsltTransformContextPtr ctxt, 1450 xmlNodePtr invocNode, 1451 xmlNodePtr node, 1452 xmlNodePtr insert, int isLRE, int topElemVisited) 1453 { 1454 xmlNodePtr copy; 1455 1456 if (node == NULL) 1457 return(NULL); 1458 switch (node->type) { 1459 case XML_ELEMENT_NODE: 1460 case XML_ENTITY_REF_NODE: 1461 case XML_ENTITY_NODE: 1462 case XML_PI_NODE: 1463 case XML_COMMENT_NODE: 1464 case XML_DOCUMENT_NODE: 1465 case XML_HTML_DOCUMENT_NODE: 1466 #ifdef LIBXML_DOCB_ENABLED 1467 case XML_DOCB_DOCUMENT_NODE: 1468 #endif 1469 break; 1470 case XML_TEXT_NODE: { 1471 int noenc = (node->name == xmlStringTextNoenc); 1472 return(xsltCopyTextString(ctxt, insert, node->content, noenc)); 1473 } 1474 case XML_CDATA_SECTION_NODE: 1475 return(xsltCopyTextString(ctxt, insert, node->content, 0)); 1476 case XML_ATTRIBUTE_NODE: 1477 return((xmlNodePtr) 1478 xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)); 1479 case XML_NAMESPACE_DECL: 1480 return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode, 1481 insert, (xmlNsPtr) node)); 1482 1483 case XML_DOCUMENT_TYPE_NODE: 1484 case XML_DOCUMENT_FRAG_NODE: 1485 case XML_NOTATION_NODE: 1486 case XML_DTD_NODE: 1487 case XML_ELEMENT_DECL: 1488 case XML_ATTRIBUTE_DECL: 1489 case XML_ENTITY_DECL: 1490 case XML_XINCLUDE_START: 1491 case XML_XINCLUDE_END: 1492 return(NULL); 1493 } 1494 if (XSLT_IS_RES_TREE_FRAG(node)) { 1495 if (node->children != NULL) 1496 copy = xsltCopyTreeList(ctxt, invocNode, 1497 node->children, insert, 0, 0); 1498 else 1499 copy = NULL; 1500 return(copy); 1501 } 1502 copy = xmlDocCopyNode(node, insert->doc, 0); 1503 if (copy != NULL) { 1504 copy->doc = ctxt->output; 1505 copy = xsltAddChild(insert, copy); 1506 /* 1507 * The node may have been coalesced into another text node. 1508 */ 1509 if (insert->last != copy) 1510 return(insert->last); 1511 copy->next = NULL; 1512 1513 if (node->type == XML_ELEMENT_NODE) { 1514 /* 1515 * Copy in-scope namespace nodes. 1516 * 1517 * REVISIT: Since we try to reuse existing in-scope ns-decls by 1518 * using xmlSearchNsByHref(), this will eventually change 1519 * the prefix of an original ns-binding; thus it might 1520 * break QNames in element/attribute content. 1521 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation 1522 * context, plus a ns-lookup function, which writes directly 1523 * to a given list, then we wouldn't need to create/free the 1524 * nsList every time. 1525 */ 1526 if ((topElemVisited == 0) && 1527 (node->parent != NULL) && 1528 (node->parent->type != XML_DOCUMENT_NODE) && 1529 (node->parent->type != XML_HTML_DOCUMENT_NODE)) 1530 { 1531 xmlNsPtr *nsList, *curns, ns; 1532 1533 /* 1534 * If this is a top-most element in a tree to be 1535 * copied, then we need to ensure that all in-scope 1536 * namespaces are copied over. For nodes deeper in the 1537 * tree, it is sufficient to reconcile only the ns-decls 1538 * (node->nsDef entries). 1539 */ 1540 1541 nsList = xmlGetNsList(node->doc, node); 1542 if (nsList != NULL) { 1543 curns = nsList; 1544 do { 1545 /* 1546 * Search by prefix first in order to break as less 1547 * QNames in element/attribute content as possible. 1548 */ 1549 ns = xmlSearchNs(insert->doc, insert, 1550 (*curns)->prefix); 1551 1552 if ((ns == NULL) || 1553 (! xmlStrEqual(ns->href, (*curns)->href))) 1554 { 1555 ns = NULL; 1556 /* 1557 * Search by namespace name. 1558 * REVISIT TODO: Currently disabled. 1559 */ 1560 #if 0 1561 ns = xmlSearchNsByHref(insert->doc, 1562 insert, (*curns)->href); 1563 #endif 1564 } 1565 if (ns == NULL) { 1566 /* 1567 * Declare a new namespace on the copied element. 1568 */ 1569 ns = xmlNewNs(copy, (*curns)->href, 1570 (*curns)->prefix); 1571 /* TODO: Handle errors */ 1572 } 1573 if (node->ns == *curns) { 1574 /* 1575 * If this was the original's namespace then set 1576 * the generated counterpart on the copy. 1577 */ 1578 copy->ns = ns; 1579 } 1580 curns++; 1581 } while (*curns != NULL); 1582 xmlFree(nsList); 1583 } 1584 } else if (node->nsDef != NULL) { 1585 /* 1586 * Copy over all namespace declaration attributes. 1587 */ 1588 if (node->nsDef != NULL) { 1589 if (isLRE) 1590 xsltCopyNamespaceList(ctxt, copy, node->nsDef); 1591 else 1592 xsltCopyNamespaceListInternal(copy, node->nsDef); 1593 } 1594 } 1595 /* 1596 * Set the namespace. 1597 */ 1598 if (node->ns != NULL) { 1599 if (copy->ns == NULL) { 1600 /* 1601 * This will map copy->ns to one of the newly created 1602 * in-scope ns-decls, OR create a new ns-decl on @copy. 1603 */ 1604 copy->ns = xsltGetSpecialNamespace(ctxt, invocNode, 1605 node->ns->href, node->ns->prefix, copy); 1606 } 1607 } else if ((insert->type == XML_ELEMENT_NODE) && 1608 (insert->ns != NULL)) 1609 { 1610 /* 1611 * "Undeclare" the default namespace on @copy with xmlns="". 1612 */ 1613 xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy); 1614 } 1615 /* 1616 * Copy attribute nodes. 1617 */ 1618 if (node->properties != NULL) { 1619 xsltCopyAttrListNoOverwrite(ctxt, invocNode, 1620 copy, node->properties); 1621 } 1622 if (topElemVisited == 0) 1623 topElemVisited = 1; 1624 } 1625 /* 1626 * Copy the subtree. 1627 */ 1628 if (node->children != NULL) { 1629 xsltCopyTreeList(ctxt, invocNode, 1630 node->children, copy, isLRE, topElemVisited); 1631 } 1632 } else { 1633 xsltTransformError(ctxt, NULL, invocNode, 1634 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name); 1635 } 1636 return(copy); 1637 } 1638 1639 /** 1640 * xsltCopyTree: 1641 * @ctxt: the XSLT transformation context 1642 * @node: the element node in the source tree 1643 * @insert: the parent in the result tree 1644 * @literal: indicates if @node is a Literal Result Element 1645 * 1646 * Make a copy of the full tree under the element node @node 1647 * and insert it as last child of @insert 1648 * For literal result element, some of the namespaces may not be copied 1649 * over according to section 7.1. 1650 * TODO: Why is this a public function? 1651 * 1652 * Returns a pointer to the new tree, or NULL in case of error 1653 */ 1654 xmlNodePtr 1655 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node, 1656 xmlNodePtr insert, int literal) 1657 { 1658 return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0)); 1659 1660 } 1661 1662 /************************************************************************ 1663 * * 1664 * Error/fallback processing * 1665 * * 1666 ************************************************************************/ 1667 1668 /** 1669 * xsltApplyFallbacks: 1670 * @ctxt: a XSLT process context 1671 * @node: the node in the source tree. 1672 * @inst: the node generating the error 1673 * 1674 * Process possible xsl:fallback nodes present under @inst 1675 * 1676 * Returns the number of xsl:fallback element found and processed 1677 */ 1678 static int 1679 xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node, 1680 xmlNodePtr inst) { 1681 1682 xmlNodePtr child; 1683 int ret = 0; 1684 1685 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || 1686 (inst->children == NULL)) 1687 return(0); 1688 1689 child = inst->children; 1690 while (child != NULL) { 1691 if ((IS_XSLT_ELEM(child)) && 1692 (xmlStrEqual(child->name, BAD_CAST "fallback"))) { 1693 #ifdef WITH_XSLT_DEBUG_PARSING 1694 xsltGenericDebug(xsltGenericDebugContext, 1695 "applying xsl:fallback\n"); 1696 #endif 1697 ret++; 1698 xsltApplySequenceConstructor(ctxt, node, child->children, 1699 NULL); 1700 } 1701 child = child->next; 1702 } 1703 return(ret); 1704 } 1705 1706 /************************************************************************ 1707 * * 1708 * Default processing * 1709 * * 1710 ************************************************************************/ 1711 1712 /** 1713 * xsltDefaultProcessOneNode: 1714 * @ctxt: a XSLT process context 1715 * @node: the node in the source tree. 1716 * @params: extra parameters passed to the template if any 1717 * 1718 * Process the source node with the default built-in template rule: 1719 * <xsl:template match="*|/"> 1720 * <xsl:apply-templates/> 1721 * </xsl:template> 1722 * 1723 * and 1724 * 1725 * <xsl:template match="text()|@*"> 1726 * <xsl:value-of select="."/> 1727 * </xsl:template> 1728 * 1729 * Note also that namespace declarations are copied directly: 1730 * 1731 * the built-in template rule is the only template rule that is applied 1732 * for namespace nodes. 1733 */ 1734 static void 1735 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, 1736 xsltStackElemPtr params) { 1737 xmlNodePtr copy; 1738 xmlNodePtr delete = NULL, cur; 1739 int nbchild = 0, oldSize; 1740 int childno = 0, oldPos; 1741 xsltTemplatePtr template; 1742 1743 CHECK_STOPPED; 1744 /* 1745 * Handling of leaves 1746 */ 1747 switch (node->type) { 1748 case XML_DOCUMENT_NODE: 1749 case XML_HTML_DOCUMENT_NODE: 1750 case XML_ELEMENT_NODE: 1751 break; 1752 case XML_CDATA_SECTION_NODE: 1753 #ifdef WITH_XSLT_DEBUG_PROCESS 1754 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1755 "xsltDefaultProcessOneNode: copy CDATA %s\n", 1756 node->content)); 1757 #endif 1758 copy = xsltCopyText(ctxt, ctxt->insert, node, 0); 1759 if (copy == NULL) { 1760 xsltTransformError(ctxt, NULL, node, 1761 "xsltDefaultProcessOneNode: cdata copy failed\n"); 1762 } 1763 return; 1764 case XML_TEXT_NODE: 1765 #ifdef WITH_XSLT_DEBUG_PROCESS 1766 if (node->content == NULL) { 1767 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1768 "xsltDefaultProcessOneNode: copy empty text\n")); 1769 return; 1770 } else { 1771 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1772 "xsltDefaultProcessOneNode: copy text %s\n", 1773 node->content)); 1774 } 1775 #endif 1776 copy = xsltCopyText(ctxt, ctxt->insert, node, 0); 1777 if (copy == NULL) { 1778 xsltTransformError(ctxt, NULL, node, 1779 "xsltDefaultProcessOneNode: text copy failed\n"); 1780 } 1781 return; 1782 case XML_ATTRIBUTE_NODE: 1783 cur = node->children; 1784 while ((cur != NULL) && (cur->type != XML_TEXT_NODE)) 1785 cur = cur->next; 1786 if (cur == NULL) { 1787 xsltTransformError(ctxt, NULL, node, 1788 "xsltDefaultProcessOneNode: no text for attribute\n"); 1789 } else { 1790 #ifdef WITH_XSLT_DEBUG_PROCESS 1791 if (cur->content == NULL) { 1792 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1793 "xsltDefaultProcessOneNode: copy empty text\n")); 1794 } else { 1795 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1796 "xsltDefaultProcessOneNode: copy text %s\n", 1797 cur->content)); 1798 } 1799 #endif 1800 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 1801 if (copy == NULL) { 1802 xsltTransformError(ctxt, NULL, node, 1803 "xsltDefaultProcessOneNode: text copy failed\n"); 1804 } 1805 } 1806 return; 1807 default: 1808 return; 1809 } 1810 /* 1811 * Handling of Elements: first pass, cleanup and counting 1812 */ 1813 cur = node->children; 1814 while (cur != NULL) { 1815 switch (cur->type) { 1816 case XML_TEXT_NODE: 1817 case XML_CDATA_SECTION_NODE: 1818 case XML_DOCUMENT_NODE: 1819 case XML_HTML_DOCUMENT_NODE: 1820 case XML_ELEMENT_NODE: 1821 case XML_PI_NODE: 1822 case XML_COMMENT_NODE: 1823 nbchild++; 1824 break; 1825 case XML_DTD_NODE: 1826 /* Unlink the DTD, it's still reachable using doc->intSubset */ 1827 if (cur->next != NULL) 1828 cur->next->prev = cur->prev; 1829 if (cur->prev != NULL) 1830 cur->prev->next = cur->next; 1831 break; 1832 default: 1833 #ifdef WITH_XSLT_DEBUG_PROCESS 1834 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1835 "xsltDefaultProcessOneNode: skipping node type %d\n", 1836 cur->type)); 1837 #endif 1838 delete = cur; 1839 } 1840 cur = cur->next; 1841 if (delete != NULL) { 1842 #ifdef WITH_XSLT_DEBUG_PROCESS 1843 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1844 "xsltDefaultProcessOneNode: removing ignorable blank node\n")); 1845 #endif 1846 xmlUnlinkNode(delete); 1847 xmlFreeNode(delete); 1848 delete = NULL; 1849 } 1850 } 1851 if (delete != NULL) { 1852 #ifdef WITH_XSLT_DEBUG_PROCESS 1853 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1854 "xsltDefaultProcessOneNode: removing ignorable blank node\n")); 1855 #endif 1856 xmlUnlinkNode(delete); 1857 xmlFreeNode(delete); 1858 delete = NULL; 1859 } 1860 1861 /* 1862 * Handling of Elements: second pass, actual processing 1863 */ 1864 oldSize = ctxt->xpathCtxt->contextSize; 1865 oldPos = ctxt->xpathCtxt->proximityPosition; 1866 cur = node->children; 1867 while (cur != NULL) { 1868 childno++; 1869 switch (cur->type) { 1870 case XML_DOCUMENT_NODE: 1871 case XML_HTML_DOCUMENT_NODE: 1872 case XML_ELEMENT_NODE: 1873 ctxt->xpathCtxt->contextSize = nbchild; 1874 ctxt->xpathCtxt->proximityPosition = childno; 1875 xsltProcessOneNode(ctxt, cur, params); 1876 break; 1877 case XML_CDATA_SECTION_NODE: 1878 template = xsltGetTemplate(ctxt, cur, NULL); 1879 if (template) { 1880 #ifdef WITH_XSLT_DEBUG_PROCESS 1881 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1882 "xsltDefaultProcessOneNode: applying template for CDATA %s\n", 1883 cur->content)); 1884 #endif 1885 /* 1886 * Instantiate the xsl:template. 1887 */ 1888 xsltApplyXSLTTemplate(ctxt, cur, template->content, 1889 template, params); 1890 } else /* if (ctxt->mode == NULL) */ { 1891 #ifdef WITH_XSLT_DEBUG_PROCESS 1892 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1893 "xsltDefaultProcessOneNode: copy CDATA %s\n", 1894 cur->content)); 1895 #endif 1896 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 1897 if (copy == NULL) { 1898 xsltTransformError(ctxt, NULL, cur, 1899 "xsltDefaultProcessOneNode: cdata copy failed\n"); 1900 } 1901 } 1902 break; 1903 case XML_TEXT_NODE: 1904 template = xsltGetTemplate(ctxt, cur, NULL); 1905 if (template) { 1906 #ifdef WITH_XSLT_DEBUG_PROCESS 1907 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1908 "xsltDefaultProcessOneNode: applying template for text %s\n", 1909 cur->content)); 1910 #endif 1911 ctxt->xpathCtxt->contextSize = nbchild; 1912 ctxt->xpathCtxt->proximityPosition = childno; 1913 /* 1914 * Instantiate the xsl:template. 1915 */ 1916 xsltApplyXSLTTemplate(ctxt, cur, template->content, 1917 template, params); 1918 } else /* if (ctxt->mode == NULL) */ { 1919 #ifdef WITH_XSLT_DEBUG_PROCESS 1920 if (cur->content == NULL) { 1921 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1922 "xsltDefaultProcessOneNode: copy empty text\n")); 1923 } else { 1924 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1925 "xsltDefaultProcessOneNode: copy text %s\n", 1926 cur->content)); 1927 } 1928 #endif 1929 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 1930 if (copy == NULL) { 1931 xsltTransformError(ctxt, NULL, cur, 1932 "xsltDefaultProcessOneNode: text copy failed\n"); 1933 } 1934 } 1935 break; 1936 case XML_PI_NODE: 1937 case XML_COMMENT_NODE: 1938 template = xsltGetTemplate(ctxt, cur, NULL); 1939 if (template) { 1940 #ifdef WITH_XSLT_DEBUG_PROCESS 1941 if (cur->type == XML_PI_NODE) { 1942 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1943 "xsltDefaultProcessOneNode: template found for PI %s\n", 1944 cur->name)); 1945 } else if (cur->type == XML_COMMENT_NODE) { 1946 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1947 "xsltDefaultProcessOneNode: template found for comment\n")); 1948 } 1949 #endif 1950 ctxt->xpathCtxt->contextSize = nbchild; 1951 ctxt->xpathCtxt->proximityPosition = childno; 1952 /* 1953 * Instantiate the xsl:template. 1954 */ 1955 xsltApplyXSLTTemplate(ctxt, cur, template->content, 1956 template, params); 1957 } 1958 break; 1959 default: 1960 break; 1961 } 1962 cur = cur->next; 1963 } 1964 ctxt->xpathCtxt->contextSize = oldSize; 1965 ctxt->xpathCtxt->proximityPosition = oldPos; 1966 } 1967 1968 /** 1969 * xsltProcessOneNode: 1970 * @ctxt: a XSLT process context 1971 * @contextNode: the "current node" in the source tree 1972 * @withParams: extra parameters (e.g. xsl:with-param) passed to the 1973 * template if any 1974 * 1975 * Process the source node. 1976 */ 1977 void 1978 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 1979 xsltStackElemPtr withParams) 1980 { 1981 xsltTemplatePtr templ; 1982 xmlNodePtr oldNode; 1983 1984 templ = xsltGetTemplate(ctxt, contextNode, NULL); 1985 /* 1986 * If no template is found, apply the default rule. 1987 */ 1988 if (templ == NULL) { 1989 #ifdef WITH_XSLT_DEBUG_PROCESS 1990 if (contextNode->type == XML_DOCUMENT_NODE) { 1991 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1992 "xsltProcessOneNode: no template found for /\n")); 1993 } else if (contextNode->type == XML_CDATA_SECTION_NODE) { 1994 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1995 "xsltProcessOneNode: no template found for CDATA\n")); 1996 } else if (contextNode->type == XML_ATTRIBUTE_NODE) { 1997 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 1998 "xsltProcessOneNode: no template found for attribute %s\n", 1999 ((xmlAttrPtr) contextNode)->name)); 2000 } else { 2001 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 2002 "xsltProcessOneNode: no template found for %s\n", contextNode->name)); 2003 } 2004 #endif 2005 oldNode = ctxt->node; 2006 ctxt->node = contextNode; 2007 xsltDefaultProcessOneNode(ctxt, contextNode, withParams); 2008 ctxt->node = oldNode; 2009 return; 2010 } 2011 2012 if (contextNode->type == XML_ATTRIBUTE_NODE) { 2013 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; 2014 /* 2015 * Set the "current template rule". 2016 */ 2017 ctxt->currentTemplateRule = templ; 2018 2019 #ifdef WITH_XSLT_DEBUG_PROCESS 2020 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 2021 "xsltProcessOneNode: applying template '%s' for attribute %s\n", 2022 templ->match, contextNode->name)); 2023 #endif 2024 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); 2025 2026 ctxt->currentTemplateRule = oldCurTempRule; 2027 } else { 2028 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; 2029 /* 2030 * Set the "current template rule". 2031 */ 2032 ctxt->currentTemplateRule = templ; 2033 2034 #ifdef WITH_XSLT_DEBUG_PROCESS 2035 if (contextNode->type == XML_DOCUMENT_NODE) { 2036 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 2037 "xsltProcessOneNode: applying template '%s' for /\n", 2038 templ->match)); 2039 } else { 2040 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 2041 "xsltProcessOneNode: applying template '%s' for %s\n", 2042 templ->match, contextNode->name)); 2043 } 2044 #endif 2045 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); 2046 2047 ctxt->currentTemplateRule = oldCurTempRule; 2048 } 2049 } 2050 2051 static xmlNodePtr 2052 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt, 2053 xmlNodePtr contextNode, 2054 xmlNodePtr list, 2055 xsltTemplatePtr templ, 2056 int *addCallResult) 2057 { 2058 xmlNodePtr debugedNode = NULL; 2059 2060 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 2061 if (templ) { 2062 *addCallResult = xslAddCall(templ, templ->elem); 2063 } else { 2064 *addCallResult = xslAddCall(NULL, list); 2065 } 2066 switch (ctxt->debugStatus) { 2067 case XSLT_DEBUG_RUN_RESTART: 2068 case XSLT_DEBUG_QUIT: 2069 if (*addCallResult) 2070 xslDropCall(); 2071 return(NULL); 2072 } 2073 if (templ) { 2074 xslHandleDebugger(templ->elem, contextNode, templ, ctxt); 2075 debugedNode = templ->elem; 2076 } else if (list) { 2077 xslHandleDebugger(list, contextNode, templ, ctxt); 2078 debugedNode = list; 2079 } else if (ctxt->inst) { 2080 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt); 2081 debugedNode = ctxt->inst; 2082 } 2083 } 2084 return(debugedNode); 2085 } 2086 2087 /** 2088 * xsltLocalVariablePush: 2089 * @ctxt: the transformation context 2090 * @variable: variable to be pushed to the variable stack 2091 * @level: new value for variable's level 2092 * 2093 * Places the variable onto the local variable stack 2094 * 2095 * Returns: 0 for success, -1 for any error 2096 * **NOTE:** 2097 * This is an internal routine and should not be called by users! 2098 */ 2099 int 2100 xsltLocalVariablePush(xsltTransformContextPtr ctxt, 2101 xsltStackElemPtr variable, 2102 int level) 2103 { 2104 if (ctxt->varsMax == 0) { 2105 ctxt->varsMax = 10; 2106 ctxt->varsTab = 2107 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * 2108 sizeof(ctxt->varsTab[0])); 2109 if (ctxt->varsTab == NULL) { 2110 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 2111 return (-1); 2112 } 2113 } 2114 if (ctxt->varsNr >= ctxt->varsMax) { 2115 ctxt->varsMax *= 2; 2116 ctxt->varsTab = 2117 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, 2118 ctxt->varsMax * 2119 sizeof(ctxt->varsTab[0])); 2120 if (ctxt->varsTab == NULL) { 2121 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 2122 return (-1); 2123 } 2124 } 2125 ctxt->varsTab[ctxt->varsNr++] = variable; 2126 ctxt->vars = variable; 2127 variable->level = level; 2128 return(0); 2129 } 2130 2131 /** 2132 * xsltReleaseLocalRVTs: 2133 * 2134 * Fragments which are results of extension instructions 2135 * are preserved; all other fragments are freed/cached. 2136 */ 2137 static void 2138 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) 2139 { 2140 xmlDocPtr cur = ctxt->localRVT, tmp; 2141 2142 while ((cur != NULL) && (cur != base)) { 2143 if (cur->psvi == (void *) ((long) 1)) { 2144 cur = (xmlDocPtr) cur->next; 2145 } else { 2146 tmp = cur; 2147 cur = (xmlDocPtr) cur->next; 2148 2149 if (tmp == ctxt->localRVT) 2150 ctxt->localRVT = cur; 2151 2152 /* 2153 * We need ctxt->localRVTBase for extension instructions 2154 * which return values (like EXSLT's function). 2155 */ 2156 if (tmp == ctxt->localRVTBase) 2157 ctxt->localRVTBase = cur; 2158 2159 if (tmp->prev) 2160 tmp->prev->next = (xmlNodePtr) cur; 2161 if (cur) 2162 cur->prev = tmp->prev; 2163 xsltReleaseRVT(ctxt, tmp); 2164 } 2165 } 2166 } 2167 2168 /** 2169 * xsltApplySequenceConstructor: 2170 * @ctxt: a XSLT process context 2171 * @contextNode: the "current node" in the source tree 2172 * @list: the nodes of a sequence constructor; 2173 * (plus leading xsl:param elements) 2174 * @templ: the compiled xsl:template (optional) 2175 * 2176 * Processes a sequence constructor. 2177 * 2178 * NOTE: ctxt->currentTemplateRule was introduced to reflect the 2179 * semantics of "current template rule". I.e. the field ctxt->templ 2180 * is not intended to reflect this, thus always pushed onto the 2181 * template stack. 2182 */ 2183 static void 2184 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, 2185 xmlNodePtr contextNode, xmlNodePtr list, 2186 xsltTemplatePtr templ) 2187 { 2188 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; 2189 xmlNodePtr cur, insert, copy = NULL; 2190 int level = 0, oldVarsNr; 2191 xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase; 2192 2193 #ifdef XSLT_REFACTORED 2194 xsltStylePreCompPtr info; 2195 #endif 2196 2197 #ifdef WITH_DEBUGGER 2198 int addCallResult = 0; 2199 xmlNodePtr debuggedNode = NULL; 2200 #endif 2201 2202 if (ctxt == NULL) 2203 return; 2204 2205 #ifdef WITH_DEBUGGER 2206 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 2207 debuggedNode = 2208 xsltDebuggerStartSequenceConstructor(ctxt, contextNode, 2209 list, templ, &addCallResult); 2210 if (debuggedNode == NULL) 2211 return; 2212 } 2213 #endif 2214 2215 if (list == NULL) 2216 return; 2217 CHECK_STOPPED; 2218 2219 oldLocalFragmentTop = ctxt->localRVT; 2220 oldInsert = insert = ctxt->insert; 2221 oldInst = oldCurInst = ctxt->inst; 2222 oldContextNode = ctxt->node; 2223 /* 2224 * Save current number of variables on the stack; new vars are popped when 2225 * exiting. 2226 */ 2227 oldVarsNr = ctxt->varsNr; 2228 /* 2229 * Process the sequence constructor. 2230 */ 2231 cur = list; 2232 while (cur != NULL) { 2233 ctxt->inst = cur; 2234 2235 #ifdef WITH_DEBUGGER 2236 switch (ctxt->debugStatus) { 2237 case XSLT_DEBUG_RUN_RESTART: 2238 case XSLT_DEBUG_QUIT: 2239 break; 2240 2241 } 2242 #endif 2243 /* 2244 * Test; we must have a valid insertion point. 2245 */ 2246 if (insert == NULL) { 2247 2248 #ifdef WITH_XSLT_DEBUG_PROCESS 2249 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2250 "xsltApplySequenceConstructor: insert == NULL !\n")); 2251 #endif 2252 goto error; 2253 } 2254 2255 #ifdef WITH_DEBUGGER 2256 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur)) 2257 xslHandleDebugger(cur, contextNode, templ, ctxt); 2258 #endif 2259 2260 #ifdef XSLT_REFACTORED 2261 if (cur->type == XML_ELEMENT_NODE) { 2262 info = (xsltStylePreCompPtr) cur->psvi; 2263 /* 2264 * We expect a compiled representation on: 2265 * 1) XSLT instructions of this XSLT version (1.0) 2266 * (with a few exceptions) 2267 * 2) Literal result elements 2268 * 3) Extension instructions 2269 * 4) XSLT instructions of future XSLT versions 2270 * (forwards-compatible mode). 2271 */ 2272 if (info == NULL) { 2273 /* 2274 * Handle the rare cases where we don't expect a compiled 2275 * representation on an XSLT element. 2276 */ 2277 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) { 2278 xsltMessage(ctxt, contextNode, cur); 2279 goto skip_children; 2280 } 2281 /* 2282 * Something really went wrong: 2283 */ 2284 xsltTransformError(ctxt, NULL, cur, 2285 "Internal error in xsltApplySequenceConstructor(): " 2286 "The element '%s' in the stylesheet has no compiled " 2287 "representation.\n", 2288 cur->name); 2289 goto skip_children; 2290 } 2291 2292 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) { 2293 xsltStyleItemLRElementInfoPtr lrInfo = 2294 (xsltStyleItemLRElementInfoPtr) info; 2295 /* 2296 * Literal result elements 2297 * -------------------------------------------------------- 2298 */ 2299 #ifdef WITH_XSLT_DEBUG_PROCESS 2300 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 2301 xsltGenericDebug(xsltGenericDebugContext, 2302 "xsltApplySequenceConstructor: copy literal result " 2303 "element '%s'\n", cur->name)); 2304 #endif 2305 /* 2306 * Copy the raw element-node. 2307 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert)) 2308 * == NULL) 2309 * goto error; 2310 */ 2311 copy = xmlDocCopyNode(cur, insert->doc, 0); 2312 if (copy == NULL) { 2313 xsltTransformError(ctxt, NULL, cur, 2314 "Internal error in xsltApplySequenceConstructor(): " 2315 "Failed to copy literal result element '%s'.\n", 2316 cur->name); 2317 goto error; 2318 } else { 2319 /* 2320 * Add the element-node to the result tree. 2321 */ 2322 copy->doc = ctxt->output; 2323 copy = xsltAddChild(insert, copy); 2324 /* 2325 * Create effective namespaces declarations. 2326 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef); 2327 */ 2328 if (lrInfo->effectiveNs != NULL) { 2329 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs; 2330 xmlNsPtr ns, lastns = NULL; 2331 2332 while (effNs != NULL) { 2333 /* 2334 * Avoid generating redundant namespace 2335 * declarations; thus lookup if there is already 2336 * such a ns-decl in the result. 2337 */ 2338 ns = xmlSearchNs(copy->doc, copy, effNs->prefix); 2339 if ((ns != NULL) && 2340 (xmlStrEqual(ns->href, effNs->nsName))) 2341 { 2342 effNs = effNs->next; 2343 continue; 2344 } 2345 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix); 2346 if (ns == NULL) { 2347 xsltTransformError(ctxt, NULL, cur, 2348 "Internal error in " 2349 "xsltApplySequenceConstructor(): " 2350 "Failed to copy a namespace " 2351 "declaration.\n"); 2352 goto error; 2353 } 2354 2355 if (lastns == NULL) 2356 copy->nsDef = ns; 2357 else 2358 lastns->next =ns; 2359 lastns = ns; 2360 2361 effNs = effNs->next; 2362 } 2363 2364 } 2365 /* 2366 * NOTE that we don't need to apply ns-alising: this was 2367 * already done at compile-time. 2368 */ 2369 if (cur->ns != NULL) { 2370 /* 2371 * If there's no such ns-decl in the result tree, 2372 * then xsltGetSpecialNamespace() will 2373 * create a ns-decl on the copied node. 2374 */ 2375 copy->ns = xsltGetSpecialNamespace(ctxt, cur, 2376 cur->ns->href, cur->ns->prefix, copy); 2377 } else { 2378 /* 2379 * Undeclare the default namespace if needed. 2380 * This can be skipped, if the result element has 2381 * no ns-decls, in which case the result element 2382 * obviously does not declare a default namespace; 2383 * AND there's either no parent, or the parent 2384 * element is in no namespace; this means there's no 2385 * default namespace is scope to care about. 2386 * 2387 * REVISIT: This might result in massive 2388 * generation of ns-decls if nodes in a default 2389 * namespaces are mixed with nodes in no namespace. 2390 * 2391 */ 2392 if (copy->nsDef || 2393 ((insert != NULL) && 2394 (insert->type == XML_ELEMENT_NODE) && 2395 (insert->ns != NULL))) 2396 { 2397 xsltGetSpecialNamespace(ctxt, cur, 2398 NULL, NULL, copy); 2399 } 2400 } 2401 } 2402 /* 2403 * SPEC XSLT 2.0 "Each attribute of the literal result 2404 * element, other than an attribute in the XSLT namespace, 2405 * is processed to produce an attribute for the element in 2406 * the result tree." 2407 * NOTE: See bug #341325. 2408 */ 2409 if (cur->properties != NULL) { 2410 xsltAttrListTemplateProcess(ctxt, copy, cur->properties); 2411 } 2412 } else if (IS_XSLT_ELEM_FAST(cur)) { 2413 /* 2414 * XSLT instructions 2415 * -------------------------------------------------------- 2416 */ 2417 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) { 2418 /* 2419 * We hit an unknown XSLT element. 2420 * Try to apply one of the fallback cases. 2421 */ 2422 ctxt->insert = insert; 2423 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 2424 xsltTransformError(ctxt, NULL, cur, 2425 "The is no fallback behaviour defined for " 2426 "the unknown XSLT element '%s'.\n", 2427 cur->name); 2428 } 2429 ctxt->insert = oldInsert; 2430 } else if (info->func != NULL) { 2431 /* 2432 * Execute the XSLT instruction. 2433 */ 2434 ctxt->insert = insert; 2435 2436 info->func(ctxt, contextNode, cur, 2437 (xsltElemPreCompPtr) info); 2438 2439 /* 2440 * Cleanup temporary tree fragments. 2441 */ 2442 if (oldLocalFragmentTop != ctxt->localRVT) 2443 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 2444 2445 ctxt->insert = oldInsert; 2446 } else if (info->type == XSLT_FUNC_VARIABLE) { 2447 xsltStackElemPtr tmpvar = ctxt->vars; 2448 2449 xsltParseStylesheetVariable(ctxt, cur); 2450 2451 if (tmpvar != ctxt->vars) { 2452 /* 2453 * TODO: Using a @tmpvar is an annoying workaround, but 2454 * the current mechanisms do not provide any other way 2455 * of knowing if the var was really pushed onto the 2456 * stack. 2457 */ 2458 ctxt->vars->level = level; 2459 } 2460 } else if (info->type == XSLT_FUNC_MESSAGE) { 2461 /* 2462 * TODO: Won't be hit, since we don't compile xsl:message. 2463 */ 2464 xsltMessage(ctxt, contextNode, cur); 2465 } else { 2466 xsltTransformError(ctxt, NULL, cur, 2467 "Unexpected XSLT element '%s'.\n", cur->name); 2468 } 2469 goto skip_children; 2470 2471 } else { 2472 xsltTransformFunction func; 2473 /* 2474 * Extension intructions (elements) 2475 * -------------------------------------------------------- 2476 */ 2477 if (cur->psvi == xsltExtMarker) { 2478 /* 2479 * The xsltExtMarker was set during the compilation 2480 * of extension instructions if there was no registered 2481 * handler for this specific extension function at 2482 * compile-time. 2483 * Libxslt will now lookup if a handler is 2484 * registered in the context of this transformation. 2485 */ 2486 func = (xsltTransformFunction) 2487 xsltExtElementLookup(ctxt, cur->name, cur->ns->href); 2488 } else 2489 func = ((xsltElemPreCompPtr) cur->psvi)->func; 2490 2491 if (func == NULL) { 2492 /* 2493 * No handler available. 2494 * Try to execute fallback behaviour via xsl:fallback. 2495 */ 2496 #ifdef WITH_XSLT_DEBUG_PROCESS 2497 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 2498 xsltGenericDebug(xsltGenericDebugContext, 2499 "xsltApplySequenceConstructor: unknown extension %s\n", 2500 cur->name)); 2501 #endif 2502 ctxt->insert = insert; 2503 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 2504 xsltTransformError(ctxt, NULL, cur, 2505 "Unknown extension instruction '{%s}%s'.\n", 2506 cur->ns->href, cur->name); 2507 } 2508 ctxt->insert = oldInsert; 2509 } else { 2510 /* 2511 * Execute the handler-callback. 2512 */ 2513 #ifdef WITH_XSLT_DEBUG_PROCESS 2514 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2515 "xsltApplySequenceConstructor: extension construct %s\n", 2516 cur->name)); 2517 #endif 2518 ctxt->insert = insert; 2519 /* 2520 * We need the fragment base for extension instructions 2521 * which return values (like EXSLT's function). 2522 */ 2523 oldLocalFragmentBase = ctxt->localRVTBase; 2524 ctxt->localRVTBase = NULL; 2525 2526 func(ctxt, contextNode, cur, cur->psvi); 2527 2528 ctxt->localRVTBase = oldLocalFragmentBase; 2529 /* 2530 * Cleanup temporary tree fragments. 2531 */ 2532 if (oldLocalFragmentTop != ctxt->localRVT) 2533 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 2534 2535 ctxt->insert = oldInsert; 2536 } 2537 goto skip_children; 2538 } 2539 2540 } else if (XSLT_IS_TEXT_NODE(cur)) { 2541 /* 2542 * Text 2543 * ------------------------------------------------------------ 2544 */ 2545 #ifdef WITH_XSLT_DEBUG_PROCESS 2546 if (cur->name == xmlStringTextNoenc) { 2547 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 2548 xsltGenericDebug(xsltGenericDebugContext, 2549 "xsltApplySequenceConstructor: copy unescaped text '%s'\n", 2550 cur->content)); 2551 } else { 2552 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 2553 xsltGenericDebug(xsltGenericDebugContext, 2554 "xsltApplySequenceConstructor: copy text '%s'\n", 2555 cur->content)); 2556 } 2557 #endif 2558 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) 2559 goto error; 2560 } 2561 2562 #else /* XSLT_REFACTORED */ 2563 2564 if (IS_XSLT_ELEM(cur)) { 2565 /* 2566 * This is an XSLT node 2567 */ 2568 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi; 2569 2570 if (info == NULL) { 2571 if (IS_XSLT_NAME(cur, "message")) { 2572 xsltMessage(ctxt, contextNode, cur); 2573 } else { 2574 /* 2575 * That's an error try to apply one of the fallback cases 2576 */ 2577 ctxt->insert = insert; 2578 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 2579 xsltGenericError(xsltGenericErrorContext, 2580 "xsltApplySequenceConstructor: %s was not compiled\n", 2581 cur->name); 2582 } 2583 ctxt->insert = oldInsert; 2584 } 2585 goto skip_children; 2586 } 2587 2588 if (info->func != NULL) { 2589 oldCurInst = ctxt->inst; 2590 ctxt->inst = cur; 2591 ctxt->insert = insert; 2592 oldLocalFragmentBase = ctxt->localRVTBase; 2593 ctxt->localRVTBase = NULL; 2594 2595 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); 2596 2597 ctxt->localRVTBase = oldLocalFragmentBase; 2598 /* 2599 * Cleanup temporary tree fragments. 2600 */ 2601 if (oldLocalFragmentTop != ctxt->localRVT) 2602 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 2603 2604 ctxt->insert = oldInsert; 2605 ctxt->inst = oldCurInst; 2606 goto skip_children; 2607 } 2608 2609 if (IS_XSLT_NAME(cur, "variable")) { 2610 xsltStackElemPtr tmpvar = ctxt->vars; 2611 2612 oldCurInst = ctxt->inst; 2613 ctxt->inst = cur; 2614 2615 xsltParseStylesheetVariable(ctxt, cur); 2616 2617 ctxt->inst = oldCurInst; 2618 2619 if (tmpvar != ctxt->vars) { 2620 /* 2621 * TODO: Using a @tmpvar is an annoying workaround, but 2622 * the current mechanisms do not provide any other way 2623 * of knowing if the var was really pushed onto the 2624 * stack. 2625 */ 2626 ctxt->vars->level = level; 2627 } 2628 } else if (IS_XSLT_NAME(cur, "message")) { 2629 xsltMessage(ctxt, contextNode, cur); 2630 } else { 2631 xsltTransformError(ctxt, NULL, cur, 2632 "Unexpected XSLT element '%s'.\n", cur->name); 2633 } 2634 goto skip_children; 2635 } else if ((cur->type == XML_TEXT_NODE) || 2636 (cur->type == XML_CDATA_SECTION_NODE)) { 2637 2638 /* 2639 * This text comes from the stylesheet 2640 * For stylesheets, the set of whitespace-preserving 2641 * element names consists of just xsl:text. 2642 */ 2643 #ifdef WITH_XSLT_DEBUG_PROCESS 2644 if (cur->type == XML_CDATA_SECTION_NODE) { 2645 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2646 "xsltApplySequenceConstructor: copy CDATA text %s\n", 2647 cur->content)); 2648 } else if (cur->name == xmlStringTextNoenc) { 2649 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2650 "xsltApplySequenceConstructor: copy unescaped text %s\n", 2651 cur->content)); 2652 } else { 2653 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2654 "xsltApplySequenceConstructor: copy text %s\n", 2655 cur->content)); 2656 } 2657 #endif 2658 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) 2659 goto error; 2660 } else if ((cur->type == XML_ELEMENT_NODE) && 2661 (cur->ns != NULL) && (cur->psvi != NULL)) { 2662 xsltTransformFunction function; 2663 2664 oldCurInst = ctxt->inst; 2665 ctxt->inst = cur; 2666 /* 2667 * Flagged as an extension element 2668 */ 2669 if (cur->psvi == xsltExtMarker) 2670 function = (xsltTransformFunction) 2671 xsltExtElementLookup(ctxt, cur->name, cur->ns->href); 2672 else 2673 function = ((xsltElemPreCompPtr) cur->psvi)->func; 2674 2675 if (function == NULL) { 2676 xmlNodePtr child; 2677 int found = 0; 2678 2679 #ifdef WITH_XSLT_DEBUG_PROCESS 2680 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2681 "xsltApplySequenceConstructor: unknown extension %s\n", 2682 cur->name)); 2683 #endif 2684 /* 2685 * Search if there are fallbacks 2686 */ 2687 child = cur->children; 2688 while (child != NULL) { 2689 if ((IS_XSLT_ELEM(child)) && 2690 (IS_XSLT_NAME(child, "fallback"))) 2691 { 2692 found = 1; 2693 xsltApplySequenceConstructor(ctxt, contextNode, 2694 child->children, NULL); 2695 } 2696 child = child->next; 2697 } 2698 2699 if (!found) { 2700 xsltTransformError(ctxt, NULL, cur, 2701 "xsltApplySequenceConstructor: failed to find extension %s\n", 2702 cur->name); 2703 } 2704 } else { 2705 #ifdef WITH_XSLT_DEBUG_PROCESS 2706 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2707 "xsltApplySequenceConstructor: extension construct %s\n", 2708 cur->name)); 2709 #endif 2710 2711 ctxt->insert = insert; 2712 /* 2713 * We need the fragment base for extension instructions 2714 * which return values (like EXSLT's function). 2715 */ 2716 oldLocalFragmentBase = ctxt->localRVTBase; 2717 ctxt->localRVTBase = NULL; 2718 2719 function(ctxt, contextNode, cur, cur->psvi); 2720 /* 2721 * Cleanup temporary tree fragments. 2722 */ 2723 if (oldLocalFragmentTop != ctxt->localRVT) 2724 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 2725 2726 ctxt->localRVTBase = oldLocalFragmentBase; 2727 ctxt->insert = oldInsert; 2728 2729 } 2730 ctxt->inst = oldCurInst; 2731 goto skip_children; 2732 } else if (cur->type == XML_ELEMENT_NODE) { 2733 #ifdef WITH_XSLT_DEBUG_PROCESS 2734 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2735 "xsltApplySequenceConstructor: copy node %s\n", 2736 cur->name)); 2737 #endif 2738 oldCurInst = ctxt->inst; 2739 ctxt->inst = cur; 2740 2741 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL) 2742 goto error; 2743 /* 2744 * Add extra namespaces inherited from the current template 2745 * if we are in the first level children and this is a 2746 * "real" template. 2747 */ 2748 if ((templ != NULL) && (oldInsert == insert) && 2749 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) { 2750 int i; 2751 xmlNsPtr ns, ret; 2752 2753 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) { 2754 const xmlChar *URI = NULL; 2755 xsltStylesheetPtr style; 2756 ns = ctxt->templ->inheritedNs[i]; 2757 2758 /* Note that the XSLT namespace was already excluded 2759 * in xsltGetInheritedNsList(). 2760 */ 2761 #if 0 2762 if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) 2763 continue; 2764 #endif 2765 style = ctxt->style; 2766 while (style != NULL) { 2767 if (style->nsAliases != NULL) 2768 URI = (const xmlChar *) 2769 xmlHashLookup(style->nsAliases, ns->href); 2770 if (URI != NULL) 2771 break; 2772 2773 style = xsltNextImport(style); 2774 } 2775 if (URI == UNDEFINED_DEFAULT_NS) 2776 continue; 2777 if (URI == NULL) 2778 URI = ns->href; 2779 /* 2780 * TODO: The following will still be buggy for the 2781 * non-refactored code. 2782 */ 2783 ret = xmlSearchNs(copy->doc, copy, ns->prefix); 2784 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI))) 2785 { 2786 xmlNewNs(copy, URI, ns->prefix); 2787 } 2788 } 2789 if (copy->ns != NULL) { 2790 /* 2791 * Fix the node namespace if needed 2792 */ 2793 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy); 2794 } 2795 } 2796 /* 2797 * all the attributes are directly inherited 2798 */ 2799 if (cur->properties != NULL) { 2800 xsltAttrListTemplateProcess(ctxt, copy, cur->properties); 2801 } 2802 ctxt->inst = oldCurInst; 2803 } 2804 #endif /* else of XSLT_REFACTORED */ 2805 2806 /* 2807 * Descend into content in document order. 2808 */ 2809 if (cur->children != NULL) { 2810 if (cur->children->type != XML_ENTITY_DECL) { 2811 cur = cur->children; 2812 level++; 2813 if (copy != NULL) 2814 insert = copy; 2815 continue; 2816 } 2817 } 2818 2819 skip_children: 2820 /* 2821 * If xslt:message was just processed, we might have hit a 2822 * terminate='yes'; if so, then break the loop and clean up. 2823 * TODO: Do we need to check this also before trying to descend 2824 * into the content? 2825 */ 2826 if (ctxt->state == XSLT_STATE_STOPPED) 2827 break; 2828 if (cur->next != NULL) { 2829 cur = cur->next; 2830 continue; 2831 } 2832 2833 do { 2834 cur = cur->parent; 2835 level--; 2836 /* 2837 * Pop variables/params (xsl:variable and xsl:param). 2838 */ 2839 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) { 2840 xsltLocalVariablePop(ctxt, oldVarsNr, level); 2841 } 2842 2843 insert = insert->parent; 2844 if (cur == NULL) 2845 break; 2846 if (cur == list->parent) { 2847 cur = NULL; 2848 break; 2849 } 2850 if (cur->next != NULL) { 2851 cur = cur->next; 2852 break; 2853 } 2854 } while (cur != NULL); 2855 } 2856 2857 error: 2858 /* 2859 * In case of errors: pop remaining variables. 2860 */ 2861 if (ctxt->varsNr > oldVarsNr) 2862 xsltLocalVariablePop(ctxt, oldVarsNr, -1); 2863 2864 ctxt->node = oldContextNode; 2865 ctxt->inst = oldInst; 2866 ctxt->insert = oldInsert; 2867 2868 #ifdef WITH_DEBUGGER 2869 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { 2870 xslDropCall(); 2871 } 2872 #endif 2873 } 2874 2875 /* 2876 * xsltApplyXSLTTemplate: 2877 * @ctxt: a XSLT transformation context 2878 * @contextNode: the node in the source tree. 2879 * @list: the nodes of a sequence constructor; 2880 * (plus leading xsl:param elements) 2881 * @templ: the compiled xsl:template declaration; 2882 * NULL if a sequence constructor 2883 * @withParams: a set of caller-parameters (xsl:with-param) or NULL 2884 * 2885 * Called by: 2886 * - xsltApplyImports() 2887 * - xsltCallTemplate() 2888 * - xsltDefaultProcessOneNode() 2889 * - xsltProcessOneNode() 2890 */ 2891 static void 2892 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, 2893 xmlNodePtr contextNode, 2894 xmlNodePtr list, 2895 xsltTemplatePtr templ, 2896 xsltStackElemPtr withParams) 2897 { 2898 int oldVarsBase = 0; 2899 long start = 0; 2900 xmlNodePtr cur; 2901 xsltStackElemPtr tmpParam = NULL; 2902 xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop; 2903 2904 #ifdef XSLT_REFACTORED 2905 xsltStyleItemParamPtr iparam; 2906 #else 2907 xsltStylePreCompPtr iparam; 2908 #endif 2909 2910 #ifdef WITH_DEBUGGER 2911 int addCallResult = 0; 2912 #endif 2913 2914 if (ctxt == NULL) 2915 return; 2916 if (templ == NULL) { 2917 xsltTransformError(ctxt, NULL, list, 2918 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n"); 2919 return; 2920 } 2921 2922 #ifdef WITH_DEBUGGER 2923 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 2924 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode, 2925 list, templ, &addCallResult) == NULL) 2926 return; 2927 } 2928 #endif 2929 2930 if (list == NULL) 2931 return; 2932 CHECK_STOPPED; 2933 2934 /* 2935 * Check for infinite recursion: stop if the maximum of nested templates 2936 * is excceeded. Adjust xsltMaxDepth if you need more. 2937 */ 2938 if (((ctxt->templNr >= xsltMaxDepth) || 2939 (ctxt->varsNr >= 5 * xsltMaxDepth))) 2940 { 2941 xsltTransformError(ctxt, NULL, list, 2942 "xsltApplyXSLTTemplate: A potential infinite template recursion " 2943 "was detected.\n" 2944 "You can adjust xsltMaxDepth (--maxdepth) in order to " 2945 "raise the maximum number of nested template calls and " 2946 "variables/params (currently set to %d).\n", 2947 xsltMaxDepth); 2948 xsltDebug(ctxt, contextNode, list, NULL); 2949 return; 2950 } 2951 2952 oldUserFragmentTop = ctxt->tmpRVT; 2953 ctxt->tmpRVT = NULL; 2954 oldLocalFragmentTop = ctxt->localRVT; 2955 2956 /* 2957 * Initiate a distinct scope of local params/variables. 2958 */ 2959 oldVarsBase = ctxt->varsBase; 2960 ctxt->varsBase = ctxt->varsNr; 2961 2962 ctxt->node = contextNode; 2963 if (ctxt->profile) { 2964 templ->nbCalls++; 2965 start = xsltTimestamp(); 2966 profPush(ctxt, 0); 2967 } 2968 /* 2969 * Push the xsl:template declaration onto the stack. 2970 */ 2971 templPush(ctxt, templ); 2972 2973 #ifdef WITH_XSLT_DEBUG_PROCESS 2974 if (templ->name != NULL) 2975 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 2976 "applying xsl:template '%s'\n", templ->name)); 2977 #endif 2978 /* 2979 * Process xsl:param instructions and skip those elements for 2980 * further processing. 2981 */ 2982 cur = list; 2983 do { 2984 if (cur->type == XML_TEXT_NODE) { 2985 cur = cur->next; 2986 continue; 2987 } 2988 if ((cur->type != XML_ELEMENT_NODE) || 2989 (cur->name[0] != 'p') || 2990 (cur->psvi == NULL) || 2991 (! xmlStrEqual(cur->name, BAD_CAST "param")) || 2992 (! IS_XSLT_ELEM(cur))) 2993 { 2994 break; 2995 } 2996 2997 list = cur->next; 2998 2999 #ifdef XSLT_REFACTORED 3000 iparam = (xsltStyleItemParamPtr) cur->psvi; 3001 #else 3002 iparam = (xsltStylePreCompPtr) cur->psvi; 3003 #endif 3004 3005 /* 3006 * Substitute xsl:param for a given xsl:with-param. 3007 * Since the XPath expression will reference the params/vars 3008 * by index, we need to slot the xsl:with-params in the 3009 * order of encountered xsl:params to keep the sequence of 3010 * params/variables in the stack exactly as it was at 3011 * compile time, 3012 */ 3013 tmpParam = NULL; 3014 if (withParams) { 3015 tmpParam = withParams; 3016 do { 3017 if ((tmpParam->name == (iparam->name)) && 3018 (tmpParam->nameURI == (iparam->ns))) 3019 { 3020 /* 3021 * Push the caller-parameter. 3022 */ 3023 xsltLocalVariablePush(ctxt, tmpParam, -1); 3024 break; 3025 } 3026 tmpParam = tmpParam->next; 3027 } while (tmpParam != NULL); 3028 } 3029 /* 3030 * Push the xsl:param. 3031 */ 3032 if (tmpParam == NULL) { 3033 /* 3034 * Note that we must assume that the added parameter 3035 * has a @depth of 0. 3036 */ 3037 xsltParseStylesheetParam(ctxt, cur); 3038 } 3039 cur = cur->next; 3040 } while (cur != NULL); 3041 /* 3042 * Process the sequence constructor. 3043 */ 3044 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 3045 3046 /* 3047 * Remove remaining xsl:param and xsl:with-param items from 3048 * the stack. Don't free xsl:with-param items. 3049 */ 3050 if (ctxt->varsNr > ctxt->varsBase) 3051 xsltTemplateParamsCleanup(ctxt); 3052 ctxt->varsBase = oldVarsBase; 3053 3054 /* 3055 * Clean up remaining local tree fragments. 3056 * This also frees fragments which are the result of 3057 * extension instructions. Should normally not be hit; but 3058 * just for the case xsltExtensionInstructionResultFinalize() 3059 * was not called by the extension author. 3060 */ 3061 if (oldLocalFragmentTop != ctxt->localRVT) { 3062 xmlDocPtr curdoc = ctxt->localRVT, tmp; 3063 3064 do { 3065 tmp = curdoc; 3066 curdoc = (xmlDocPtr) curdoc->next; 3067 /* Need to housekeep localRVTBase */ 3068 if (tmp == ctxt->localRVTBase) 3069 ctxt->localRVTBase = curdoc; 3070 if (tmp->prev) 3071 tmp->prev->next = (xmlNodePtr) curdoc; 3072 if (curdoc) 3073 curdoc->prev = tmp->prev; 3074 xsltReleaseRVT(ctxt, tmp); 3075 } while (curdoc != oldLocalFragmentTop); 3076 } 3077 ctxt->localRVT = oldLocalFragmentTop; 3078 3079 /* 3080 * Release user-created fragments stored in the scope 3081 * of xsl:template. Note that this mechanism is deprecated: 3082 * user code should now use xsltRegisterLocalRVT() instead 3083 * of the obsolete xsltRegisterTmpRVT(). 3084 */ 3085 if (ctxt->tmpRVT) { 3086 xmlDocPtr curdoc = ctxt->tmpRVT, tmp; 3087 3088 while (curdoc != NULL) { 3089 tmp = curdoc; 3090 curdoc = (xmlDocPtr) curdoc->next; 3091 xsltReleaseRVT(ctxt, tmp); 3092 } 3093 } 3094 ctxt->tmpRVT = oldUserFragmentTop; 3095 3096 /* 3097 * Pop the xsl:template declaration from the stack. 3098 */ 3099 templPop(ctxt); 3100 if (ctxt->profile) { 3101 long spent, child, total, end; 3102 3103 end = xsltTimestamp(); 3104 child = profPop(ctxt); 3105 total = end - start; 3106 spent = total - child; 3107 if (spent <= 0) { 3108 /* 3109 * Not possible unless the original calibration failed 3110 * we can try to correct it on the fly. 3111 */ 3112 xsltCalibrateAdjust(spent); 3113 spent = 0; 3114 } 3115 3116 templ->time += spent; 3117 if (ctxt->profNr > 0) 3118 ctxt->profTab[ctxt->profNr - 1] += total; 3119 } 3120 3121 #ifdef WITH_DEBUGGER 3122 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { 3123 xslDropCall(); 3124 } 3125 #endif 3126 } 3127 3128 3129 /** 3130 * xsltApplyOneTemplate: 3131 * @ctxt: a XSLT process context 3132 * @contextNode: the node in the source tree. 3133 * @list: the nodes of a sequence constructor 3134 * @templ: not used 3135 * @params: a set of parameters (xsl:param) or NULL 3136 * 3137 * Processes a sequence constructor on the current node in the source tree. 3138 * 3139 * @params are the already computed variable stack items; this function 3140 * pushes them on the variable stack, and pops them before exiting; it's 3141 * left to the caller to free or reuse @params afterwards. The initial 3142 * states of the variable stack will always be restored before this 3143 * function exits. 3144 * NOTE that this does *not* initiate a new distinct variable scope; i.e. 3145 * variables already on the stack are visible to the process. The caller's 3146 * side needs to start a new variable scope if needed (e.g. in exsl:function). 3147 * 3148 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not 3149 * provide a @templ); a non-NULL @templ might raise an error in the future. 3150 * 3151 * BIG NOTE: This function is not intended to process the content of an 3152 * xsl:template; it does not expect xsl:param instructions in @list and 3153 * will report errors if found. 3154 * 3155 * Called by: 3156 * - xsltEvalVariable() (variables.c) 3157 * - exsltFuncFunctionFunction() (libexsl/functions.c) 3158 */ 3159 void 3160 xsltApplyOneTemplate(xsltTransformContextPtr ctxt, 3161 xmlNodePtr contextNode, 3162 xmlNodePtr list, 3163 xsltTemplatePtr templ ATTRIBUTE_UNUSED, 3164 xsltStackElemPtr params) 3165 { 3166 if ((ctxt == NULL) || (list == NULL)) 3167 return; 3168 CHECK_STOPPED; 3169 3170 if (params) { 3171 /* 3172 * This code should be obsolete - was previously used 3173 * by libexslt/functions.c, but due to bug 381319 the 3174 * logic there was changed. 3175 */ 3176 int oldVarsNr = ctxt->varsNr; 3177 3178 /* 3179 * Push the given xsl:param(s) onto the variable stack. 3180 */ 3181 while (params != NULL) { 3182 xsltLocalVariablePush(ctxt, params, -1); 3183 params = params->next; 3184 } 3185 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 3186 /* 3187 * Pop the given xsl:param(s) from the stack but don't free them. 3188 */ 3189 xsltLocalVariablePop(ctxt, oldVarsNr, -2); 3190 } else 3191 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 3192 } 3193 3194 /************************************************************************ 3195 * * 3196 * XSLT-1.1 extensions * 3197 * * 3198 ************************************************************************/ 3199 3200 /** 3201 * xsltDocumentElem: 3202 * @ctxt: an XSLT processing context 3203 * @node: The current node 3204 * @inst: the instruction in the stylesheet 3205 * @castedComp: precomputed information 3206 * 3207 * Process an EXSLT/XSLT-1.1 document element 3208 */ 3209 void 3210 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, 3211 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 3212 { 3213 #ifdef XSLT_REFACTORED 3214 xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp; 3215 #else 3216 xsltStylePreCompPtr comp = castedComp; 3217 #endif 3218 xsltStylesheetPtr style = NULL; 3219 int ret; 3220 xmlChar *filename = NULL, *prop, *elements; 3221 xmlChar *element, *end; 3222 xmlDocPtr res = NULL; 3223 xmlDocPtr oldOutput; 3224 xmlNodePtr oldInsert, root; 3225 const char *oldOutputFile; 3226 xsltOutputType oldType; 3227 xmlChar *URL = NULL; 3228 const xmlChar *method; 3229 const xmlChar *doctypePublic; 3230 const xmlChar *doctypeSystem; 3231 const xmlChar *version; 3232 const xmlChar *encoding; 3233 3234 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 3235 return; 3236 3237 if (comp->filename == NULL) { 3238 3239 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { 3240 /* 3241 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE 3242 * (http://icl.com/saxon) 3243 * The @file is in no namespace. 3244 */ 3245 #ifdef WITH_XSLT_DEBUG_EXTRA 3246 xsltGenericDebug(xsltGenericDebugContext, 3247 "Found saxon:output extension\n"); 3248 #endif 3249 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3250 (const xmlChar *) "file", 3251 XSLT_SAXON_NAMESPACE); 3252 3253 if (URL == NULL) 3254 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3255 (const xmlChar *) "href", 3256 XSLT_SAXON_NAMESPACE); 3257 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { 3258 #ifdef WITH_XSLT_DEBUG_EXTRA 3259 xsltGenericDebug(xsltGenericDebugContext, 3260 "Found xalan:write extension\n"); 3261 #endif 3262 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3263 (const xmlChar *) 3264 "select", 3265 XSLT_XALAN_NAMESPACE); 3266 if (URL != NULL) { 3267 xmlXPathCompExprPtr cmp; 3268 xmlChar *val; 3269 3270 /* 3271 * Trying to handle bug #59212 3272 * The value of the "select" attribute is an 3273 * XPath expression. 3274 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) 3275 */ 3276 cmp = xmlXPathCompile(URL); 3277 val = xsltEvalXPathString(ctxt, cmp); 3278 xmlXPathFreeCompExpr(cmp); 3279 xmlFree(URL); 3280 URL = val; 3281 } 3282 if (URL == NULL) 3283 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3284 (const xmlChar *) 3285 "file", 3286 XSLT_XALAN_NAMESPACE); 3287 if (URL == NULL) 3288 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3289 (const xmlChar *) 3290 "href", 3291 XSLT_XALAN_NAMESPACE); 3292 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { 3293 URL = xsltEvalAttrValueTemplate(ctxt, inst, 3294 (const xmlChar *) "href", 3295 NULL); 3296 } 3297 3298 } else { 3299 URL = xmlStrdup(comp->filename); 3300 } 3301 3302 if (URL == NULL) { 3303 xsltTransformError(ctxt, NULL, inst, 3304 "xsltDocumentElem: href/URI-Reference not found\n"); 3305 return; 3306 } 3307 3308 /* 3309 * If the computation failed, it's likely that the URL wasn't escaped 3310 */ 3311 filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile); 3312 if (filename == NULL) { 3313 xmlChar *escURL; 3314 3315 escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,"); 3316 if (escURL != NULL) { 3317 filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile); 3318 xmlFree(escURL); 3319 } 3320 } 3321 3322 if (filename == NULL) { 3323 xsltTransformError(ctxt, NULL, inst, 3324 "xsltDocumentElem: URL computation failed for %s\n", 3325 URL); 3326 xmlFree(URL); 3327 return; 3328 } 3329 3330 /* 3331 * Security checking: can we write to this resource 3332 */ 3333 if (ctxt->sec != NULL) { 3334 ret = xsltCheckWrite(ctxt->sec, ctxt, filename); 3335 if (ret == 0) { 3336 xsltTransformError(ctxt, NULL, inst, 3337 "xsltDocumentElem: write rights for %s denied\n", 3338 filename); 3339 xmlFree(URL); 3340 xmlFree(filename); 3341 return; 3342 } 3343 } 3344 3345 oldOutputFile = ctxt->outputFile; 3346 oldOutput = ctxt->output; 3347 oldInsert = ctxt->insert; 3348 oldType = ctxt->type; 3349 ctxt->outputFile = (const char *) filename; 3350 3351 style = xsltNewStylesheet(); 3352 if (style == NULL) { 3353 xsltTransformError(ctxt, NULL, inst, 3354 "xsltDocumentElem: out of memory\n"); 3355 goto error; 3356 } 3357 3358 /* 3359 * Version described in 1.1 draft allows full parameterization 3360 * of the output. 3361 */ 3362 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3363 (const xmlChar *) "version", 3364 NULL); 3365 if (prop != NULL) { 3366 if (style->version != NULL) 3367 xmlFree(style->version); 3368 style->version = prop; 3369 } 3370 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3371 (const xmlChar *) "encoding", 3372 NULL); 3373 if (prop != NULL) { 3374 if (style->encoding != NULL) 3375 xmlFree(style->encoding); 3376 style->encoding = prop; 3377 } 3378 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3379 (const xmlChar *) "method", 3380 NULL); 3381 if (prop != NULL) { 3382 const xmlChar *URI; 3383 3384 if (style->method != NULL) 3385 xmlFree(style->method); 3386 style->method = NULL; 3387 if (style->methodURI != NULL) 3388 xmlFree(style->methodURI); 3389 style->methodURI = NULL; 3390 3391 URI = xsltGetQNameURI(inst, &prop); 3392 if (prop == NULL) { 3393 if (style != NULL) style->errors++; 3394 } else if (URI == NULL) { 3395 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || 3396 (xmlStrEqual(prop, (const xmlChar *) "html")) || 3397 (xmlStrEqual(prop, (const xmlChar *) "text"))) { 3398 style->method = prop; 3399 } else { 3400 xsltTransformError(ctxt, NULL, inst, 3401 "invalid value for method: %s\n", prop); 3402 if (style != NULL) style->warnings++; 3403 } 3404 } else { 3405 style->method = prop; 3406 style->methodURI = xmlStrdup(URI); 3407 } 3408 } 3409 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3410 (const xmlChar *) 3411 "doctype-system", NULL); 3412 if (prop != NULL) { 3413 if (style->doctypeSystem != NULL) 3414 xmlFree(style->doctypeSystem); 3415 style->doctypeSystem = prop; 3416 } 3417 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3418 (const xmlChar *) 3419 "doctype-public", NULL); 3420 if (prop != NULL) { 3421 if (style->doctypePublic != NULL) 3422 xmlFree(style->doctypePublic); 3423 style->doctypePublic = prop; 3424 } 3425 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3426 (const xmlChar *) "standalone", 3427 NULL); 3428 if (prop != NULL) { 3429 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 3430 style->standalone = 1; 3431 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 3432 style->standalone = 0; 3433 } else { 3434 xsltTransformError(ctxt, NULL, inst, 3435 "invalid value for standalone: %s\n", 3436 prop); 3437 if (style != NULL) style->warnings++; 3438 } 3439 xmlFree(prop); 3440 } 3441 3442 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3443 (const xmlChar *) "indent", 3444 NULL); 3445 if (prop != NULL) { 3446 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 3447 style->indent = 1; 3448 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 3449 style->indent = 0; 3450 } else { 3451 xsltTransformError(ctxt, NULL, inst, 3452 "invalid value for indent: %s\n", prop); 3453 if (style != NULL) style->warnings++; 3454 } 3455 xmlFree(prop); 3456 } 3457 3458 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3459 (const xmlChar *) 3460 "omit-xml-declaration", 3461 NULL); 3462 if (prop != NULL) { 3463 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 3464 style->omitXmlDeclaration = 1; 3465 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 3466 style->omitXmlDeclaration = 0; 3467 } else { 3468 xsltTransformError(ctxt, NULL, inst, 3469 "invalid value for omit-xml-declaration: %s\n", 3470 prop); 3471 if (style != NULL) style->warnings++; 3472 } 3473 xmlFree(prop); 3474 } 3475 3476 elements = xsltEvalAttrValueTemplate(ctxt, inst, 3477 (const xmlChar *) 3478 "cdata-section-elements", 3479 NULL); 3480 if (elements != NULL) { 3481 if (style->stripSpaces == NULL) 3482 style->stripSpaces = xmlHashCreate(10); 3483 if (style->stripSpaces == NULL) 3484 return; 3485 3486 element = elements; 3487 while (*element != 0) { 3488 while (IS_BLANK_CH(*element)) 3489 element++; 3490 if (*element == 0) 3491 break; 3492 end = element; 3493 while ((*end != 0) && (!IS_BLANK_CH(*end))) 3494 end++; 3495 element = xmlStrndup(element, end - element); 3496 if (element) { 3497 const xmlChar *URI; 3498 3499 #ifdef WITH_XSLT_DEBUG_PARSING 3500 xsltGenericDebug(xsltGenericDebugContext, 3501 "add cdata section output element %s\n", 3502 element); 3503 #endif 3504 URI = xsltGetQNameURI(inst, &element); 3505 3506 xmlHashAddEntry2(style->stripSpaces, element, URI, 3507 (xmlChar *) "cdata"); 3508 xmlFree(element); 3509 } 3510 element = end; 3511 } 3512 xmlFree(elements); 3513 } 3514 3515 /* 3516 * Create a new document tree and process the element template 3517 */ 3518 XSLT_GET_IMPORT_PTR(method, style, method) 3519 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 3520 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 3521 XSLT_GET_IMPORT_PTR(version, style, version) 3522 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 3523 3524 if ((method != NULL) && 3525 (!xmlStrEqual(method, (const xmlChar *) "xml"))) { 3526 if (xmlStrEqual(method, (const xmlChar *) "html")) { 3527 ctxt->type = XSLT_OUTPUT_HTML; 3528 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 3529 res = htmlNewDoc(doctypeSystem, doctypePublic); 3530 else { 3531 if (version != NULL) { 3532 #ifdef XSLT_GENERATE_HTML_DOCTYPE 3533 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); 3534 #endif 3535 } 3536 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); 3537 } 3538 if (res == NULL) 3539 goto error; 3540 res->dict = ctxt->dict; 3541 xmlDictReference(res->dict); 3542 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { 3543 xsltTransformError(ctxt, NULL, inst, 3544 "xsltDocumentElem: unsupported method xhtml\n", 3545 style->method); 3546 ctxt->type = XSLT_OUTPUT_HTML; 3547 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); 3548 if (res == NULL) 3549 goto error; 3550 res->dict = ctxt->dict; 3551 xmlDictReference(res->dict); 3552 } else if (xmlStrEqual(method, (const xmlChar *) "text")) { 3553 ctxt->type = XSLT_OUTPUT_TEXT; 3554 res = xmlNewDoc(style->version); 3555 if (res == NULL) 3556 goto error; 3557 res->dict = ctxt->dict; 3558 xmlDictReference(res->dict); 3559 #ifdef WITH_XSLT_DEBUG 3560 xsltGenericDebug(xsltGenericDebugContext, 3561 "reusing transformation dict for output\n"); 3562 #endif 3563 } else { 3564 xsltTransformError(ctxt, NULL, inst, 3565 "xsltDocumentElem: unsupported method %s\n", 3566 style->method); 3567 goto error; 3568 } 3569 } else { 3570 ctxt->type = XSLT_OUTPUT_XML; 3571 res = xmlNewDoc(style->version); 3572 if (res == NULL) 3573 goto error; 3574 res->dict = ctxt->dict; 3575 xmlDictReference(res->dict); 3576 #ifdef WITH_XSLT_DEBUG 3577 xsltGenericDebug(xsltGenericDebugContext, 3578 "reusing transformation dict for output\n"); 3579 #endif 3580 } 3581 res->charset = XML_CHAR_ENCODING_UTF8; 3582 if (encoding != NULL) 3583 res->encoding = xmlStrdup(encoding); 3584 ctxt->output = res; 3585 ctxt->insert = (xmlNodePtr) res; 3586 xsltApplySequenceConstructor(ctxt, node, inst->children, NULL); 3587 3588 /* 3589 * Do some post processing work depending on the generated output 3590 */ 3591 root = xmlDocGetRootElement(res); 3592 if (root != NULL) { 3593 const xmlChar *doctype = NULL; 3594 3595 if ((root->ns != NULL) && (root->ns->prefix != NULL)) 3596 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); 3597 if (doctype == NULL) 3598 doctype = root->name; 3599 3600 /* 3601 * Apply the default selection of the method 3602 */ 3603 if ((method == NULL) && 3604 (root->ns == NULL) && 3605 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { 3606 xmlNodePtr tmp; 3607 3608 tmp = res->children; 3609 while ((tmp != NULL) && (tmp != root)) { 3610 if (tmp->type == XML_ELEMENT_NODE) 3611 break; 3612 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) 3613 break; 3614 tmp = tmp->next; 3615 } 3616 if (tmp == root) { 3617 ctxt->type = XSLT_OUTPUT_HTML; 3618 res->type = XML_HTML_DOCUMENT_NODE; 3619 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 3620 res->intSubset = xmlCreateIntSubset(res, doctype, 3621 doctypePublic, 3622 doctypeSystem); 3623 #ifdef XSLT_GENERATE_HTML_DOCTYPE 3624 } else if (version != NULL) { 3625 xsltGetHTMLIDs(version, &doctypePublic, 3626 &doctypeSystem); 3627 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 3628 res->intSubset = 3629 xmlCreateIntSubset(res, doctype, 3630 doctypePublic, 3631 doctypeSystem); 3632 #endif 3633 } 3634 } 3635 3636 } 3637 if (ctxt->type == XSLT_OUTPUT_XML) { 3638 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 3639 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 3640 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 3641 res->intSubset = xmlCreateIntSubset(res, doctype, 3642 doctypePublic, 3643 doctypeSystem); 3644 } 3645 } 3646 3647 /* 3648 * Save the result 3649 */ 3650 ret = xsltSaveResultToFilename((const char *) filename, 3651 res, style, 0); 3652 if (ret < 0) { 3653 xsltTransformError(ctxt, NULL, inst, 3654 "xsltDocumentElem: unable to save to %s\n", 3655 filename); 3656 ctxt->state = XSLT_STATE_ERROR; 3657 #ifdef WITH_XSLT_DEBUG_EXTRA 3658 } else { 3659 xsltGenericDebug(xsltGenericDebugContext, 3660 "Wrote %d bytes to %s\n", ret, filename); 3661 #endif 3662 } 3663 3664 error: 3665 ctxt->output = oldOutput; 3666 ctxt->insert = oldInsert; 3667 ctxt->type = oldType; 3668 ctxt->outputFile = oldOutputFile; 3669 if (URL != NULL) 3670 xmlFree(URL); 3671 if (filename != NULL) 3672 xmlFree(filename); 3673 if (style != NULL) 3674 xsltFreeStylesheet(style); 3675 if (res != NULL) 3676 xmlFreeDoc(res); 3677 } 3678 3679 /************************************************************************ 3680 * * 3681 * Most of the XSLT-1.0 transformations * 3682 * * 3683 ************************************************************************/ 3684 3685 /** 3686 * xsltSort: 3687 * @ctxt: a XSLT process context 3688 * @node: the node in the source tree. 3689 * @inst: the xslt sort node 3690 * @comp: precomputed information 3691 * 3692 * function attached to xsl:sort nodes, but this should not be 3693 * called directly 3694 */ 3695 void 3696 xsltSort(xsltTransformContextPtr ctxt, 3697 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, 3698 xsltStylePreCompPtr comp) { 3699 if (comp == NULL) { 3700 xsltTransformError(ctxt, NULL, inst, 3701 "xsl:sort : compilation failed\n"); 3702 return; 3703 } 3704 xsltTransformError(ctxt, NULL, inst, 3705 "xsl:sort : improper use this should not be reached\n"); 3706 } 3707 3708 /** 3709 * xsltCopy: 3710 * @ctxt: an XSLT process context 3711 * @node: the node in the source tree 3712 * @inst: the element node of the XSLT-copy instruction 3713 * @castedComp: computed information of the XSLT-copy instruction 3714 * 3715 * Execute the XSLT-copy instruction on the source node. 3716 */ 3717 void 3718 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node, 3719 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 3720 { 3721 #ifdef XSLT_REFACTORED 3722 xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp; 3723 #else 3724 xsltStylePreCompPtr comp = castedComp; 3725 #endif 3726 xmlNodePtr copy, oldInsert; 3727 3728 oldInsert = ctxt->insert; 3729 if (ctxt->insert != NULL) { 3730 switch (node->type) { 3731 case XML_TEXT_NODE: 3732 case XML_CDATA_SECTION_NODE: 3733 /* 3734 * This text comes from the stylesheet 3735 * For stylesheets, the set of whitespace-preserving 3736 * element names consists of just xsl:text. 3737 */ 3738 #ifdef WITH_XSLT_DEBUG_PROCESS 3739 if (node->type == XML_CDATA_SECTION_NODE) { 3740 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3741 "xsltCopy: CDATA text %s\n", node->content)); 3742 } else { 3743 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3744 "xsltCopy: text %s\n", node->content)); 3745 } 3746 #endif 3747 xsltCopyText(ctxt, ctxt->insert, node, 0); 3748 break; 3749 case XML_DOCUMENT_NODE: 3750 case XML_HTML_DOCUMENT_NODE: 3751 break; 3752 case XML_ELEMENT_NODE: 3753 /* 3754 * REVISIT NOTE: The "fake" is a doc-node, not an element node. 3755 * REMOVED: 3756 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) 3757 * return; 3758 */ 3759 3760 #ifdef WITH_XSLT_DEBUG_PROCESS 3761 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3762 "xsltCopy: node %s\n", node->name)); 3763 #endif 3764 copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0); 3765 ctxt->insert = copy; 3766 if (comp->use != NULL) { 3767 xsltApplyAttributeSet(ctxt, node, inst, comp->use); 3768 } 3769 break; 3770 case XML_ATTRIBUTE_NODE: { 3771 #ifdef WITH_XSLT_DEBUG_PROCESS 3772 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3773 "xsltCopy: attribute %s\n", node->name)); 3774 #endif 3775 /* 3776 * REVISIT: We could also raise an error if the parent is not 3777 * an element node. 3778 * OPTIMIZE TODO: Can we set the value/children of the 3779 * attribute without an intermediate copy of the string value? 3780 */ 3781 xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); 3782 break; 3783 } 3784 case XML_PI_NODE: 3785 #ifdef WITH_XSLT_DEBUG_PROCESS 3786 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3787 "xsltCopy: PI %s\n", node->name)); 3788 #endif 3789 copy = xmlNewDocPI(ctxt->insert->doc, node->name, 3790 node->content); 3791 copy = xsltAddChild(ctxt->insert, copy); 3792 break; 3793 case XML_COMMENT_NODE: 3794 #ifdef WITH_XSLT_DEBUG_PROCESS 3795 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3796 "xsltCopy: comment\n")); 3797 #endif 3798 copy = xmlNewComment(node->content); 3799 copy = xsltAddChild(ctxt->insert, copy); 3800 break; 3801 case XML_NAMESPACE_DECL: 3802 #ifdef WITH_XSLT_DEBUG_PROCESS 3803 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 3804 "xsltCopy: namespace declaration\n")); 3805 #endif 3806 xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); 3807 break; 3808 default: 3809 break; 3810 3811 } 3812 } 3813 3814 switch (node->type) { 3815 case XML_DOCUMENT_NODE: 3816 case XML_HTML_DOCUMENT_NODE: 3817 case XML_ELEMENT_NODE: 3818 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, 3819 NULL); 3820 break; 3821 default: 3822 break; 3823 } 3824 ctxt->insert = oldInsert; 3825 } 3826 3827 /** 3828 * xsltText: 3829 * @ctxt: a XSLT process context 3830 * @node: the node in the source tree. 3831 * @inst: the xslt text node 3832 * @comp: precomputed information 3833 * 3834 * Process the xslt text node on the source node 3835 */ 3836 void 3837 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, 3838 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { 3839 if ((inst->children != NULL) && (comp != NULL)) { 3840 xmlNodePtr text = inst->children; 3841 xmlNodePtr copy; 3842 3843 while (text != NULL) { 3844 if ((text->type != XML_TEXT_NODE) && 3845 (text->type != XML_CDATA_SECTION_NODE)) { 3846 xsltTransformError(ctxt, NULL, inst, 3847 "xsl:text content problem\n"); 3848 break; 3849 } 3850 copy = xmlNewDocText(ctxt->output, text->content); 3851 if (text->type != XML_CDATA_SECTION_NODE) { 3852 #ifdef WITH_XSLT_DEBUG_PARSING 3853 xsltGenericDebug(xsltGenericDebugContext, 3854 "Disable escaping: %s\n", text->content); 3855 #endif 3856 copy->name = xmlStringTextNoenc; 3857 } 3858 copy = xsltAddChild(ctxt->insert, copy); 3859 text = text->next; 3860 } 3861 } 3862 } 3863 3864 /** 3865 * xsltElement: 3866 * @ctxt: a XSLT process context 3867 * @node: the node in the source tree. 3868 * @inst: the xslt element node 3869 * @castedComp: precomputed information 3870 * 3871 * Process the xslt element node on the source node 3872 */ 3873 void 3874 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, 3875 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 3876 #ifdef XSLT_REFACTORED 3877 xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp; 3878 #else 3879 xsltStylePreCompPtr comp = castedComp; 3880 #endif 3881 xmlChar *prop = NULL; 3882 const xmlChar *name, *prefix = NULL, *nsName = NULL; 3883 xmlNodePtr copy; 3884 xmlNodePtr oldInsert; 3885 3886 if (ctxt->insert == NULL) 3887 return; 3888 3889 /* 3890 * A comp->has_name == 0 indicates that we need to skip this instruction, 3891 * since it was evaluated to be invalid already during compilation. 3892 */ 3893 if (!comp->has_name) 3894 return; 3895 3896 /* 3897 * stack and saves 3898 */ 3899 oldInsert = ctxt->insert; 3900 3901 if (comp->name == NULL) { 3902 /* TODO: fix attr acquisition wrt to the XSLT namespace */ 3903 prop = xsltEvalAttrValueTemplate(ctxt, inst, 3904 (const xmlChar *) "name", XSLT_NAMESPACE); 3905 if (prop == NULL) { 3906 xsltTransformError(ctxt, NULL, inst, 3907 "xsl:element: The attribute 'name' is missing.\n"); 3908 goto error; 3909 } 3910 if (xmlValidateQName(prop, 0)) { 3911 xsltTransformError(ctxt, NULL, inst, 3912 "xsl:element: The effective name '%s' is not a " 3913 "valid QName.\n", prop); 3914 /* we fall through to catch any further errors, if possible */ 3915 } 3916 name = xsltSplitQName(ctxt->dict, prop, &prefix); 3917 xmlFree(prop); 3918 if ((prefix != NULL) && 3919 (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) 3920 { 3921 /* 3922 * TODO: Should we really disallow an "xml" prefix? 3923 */ 3924 goto error; 3925 } 3926 } else { 3927 /* 3928 * The "name" value was static. 3929 */ 3930 #ifdef XSLT_REFACTORED 3931 prefix = comp->nsPrefix; 3932 name = comp->name; 3933 #else 3934 name = xsltSplitQName(ctxt->dict, comp->name, &prefix); 3935 #endif 3936 } 3937 3938 /* 3939 * Create the new element 3940 */ 3941 if (ctxt->output->dict == ctxt->dict) { 3942 copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); 3943 } else { 3944 copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL); 3945 } 3946 if (copy == NULL) { 3947 xsltTransformError(ctxt, NULL, inst, 3948 "xsl:element : creation of %s failed\n", name); 3949 return; 3950 } 3951 copy = xsltAddChild(ctxt->insert, copy); 3952 3953 /* 3954 * Namespace 3955 * --------- 3956 */ 3957 if (comp->has_ns) { 3958 if (comp->ns != NULL) { 3959 /* 3960 * No AVT; just plain text for the namespace name. 3961 */ 3962 if (comp->ns[0] != 0) 3963 nsName = comp->ns; 3964 } else { 3965 xmlChar *tmpNsName; 3966 /* 3967 * Eval the AVT. 3968 */ 3969 /* TODO: check attr acquisition wrt to the XSLT namespace */ 3970 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, 3971 (const xmlChar *) "namespace", XSLT_NAMESPACE); 3972 /* 3973 * SPEC XSLT 1.0: 3974 * "If the string is empty, then the expanded-name of the 3975 * attribute has a null namespace URI." 3976 */ 3977 if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) 3978 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); 3979 xmlFree(tmpNsName); 3980 }; 3981 } else { 3982 xmlNsPtr ns; 3983 /* 3984 * SPEC XSLT 1.0: 3985 * "If the namespace attribute is not present, then the QName is 3986 * expanded into an expanded-name using the namespace declarations 3987 * in effect for the xsl:element element, including any default 3988 * namespace declaration. 3989 */ 3990 ns = xmlSearchNs(inst->doc, inst, prefix); 3991 if (ns == NULL) { 3992 /* 3993 * TODO: Check this in the compilation layer in case it's a 3994 * static value. 3995 */ 3996 if (prefix != NULL) { 3997 xsltTransformError(ctxt, NULL, inst, 3998 "xsl:element: The QName '%s:%s' has no " 3999 "namespace binding in scope in the stylesheet; " 4000 "this is an error, since the namespace was not " 4001 "specified by the instruction itself.\n", prefix, name); 4002 } 4003 } else 4004 nsName = ns->href; 4005 } 4006 /* 4007 * Find/create a matching ns-decl in the result tree. 4008 */ 4009 if (nsName != NULL) { 4010 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy); 4011 } else if ((copy->parent != NULL) && 4012 (copy->parent->type == XML_ELEMENT_NODE) && 4013 (copy->parent->ns != NULL)) 4014 { 4015 /* 4016 * "Undeclare" the default namespace. 4017 */ 4018 xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy); 4019 } 4020 4021 ctxt->insert = copy; 4022 4023 if (comp->has_use) { 4024 if (comp->use != NULL) { 4025 xsltApplyAttributeSet(ctxt, node, inst, comp->use); 4026 } else { 4027 xmlChar *attrSets = NULL; 4028 /* 4029 * BUG TODO: use-attribute-sets is not a value template. 4030 * use-attribute-sets = qnames 4031 */ 4032 attrSets = xsltEvalAttrValueTemplate(ctxt, inst, 4033 (const xmlChar *)"use-attribute-sets", NULL); 4034 if (attrSets != NULL) { 4035 xsltApplyAttributeSet(ctxt, node, inst, attrSets); 4036 xmlFree(attrSets); 4037 } 4038 } 4039 } 4040 /* 4041 * Instantiate the sequence constructor. 4042 */ 4043 if (inst->children != NULL) 4044 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, 4045 NULL); 4046 4047 error: 4048 ctxt->insert = oldInsert; 4049 return; 4050 } 4051 4052 4053 /** 4054 * xsltComment: 4055 * @ctxt: a XSLT process context 4056 * @node: the node in the source tree. 4057 * @inst: the xslt comment node 4058 * @comp: precomputed information 4059 * 4060 * Process the xslt comment node on the source node 4061 */ 4062 void 4063 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, 4064 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { 4065 xmlChar *value = NULL; 4066 xmlNodePtr commentNode; 4067 int len; 4068 4069 value = xsltEvalTemplateString(ctxt, node, inst); 4070 /* TODO: use or generate the compiled form */ 4071 len = xmlStrlen(value); 4072 if (len > 0) { 4073 if ((value[len-1] == '-') || 4074 (xmlStrstr(value, BAD_CAST "--"))) { 4075 xsltTransformError(ctxt, NULL, inst, 4076 "xsl:comment : '--' or ending '-' not allowed in comment\n"); 4077 /* fall through to try to catch further errors */ 4078 } 4079 } 4080 #ifdef WITH_XSLT_DEBUG_PROCESS 4081 if (value == NULL) { 4082 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, 4083 "xsltComment: empty\n")); 4084 } else { 4085 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, 4086 "xsltComment: content %s\n", value)); 4087 } 4088 #endif 4089 4090 commentNode = xmlNewComment(value); 4091 commentNode = xsltAddChild(ctxt->insert, commentNode); 4092 4093 if (value != NULL) 4094 xmlFree(value); 4095 } 4096 4097 /** 4098 * xsltProcessingInstruction: 4099 * @ctxt: a XSLT process context 4100 * @node: the node in the source tree. 4101 * @inst: the xslt processing-instruction node 4102 * @castedComp: precomputed information 4103 * 4104 * Process the xslt processing-instruction node on the source node 4105 */ 4106 void 4107 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, 4108 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 4109 #ifdef XSLT_REFACTORED 4110 xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp; 4111 #else 4112 xsltStylePreCompPtr comp = castedComp; 4113 #endif 4114 const xmlChar *name; 4115 xmlChar *value = NULL; 4116 xmlNodePtr pi; 4117 4118 4119 if (ctxt->insert == NULL) 4120 return; 4121 if (comp->has_name == 0) 4122 return; 4123 if (comp->name == NULL) { 4124 name = xsltEvalAttrValueTemplate(ctxt, inst, 4125 (const xmlChar *)"name", NULL); 4126 if (name == NULL) { 4127 xsltTransformError(ctxt, NULL, inst, 4128 "xsl:processing-instruction : name is missing\n"); 4129 goto error; 4130 } 4131 } else { 4132 name = comp->name; 4133 } 4134 /* TODO: check that it's both an an NCName and a PITarget. */ 4135 4136 4137 value = xsltEvalTemplateString(ctxt, node, inst); 4138 if (xmlStrstr(value, BAD_CAST "?>") != NULL) { 4139 xsltTransformError(ctxt, NULL, inst, 4140 "xsl:processing-instruction: '?>' not allowed within PI content\n"); 4141 goto error; 4142 } 4143 #ifdef WITH_XSLT_DEBUG_PROCESS 4144 if (value == NULL) { 4145 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, 4146 "xsltProcessingInstruction: %s empty\n", name)); 4147 } else { 4148 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, 4149 "xsltProcessingInstruction: %s content %s\n", name, value)); 4150 } 4151 #endif 4152 4153 pi = xmlNewDocPI(ctxt->insert->doc, name, value); 4154 pi = xsltAddChild(ctxt->insert, pi); 4155 4156 error: 4157 if ((name != NULL) && (name != comp->name)) 4158 xmlFree((xmlChar *) name); 4159 if (value != NULL) 4160 xmlFree(value); 4161 } 4162 4163 /** 4164 * xsltCopyOf: 4165 * @ctxt: an XSLT transformation context 4166 * @node: the current node in the source tree 4167 * @inst: the element node of the XSLT copy-of instruction 4168 * @castedComp: precomputed information of the XSLT copy-of instruction 4169 * 4170 * Process the XSLT copy-of instruction. 4171 */ 4172 void 4173 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, 4174 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 4175 #ifdef XSLT_REFACTORED 4176 xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp; 4177 #else 4178 xsltStylePreCompPtr comp = castedComp; 4179 #endif 4180 xmlXPathObjectPtr res = NULL; 4181 xmlNodeSetPtr list = NULL; 4182 int i; 4183 xmlDocPtr oldXPContextDoc; 4184 xmlNsPtr *oldXPNamespaces; 4185 xmlNodePtr oldXPContextNode; 4186 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 4187 xmlXPathContextPtr xpctxt; 4188 4189 if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) 4190 return; 4191 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { 4192 xsltTransformError(ctxt, NULL, inst, 4193 "xsl:copy-of : compilation failed\n"); 4194 return; 4195 } 4196 4197 /* 4198 * SPEC XSLT 1.0: 4199 * "The xsl:copy-of element can be used to insert a result tree 4200 * fragment into the result tree, without first converting it to 4201 * a string as xsl:value-of does (see [7.6.1 Generating Text with 4202 * xsl:value-of]). The required select attribute contains an 4203 * expression. When the result of evaluating the expression is a 4204 * result tree fragment, the complete fragment is copied into the 4205 * result tree. When the result is a node-set, all the nodes in the 4206 * set are copied in document order into the result tree; copying 4207 * an element node copies the attribute nodes, namespace nodes and 4208 * children of the element node as well as the element node itself; 4209 * a root node is copied by copying its children. When the result 4210 * is neither a node-set nor a result tree fragment, the result is 4211 * converted to a string and then inserted into the result tree, 4212 * as with xsl:value-of. 4213 */ 4214 4215 #ifdef WITH_XSLT_DEBUG_PROCESS 4216 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 4217 "xsltCopyOf: select %s\n", comp->select)); 4218 #endif 4219 4220 /* 4221 * Evaluate the "select" expression. 4222 */ 4223 xpctxt = ctxt->xpathCtxt; 4224 oldXPContextDoc = xpctxt->doc; 4225 oldXPContextNode = xpctxt->node; 4226 oldXPProximityPosition = xpctxt->proximityPosition; 4227 oldXPContextSize = xpctxt->contextSize; 4228 oldXPNsNr = xpctxt->nsNr; 4229 oldXPNamespaces = xpctxt->namespaces; 4230 4231 xpctxt->node = node; 4232 if (comp != NULL) { 4233 4234 #ifdef XSLT_REFACTORED 4235 if (comp->inScopeNs != NULL) { 4236 xpctxt->namespaces = comp->inScopeNs->list; 4237 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 4238 } else { 4239 xpctxt->namespaces = NULL; 4240 xpctxt->nsNr = 0; 4241 } 4242 #else 4243 xpctxt->namespaces = comp->nsList; 4244 xpctxt->nsNr = comp->nsNr; 4245 #endif 4246 } else { 4247 xpctxt->namespaces = NULL; 4248 xpctxt->nsNr = 0; 4249 } 4250 4251 res = xmlXPathCompiledEval(comp->comp, xpctxt); 4252 4253 xpctxt->doc = oldXPContextDoc; 4254 xpctxt->node = oldXPContextNode; 4255 xpctxt->contextSize = oldXPContextSize; 4256 xpctxt->proximityPosition = oldXPProximityPosition; 4257 xpctxt->nsNr = oldXPNsNr; 4258 xpctxt->namespaces = oldXPNamespaces; 4259 4260 if (res != NULL) { 4261 if (res->type == XPATH_NODESET) { 4262 /* 4263 * Node-set 4264 * -------- 4265 */ 4266 #ifdef WITH_XSLT_DEBUG_PROCESS 4267 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 4268 "xsltCopyOf: result is a node set\n")); 4269 #endif 4270 list = res->nodesetval; 4271 if (list != NULL) { 4272 xmlNodePtr cur; 4273 /* 4274 * The list is already sorted in document order by XPath. 4275 * Append everything in this order under ctxt->insert. 4276 */ 4277 for (i = 0;i < list->nodeNr;i++) { 4278 cur = list->nodeTab[i]; 4279 if (cur == NULL) 4280 continue; 4281 if ((cur->type == XML_DOCUMENT_NODE) || 4282 (cur->type == XML_HTML_DOCUMENT_NODE)) 4283 { 4284 xsltCopyTreeList(ctxt, inst, 4285 cur->children, ctxt->insert, 0, 0); 4286 } else if (cur->type == XML_ATTRIBUTE_NODE) { 4287 xsltShallowCopyAttr(ctxt, inst, 4288 ctxt->insert, (xmlAttrPtr) cur); 4289 } else { 4290 xsltCopyTreeInternal(ctxt, inst, 4291 cur, ctxt->insert, 0, 0); 4292 } 4293 } 4294 } 4295 } else if (res->type == XPATH_XSLT_TREE) { 4296 /* 4297 * Result tree fragment 4298 * -------------------- 4299 * E.g. via <xsl:variable ...><foo/></xsl:variable> 4300 * Note that the root node of such trees is an xmlDocPtr in Libxslt. 4301 */ 4302 #ifdef WITH_XSLT_DEBUG_PROCESS 4303 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 4304 "xsltCopyOf: result is a result tree fragment\n")); 4305 #endif 4306 list = res->nodesetval; 4307 if ((list != NULL) && (list->nodeTab != NULL) && 4308 (list->nodeTab[0] != NULL) && 4309 (IS_XSLT_REAL_NODE(list->nodeTab[0]))) 4310 { 4311 xsltCopyTreeList(ctxt, inst, 4312 list->nodeTab[0]->children, ctxt->insert, 0, 0); 4313 } 4314 } else { 4315 xmlChar *value = NULL; 4316 /* 4317 * Convert to a string. 4318 */ 4319 value = xmlXPathCastToString(res); 4320 if (value == NULL) { 4321 xsltTransformError(ctxt, NULL, inst, 4322 "Internal error in xsltCopyOf(): " 4323 "failed to cast an XPath object to string.\n"); 4324 ctxt->state = XSLT_STATE_STOPPED; 4325 } else { 4326 if (value[0] != 0) { 4327 /* 4328 * Append content as text node. 4329 */ 4330 xsltCopyTextString(ctxt, ctxt->insert, value, 0); 4331 } 4332 xmlFree(value); 4333 4334 #ifdef WITH_XSLT_DEBUG_PROCESS 4335 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 4336 "xsltCopyOf: result %s\n", res->stringval)); 4337 #endif 4338 } 4339 } 4340 } else { 4341 ctxt->state = XSLT_STATE_STOPPED; 4342 } 4343 4344 if (res != NULL) 4345 xmlXPathFreeObject(res); 4346 } 4347 4348 /** 4349 * xsltValueOf: 4350 * @ctxt: a XSLT process context 4351 * @node: the node in the source tree. 4352 * @inst: the xslt value-of node 4353 * @castedComp: precomputed information 4354 * 4355 * Process the xslt value-of node on the source node 4356 */ 4357 void 4358 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, 4359 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 4360 { 4361 #ifdef XSLT_REFACTORED 4362 xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp; 4363 #else 4364 xsltStylePreCompPtr comp = castedComp; 4365 #endif 4366 xmlXPathObjectPtr res = NULL; 4367 xmlNodePtr copy = NULL; 4368 xmlChar *value = NULL; 4369 xmlDocPtr oldXPContextDoc; 4370 xmlNsPtr *oldXPNamespaces; 4371 xmlNodePtr oldXPContextNode; 4372 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 4373 xmlXPathContextPtr xpctxt; 4374 4375 if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) 4376 return; 4377 4378 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { 4379 xsltTransformError(ctxt, NULL, inst, 4380 "Internal error in xsltValueOf(): " 4381 "The XSLT 'value-of' instruction was not compiled.\n"); 4382 return; 4383 } 4384 4385 #ifdef WITH_XSLT_DEBUG_PROCESS 4386 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, 4387 "xsltValueOf: select %s\n", comp->select)); 4388 #endif 4389 4390 xpctxt = ctxt->xpathCtxt; 4391 oldXPContextDoc = xpctxt->doc; 4392 oldXPContextNode = xpctxt->node; 4393 oldXPProximityPosition = xpctxt->proximityPosition; 4394 oldXPContextSize = xpctxt->contextSize; 4395 oldXPNsNr = xpctxt->nsNr; 4396 oldXPNamespaces = xpctxt->namespaces; 4397 4398 xpctxt->node = node; 4399 if (comp != NULL) { 4400 4401 #ifdef XSLT_REFACTORED 4402 if (comp->inScopeNs != NULL) { 4403 xpctxt->namespaces = comp->inScopeNs->list; 4404 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 4405 } else { 4406 xpctxt->namespaces = NULL; 4407 xpctxt->nsNr = 0; 4408 } 4409 #else 4410 xpctxt->namespaces = comp->nsList; 4411 xpctxt->nsNr = comp->nsNr; 4412 #endif 4413 } else { 4414 xpctxt->namespaces = NULL; 4415 xpctxt->nsNr = 0; 4416 } 4417 4418 res = xmlXPathCompiledEval(comp->comp, xpctxt); 4419 4420 xpctxt->doc = oldXPContextDoc; 4421 xpctxt->node = oldXPContextNode; 4422 xpctxt->contextSize = oldXPContextSize; 4423 xpctxt->proximityPosition = oldXPProximityPosition; 4424 xpctxt->nsNr = oldXPNsNr; 4425 xpctxt->namespaces = oldXPNamespaces; 4426 4427 /* 4428 * Cast the XPath object to string. 4429 */ 4430 if (res != NULL) { 4431 value = xmlXPathCastToString(res); 4432 if (value == NULL) { 4433 xsltTransformError(ctxt, NULL, inst, 4434 "Internal error in xsltValueOf(): " 4435 "failed to cast an XPath object to string.\n"); 4436 ctxt->state = XSLT_STATE_STOPPED; 4437 goto error; 4438 } 4439 if (value[0] != 0) { 4440 copy = xsltCopyTextString(ctxt, 4441 ctxt->insert, value, comp->noescape); 4442 } 4443 } else { 4444 xsltTransformError(ctxt, NULL, inst, 4445 "XPath evaluation returned no result.\n"); 4446 ctxt->state = XSLT_STATE_STOPPED; 4447 goto error; 4448 } 4449 4450 #ifdef WITH_XSLT_DEBUG_PROCESS 4451 if (value) { 4452 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, 4453 "xsltValueOf: result '%s'\n", value)); 4454 } 4455 #endif 4456 4457 error: 4458 if (value != NULL) 4459 xmlFree(value); 4460 if (res != NULL) 4461 xmlXPathFreeObject(res); 4462 } 4463 4464 /** 4465 * xsltNumber: 4466 * @ctxt: a XSLT process context 4467 * @node: the node in the source tree. 4468 * @inst: the xslt number node 4469 * @castedComp: precomputed information 4470 * 4471 * Process the xslt number node on the source node 4472 */ 4473 void 4474 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node, 4475 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 4476 { 4477 #ifdef XSLT_REFACTORED 4478 xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp; 4479 #else 4480 xsltStylePreCompPtr comp = castedComp; 4481 #endif 4482 if (comp == NULL) { 4483 xsltTransformError(ctxt, NULL, inst, 4484 "xsl:number : compilation failed\n"); 4485 return; 4486 } 4487 4488 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 4489 return; 4490 4491 comp->numdata.doc = inst->doc; 4492 comp->numdata.node = inst; 4493 4494 xsltNumberFormat(ctxt, &comp->numdata, node); 4495 } 4496 4497 /** 4498 * xsltApplyImports: 4499 * @ctxt: an XSLT transformation context 4500 * @contextNode: the current node in the source tree. 4501 * @inst: the element node of the XSLT 'apply-imports' instruction 4502 * @comp: the compiled instruction 4503 * 4504 * Process the XSLT apply-imports element. 4505 */ 4506 void 4507 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 4508 xmlNodePtr inst, 4509 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) 4510 { 4511 xsltTemplatePtr templ; 4512 4513 if ((ctxt == NULL) || (inst == NULL)) 4514 return; 4515 4516 if (comp == NULL) { 4517 xsltTransformError(ctxt, NULL, inst, 4518 "Internal error in xsltApplyImports(): " 4519 "The XSLT 'apply-imports' instruction was not compiled.\n"); 4520 return; 4521 } 4522 /* 4523 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the 4524 * same; the former is the "Current Template Rule" as defined by the 4525 * XSLT spec, the latter is simply the template struct being 4526 * currently processed. 4527 */ 4528 if (ctxt->currentTemplateRule == NULL) { 4529 /* 4530 * SPEC XSLT 2.0: 4531 * "[ERR XTDE0560] It is a non-recoverable dynamic error if 4532 * xsl:apply-imports or xsl:next-match is evaluated when the 4533 * current template rule is null." 4534 */ 4535 xsltTransformError(ctxt, NULL, inst, 4536 "It is an error to call 'apply-imports' " 4537 "when there's no current template rule.\n"); 4538 return; 4539 } 4540 /* 4541 * TODO: Check if this is correct. 4542 */ 4543 templ = xsltGetTemplate(ctxt, contextNode, 4544 ctxt->currentTemplateRule->style); 4545 4546 if (templ != NULL) { 4547 xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule; 4548 /* 4549 * Set the current template rule. 4550 */ 4551 ctxt->currentTemplateRule = templ; 4552 /* 4553 * URGENT TODO: Need xsl:with-param be handled somehow here? 4554 */ 4555 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, 4556 templ, NULL); 4557 4558 ctxt->currentTemplateRule = oldCurTemplRule; 4559 } 4560 } 4561 4562 /** 4563 * xsltCallTemplate: 4564 * @ctxt: a XSLT transformation context 4565 * @node: the "current node" in the source tree 4566 * @inst: the XSLT 'call-template' instruction 4567 * @castedComp: the compiled information of the instruction 4568 * 4569 * Processes the XSLT call-template instruction on the source node. 4570 */ 4571 void 4572 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, 4573 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 4574 { 4575 #ifdef XSLT_REFACTORED 4576 xsltStyleItemCallTemplatePtr comp = 4577 (xsltStyleItemCallTemplatePtr) castedComp; 4578 #else 4579 xsltStylePreCompPtr comp = castedComp; 4580 #endif 4581 xsltStackElemPtr withParams = NULL; 4582 4583 if (ctxt->insert == NULL) 4584 return; 4585 if (comp == NULL) { 4586 xsltTransformError(ctxt, NULL, inst, 4587 "The XSLT 'call-template' instruction was not compiled.\n"); 4588 return; 4589 } 4590 4591 /* 4592 * The template must have been precomputed 4593 */ 4594 if (comp->templ == NULL) { 4595 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns); 4596 if (comp->templ == NULL) { 4597 if (comp->ns != NULL) { 4598 xsltTransformError(ctxt, NULL, inst, 4599 "The called template '{%s}%s' was not found.\n", 4600 comp->ns, comp->name); 4601 } else { 4602 xsltTransformError(ctxt, NULL, inst, 4603 "The called template '%s' was not found.\n", 4604 comp->name); 4605 } 4606 return; 4607 } 4608 } 4609 4610 #ifdef WITH_XSLT_DEBUG_PROCESS 4611 if ((comp != NULL) && (comp->name != NULL)) 4612 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 4613 "call-template: name %s\n", comp->name)); 4614 #endif 4615 4616 if (inst->children) { 4617 xmlNodePtr cur; 4618 xsltStackElemPtr param; 4619 4620 cur = inst->children; 4621 while (cur != NULL) { 4622 #ifdef WITH_DEBUGGER 4623 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 4624 xslHandleDebugger(cur, node, comp->templ, ctxt); 4625 #endif 4626 if (ctxt->state == XSLT_STATE_STOPPED) break; 4627 /* 4628 * TODO: The "with-param"s could be part of the "call-template" 4629 * structure. Avoid to "search" for params dynamically 4630 * in the XML tree every time. 4631 */ 4632 if (IS_XSLT_ELEM(cur)) { 4633 if (IS_XSLT_NAME(cur, "with-param")) { 4634 param = xsltParseStylesheetCallerParam(ctxt, cur); 4635 if (param != NULL) { 4636 param->next = withParams; 4637 withParams = param; 4638 } 4639 } else { 4640 xsltGenericError(xsltGenericErrorContext, 4641 "xsl:call-template: misplaced xsl:%s\n", cur->name); 4642 } 4643 } else { 4644 xsltGenericError(xsltGenericErrorContext, 4645 "xsl:call-template: misplaced %s element\n", cur->name); 4646 } 4647 cur = cur->next; 4648 } 4649 } 4650 /* 4651 * Create a new frame using the params first 4652 */ 4653 xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ, 4654 withParams); 4655 if (withParams != NULL) 4656 xsltFreeStackElemList(withParams); 4657 4658 #ifdef WITH_XSLT_DEBUG_PROCESS 4659 if ((comp != NULL) && (comp->name != NULL)) 4660 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 4661 "call-template returned: name %s\n", comp->name)); 4662 #endif 4663 } 4664 4665 /** 4666 * xsltApplyTemplates: 4667 * @ctxt: a XSLT transformation context 4668 * @node: the 'current node' in the source tree 4669 * @inst: the element node of an XSLT 'apply-templates' instruction 4670 * @castedComp: the compiled instruction 4671 * 4672 * Processes the XSLT 'apply-templates' instruction on the current node. 4673 */ 4674 void 4675 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, 4676 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 4677 { 4678 #ifdef XSLT_REFACTORED 4679 xsltStyleItemApplyTemplatesPtr comp = 4680 (xsltStyleItemApplyTemplatesPtr) castedComp; 4681 #else 4682 xsltStylePreCompPtr comp = castedComp; 4683 #endif 4684 int i; 4685 xmlNodePtr cur, delNode = NULL, oldContextNode; 4686 xmlNodeSetPtr list = NULL, oldList; 4687 xsltStackElemPtr withParams = NULL; 4688 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 4689 const xmlChar *oldMode, *oldModeURI; 4690 xmlDocPtr oldXPDoc; 4691 xsltDocumentPtr oldDocInfo; 4692 xmlXPathContextPtr xpctxt; 4693 xmlNsPtr *oldXPNamespaces; 4694 4695 if (comp == NULL) { 4696 xsltTransformError(ctxt, NULL, inst, 4697 "xsl:apply-templates : compilation failed\n"); 4698 return; 4699 } 4700 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 4701 return; 4702 4703 #ifdef WITH_XSLT_DEBUG_PROCESS 4704 if ((node != NULL) && (node->name != NULL)) 4705 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4706 "xsltApplyTemplates: node: '%s'\n", node->name)); 4707 #endif 4708 4709 xpctxt = ctxt->xpathCtxt; 4710 /* 4711 * Save context states. 4712 */ 4713 oldContextNode = ctxt->node; 4714 oldMode = ctxt->mode; 4715 oldModeURI = ctxt->modeURI; 4716 oldDocInfo = ctxt->document; 4717 oldList = ctxt->nodeList; 4718 4719 /* 4720 * The xpath context size and proximity position, as 4721 * well as the xpath and context documents, may be changed 4722 * so we save their initial state and will restore on exit 4723 */ 4724 oldXPContextSize = xpctxt->contextSize; 4725 oldXPProximityPosition = xpctxt->proximityPosition; 4726 oldXPDoc = xpctxt->doc; 4727 oldXPNsNr = xpctxt->nsNr; 4728 oldXPNamespaces = xpctxt->namespaces; 4729 4730 /* 4731 * Set up contexts. 4732 */ 4733 ctxt->mode = comp->mode; 4734 ctxt->modeURI = comp->modeURI; 4735 4736 if (comp->select != NULL) { 4737 xmlXPathObjectPtr res = NULL; 4738 4739 if (comp->comp == NULL) { 4740 xsltTransformError(ctxt, NULL, inst, 4741 "xsl:apply-templates : compilation failed\n"); 4742 goto error; 4743 } 4744 #ifdef WITH_XSLT_DEBUG_PROCESS 4745 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4746 "xsltApplyTemplates: select %s\n", comp->select)); 4747 #endif 4748 4749 /* 4750 * Set up XPath. 4751 */ 4752 xpctxt->node = node; /* Set the "context node" */ 4753 #ifdef XSLT_REFACTORED 4754 if (comp->inScopeNs != NULL) { 4755 xpctxt->namespaces = comp->inScopeNs->list; 4756 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 4757 } else { 4758 xpctxt->namespaces = NULL; 4759 xpctxt->nsNr = 0; 4760 } 4761 #else 4762 xpctxt->namespaces = comp->nsList; 4763 xpctxt->nsNr = comp->nsNr; 4764 #endif 4765 res = xmlXPathCompiledEval(comp->comp, xpctxt); 4766 4767 xpctxt->contextSize = oldXPContextSize; 4768 xpctxt->proximityPosition = oldXPProximityPosition; 4769 if (res != NULL) { 4770 if (res->type == XPATH_NODESET) { 4771 list = res->nodesetval; /* consume the node set */ 4772 res->nodesetval = NULL; 4773 } else { 4774 xsltTransformError(ctxt, NULL, inst, 4775 "The 'select' expression did not evaluate to a " 4776 "node set.\n"); 4777 ctxt->state = XSLT_STATE_STOPPED; 4778 xmlXPathFreeObject(res); 4779 goto error; 4780 } 4781 xmlXPathFreeObject(res); 4782 /* 4783 * Note: An xsl:apply-templates with a 'select' attribute, 4784 * can change the current source doc. 4785 */ 4786 } else { 4787 xsltTransformError(ctxt, NULL, inst, 4788 "Failed to evaluate the 'select' expression.\n"); 4789 ctxt->state = XSLT_STATE_STOPPED; 4790 goto error; 4791 } 4792 if (list == NULL) { 4793 #ifdef WITH_XSLT_DEBUG_PROCESS 4794 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4795 "xsltApplyTemplates: select didn't evaluate to a node list\n")); 4796 #endif 4797 goto exit; 4798 } 4799 /* 4800 * 4801 * NOTE: Previously a document info (xsltDocument) was 4802 * created and attached to the Result Tree Fragment. 4803 * But such a document info is created on demand in 4804 * xsltKeyFunction() (functions.c), so we need to create 4805 * it here beforehand. 4806 * In order to take care of potential keys we need to 4807 * do some extra work for the case when a Result Tree Fragment 4808 * is converted into a nodeset (e.g. exslt:node-set()) : 4809 * We attach a "pseudo-doc" (xsltDocument) to _private. 4810 * This xsltDocument, together with the keyset, will be freed 4811 * when the Result Tree Fragment is freed. 4812 * 4813 */ 4814 #if 0 4815 if ((ctxt->nbKeys > 0) && 4816 (list->nodeNr != 0) && 4817 (list->nodeTab[0]->doc != NULL) && 4818 XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc)) 4819 { 4820 /* 4821 * NOTE that it's also OK if @effectiveDocInfo will be 4822 * set to NULL. 4823 */ 4824 isRTF = 1; 4825 effectiveDocInfo = list->nodeTab[0]->doc->_private; 4826 } 4827 #endif 4828 } else { 4829 /* 4830 * Build an XPath node set with the children 4831 */ 4832 list = xmlXPathNodeSetCreate(NULL); 4833 if (list == NULL) 4834 goto error; 4835 cur = node->children; 4836 while (cur != NULL) { 4837 switch (cur->type) { 4838 case XML_TEXT_NODE: 4839 if ((IS_BLANK_NODE(cur)) && 4840 (cur->parent != NULL) && 4841 (cur->parent->type == XML_ELEMENT_NODE) && 4842 (ctxt->style->stripSpaces != NULL)) { 4843 const xmlChar *val; 4844 4845 if (cur->parent->ns != NULL) { 4846 val = (const xmlChar *) 4847 xmlHashLookup2(ctxt->style->stripSpaces, 4848 cur->parent->name, 4849 cur->parent->ns->href); 4850 if (val == NULL) { 4851 val = (const xmlChar *) 4852 xmlHashLookup2(ctxt->style->stripSpaces, 4853 BAD_CAST "*", 4854 cur->parent->ns->href); 4855 } 4856 } else { 4857 val = (const xmlChar *) 4858 xmlHashLookup2(ctxt->style->stripSpaces, 4859 cur->parent->name, NULL); 4860 } 4861 if ((val != NULL) && 4862 (xmlStrEqual(val, (xmlChar *) "strip"))) { 4863 delNode = cur; 4864 break; 4865 } 4866 } 4867 /* no break on purpose */ 4868 case XML_ELEMENT_NODE: 4869 case XML_DOCUMENT_NODE: 4870 case XML_HTML_DOCUMENT_NODE: 4871 case XML_CDATA_SECTION_NODE: 4872 case XML_PI_NODE: 4873 case XML_COMMENT_NODE: 4874 xmlXPathNodeSetAddUnique(list, cur); 4875 break; 4876 case XML_DTD_NODE: 4877 /* Unlink the DTD, it's still reachable 4878 * using doc->intSubset */ 4879 if (cur->next != NULL) 4880 cur->next->prev = cur->prev; 4881 if (cur->prev != NULL) 4882 cur->prev->next = cur->next; 4883 break; 4884 default: 4885 #ifdef WITH_XSLT_DEBUG_PROCESS 4886 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4887 "xsltApplyTemplates: skipping cur type %d\n", 4888 cur->type)); 4889 #endif 4890 delNode = cur; 4891 } 4892 cur = cur->next; 4893 if (delNode != NULL) { 4894 #ifdef WITH_XSLT_DEBUG_PROCESS 4895 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4896 "xsltApplyTemplates: removing ignorable blank cur\n")); 4897 #endif 4898 xmlUnlinkNode(delNode); 4899 xmlFreeNode(delNode); 4900 delNode = NULL; 4901 } 4902 } 4903 } 4904 4905 #ifdef WITH_XSLT_DEBUG_PROCESS 4906 if (list != NULL) 4907 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 4908 "xsltApplyTemplates: list of %d nodes\n", list->nodeNr)); 4909 #endif 4910 4911 if ((list == NULL) || (list->nodeNr == 0)) 4912 goto exit; 4913 4914 /* 4915 * Set the context's node set and size; this is also needed for 4916 * for xsltDoSortFunction(). 4917 */ 4918 ctxt->nodeList = list; 4919 /* 4920 * Process xsl:with-param and xsl:sort instructions. 4921 * (The code became so verbose just to avoid the 4922 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort) 4923 * BUG TODO: We are not using namespaced potentially defined on the 4924 * xsl:sort or xsl:with-param elements; XPath expression might fail. 4925 */ 4926 if (inst->children) { 4927 xsltStackElemPtr param; 4928 4929 cur = inst->children; 4930 while (cur) { 4931 4932 #ifdef WITH_DEBUGGER 4933 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 4934 xslHandleDebugger(cur, node, NULL, ctxt); 4935 #endif 4936 if (ctxt->state == XSLT_STATE_STOPPED) 4937 break; 4938 if (cur->type == XML_TEXT_NODE) { 4939 cur = cur->next; 4940 continue; 4941 } 4942 if (! IS_XSLT_ELEM(cur)) 4943 break; 4944 if (IS_XSLT_NAME(cur, "with-param")) { 4945 param = xsltParseStylesheetCallerParam(ctxt, cur); 4946 if (param != NULL) { 4947 param->next = withParams; 4948 withParams = param; 4949 } 4950 } 4951 if (IS_XSLT_NAME(cur, "sort")) { 4952 xsltTemplatePtr oldCurTempRule = 4953 ctxt->currentTemplateRule; 4954 int nbsorts = 0; 4955 xmlNodePtr sorts[XSLT_MAX_SORT]; 4956 4957 sorts[nbsorts++] = cur; 4958 4959 while (cur) { 4960 4961 #ifdef WITH_DEBUGGER 4962 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 4963 xslHandleDebugger(cur, node, NULL, ctxt); 4964 #endif 4965 if (ctxt->state == XSLT_STATE_STOPPED) 4966 break; 4967 4968 if (cur->type == XML_TEXT_NODE) { 4969 cur = cur->next; 4970 continue; 4971 } 4972 4973 if (! IS_XSLT_ELEM(cur)) 4974 break; 4975 if (IS_XSLT_NAME(cur, "with-param")) { 4976 param = xsltParseStylesheetCallerParam(ctxt, cur); 4977 if (param != NULL) { 4978 param->next = withParams; 4979 withParams = param; 4980 } 4981 } 4982 if (IS_XSLT_NAME(cur, "sort")) { 4983 if (nbsorts >= XSLT_MAX_SORT) { 4984 xsltTransformError(ctxt, NULL, cur, 4985 "The number (%d) of xsl:sort instructions exceeds the " 4986 "maximum allowed by this processor's settings.\n", 4987 nbsorts); 4988 ctxt->state = XSLT_STATE_STOPPED; 4989 break; 4990 } else { 4991 sorts[nbsorts++] = cur; 4992 } 4993 } 4994 cur = cur->next; 4995 } 4996 /* 4997 * The "current template rule" is cleared for xsl:sort. 4998 */ 4999 ctxt->currentTemplateRule = NULL; 5000 /* 5001 * Sort. 5002 */ 5003 xsltDoSortFunction(ctxt, sorts, nbsorts); 5004 ctxt->currentTemplateRule = oldCurTempRule; 5005 break; 5006 } 5007 cur = cur->next; 5008 } 5009 } 5010 xpctxt->contextSize = list->nodeNr; 5011 /* 5012 * Apply templates for all selected source nodes. 5013 */ 5014 for (i = 0; i < list->nodeNr; i++) { 5015 cur = list->nodeTab[i]; 5016 /* 5017 * The node becomes the "current node". 5018 */ 5019 ctxt->node = cur; 5020 /* 5021 * An xsl:apply-templates can change the current context doc. 5022 * OPTIMIZE TODO: Get rid of the need to set the context doc. 5023 */ 5024 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) 5025 xpctxt->doc = cur->doc; 5026 5027 xpctxt->proximityPosition = i + 1; 5028 /* 5029 * Find and apply a template for this node. 5030 */ 5031 xsltProcessOneNode(ctxt, cur, withParams); 5032 } 5033 5034 exit: 5035 error: 5036 /* 5037 * Free the parameter list. 5038 */ 5039 if (withParams != NULL) 5040 xsltFreeStackElemList(withParams); 5041 if (list != NULL) 5042 xmlXPathFreeNodeSet(list); 5043 /* 5044 * Restore context states. 5045 */ 5046 xpctxt->nsNr = oldXPNsNr; 5047 xpctxt->namespaces = oldXPNamespaces; 5048 xpctxt->doc = oldXPDoc; 5049 xpctxt->contextSize = oldXPContextSize; 5050 xpctxt->proximityPosition = oldXPProximityPosition; 5051 5052 ctxt->document = oldDocInfo; 5053 ctxt->nodeList = oldList; 5054 ctxt->node = oldContextNode; 5055 ctxt->mode = oldMode; 5056 ctxt->modeURI = oldModeURI; 5057 } 5058 5059 5060 /** 5061 * xsltChoose: 5062 * @ctxt: a XSLT process context 5063 * @contextNode: the current node in the source tree 5064 * @inst: the xsl:choose instruction 5065 * @comp: compiled information of the instruction 5066 * 5067 * Processes the xsl:choose instruction on the source node. 5068 */ 5069 void 5070 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 5071 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) 5072 { 5073 xmlNodePtr cur; 5074 5075 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) 5076 return; 5077 5078 /* 5079 * TODO: Content model checks should be done only at compilation 5080 * time. 5081 */ 5082 cur = inst->children; 5083 if (cur == NULL) { 5084 xsltTransformError(ctxt, NULL, inst, 5085 "xsl:choose: The instruction has no content.\n"); 5086 return; 5087 } 5088 5089 #ifdef XSLT_REFACTORED 5090 /* 5091 * We don't check the content model during transformation. 5092 */ 5093 #else 5094 if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) { 5095 xsltTransformError(ctxt, NULL, inst, 5096 "xsl:choose: xsl:when expected first\n"); 5097 return; 5098 } 5099 #endif 5100 5101 { 5102 int testRes = 0, res = 0; 5103 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 5104 xmlDocPtr oldXPContextDoc = xpctxt->doc; 5105 int oldXPProximityPosition = xpctxt->proximityPosition; 5106 int oldXPContextSize = xpctxt->contextSize; 5107 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 5108 int oldXPNsNr = xpctxt->nsNr; 5109 5110 #ifdef XSLT_REFACTORED 5111 xsltStyleItemWhenPtr wcomp = NULL; 5112 #else 5113 xsltStylePreCompPtr wcomp = NULL; 5114 #endif 5115 5116 /* 5117 * Process xsl:when --------------------------------------------------- 5118 */ 5119 while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { 5120 wcomp = cur->psvi; 5121 5122 if ((wcomp == NULL) || (wcomp->test == NULL) || 5123 (wcomp->comp == NULL)) 5124 { 5125 xsltTransformError(ctxt, NULL, cur, 5126 "Internal error in xsltChoose(): " 5127 "The XSLT 'when' instruction was not compiled.\n"); 5128 goto error; 5129 } 5130 5131 5132 #ifdef WITH_DEBUGGER 5133 if (xslDebugStatus != XSLT_DEBUG_NONE) { 5134 /* 5135 * TODO: Isn't comp->templ always NULL for xsl:choose? 5136 */ 5137 xslHandleDebugger(cur, contextNode, NULL, ctxt); 5138 } 5139 #endif 5140 #ifdef WITH_XSLT_DEBUG_PROCESS 5141 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 5142 "xsltChoose: test %s\n", wcomp->test)); 5143 #endif 5144 5145 xpctxt->node = contextNode; 5146 xpctxt->doc = oldXPContextDoc; 5147 xpctxt->proximityPosition = oldXPProximityPosition; 5148 xpctxt->contextSize = oldXPContextSize; 5149 5150 #ifdef XSLT_REFACTORED 5151 if (wcomp->inScopeNs != NULL) { 5152 xpctxt->namespaces = wcomp->inScopeNs->list; 5153 xpctxt->nsNr = wcomp->inScopeNs->xpathNumber; 5154 } else { 5155 xpctxt->namespaces = NULL; 5156 xpctxt->nsNr = 0; 5157 } 5158 #else 5159 xpctxt->namespaces = wcomp->nsList; 5160 xpctxt->nsNr = wcomp->nsNr; 5161 #endif 5162 5163 5164 #ifdef XSLT_FAST_IF 5165 res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt); 5166 5167 if (res == -1) { 5168 ctxt->state = XSLT_STATE_STOPPED; 5169 goto error; 5170 } 5171 testRes = (res == 1) ? 1 : 0; 5172 5173 #else /* XSLT_FAST_IF */ 5174 5175 res = xmlXPathCompiledEval(wcomp->comp, xpctxt); 5176 5177 if (res != NULL) { 5178 if (res->type != XPATH_BOOLEAN) 5179 res = xmlXPathConvertBoolean(res); 5180 if (res->type == XPATH_BOOLEAN) 5181 testRes = res->boolval; 5182 else { 5183 #ifdef WITH_XSLT_DEBUG_PROCESS 5184 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 5185 "xsltChoose: test didn't evaluate to a boolean\n")); 5186 #endif 5187 goto error; 5188 } 5189 xmlXPathFreeObject(res); 5190 res = NULL; 5191 } else { 5192 ctxt->state = XSLT_STATE_STOPPED; 5193 goto error; 5194 } 5195 5196 #endif /* else of XSLT_FAST_IF */ 5197 5198 #ifdef WITH_XSLT_DEBUG_PROCESS 5199 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 5200 "xsltChoose: test evaluate to %d\n", testRes)); 5201 #endif 5202 if (testRes) 5203 goto test_is_true; 5204 5205 cur = cur->next; 5206 } 5207 5208 /* 5209 * Process xsl:otherwise ---------------------------------------------- 5210 */ 5211 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) { 5212 5213 #ifdef WITH_DEBUGGER 5214 if (xslDebugStatus != XSLT_DEBUG_NONE) 5215 xslHandleDebugger(cur, contextNode, NULL, ctxt); 5216 #endif 5217 5218 #ifdef WITH_XSLT_DEBUG_PROCESS 5219 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 5220 "evaluating xsl:otherwise\n")); 5221 #endif 5222 goto test_is_true; 5223 } 5224 xpctxt->node = contextNode; 5225 xpctxt->doc = oldXPContextDoc; 5226 xpctxt->proximityPosition = oldXPProximityPosition; 5227 xpctxt->contextSize = oldXPContextSize; 5228 xpctxt->namespaces = oldXPNamespaces; 5229 xpctxt->nsNr = oldXPNsNr; 5230 goto exit; 5231 5232 test_is_true: 5233 5234 xpctxt->node = contextNode; 5235 xpctxt->doc = oldXPContextDoc; 5236 xpctxt->proximityPosition = oldXPProximityPosition; 5237 xpctxt->contextSize = oldXPContextSize; 5238 xpctxt->namespaces = oldXPNamespaces; 5239 xpctxt->nsNr = oldXPNsNr; 5240 goto process_sequence; 5241 } 5242 5243 process_sequence: 5244 5245 /* 5246 * Instantiate the sequence constructor. 5247 */ 5248 xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children, 5249 NULL); 5250 5251 exit: 5252 error: 5253 return; 5254 } 5255 5256 /** 5257 * xsltIf: 5258 * @ctxt: a XSLT process context 5259 * @contextNode: the current node in the source tree 5260 * @inst: the xsl:if instruction 5261 * @castedComp: compiled information of the instruction 5262 * 5263 * Processes the xsl:if instruction on the source node. 5264 */ 5265 void 5266 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 5267 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 5268 { 5269 int res = 0; 5270 5271 #ifdef XSLT_REFACTORED 5272 xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp; 5273 #else 5274 xsltStylePreCompPtr comp = castedComp; 5275 #endif 5276 5277 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) 5278 return; 5279 if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) { 5280 xsltTransformError(ctxt, NULL, inst, 5281 "Internal error in xsltIf(): " 5282 "The XSLT 'if' instruction was not compiled.\n"); 5283 return; 5284 } 5285 5286 #ifdef WITH_XSLT_DEBUG_PROCESS 5287 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 5288 "xsltIf: test %s\n", comp->test)); 5289 #endif 5290 5291 #ifdef XSLT_FAST_IF 5292 { 5293 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 5294 xmlDocPtr oldXPContextDoc = xpctxt->doc; 5295 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 5296 xmlNodePtr oldXPContextNode = xpctxt->node; 5297 int oldXPProximityPosition = xpctxt->proximityPosition; 5298 int oldXPContextSize = xpctxt->contextSize; 5299 int oldXPNsNr = xpctxt->nsNr; 5300 xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; 5301 5302 xpctxt->node = contextNode; 5303 if (comp != NULL) { 5304 5305 #ifdef XSLT_REFACTORED 5306 if (comp->inScopeNs != NULL) { 5307 xpctxt->namespaces = comp->inScopeNs->list; 5308 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 5309 } else { 5310 xpctxt->namespaces = NULL; 5311 xpctxt->nsNr = 0; 5312 } 5313 #else 5314 xpctxt->namespaces = comp->nsList; 5315 xpctxt->nsNr = comp->nsNr; 5316 #endif 5317 } else { 5318 xpctxt->namespaces = NULL; 5319 xpctxt->nsNr = 0; 5320 } 5321 /* 5322 * This XPath function is optimized for boolean results. 5323 */ 5324 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt); 5325 5326 /* 5327 * Cleanup fragments created during evaluation of the 5328 * "select" expression. 5329 */ 5330 if (oldLocalFragmentTop != ctxt->localRVT) 5331 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 5332 5333 xpctxt->doc = oldXPContextDoc; 5334 xpctxt->node = oldXPContextNode; 5335 xpctxt->contextSize = oldXPContextSize; 5336 xpctxt->proximityPosition = oldXPProximityPosition; 5337 xpctxt->nsNr = oldXPNsNr; 5338 xpctxt->namespaces = oldXPNamespaces; 5339 } 5340 5341 #ifdef WITH_XSLT_DEBUG_PROCESS 5342 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 5343 "xsltIf: test evaluate to %d\n", res)); 5344 #endif 5345 5346 if (res == -1) { 5347 ctxt->state = XSLT_STATE_STOPPED; 5348 goto error; 5349 } 5350 if (res == 1) { 5351 /* 5352 * Instantiate the sequence constructor of xsl:if. 5353 */ 5354 xsltApplySequenceConstructor(ctxt, 5355 contextNode, inst->children, NULL); 5356 } 5357 5358 #else /* XSLT_FAST_IF */ 5359 { 5360 xmlXPathObjectPtr xpobj = NULL; 5361 /* 5362 * OLD CODE: 5363 */ 5364 { 5365 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 5366 xmlDocPtr oldXPContextDoc = xpctxt->doc; 5367 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 5368 xmlNodePtr oldXPContextNode = xpctxt->node; 5369 int oldXPProximityPosition = xpctxt->proximityPosition; 5370 int oldXPContextSize = xpctxt->contextSize; 5371 int oldXPNsNr = xpctxt->nsNr; 5372 5373 xpctxt->node = contextNode; 5374 if (comp != NULL) { 5375 5376 #ifdef XSLT_REFACTORED 5377 if (comp->inScopeNs != NULL) { 5378 xpctxt->namespaces = comp->inScopeNs->list; 5379 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 5380 } else { 5381 xpctxt->namespaces = NULL; 5382 xpctxt->nsNr = 0; 5383 } 5384 #else 5385 xpctxt->namespaces = comp->nsList; 5386 xpctxt->nsNr = comp->nsNr; 5387 #endif 5388 } else { 5389 xpctxt->namespaces = NULL; 5390 xpctxt->nsNr = 0; 5391 } 5392 5393 /* 5394 * This XPath function is optimized for boolean results. 5395 */ 5396 xpobj = xmlXPathCompiledEval(comp->comp, xpctxt); 5397 5398 xpctxt->doc = oldXPContextDoc; 5399 xpctxt->node = oldXPContextNode; 5400 xpctxt->contextSize = oldXPContextSize; 5401 xpctxt->proximityPosition = oldXPProximityPosition; 5402 xpctxt->nsNr = oldXPNsNr; 5403 xpctxt->namespaces = oldXPNamespaces; 5404 } 5405 if (xpobj != NULL) { 5406 if (xpobj->type != XPATH_BOOLEAN) 5407 xpobj = xmlXPathConvertBoolean(xpobj); 5408 if (xpobj->type == XPATH_BOOLEAN) { 5409 res = xpobj->boolval; 5410 5411 #ifdef WITH_XSLT_DEBUG_PROCESS 5412 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 5413 "xsltIf: test evaluate to %d\n", res)); 5414 #endif 5415 if (res) { 5416 xsltApplySequenceConstructor(ctxt, 5417 contextNode, inst->children, NULL); 5418 } 5419 } else { 5420 5421 #ifdef WITH_XSLT_DEBUG_PROCESS 5422 XSLT_TRACE(ctxt, XSLT_TRACE_IF, 5423 xsltGenericDebug(xsltGenericDebugContext, 5424 "xsltIf: test didn't evaluate to a boolean\n")); 5425 #endif 5426 ctxt->state = XSLT_STATE_STOPPED; 5427 } 5428 xmlXPathFreeObject(xpobj); 5429 } else { 5430 ctxt->state = XSLT_STATE_STOPPED; 5431 } 5432 } 5433 #endif /* else of XSLT_FAST_IF */ 5434 5435 error: 5436 return; 5437 } 5438 5439 /** 5440 * xsltForEach: 5441 * @ctxt: an XSLT transformation context 5442 * @contextNode: the "current node" in the source tree 5443 * @inst: the element node of the xsl:for-each instruction 5444 * @castedComp: the compiled information of the instruction 5445 * 5446 * Process the xslt for-each node on the source node 5447 */ 5448 void 5449 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 5450 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 5451 { 5452 #ifdef XSLT_REFACTORED 5453 xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp; 5454 #else 5455 xsltStylePreCompPtr comp = castedComp; 5456 #endif 5457 int i; 5458 xmlXPathObjectPtr res = NULL; 5459 xmlNodePtr cur, curInst; 5460 xmlNodeSetPtr list = NULL; 5461 xmlNodeSetPtr oldList; 5462 int oldXPProximityPosition, oldXPContextSize; 5463 xmlNodePtr oldContextNode; 5464 xsltTemplatePtr oldCurTemplRule; 5465 xmlDocPtr oldXPDoc; 5466 xsltDocumentPtr oldDocInfo; 5467 xmlXPathContextPtr xpctxt; 5468 5469 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) { 5470 xsltGenericError(xsltGenericErrorContext, 5471 "xsltForEach(): Bad arguments.\n"); 5472 return; 5473 } 5474 5475 if (comp == NULL) { 5476 xsltTransformError(ctxt, NULL, inst, 5477 "Internal error in xsltForEach(): " 5478 "The XSLT 'for-each' instruction was not compiled.\n"); 5479 return; 5480 } 5481 if ((comp->select == NULL) || (comp->comp == NULL)) { 5482 xsltTransformError(ctxt, NULL, inst, 5483 "Internal error in xsltForEach(): " 5484 "The selecting expression of the XSLT 'for-each' " 5485 "instruction was not compiled correctly.\n"); 5486 return; 5487 } 5488 xpctxt = ctxt->xpathCtxt; 5489 5490 #ifdef WITH_XSLT_DEBUG_PROCESS 5491 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 5492 "xsltForEach: select %s\n", comp->select)); 5493 #endif 5494 5495 /* 5496 * Save context states. 5497 */ 5498 oldDocInfo = ctxt->document; 5499 oldList = ctxt->nodeList; 5500 oldContextNode = ctxt->node; 5501 /* 5502 * The "current template rule" is cleared for the instantiation of 5503 * xsl:for-each. 5504 */ 5505 oldCurTemplRule = ctxt->currentTemplateRule; 5506 ctxt->currentTemplateRule = NULL; 5507 5508 oldXPDoc = xpctxt->doc; 5509 oldXPProximityPosition = xpctxt->proximityPosition; 5510 oldXPContextSize = xpctxt->contextSize; 5511 /* 5512 * Set up XPath. 5513 */ 5514 xpctxt->node = contextNode; 5515 #ifdef XSLT_REFACTORED 5516 if (comp->inScopeNs != NULL) { 5517 xpctxt->namespaces = comp->inScopeNs->list; 5518 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 5519 } else { 5520 xpctxt->namespaces = NULL; 5521 xpctxt->nsNr = 0; 5522 } 5523 #else 5524 xpctxt->namespaces = comp->nsList; 5525 xpctxt->nsNr = comp->nsNr; 5526 #endif 5527 5528 /* 5529 * Evaluate the 'select' expression. 5530 */ 5531 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); 5532 5533 if (res != NULL) { 5534 if (res->type == XPATH_NODESET) 5535 list = res->nodesetval; 5536 else { 5537 xsltTransformError(ctxt, NULL, inst, 5538 "The 'select' expression does not evaluate to a node set.\n"); 5539 5540 #ifdef WITH_XSLT_DEBUG_PROCESS 5541 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 5542 "xsltForEach: select didn't evaluate to a node list\n")); 5543 #endif 5544 goto error; 5545 } 5546 } else { 5547 xsltTransformError(ctxt, NULL, inst, 5548 "Failed to evaluate the 'select' expression.\n"); 5549 ctxt->state = XSLT_STATE_STOPPED; 5550 goto error; 5551 } 5552 5553 if ((list == NULL) || (list->nodeNr <= 0)) 5554 goto exit; 5555 5556 #ifdef WITH_XSLT_DEBUG_PROCESS 5557 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 5558 "xsltForEach: select evaluates to %d nodes\n", list->nodeNr)); 5559 #endif 5560 5561 /* 5562 * Restore XPath states for the "current node". 5563 */ 5564 xpctxt->contextSize = oldXPContextSize; 5565 xpctxt->proximityPosition = oldXPProximityPosition; 5566 xpctxt->node = contextNode; 5567 5568 /* 5569 * Set the list; this has to be done already here for xsltDoSortFunction(). 5570 */ 5571 ctxt->nodeList = list; 5572 /* 5573 * Handle xsl:sort instructions and skip them for further processing. 5574 * BUG TODO: We are not using namespaced potentially defined on the 5575 * xsl:sort element; XPath expression might fail. 5576 */ 5577 curInst = inst->children; 5578 if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { 5579 int nbsorts = 0; 5580 xmlNodePtr sorts[XSLT_MAX_SORT]; 5581 5582 sorts[nbsorts++] = curInst; 5583 5584 #ifdef WITH_DEBUGGER 5585 if (xslDebugStatus != XSLT_DEBUG_NONE) 5586 xslHandleDebugger(curInst, contextNode, NULL, ctxt); 5587 #endif 5588 5589 curInst = curInst->next; 5590 while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { 5591 if (nbsorts >= XSLT_MAX_SORT) { 5592 xsltTransformError(ctxt, NULL, curInst, 5593 "The number of xsl:sort instructions exceeds the " 5594 "maximum (%d) allowed by this processor.\n", 5595 XSLT_MAX_SORT); 5596 goto error; 5597 } else { 5598 sorts[nbsorts++] = curInst; 5599 } 5600 5601 #ifdef WITH_DEBUGGER 5602 if (xslDebugStatus != XSLT_DEBUG_NONE) 5603 xslHandleDebugger(curInst, contextNode, NULL, ctxt); 5604 #endif 5605 curInst = curInst->next; 5606 } 5607 xsltDoSortFunction(ctxt, sorts, nbsorts); 5608 } 5609 xpctxt->contextSize = list->nodeNr; 5610 /* 5611 * Instantiate the sequence constructor for each selected node. 5612 */ 5613 for (i = 0; i < list->nodeNr; i++) { 5614 cur = list->nodeTab[i]; 5615 /* 5616 * The selected node becomes the "current node". 5617 */ 5618 ctxt->node = cur; 5619 /* 5620 * An xsl:for-each can change the current context doc. 5621 * OPTIMIZE TODO: Get rid of the need to set the context doc. 5622 */ 5623 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) 5624 xpctxt->doc = cur->doc; 5625 5626 xpctxt->proximityPosition = i + 1; 5627 5628 xsltApplySequenceConstructor(ctxt, cur, curInst, NULL); 5629 } 5630 5631 exit: 5632 error: 5633 if (res != NULL) 5634 xmlXPathFreeObject(res); 5635 /* 5636 * Restore old states. 5637 */ 5638 ctxt->document = oldDocInfo; 5639 ctxt->nodeList = oldList; 5640 ctxt->node = oldContextNode; 5641 ctxt->currentTemplateRule = oldCurTemplRule; 5642 5643 xpctxt->doc = oldXPDoc; 5644 xpctxt->contextSize = oldXPContextSize; 5645 xpctxt->proximityPosition = oldXPProximityPosition; 5646 } 5647 5648 /************************************************************************ 5649 * * 5650 * Generic interface * 5651 * * 5652 ************************************************************************/ 5653 5654 #ifdef XSLT_GENERATE_HTML_DOCTYPE 5655 typedef struct xsltHTMLVersion { 5656 const char *version; 5657 const char *public; 5658 const char *system; 5659 } xsltHTMLVersion; 5660 5661 static xsltHTMLVersion xsltHTMLVersions[] = { 5662 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", 5663 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, 5664 { "4.01strict", "-//W3C//DTD HTML 4.01//EN", 5665 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"}, 5666 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN", 5667 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, 5668 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN", 5669 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, 5670 { "4.0strict", "-//W3C//DTD HTML 4.01//EN", 5671 "http://www.w3.org/TR/html4/strict.dtd"}, 5672 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN", 5673 "http://www.w3.org/TR/html4/loose.dtd"}, 5674 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN", 5675 "http://www.w3.org/TR/html4/frameset.dtd"}, 5676 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN", 5677 "http://www.w3.org/TR/html4/loose.dtd"}, 5678 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL } 5679 }; 5680 5681 /** 5682 * xsltGetHTMLIDs: 5683 * @version: the version string 5684 * @publicID: used to return the public ID 5685 * @systemID: used to return the system ID 5686 * 5687 * Returns -1 if not found, 0 otherwise and the system and public 5688 * Identifier for this given verion of HTML 5689 */ 5690 static int 5691 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, 5692 const xmlChar **systemID) { 5693 unsigned int i; 5694 if (version == NULL) 5695 return(-1); 5696 for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1])); 5697 i++) { 5698 if (!xmlStrcasecmp(version, 5699 (const xmlChar *) xsltHTMLVersions[i].version)) { 5700 if (publicID != NULL) 5701 *publicID = (const xmlChar *) xsltHTMLVersions[i].public; 5702 if (systemID != NULL) 5703 *systemID = (const xmlChar *) xsltHTMLVersions[i].system; 5704 return(0); 5705 } 5706 } 5707 return(-1); 5708 } 5709 #endif 5710 5711 /** 5712 * xsltApplyStripSpaces: 5713 * @ctxt: a XSLT process context 5714 * @node: the root of the XML tree 5715 * 5716 * Strip the unwanted ignorable spaces from the input tree 5717 */ 5718 void 5719 xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) { 5720 xmlNodePtr current; 5721 #ifdef WITH_XSLT_DEBUG_PROCESS 5722 int nb = 0; 5723 #endif 5724 5725 5726 current = node; 5727 while (current != NULL) { 5728 /* 5729 * Cleanup children empty nodes if asked for 5730 */ 5731 if ((IS_XSLT_REAL_NODE(current)) && 5732 (current->children != NULL) && 5733 (xsltFindElemSpaceHandling(ctxt, current))) { 5734 xmlNodePtr delete = NULL, cur = current->children; 5735 5736 while (cur != NULL) { 5737 if (IS_BLANK_NODE(cur)) 5738 delete = cur; 5739 5740 cur = cur->next; 5741 if (delete != NULL) { 5742 xmlUnlinkNode(delete); 5743 xmlFreeNode(delete); 5744 delete = NULL; 5745 #ifdef WITH_XSLT_DEBUG_PROCESS 5746 nb++; 5747 #endif 5748 } 5749 } 5750 } 5751 5752 /* 5753 * Skip to next node in document order. 5754 */ 5755 if (node->type == XML_ENTITY_REF_NODE) { 5756 /* process deep in entities */ 5757 xsltApplyStripSpaces(ctxt, node->children); 5758 } 5759 if ((current->children != NULL) && 5760 (current->type != XML_ENTITY_REF_NODE)) { 5761 current = current->children; 5762 } else if (current->next != NULL) { 5763 current = current->next; 5764 } else { 5765 do { 5766 current = current->parent; 5767 if (current == NULL) 5768 break; 5769 if (current == node) 5770 goto done; 5771 if (current->next != NULL) { 5772 current = current->next; 5773 break; 5774 } 5775 } while (current != NULL); 5776 } 5777 } 5778 5779 done: 5780 #ifdef WITH_XSLT_DEBUG_PROCESS 5781 XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext, 5782 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb)); 5783 #endif 5784 return; 5785 } 5786 5787 static int 5788 xsltCountKeys(xsltTransformContextPtr ctxt) 5789 { 5790 xsltStylesheetPtr style; 5791 xsltKeyDefPtr keyd; 5792 5793 if (ctxt == NULL) 5794 return(-1); 5795 5796 /* 5797 * Do we have those nastly templates with a key() in the match pattern? 5798 */ 5799 ctxt->hasTemplKeyPatterns = 0; 5800 style = ctxt->style; 5801 while (style != NULL) { 5802 if (style->keyMatch != NULL) { 5803 ctxt->hasTemplKeyPatterns = 1; 5804 break; 5805 } 5806 style = xsltNextImport(style); 5807 } 5808 /* 5809 * Count number of key declarations. 5810 */ 5811 ctxt->nbKeys = 0; 5812 style = ctxt->style; 5813 while (style != NULL) { 5814 keyd = style->keys; 5815 while (keyd) { 5816 ctxt->nbKeys++; 5817 keyd = keyd->next; 5818 } 5819 style = xsltNextImport(style); 5820 } 5821 return(ctxt->nbKeys); 5822 } 5823 5824 /** 5825 * xsltApplyStylesheetInternal: 5826 * @style: a parsed XSLT stylesheet 5827 * @doc: a parsed XML document 5828 * @params: a NULL terminated array of parameters names/values tuples 5829 * @output: the targetted output 5830 * @profile: profile FILE * output or NULL 5831 * @user: user provided parameter 5832 * 5833 * Apply the stylesheet to the document 5834 * NOTE: This may lead to a non-wellformed output XML wise ! 5835 * 5836 * Returns the result document or NULL in case of error 5837 */ 5838 static xmlDocPtr 5839 xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, 5840 const char **params, const char *output, 5841 FILE * profile, xsltTransformContextPtr userCtxt) 5842 { 5843 xmlDocPtr res = NULL; 5844 xsltTransformContextPtr ctxt = NULL; 5845 xmlNodePtr root, node; 5846 const xmlChar *method; 5847 const xmlChar *doctypePublic; 5848 const xmlChar *doctypeSystem; 5849 const xmlChar *version; 5850 const xmlChar *encoding; 5851 xsltStackElemPtr variables; 5852 xsltStackElemPtr vptr; 5853 5854 xsltInitGlobals(); 5855 5856 if ((style == NULL) || (doc == NULL)) 5857 return (NULL); 5858 5859 if (style->internalized == 0) { 5860 #ifdef WITH_XSLT_DEBUG 5861 xsltGenericDebug(xsltGenericDebugContext, 5862 "Stylesheet was not fully internalized !\n"); 5863 #endif 5864 } 5865 if (doc->intSubset != NULL) { 5866 /* 5867 * Avoid hitting the DTD when scanning nodes 5868 * but keep it linked as doc->intSubset 5869 */ 5870 xmlNodePtr cur = (xmlNodePtr) doc->intSubset; 5871 if (cur->next != NULL) 5872 cur->next->prev = cur->prev; 5873 if (cur->prev != NULL) 5874 cur->prev->next = cur->next; 5875 if (doc->children == cur) 5876 doc->children = cur->next; 5877 if (doc->last == cur) 5878 doc->last = cur->prev; 5879 cur->prev = cur->next = NULL; 5880 } 5881 5882 /* 5883 * Check for XPath document order availability 5884 */ 5885 root = xmlDocGetRootElement(doc); 5886 if (root != NULL) { 5887 if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE)) 5888 xmlXPathOrderDocElems(doc); 5889 } 5890 5891 if (userCtxt != NULL) 5892 ctxt = userCtxt; 5893 else 5894 ctxt = xsltNewTransformContext(style, doc); 5895 5896 if (ctxt == NULL) 5897 return (NULL); 5898 5899 ctxt->initialContextDoc = doc; 5900 ctxt->initialContextNode = (xmlNodePtr) doc; 5901 5902 if (profile != NULL) 5903 ctxt->profile = 1; 5904 5905 if (output != NULL) 5906 ctxt->outputFile = output; 5907 else 5908 ctxt->outputFile = NULL; 5909 5910 /* 5911 * internalize the modes if needed 5912 */ 5913 if (ctxt->dict != NULL) { 5914 if (ctxt->mode != NULL) 5915 ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1); 5916 if (ctxt->modeURI != NULL) 5917 ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1); 5918 } 5919 5920 XSLT_GET_IMPORT_PTR(method, style, method) 5921 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 5922 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 5923 XSLT_GET_IMPORT_PTR(version, style, version) 5924 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 5925 5926 if ((method != NULL) && 5927 (!xmlStrEqual(method, (const xmlChar *) "xml"))) 5928 { 5929 if (xmlStrEqual(method, (const xmlChar *) "html")) { 5930 ctxt->type = XSLT_OUTPUT_HTML; 5931 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 5932 res = htmlNewDoc(doctypeSystem, doctypePublic); 5933 } else { 5934 if (version == NULL) { 5935 xmlDtdPtr dtd; 5936 5937 res = htmlNewDoc(NULL, NULL); 5938 /* 5939 * Make sure no DTD node is generated in this case 5940 */ 5941 if (res != NULL) { 5942 dtd = xmlGetIntSubset(res); 5943 if (dtd != NULL) { 5944 xmlUnlinkNode((xmlNodePtr) dtd); 5945 xmlFreeDtd(dtd); 5946 } 5947 res->intSubset = NULL; 5948 res->extSubset = NULL; 5949 } 5950 } else { 5951 5952 #ifdef XSLT_GENERATE_HTML_DOCTYPE 5953 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); 5954 #endif 5955 res = htmlNewDoc(doctypeSystem, doctypePublic); 5956 } 5957 } 5958 if (res == NULL) 5959 goto error; 5960 res->dict = ctxt->dict; 5961 xmlDictReference(res->dict); 5962 5963 #ifdef WITH_XSLT_DEBUG 5964 xsltGenericDebug(xsltGenericDebugContext, 5965 "reusing transformation dict for output\n"); 5966 #endif 5967 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { 5968 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, 5969 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n", 5970 style->method); 5971 ctxt->type = XSLT_OUTPUT_HTML; 5972 res = htmlNewDoc(doctypeSystem, doctypePublic); 5973 if (res == NULL) 5974 goto error; 5975 res->dict = ctxt->dict; 5976 xmlDictReference(res->dict); 5977 5978 #ifdef WITH_XSLT_DEBUG 5979 xsltGenericDebug(xsltGenericDebugContext, 5980 "reusing transformation dict for output\n"); 5981 #endif 5982 } else if (xmlStrEqual(method, (const xmlChar *) "text")) { 5983 ctxt->type = XSLT_OUTPUT_TEXT; 5984 res = xmlNewDoc(style->version); 5985 if (res == NULL) 5986 goto error; 5987 res->dict = ctxt->dict; 5988 xmlDictReference(res->dict); 5989 5990 #ifdef WITH_XSLT_DEBUG 5991 xsltGenericDebug(xsltGenericDebugContext, 5992 "reusing transformation dict for output\n"); 5993 #endif 5994 } else { 5995 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, 5996 "xsltApplyStylesheetInternal: unsupported method %s\n", 5997 style->method); 5998 goto error; 5999 } 6000 } else { 6001 ctxt->type = XSLT_OUTPUT_XML; 6002 res = xmlNewDoc(style->version); 6003 if (res == NULL) 6004 goto error; 6005 res->dict = ctxt->dict; 6006 xmlDictReference(ctxt->dict); 6007 #ifdef WITH_XSLT_DEBUG 6008 xsltGenericDebug(xsltGenericDebugContext, 6009 "reusing transformation dict for output\n"); 6010 #endif 6011 } 6012 res->charset = XML_CHAR_ENCODING_UTF8; 6013 if (encoding != NULL) 6014 res->encoding = xmlStrdup(encoding); 6015 variables = style->variables; 6016 6017 /* 6018 * Start the evaluation, evaluate the params, the stylesheets globals 6019 * and start by processing the top node. 6020 */ 6021 if (xsltNeedElemSpaceHandling(ctxt)) 6022 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); 6023 /* 6024 * Evaluate global params and user-provided params. 6025 */ 6026 ctxt->node = (xmlNodePtr) doc; 6027 if (ctxt->globalVars == NULL) 6028 ctxt->globalVars = xmlHashCreate(20); 6029 if (params != NULL) { 6030 xsltEvalUserParams(ctxt, params); 6031 } 6032 6033 /* need to be called before evaluating global variables */ 6034 xsltCountKeys(ctxt); 6035 6036 xsltEvalGlobalVariables(ctxt); 6037 6038 ctxt->node = (xmlNodePtr) doc; 6039 ctxt->output = res; 6040 ctxt->insert = (xmlNodePtr) res; 6041 ctxt->varsBase = ctxt->varsNr - 1; 6042 6043 ctxt->xpathCtxt->contextSize = 1; 6044 ctxt->xpathCtxt->proximityPosition = 1; 6045 ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */ 6046 /* 6047 * Start processing the source tree ----------------------------------- 6048 */ 6049 xsltProcessOneNode(ctxt, ctxt->node, NULL); 6050 /* 6051 * Remove all remaining vars from the stack. 6052 */ 6053 xsltLocalVariablePop(ctxt, 0, -2); 6054 xsltShutdownCtxtExts(ctxt); 6055 6056 xsltCleanupTemplates(style); /* TODO: <- style should be read only */ 6057 6058 /* 6059 * Now cleanup our variables so stylesheet can be re-used 6060 * 6061 * TODO: this is not needed anymore global variables are copied 6062 * and not evaluated directly anymore, keep this as a check 6063 */ 6064 if (style->variables != variables) { 6065 vptr = style->variables; 6066 while (vptr->next != variables) 6067 vptr = vptr->next; 6068 vptr->next = NULL; 6069 xsltFreeStackElemList(style->variables); 6070 style->variables = variables; 6071 } 6072 vptr = style->variables; 6073 while (vptr != NULL) { 6074 if (vptr->computed) { 6075 if (vptr->value != NULL) { 6076 xmlXPathFreeObject(vptr->value); 6077 vptr->value = NULL; 6078 vptr->computed = 0; 6079 } 6080 } 6081 vptr = vptr->next; 6082 } 6083 #if 0 6084 /* 6085 * code disabled by wmb; awaiting kb's review 6086 * problem is that global variable(s) may contain xpath objects 6087 * from doc associated with RVT, so can't be freed at this point. 6088 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so 6089 * I assume this shouldn't be required at this point. 6090 */ 6091 /* 6092 * Free all remaining tree fragments. 6093 */ 6094 xsltFreeRVTs(ctxt); 6095 #endif 6096 /* 6097 * Do some post processing work depending on the generated output 6098 */ 6099 root = xmlDocGetRootElement(res); 6100 if (root != NULL) { 6101 const xmlChar *doctype = NULL; 6102 6103 if ((root->ns != NULL) && (root->ns->prefix != NULL)) 6104 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); 6105 if (doctype == NULL) 6106 doctype = root->name; 6107 6108 /* 6109 * Apply the default selection of the method 6110 */ 6111 if ((method == NULL) && 6112 (root->ns == NULL) && 6113 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { 6114 xmlNodePtr tmp; 6115 6116 tmp = res->children; 6117 while ((tmp != NULL) && (tmp != root)) { 6118 if (tmp->type == XML_ELEMENT_NODE) 6119 break; 6120 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) 6121 break; 6122 tmp = tmp->next; 6123 } 6124 if (tmp == root) { 6125 ctxt->type = XSLT_OUTPUT_HTML; 6126 /* 6127 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the 6128 * transformation on the doc, but functions like 6129 */ 6130 res->type = XML_HTML_DOCUMENT_NODE; 6131 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 6132 res->intSubset = xmlCreateIntSubset(res, doctype, 6133 doctypePublic, 6134 doctypeSystem); 6135 #ifdef XSLT_GENERATE_HTML_DOCTYPE 6136 } else if (version != NULL) { 6137 xsltGetHTMLIDs(version, &doctypePublic, 6138 &doctypeSystem); 6139 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 6140 res->intSubset = 6141 xmlCreateIntSubset(res, doctype, 6142 doctypePublic, 6143 doctypeSystem); 6144 #endif 6145 } 6146 } 6147 6148 } 6149 if (ctxt->type == XSLT_OUTPUT_XML) { 6150 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 6151 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 6152 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 6153 xmlNodePtr last; 6154 /* Need a small "hack" here to assure DTD comes before 6155 possible comment nodes */ 6156 node = res->children; 6157 last = res->last; 6158 res->children = NULL; 6159 res->last = NULL; 6160 res->intSubset = xmlCreateIntSubset(res, doctype, 6161 doctypePublic, 6162 doctypeSystem); 6163 if (res->children != NULL) { 6164 res->children->next = node; 6165 node->prev = res->children; 6166 res->last = last; 6167 } else { 6168 res->children = node; 6169 res->last = last; 6170 } 6171 } 6172 } 6173 } 6174 xmlXPathFreeNodeSet(ctxt->nodeList); 6175 if (profile != NULL) { 6176 xsltSaveProfiling(ctxt, profile); 6177 } 6178 6179 /* 6180 * Be pedantic. 6181 */ 6182 if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) { 6183 xmlFreeDoc(res); 6184 res = NULL; 6185 } 6186 if ((res != NULL) && (ctxt != NULL) && (output != NULL)) { 6187 int ret; 6188 6189 ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output); 6190 if (ret == 0) { 6191 xsltTransformError(ctxt, NULL, NULL, 6192 "xsltApplyStylesheet: forbidden to save to %s\n", 6193 output); 6194 } else if (ret < 0) { 6195 xsltTransformError(ctxt, NULL, NULL, 6196 "xsltApplyStylesheet: saving to %s may not be possible\n", 6197 output); 6198 } 6199 } 6200 6201 #ifdef XSLT_DEBUG_PROFILE_CACHE 6202 printf("# Cache:\n"); 6203 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); 6204 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); 6205 #endif 6206 6207 if ((ctxt != NULL) && (userCtxt == NULL)) 6208 xsltFreeTransformContext(ctxt); 6209 6210 return (res); 6211 6212 error: 6213 if (res != NULL) 6214 xmlFreeDoc(res); 6215 6216 #ifdef XSLT_DEBUG_PROFILE_CACHE 6217 printf("# Cache:\n"); 6218 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); 6219 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); 6220 #endif 6221 6222 if ((ctxt != NULL) && (userCtxt == NULL)) 6223 xsltFreeTransformContext(ctxt); 6224 return (NULL); 6225 } 6226 6227 /** 6228 * xsltApplyStylesheet: 6229 * @style: a parsed XSLT stylesheet 6230 * @doc: a parsed XML document 6231 * @params: a NULL terminated arry of parameters names/values tuples 6232 * 6233 * Apply the stylesheet to the document 6234 * NOTE: This may lead to a non-wellformed output XML wise ! 6235 * 6236 * Returns the result document or NULL in case of error 6237 */ 6238 xmlDocPtr 6239 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 6240 const char **params) 6241 { 6242 return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL)); 6243 } 6244 6245 /** 6246 * xsltProfileStylesheet: 6247 * @style: a parsed XSLT stylesheet 6248 * @doc: a parsed XML document 6249 * @params: a NULL terminated arry of parameters names/values tuples 6250 * @output: a FILE * for the profiling output 6251 * 6252 * Apply the stylesheet to the document and dump the profiling to 6253 * the given output. 6254 * 6255 * Returns the result document or NULL in case of error 6256 */ 6257 xmlDocPtr 6258 xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 6259 const char **params, FILE * output) 6260 { 6261 xmlDocPtr res; 6262 6263 res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL); 6264 return (res); 6265 } 6266 6267 /** 6268 * xsltApplyStylesheetUser: 6269 * @style: a parsed XSLT stylesheet 6270 * @doc: a parsed XML document 6271 * @params: a NULL terminated array of parameters names/values tuples 6272 * @output: the targetted output 6273 * @profile: profile FILE * output or NULL 6274 * @userCtxt: user provided transform context 6275 * 6276 * Apply the stylesheet to the document and allow the user to provide 6277 * its own transformation context. 6278 * 6279 * Returns the result document or NULL in case of error 6280 */ 6281 xmlDocPtr 6282 xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, 6283 const char **params, const char *output, 6284 FILE * profile, xsltTransformContextPtr userCtxt) 6285 { 6286 xmlDocPtr res; 6287 6288 res = xsltApplyStylesheetInternal(style, doc, params, output, 6289 profile, userCtxt); 6290 return (res); 6291 } 6292 6293 /** 6294 * xsltRunStylesheetUser: 6295 * @style: a parsed XSLT stylesheet 6296 * @doc: a parsed XML document 6297 * @params: a NULL terminated array of parameters names/values tuples 6298 * @output: the URL/filename ot the generated resource if available 6299 * @SAX: a SAX handler for progressive callback output (not implemented yet) 6300 * @IObuf: an output buffer for progressive output (not implemented yet) 6301 * @profile: profile FILE * output or NULL 6302 * @userCtxt: user provided transform context 6303 * 6304 * Apply the stylesheet to the document and generate the output according 6305 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. 6306 * 6307 * NOTE: This may lead to a non-wellformed output XML wise ! 6308 * NOTE: This may also result in multiple files being generated 6309 * NOTE: using IObuf, the result encoding used will be the one used for 6310 * creating the output buffer, use the following macro to read it 6311 * from the stylesheet 6312 * XSLT_GET_IMPORT_PTR(encoding, style, encoding) 6313 * NOTE: using SAX, any encoding specified in the stylesheet will be lost 6314 * since the interface uses only UTF8 6315 * 6316 * Returns the number of by written to the main resource or -1 in case of 6317 * error. 6318 */ 6319 int 6320 xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, 6321 const char **params, const char *output, 6322 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf, 6323 FILE * profile, xsltTransformContextPtr userCtxt) 6324 { 6325 xmlDocPtr tmp; 6326 int ret; 6327 6328 if ((output == NULL) && (SAX == NULL) && (IObuf == NULL)) 6329 return (-1); 6330 if ((SAX != NULL) && (IObuf != NULL)) 6331 return (-1); 6332 6333 /* unsupported yet */ 6334 if (SAX != NULL) { 6335 XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */ 6336 return (-1); 6337 } 6338 6339 tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile, 6340 userCtxt); 6341 if (tmp == NULL) { 6342 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 6343 "xsltRunStylesheet : run failed\n"); 6344 return (-1); 6345 } 6346 if (IObuf != NULL) { 6347 /* TODO: incomplete, IObuf output not progressive */ 6348 ret = xsltSaveResultTo(IObuf, tmp, style); 6349 } else { 6350 ret = xsltSaveResultToFilename(output, tmp, style, 0); 6351 } 6352 xmlFreeDoc(tmp); 6353 return (ret); 6354 } 6355 6356 /** 6357 * xsltRunStylesheet: 6358 * @style: a parsed XSLT stylesheet 6359 * @doc: a parsed XML document 6360 * @params: a NULL terminated array of parameters names/values tuples 6361 * @output: the URL/filename ot the generated resource if available 6362 * @SAX: a SAX handler for progressive callback output (not implemented yet) 6363 * @IObuf: an output buffer for progressive output (not implemented yet) 6364 * 6365 * Apply the stylesheet to the document and generate the output according 6366 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. 6367 * 6368 * NOTE: This may lead to a non-wellformed output XML wise ! 6369 * NOTE: This may also result in multiple files being generated 6370 * NOTE: using IObuf, the result encoding used will be the one used for 6371 * creating the output buffer, use the following macro to read it 6372 * from the stylesheet 6373 * XSLT_GET_IMPORT_PTR(encoding, style, encoding) 6374 * NOTE: using SAX, any encoding specified in the stylesheet will be lost 6375 * since the interface uses only UTF8 6376 * 6377 * Returns the number of bytes written to the main resource or -1 in case of 6378 * error. 6379 */ 6380 int 6381 xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 6382 const char **params, const char *output, 6383 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf) 6384 { 6385 return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf, 6386 NULL, NULL)); 6387 } 6388 6389 /** 6390 * xsltRegisterAllElement: 6391 * @ctxt: the XPath context 6392 * 6393 * Registers all default XSLT elements in this context 6394 */ 6395 void 6396 xsltRegisterAllElement(xsltTransformContextPtr ctxt) 6397 { 6398 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates", 6399 XSLT_NAMESPACE, 6400 (xsltTransformFunction) xsltApplyTemplates); 6401 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports", 6402 XSLT_NAMESPACE, 6403 (xsltTransformFunction) xsltApplyImports); 6404 xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template", 6405 XSLT_NAMESPACE, 6406 (xsltTransformFunction) xsltCallTemplate); 6407 xsltRegisterExtElement(ctxt, (const xmlChar *) "element", 6408 XSLT_NAMESPACE, 6409 (xsltTransformFunction) xsltElement); 6410 xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute", 6411 XSLT_NAMESPACE, 6412 (xsltTransformFunction) xsltAttribute); 6413 xsltRegisterExtElement(ctxt, (const xmlChar *) "text", 6414 XSLT_NAMESPACE, 6415 (xsltTransformFunction) xsltText); 6416 xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction", 6417 XSLT_NAMESPACE, 6418 (xsltTransformFunction) xsltProcessingInstruction); 6419 xsltRegisterExtElement(ctxt, (const xmlChar *) "comment", 6420 XSLT_NAMESPACE, 6421 (xsltTransformFunction) xsltComment); 6422 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy", 6423 XSLT_NAMESPACE, 6424 (xsltTransformFunction) xsltCopy); 6425 xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of", 6426 XSLT_NAMESPACE, 6427 (xsltTransformFunction) xsltValueOf); 6428 xsltRegisterExtElement(ctxt, (const xmlChar *) "number", 6429 XSLT_NAMESPACE, 6430 (xsltTransformFunction) xsltNumber); 6431 xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each", 6432 XSLT_NAMESPACE, 6433 (xsltTransformFunction) xsltForEach); 6434 xsltRegisterExtElement(ctxt, (const xmlChar *) "if", 6435 XSLT_NAMESPACE, 6436 (xsltTransformFunction) xsltIf); 6437 xsltRegisterExtElement(ctxt, (const xmlChar *) "choose", 6438 XSLT_NAMESPACE, 6439 (xsltTransformFunction) xsltChoose); 6440 xsltRegisterExtElement(ctxt, (const xmlChar *) "sort", 6441 XSLT_NAMESPACE, 6442 (xsltTransformFunction) xsltSort); 6443 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of", 6444 XSLT_NAMESPACE, 6445 (xsltTransformFunction) xsltCopyOf); 6446 xsltRegisterExtElement(ctxt, (const xmlChar *) "message", 6447 XSLT_NAMESPACE, 6448 (xsltTransformFunction) xsltMessage); 6449 6450 /* 6451 * Those don't have callable entry points but are registered anyway 6452 */ 6453 xsltRegisterExtElement(ctxt, (const xmlChar *) "variable", 6454 XSLT_NAMESPACE, 6455 (xsltTransformFunction) xsltDebug); 6456 xsltRegisterExtElement(ctxt, (const xmlChar *) "param", 6457 XSLT_NAMESPACE, 6458 (xsltTransformFunction) xsltDebug); 6459 xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param", 6460 XSLT_NAMESPACE, 6461 (xsltTransformFunction) xsltDebug); 6462 xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format", 6463 XSLT_NAMESPACE, 6464 (xsltTransformFunction) xsltDebug); 6465 xsltRegisterExtElement(ctxt, (const xmlChar *) "when", 6466 XSLT_NAMESPACE, 6467 (xsltTransformFunction) xsltDebug); 6468 xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise", 6469 XSLT_NAMESPACE, 6470 (xsltTransformFunction) xsltDebug); 6471 xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback", 6472 XSLT_NAMESPACE, 6473 (xsltTransformFunction) xsltDebug); 6474 6475 } 6476