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