1/* 2 * xslt.c: Implemetation of an XSL Transformation 1.0 engine 3 * 4 * Reference: 5 * XSLT specification 6 * http://www.w3.org/TR/1999/REC-xslt-19991116 7 * 8 * Associating Style Sheets with XML documents 9 * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629 10 * 11 * See Copyright for the status of this software. 12 * 13 * daniel@veillard.com 14 */ 15 16#define IN_LIBXSLT 17#include "libxslt.h" 18 19#include <string.h> 20 21#include <libxml/xmlmemory.h> 22#include <libxml/parser.h> 23#include <libxml/tree.h> 24#include <libxml/valid.h> 25#include <libxml/hash.h> 26#include <libxml/uri.h> 27#include <libxml/xmlerror.h> 28#include <libxml/parserInternals.h> 29#include <libxml/xpathInternals.h> 30#include <libxml/xpath.h> 31#include "xslt.h" 32#include "xsltInternals.h" 33#include "pattern.h" 34#include "variables.h" 35#include "namespaces.h" 36#include "attributes.h" 37#include "xsltutils.h" 38#include "imports.h" 39#include "keys.h" 40#include "documents.h" 41#include "extensions.h" 42#include "preproc.h" 43#include "extra.h" 44#include "security.h" 45 46#ifdef WITH_XSLT_DEBUG 47#define WITH_XSLT_DEBUG_PARSING 48/* #define WITH_XSLT_DEBUG_BLANKS */ 49#endif 50 51const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA; 52const int xsltLibxsltVersion = LIBXSLT_VERSION; 53const int xsltLibxmlVersion = LIBXML_VERSION; 54 55#ifdef XSLT_REFACTORED 56 57const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE; 58 59#define XSLT_ELEMENT_CATEGORY_XSLT 0 60#define XSLT_ELEMENT_CATEGORY_EXTENSION 1 61#define XSLT_ELEMENT_CATEGORY_LRE 2 62 63/* 64* xsltLiteralResultMarker: 65* Marker for Literal result elements, in order to avoid multiple attempts 66* to recognize such elements in the stylesheet's tree. 67* This marker is set on node->psvi during the initial traversal 68* of a stylesheet's node tree. 69* 70const xmlChar *xsltLiteralResultMarker = 71 (const xmlChar *) "Literal Result Element"; 72*/ 73 74/* 75* xsltXSLTTextMarker: 76* Marker for xsl:text elements. Used to recognize xsl:text elements 77* for post-processing of the stylesheet's tree, where those 78* elements are removed from the tree. 79*/ 80const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element"; 81 82/* 83* xsltXSLTAttrMarker: 84* Marker for XSLT attribute on Literal Result Elements. 85*/ 86const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr"; 87 88#endif 89 90#ifdef XSLT_LOCALE_WINAPI 91extern xmlRMutexPtr xsltLocaleMutex; 92#endif 93/* 94 * Harmless but avoiding a problem when compiling against a 95 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED 96 */ 97#ifndef LIBXML_DEBUG_ENABLED 98double xmlXPathStringEvalNumber(const xmlChar *str); 99#endif 100/* 101 * Useful macros 102 */ 103 104#ifdef IS_BLANK 105#undef IS_BLANK 106#endif 107#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ 108 ((c) == 0x0D)) 109 110#ifdef IS_BLANK_NODE 111#undef IS_BLANK_NODE 112#endif 113#define IS_BLANK_NODE(n) \ 114 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) 115 116/** 117 * xsltParseContentError: 118 * 119 * @style: the stylesheet 120 * @node: the node where the error occured 121 * 122 * Compile-time error function. 123 */ 124static void 125xsltParseContentError(xsltStylesheetPtr style, 126 xmlNodePtr node) 127{ 128 if ((style == NULL) || (node == NULL)) 129 return; 130 131 if (IS_XSLT_ELEM(node)) 132 xsltTransformError(NULL, style, node, 133 "The XSLT-element '%s' is not allowed at this position.\n", 134 node->name); 135 else 136 xsltTransformError(NULL, style, node, 137 "The element '%s' is not allowed at this position.\n", 138 node->name); 139 style->errors++; 140} 141 142#ifdef XSLT_REFACTORED 143#else 144/** 145 * exclPrefixPush: 146 * @style: the transformation stylesheet 147 * @value: the excluded namespace name to push on the stack 148 * 149 * Push an excluded namespace name on the stack 150 * 151 * Returns the new index in the stack or -1 if already present or 152 * in case of error 153 */ 154static int 155exclPrefixPush(xsltStylesheetPtr style, xmlChar * value) 156{ 157 int i; 158 159 if (style->exclPrefixMax == 0) { 160 style->exclPrefixMax = 4; 161 style->exclPrefixTab = 162 (xmlChar * *)xmlMalloc(style->exclPrefixMax * 163 sizeof(style->exclPrefixTab[0])); 164 if (style->exclPrefixTab == NULL) { 165 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 166 return (-1); 167 } 168 } 169 /* do not push duplicates */ 170 for (i = 0;i < style->exclPrefixNr;i++) { 171 if (xmlStrEqual(style->exclPrefixTab[i], value)) 172 return(-1); 173 } 174 if (style->exclPrefixNr >= style->exclPrefixMax) { 175 style->exclPrefixMax *= 2; 176 style->exclPrefixTab = 177 (xmlChar * *)xmlRealloc(style->exclPrefixTab, 178 style->exclPrefixMax * 179 sizeof(style->exclPrefixTab[0])); 180 if (style->exclPrefixTab == NULL) { 181 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 182 return (-1); 183 } 184 } 185 style->exclPrefixTab[style->exclPrefixNr] = value; 186 style->exclPrefix = value; 187 return (style->exclPrefixNr++); 188} 189/** 190 * exclPrefixPop: 191 * @style: the transformation stylesheet 192 * 193 * Pop an excluded prefix value from the stack 194 * 195 * Returns the stored excluded prefix value 196 */ 197static xmlChar * 198exclPrefixPop(xsltStylesheetPtr style) 199{ 200 xmlChar *ret; 201 202 if (style->exclPrefixNr <= 0) 203 return (0); 204 style->exclPrefixNr--; 205 if (style->exclPrefixNr > 0) 206 style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1]; 207 else 208 style->exclPrefix = NULL; 209 ret = style->exclPrefixTab[style->exclPrefixNr]; 210 style->exclPrefixTab[style->exclPrefixNr] = 0; 211 return (ret); 212} 213#endif 214 215/************************************************************************ 216 * * 217 * Helper functions * 218 * * 219 ************************************************************************/ 220 221static int initialized = 0; 222/** 223 * xsltInit: 224 * 225 * Initializes the processor (e.g. registers built-in extensions, 226 * etc.) 227 */ 228void 229xsltInit (void) { 230 if (initialized == 0) { 231 initialized = 1; 232#ifdef XSLT_LOCALE_WINAPI 233 xsltLocaleMutex = xmlNewRMutex(); 234#endif 235 xsltRegisterAllExtras(); 236 } 237} 238 239/** 240 * xsltUninit: 241 * 242 * Uninitializes the processor. 243 */ 244void 245xsltUninit (void) { 246#ifdef XSLT_LOCALE_WINAPI 247 xmlFreeRMutex(xsltLocaleMutex); 248 xsltLocaleMutex = NULL; 249#endif 250 initialized = 0; 251} 252 253/** 254 * xsltIsBlank: 255 * @str: a string 256 * 257 * Check if a string is ignorable 258 * 259 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise 260 */ 261int 262xsltIsBlank(xmlChar *str) { 263 if (str == NULL) 264 return(1); 265 while (*str != 0) { 266 if (!(IS_BLANK(*str))) return(0); 267 str++; 268 } 269 return(1); 270} 271 272/************************************************************************ 273 * * 274 * Routines to handle XSLT data structures * 275 * * 276 ************************************************************************/ 277static xsltDecimalFormatPtr 278xsltNewDecimalFormat(xmlChar *name) 279{ 280 xsltDecimalFormatPtr self; 281 /* UTF-8 for 0x2030 */ 282 static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0}; 283 284 self = xmlMalloc(sizeof(xsltDecimalFormat)); 285 if (self != NULL) { 286 self->next = NULL; 287 self->name = name; 288 289 /* Default values */ 290 self->digit = xmlStrdup(BAD_CAST("#")); 291 self->patternSeparator = xmlStrdup(BAD_CAST(";")); 292 self->decimalPoint = xmlStrdup(BAD_CAST(".")); 293 self->grouping = xmlStrdup(BAD_CAST(",")); 294 self->percent = xmlStrdup(BAD_CAST("%")); 295 self->permille = xmlStrdup(BAD_CAST(permille)); 296 self->zeroDigit = xmlStrdup(BAD_CAST("0")); 297 self->minusSign = xmlStrdup(BAD_CAST("-")); 298 self->infinity = xmlStrdup(BAD_CAST("Infinity")); 299 self->noNumber = xmlStrdup(BAD_CAST("NaN")); 300 } 301 return self; 302} 303 304static void 305xsltFreeDecimalFormat(xsltDecimalFormatPtr self) 306{ 307 if (self != NULL) { 308 if (self->digit) 309 xmlFree(self->digit); 310 if (self->patternSeparator) 311 xmlFree(self->patternSeparator); 312 if (self->decimalPoint) 313 xmlFree(self->decimalPoint); 314 if (self->grouping) 315 xmlFree(self->grouping); 316 if (self->percent) 317 xmlFree(self->percent); 318 if (self->permille) 319 xmlFree(self->permille); 320 if (self->zeroDigit) 321 xmlFree(self->zeroDigit); 322 if (self->minusSign) 323 xmlFree(self->minusSign); 324 if (self->infinity) 325 xmlFree(self->infinity); 326 if (self->noNumber) 327 xmlFree(self->noNumber); 328 if (self->name) 329 xmlFree(self->name); 330 xmlFree(self); 331 } 332} 333 334static void 335xsltFreeDecimalFormatList(xsltStylesheetPtr self) 336{ 337 xsltDecimalFormatPtr iter; 338 xsltDecimalFormatPtr tmp; 339 340 if (self == NULL) 341 return; 342 343 iter = self->decimalFormat; 344 while (iter != NULL) { 345 tmp = iter->next; 346 xsltFreeDecimalFormat(iter); 347 iter = tmp; 348 } 349} 350 351/** 352 * xsltDecimalFormatGetByName: 353 * @style: the XSLT stylesheet 354 * @name: the decimal-format name to find 355 * 356 * Find decimal-format by name 357 * 358 * Returns the xsltDecimalFormatPtr 359 */ 360xsltDecimalFormatPtr 361xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name) 362{ 363 xsltDecimalFormatPtr result = NULL; 364 365 if (name == NULL) 366 return style->decimalFormat; 367 368 while (style != NULL) { 369 for (result = style->decimalFormat->next; 370 result != NULL; 371 result = result->next) { 372 if (xmlStrEqual(name, result->name)) 373 return result; 374 } 375 style = xsltNextImport(style); 376 } 377 return result; 378} 379 380 381/** 382 * xsltNewTemplate: 383 * 384 * Create a new XSLT Template 385 * 386 * Returns the newly allocated xsltTemplatePtr or NULL in case of error 387 */ 388static xsltTemplatePtr 389xsltNewTemplate(void) { 390 xsltTemplatePtr cur; 391 392 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate)); 393 if (cur == NULL) { 394 xsltTransformError(NULL, NULL, NULL, 395 "xsltNewTemplate : malloc failed\n"); 396 return(NULL); 397 } 398 memset(cur, 0, sizeof(xsltTemplate)); 399 cur->priority = XSLT_PAT_NO_PRIORITY; 400 return(cur); 401} 402 403/** 404 * xsltFreeTemplate: 405 * @template: an XSLT template 406 * 407 * Free up the memory allocated by @template 408 */ 409static void 410xsltFreeTemplate(xsltTemplatePtr template) { 411 if (template == NULL) 412 return; 413 if (template->match) xmlFree(template->match); 414/* 415* NOTE: @name and @nameURI are put into the string dict now. 416* if (template->name) xmlFree(template->name); 417* if (template->nameURI) xmlFree(template->nameURI); 418*/ 419/* 420 if (template->mode) xmlFree(template->mode); 421 if (template->modeURI) xmlFree(template->modeURI); 422 */ 423 if (template->inheritedNs) xmlFree(template->inheritedNs); 424 425 /* free profiling data */ 426 if (template->templCalledTab) xmlFree(template->templCalledTab); 427 if (template->templCountTab) xmlFree(template->templCountTab); 428 429 memset(template, -1, sizeof(xsltTemplate)); 430 xmlFree(template); 431} 432 433/** 434 * xsltFreeTemplateList: 435 * @template: an XSLT template list 436 * 437 * Free up the memory allocated by all the elements of @template 438 */ 439static void 440xsltFreeTemplateList(xsltTemplatePtr template) { 441 xsltTemplatePtr cur; 442 443 while (template != NULL) { 444 cur = template; 445 template = template->next; 446 xsltFreeTemplate(cur); 447 } 448} 449 450#ifdef XSLT_REFACTORED 451 452static void 453xsltFreeNsAliasList(xsltNsAliasPtr item) 454{ 455 xsltNsAliasPtr tmp; 456 457 while (item) { 458 tmp = item; 459 item = item->next; 460 xmlFree(tmp); 461 } 462 return; 463} 464 465#ifdef XSLT_REFACTORED_XSLT_NSCOMP 466static void 467xsltFreeNamespaceMap(xsltNsMapPtr item) 468{ 469 xsltNsMapPtr tmp; 470 471 while (item) { 472 tmp = item; 473 item = item->next; 474 xmlFree(tmp); 475 } 476 return; 477} 478 479static xsltNsMapPtr 480xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt, 481 xmlDocPtr doc, 482 xmlNsPtr ns, 483 xmlNodePtr elem) 484{ 485 xsltNsMapPtr ret; 486 487 if ((cctxt == NULL) || (doc == NULL) || (ns == NULL)) 488 return(NULL); 489 490 ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap)); 491 if (ret == NULL) { 492 xsltTransformError(NULL, cctxt->style, elem, 493 "Internal error: (xsltNewNamespaceMapItem) " 494 "memory allocation failed.\n"); 495 return(NULL); 496 } 497 memset(ret, 0, sizeof(xsltNsMap)); 498 ret->doc = doc; 499 ret->ns = ns; 500 ret->origNsName = ns->href; 501 /* 502 * Store the item at current stylesheet-level. 503 */ 504 if (cctxt->psData->nsMap != NULL) 505 ret->next = cctxt->psData->nsMap; 506 cctxt->psData->nsMap = ret; 507 508 return(ret); 509} 510#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ 511 512/** 513 * xsltCompilerVarInfoFree: 514 * @cctxt: the compilation context 515 * 516 * Frees the list of information for vars/params. 517 */ 518static void 519xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt) 520{ 521 xsltVarInfoPtr ivar = cctxt->ivars, ivartmp; 522 523 while (ivar) { 524 ivartmp = ivar; 525 ivar = ivar->next; 526 xmlFree(ivartmp); 527 } 528} 529 530/** 531 * xsltCompilerCtxtFree: 532 * 533 * Free an XSLT compiler context. 534 */ 535static void 536xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt) 537{ 538 if (cctxt == NULL) 539 return; 540#ifdef WITH_XSLT_DEBUG_PARSING 541 xsltGenericDebug(xsltGenericDebugContext, 542 "Freeing compilation context\n"); 543 xsltGenericDebug(xsltGenericDebugContext, 544 "### Max inodes: %d\n", cctxt->maxNodeInfos); 545 xsltGenericDebug(xsltGenericDebugContext, 546 "### Max LREs : %d\n", cctxt->maxLREs); 547#endif 548 /* 549 * Free node-infos. 550 */ 551 if (cctxt->inodeList != NULL) { 552 xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList; 553 while (cur != NULL) { 554 tmp = cur; 555 cur = cur->next; 556 xmlFree(tmp); 557 } 558 } 559 if (cctxt->tmpList != NULL) 560 xsltPointerListFree(cctxt->tmpList); 561#ifdef XSLT_REFACTORED_XPATHCOMP 562 if (cctxt->xpathCtxt != NULL) 563 xmlXPathFreeContext(cctxt->xpathCtxt); 564#endif 565 if (cctxt->nsAliases != NULL) 566 xsltFreeNsAliasList(cctxt->nsAliases); 567 568 if (cctxt->ivars) 569 xsltCompilerVarInfoFree(cctxt); 570 571 xmlFree(cctxt); 572} 573 574/** 575 * xsltCompilerCreate: 576 * 577 * Creates an XSLT compiler context. 578 * 579 * Returns the pointer to the created xsltCompilerCtxt or 580 * NULL in case of an internal error. 581 */ 582static xsltCompilerCtxtPtr 583xsltCompilationCtxtCreate(xsltStylesheetPtr style) { 584 xsltCompilerCtxtPtr ret; 585 586 ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt)); 587 if (ret == NULL) { 588 xsltTransformError(NULL, style, NULL, 589 "xsltCompilerCreate: allocation of compiler " 590 "context failed.\n"); 591 return(NULL); 592 } 593 memset(ret, 0, sizeof(xsltCompilerCtxt)); 594 595 ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR; 596 ret->tmpList = xsltPointerListCreate(20); 597 if (ret->tmpList == NULL) { 598 goto internal_err; 599 } 600#ifdef XSLT_REFACTORED_XPATHCOMP 601 /* 602 * Create the XPath compilation context in order 603 * to speed up precompilation of XPath expressions. 604 */ 605 ret->xpathCtxt = xmlXPathNewContext(NULL); 606 if (ret->xpathCtxt == NULL) 607 goto internal_err; 608#endif 609 610 return(ret); 611 612internal_err: 613 xsltCompilationCtxtFree(ret); 614 return(NULL); 615} 616 617static void 618xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first) 619{ 620 xsltEffectiveNsPtr tmp; 621 622 while (first != NULL) { 623 tmp = first; 624 first = first->nextInStore; 625 xmlFree(tmp); 626 } 627} 628 629static void 630xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data) 631{ 632 if (data == NULL) 633 return; 634 635 if (data->inScopeNamespaces != NULL) { 636 int i; 637 xsltNsListContainerPtr nsi; 638 xsltPointerListPtr list = 639 (xsltPointerListPtr) data->inScopeNamespaces; 640 641 for (i = 0; i < list->number; i++) { 642 /* 643 * REVISIT TODO: Free info of in-scope namespaces. 644 */ 645 nsi = (xsltNsListContainerPtr) list->items[i]; 646 if (nsi->list != NULL) 647 xmlFree(nsi->list); 648 xmlFree(nsi); 649 } 650 xsltPointerListFree(list); 651 data->inScopeNamespaces = NULL; 652 } 653 654 if (data->exclResultNamespaces != NULL) { 655 int i; 656 xsltPointerListPtr list = (xsltPointerListPtr) 657 data->exclResultNamespaces; 658 659 for (i = 0; i < list->number; i++) 660 xsltPointerListFree((xsltPointerListPtr) list->items[i]); 661 662 xsltPointerListFree(list); 663 data->exclResultNamespaces = NULL; 664 } 665 666 if (data->extElemNamespaces != NULL) { 667 xsltPointerListPtr list = (xsltPointerListPtr) 668 data->extElemNamespaces; 669 int i; 670 671 for (i = 0; i < list->number; i++) 672 xsltPointerListFree((xsltPointerListPtr) list->items[i]); 673 674 xsltPointerListFree(list); 675 data->extElemNamespaces = NULL; 676 } 677 if (data->effectiveNs) { 678 xsltLREEffectiveNsNodesFree(data->effectiveNs); 679 data->effectiveNs = NULL; 680 } 681#ifdef XSLT_REFACTORED_XSLT_NSCOMP 682 xsltFreeNamespaceMap(data->nsMap); 683#endif 684 xmlFree(data); 685} 686 687static xsltPrincipalStylesheetDataPtr 688xsltNewPrincipalStylesheetData(void) 689{ 690 xsltPrincipalStylesheetDataPtr ret; 691 692 ret = (xsltPrincipalStylesheetDataPtr) 693 xmlMalloc(sizeof(xsltPrincipalStylesheetData)); 694 if (ret == NULL) { 695 xsltTransformError(NULL, NULL, NULL, 696 "xsltNewPrincipalStylesheetData: memory allocation failed.\n"); 697 return(NULL); 698 } 699 memset(ret, 0, sizeof(xsltPrincipalStylesheetData)); 700 701 /* 702 * Global list of in-scope namespaces. 703 */ 704 ret->inScopeNamespaces = xsltPointerListCreate(-1); 705 if (ret->inScopeNamespaces == NULL) 706 goto internal_err; 707 /* 708 * Global list of excluded result ns-decls. 709 */ 710 ret->exclResultNamespaces = xsltPointerListCreate(-1); 711 if (ret->exclResultNamespaces == NULL) 712 goto internal_err; 713 /* 714 * Global list of extension instruction namespace names. 715 */ 716 ret->extElemNamespaces = xsltPointerListCreate(-1); 717 if (ret->extElemNamespaces == NULL) 718 goto internal_err; 719 720 return(ret); 721 722internal_err: 723 724 return(NULL); 725} 726 727#endif 728 729/** 730 * xsltNewStylesheet: 731 * 732 * Create a new XSLT Stylesheet 733 * 734 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error 735 */ 736xsltStylesheetPtr 737xsltNewStylesheet(void) { 738 xsltStylesheetPtr ret = NULL; 739 740 ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet)); 741 if (ret == NULL) { 742 xsltTransformError(NULL, NULL, NULL, 743 "xsltNewStylesheet : malloc failed\n"); 744 goto internal_err; 745 } 746 memset(ret, 0, sizeof(xsltStylesheet)); 747 748 ret->omitXmlDeclaration = -1; 749 ret->standalone = -1; 750 ret->decimalFormat = xsltNewDecimalFormat(NULL); 751 ret->indent = -1; 752 ret->errors = 0; 753 ret->warnings = 0; 754 ret->exclPrefixNr = 0; 755 ret->exclPrefixMax = 0; 756 ret->exclPrefixTab = NULL; 757 ret->extInfos = NULL; 758 ret->extrasNr = 0; 759 ret->internalized = 1; 760 ret->literal_result = 0; 761 ret->forwards_compatible = 0; 762 ret->dict = xmlDictCreate(); 763#ifdef WITH_XSLT_DEBUG 764 xsltGenericDebug(xsltGenericDebugContext, 765 "creating dictionary for stylesheet\n"); 766#endif 767 768 xsltInit(); 769 770 return(ret); 771 772internal_err: 773 if (ret != NULL) 774 xsltFreeStylesheet(ret); 775 return(NULL); 776} 777 778/** 779 * xsltAllocateExtra: 780 * @style: an XSLT stylesheet 781 * 782 * Allocate an extra runtime information slot statically while compiling 783 * the stylesheet and return its number 784 * 785 * Returns the number of the slot 786 */ 787int 788xsltAllocateExtra(xsltStylesheetPtr style) 789{ 790 return(style->extrasNr++); 791} 792 793/** 794 * xsltAllocateExtraCtxt: 795 * @ctxt: an XSLT transformation context 796 * 797 * Allocate an extra runtime information slot at run-time 798 * and return its number 799 * This make sure there is a slot ready in the transformation context 800 * 801 * Returns the number of the slot 802 */ 803int 804xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt) 805{ 806 if (ctxt->extrasNr >= ctxt->extrasMax) { 807 int i; 808 if (ctxt->extrasNr == 0) { 809 ctxt->extrasMax = 20; 810 ctxt->extras = (xsltRuntimeExtraPtr) 811 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra)); 812 if (ctxt->extras == NULL) { 813 xmlGenericError(xmlGenericErrorContext, 814 "xsltAllocateExtraCtxt: out of memory\n"); 815 ctxt->state = XSLT_STATE_ERROR; 816 return(0); 817 } 818 for (i = 0;i < ctxt->extrasMax;i++) { 819 ctxt->extras[i].info = NULL; 820 ctxt->extras[i].deallocate = NULL; 821 ctxt->extras[i].val.ptr = NULL; 822 } 823 824 } else { 825 xsltRuntimeExtraPtr tmp; 826 827 ctxt->extrasMax += 100; 828 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras, 829 ctxt->extrasMax * sizeof(xsltRuntimeExtra)); 830 if (tmp == NULL) { 831 xmlGenericError(xmlGenericErrorContext, 832 "xsltAllocateExtraCtxt: out of memory\n"); 833 ctxt->state = XSLT_STATE_ERROR; 834 return(0); 835 } 836 ctxt->extras = tmp; 837 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) { 838 ctxt->extras[i].info = NULL; 839 ctxt->extras[i].deallocate = NULL; 840 ctxt->extras[i].val.ptr = NULL; 841 } 842 } 843 } 844 return(ctxt->extrasNr++); 845} 846 847/** 848 * xsltFreeStylesheetList: 849 * @style: an XSLT stylesheet list 850 * 851 * Free up the memory allocated by the list @style 852 */ 853static void 854xsltFreeStylesheetList(xsltStylesheetPtr style) { 855 xsltStylesheetPtr next; 856 857 while (style != NULL) { 858 next = style->next; 859 xsltFreeStylesheet(style); 860 style = next; 861 } 862} 863 864/** 865 * xsltCleanupStylesheetTree: 866 * 867 * @doc: the document-node 868 * @node: the element where the stylesheet is rooted at 869 * 870 * Actually @node need not be the document-element, but 871 * currently Libxslt does not support embedded stylesheets. 872 * 873 * Returns 0 if OK, -1 on API or internal errors. 874 */ 875static int 876xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED, 877 xmlNodePtr rootElem ATTRIBUTE_UNUSED) 878{ 879#if 0 /* TODO: Currently disabled, since probably not needed. */ 880 xmlNodePtr cur; 881 882 if ((doc == NULL) || (rootElem == NULL) || 883 (rootElem->type != XML_ELEMENT_NODE) || 884 (doc != rootElem->doc)) 885 return(-1); 886 887 /* 888 * Cleanup was suggested by Aleksey Sanin: 889 * Clear the PSVI field to avoid problems if the 890 * node-tree of the stylesheet is intended to be used for 891 * further processing by the user (e.g. for compiling it 892 * once again - although not recommended). 893 */ 894 895 cur = rootElem; 896 while (cur != NULL) { 897 if (cur->type == XML_ELEMENT_NODE) { 898 /* 899 * Clear the PSVI field. 900 */ 901 cur->psvi = NULL; 902 if (cur->children) { 903 cur = cur->children; 904 continue; 905 } 906 } 907 908leave_node: 909 if (cur == rootElem) 910 break; 911 if (cur->next != NULL) 912 cur = cur->next; 913 else { 914 cur = cur->parent; 915 if (cur == NULL) 916 break; 917 goto leave_node; 918 } 919 } 920#endif /* #if 0 */ 921 return(0); 922} 923 924/** 925 * xsltFreeStylesheet: 926 * @style: an XSLT stylesheet 927 * 928 * Free up the memory allocated by @style 929 */ 930void 931xsltFreeStylesheet(xsltStylesheetPtr style) 932{ 933 if (style == NULL) 934 return; 935 936#ifdef XSLT_REFACTORED 937 /* 938 * Start with a cleanup of the main stylesheet's doc. 939 */ 940 if ((style->principal == style) && (style->doc)) 941 xsltCleanupStylesheetTree(style->doc, 942 xmlDocGetRootElement(style->doc)); 943#ifdef XSLT_REFACTORED_XSLT_NSCOMP 944 /* 945 * Restore changed ns-decls before freeing the document. 946 */ 947 if ((style->doc != NULL) && 948 XSLT_HAS_INTERNAL_NSMAP(style)) 949 { 950 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style), 951 style->doc); 952 } 953#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ 954#else 955 /* 956 * Start with a cleanup of the main stylesheet's doc. 957 */ 958 if ((style->parent == NULL) && (style->doc)) 959 xsltCleanupStylesheetTree(style->doc, 960 xmlDocGetRootElement(style->doc)); 961#endif /* XSLT_REFACTORED */ 962 963 xsltFreeKeys(style); 964 xsltFreeExts(style); 965 xsltFreeTemplateHashes(style); 966 xsltFreeDecimalFormatList(style); 967 xsltFreeTemplateList(style->templates); 968 xsltFreeAttributeSetsHashes(style); 969 xsltFreeNamespaceAliasHashes(style); 970 xsltFreeStylePreComps(style); 971 /* 972 * Free documents of all included stylsheet modules of this 973 * stylesheet level. 974 */ 975 xsltFreeStyleDocuments(style); 976 /* 977 * TODO: Best time to shutdown extension stuff? 978 */ 979 xsltShutdownExts(style); 980 981 if (style->variables != NULL) 982 xsltFreeStackElemList(style->variables); 983 if (style->cdataSection != NULL) 984 xmlHashFree(style->cdataSection, NULL); 985 if (style->stripSpaces != NULL) 986 xmlHashFree(style->stripSpaces, NULL); 987 if (style->nsHash != NULL) 988 xmlHashFree(style->nsHash, NULL); 989 if (style->exclPrefixTab != NULL) 990 xmlFree(style->exclPrefixTab); 991 if (style->method != NULL) 992 xmlFree(style->method); 993 if (style->methodURI != NULL) 994 xmlFree(style->methodURI); 995 if (style->version != NULL) 996 xmlFree(style->version); 997 if (style->encoding != NULL) 998 xmlFree(style->encoding); 999 if (style->doctypePublic != NULL) 1000 xmlFree(style->doctypePublic); 1001 if (style->doctypeSystem != NULL) 1002 xmlFree(style->doctypeSystem); 1003 if (style->mediaType != NULL) 1004 xmlFree(style->mediaType); 1005 if (style->attVTs) 1006 xsltFreeAVTList(style->attVTs); 1007 if (style->imports != NULL) 1008 xsltFreeStylesheetList(style->imports); 1009 1010#ifdef XSLT_REFACTORED 1011 /* 1012 * If this is the principal stylesheet, then 1013 * free its internal data. 1014 */ 1015 if (style->principal == style) { 1016 if (style->principalData) { 1017 xsltFreePrincipalStylesheetData(style->principalData); 1018 style->principalData = NULL; 1019 } 1020 } 1021#endif 1022 /* 1023 * Better to free the main document of this stylesheet level 1024 * at the end - so here. 1025 */ 1026 if (style->doc != NULL) { 1027 xmlFreeDoc(style->doc); 1028 } 1029 1030#ifdef WITH_XSLT_DEBUG 1031 xsltGenericDebug(xsltGenericDebugContext, 1032 "freeing dictionary from stylesheet\n"); 1033#endif 1034 xmlDictFree(style->dict); 1035 1036 memset(style, -1, sizeof(xsltStylesheet)); 1037 xmlFree(style); 1038} 1039 1040/************************************************************************ 1041 * * 1042 * Parsing of an XSLT Stylesheet * 1043 * * 1044 ************************************************************************/ 1045 1046#ifdef XSLT_REFACTORED 1047 /* 1048 * This is now performed in an optimized way in xsltParseXSLTTemplate. 1049 */ 1050#else 1051/** 1052 * xsltGetInheritedNsList: 1053 * @style: the stylesheet 1054 * @template: the template 1055 * @node: the current node 1056 * 1057 * Search all the namespace applying to a given element except the ones 1058 * from excluded output prefixes currently in scope. Initialize the 1059 * template inheritedNs list with it. 1060 * 1061 * Returns the number of entries found 1062 */ 1063static int 1064xsltGetInheritedNsList(xsltStylesheetPtr style, 1065 xsltTemplatePtr template, 1066 xmlNodePtr node) 1067{ 1068 xmlNsPtr cur; 1069 xmlNsPtr *ret = NULL; 1070 int nbns = 0; 1071 int maxns = 10; 1072 int i; 1073 1074 if ((style == NULL) || (template == NULL) || (node == NULL) || 1075 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL)) 1076 return(0); 1077 while (node != NULL) { 1078 if (node->type == XML_ELEMENT_NODE) { 1079 cur = node->nsDef; 1080 while (cur != NULL) { 1081 if (xmlStrEqual(cur->href, XSLT_NAMESPACE)) 1082 goto skip_ns; 1083 1084 if ((cur->prefix != NULL) && 1085 (xsltCheckExtPrefix(style, cur->prefix))) 1086 goto skip_ns; 1087 /* 1088 * Check if this namespace was excluded. 1089 * Note that at this point only the exclusions defined 1090 * on the topmost stylesheet element are in the exclusion-list. 1091 */ 1092 for (i = 0;i < style->exclPrefixNr;i++) { 1093 if (xmlStrEqual(cur->href, style->exclPrefixTab[i])) 1094 goto skip_ns; 1095 } 1096 if (ret == NULL) { 1097 ret = 1098 (xmlNsPtr *) xmlMalloc((maxns + 1) * 1099 sizeof(xmlNsPtr)); 1100 if (ret == NULL) { 1101 xmlGenericError(xmlGenericErrorContext, 1102 "xsltGetInheritedNsList : out of memory!\n"); 1103 return(0); 1104 } 1105 ret[nbns] = NULL; 1106 } 1107 /* 1108 * Skip shadowed namespace bindings. 1109 */ 1110 for (i = 0; i < nbns; i++) { 1111 if ((cur->prefix == ret[i]->prefix) || 1112 (xmlStrEqual(cur->prefix, ret[i]->prefix))) 1113 break; 1114 } 1115 if (i >= nbns) { 1116 if (nbns >= maxns) { 1117 maxns *= 2; 1118 ret = (xmlNsPtr *) xmlRealloc(ret, 1119 (maxns + 1120 1) * 1121 sizeof(xmlNsPtr)); 1122 if (ret == NULL) { 1123 xmlGenericError(xmlGenericErrorContext, 1124 "xsltGetInheritedNsList : realloc failed!\n"); 1125 return(0); 1126 } 1127 } 1128 ret[nbns++] = cur; 1129 ret[nbns] = NULL; 1130 } 1131skip_ns: 1132 cur = cur->next; 1133 } 1134 } 1135 node = node->parent; 1136 } 1137 if (nbns != 0) { 1138#ifdef WITH_XSLT_DEBUG_PARSING 1139 xsltGenericDebug(xsltGenericDebugContext, 1140 "template has %d inherited namespaces\n", nbns); 1141#endif 1142 template->inheritedNsNr = nbns; 1143 template->inheritedNs = ret; 1144 } 1145 return (nbns); 1146} 1147#endif /* else of XSLT_REFACTORED */ 1148 1149/** 1150 * xsltParseStylesheetOutput: 1151 * @style: the XSLT stylesheet 1152 * @cur: the "output" element 1153 * 1154 * parse an XSLT stylesheet output element and record 1155 * information related to the stylesheet output 1156 */ 1157 1158void 1159xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) 1160{ 1161 xmlChar *elements, 1162 *prop; 1163 xmlChar *element, 1164 *end; 1165 1166 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1167 return; 1168 1169 prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL); 1170 if (prop != NULL) { 1171 if (style->version != NULL) 1172 xmlFree(style->version); 1173 style->version = prop; 1174 } 1175 1176 prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL); 1177 if (prop != NULL) { 1178 if (style->encoding != NULL) 1179 xmlFree(style->encoding); 1180 style->encoding = prop; 1181 } 1182 1183 /* relaxed to support xt:document 1184 * TODO KB: What does "relaxed to support xt:document" mean? 1185 */ 1186 prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL); 1187 if (prop != NULL) { 1188 const xmlChar *URI; 1189 1190 if (style->method != NULL) 1191 xmlFree(style->method); 1192 style->method = NULL; 1193 if (style->methodURI != NULL) 1194 xmlFree(style->methodURI); 1195 style->methodURI = NULL; 1196 1197 /* 1198 * TODO: Don't use xsltGetQNameURI(). 1199 */ 1200 URI = xsltGetQNameURI(cur, &prop); 1201 if (prop == NULL) { 1202 if (style != NULL) style->errors++; 1203 } else if (URI == NULL) { 1204 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || 1205 (xmlStrEqual(prop, (const xmlChar *) "html")) || 1206 (xmlStrEqual(prop, (const xmlChar *) "text"))) { 1207 style->method = prop; 1208 } else { 1209 xsltTransformError(NULL, style, cur, 1210 "invalid value for method: %s\n", prop); 1211 if (style != NULL) style->warnings++; 1212 } 1213 } else { 1214 style->method = prop; 1215 style->methodURI = xmlStrdup(URI); 1216 } 1217 } 1218 1219 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL); 1220 if (prop != NULL) { 1221 if (style->doctypeSystem != NULL) 1222 xmlFree(style->doctypeSystem); 1223 style->doctypeSystem = prop; 1224 } 1225 1226 prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL); 1227 if (prop != NULL) { 1228 if (style->doctypePublic != NULL) 1229 xmlFree(style->doctypePublic); 1230 style->doctypePublic = prop; 1231 } 1232 1233 prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL); 1234 if (prop != NULL) { 1235 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 1236 style->standalone = 1; 1237 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 1238 style->standalone = 0; 1239 } else { 1240 xsltTransformError(NULL, style, cur, 1241 "invalid value for standalone: %s\n", prop); 1242 style->errors++; 1243 } 1244 xmlFree(prop); 1245 } 1246 1247 prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL); 1248 if (prop != NULL) { 1249 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 1250 style->indent = 1; 1251 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 1252 style->indent = 0; 1253 } else { 1254 xsltTransformError(NULL, style, cur, 1255 "invalid value for indent: %s\n", prop); 1256 style->errors++; 1257 } 1258 xmlFree(prop); 1259 } 1260 1261 prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL); 1262 if (prop != NULL) { 1263 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 1264 style->omitXmlDeclaration = 1; 1265 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 1266 style->omitXmlDeclaration = 0; 1267 } else { 1268 xsltTransformError(NULL, style, cur, 1269 "invalid value for omit-xml-declaration: %s\n", 1270 prop); 1271 style->errors++; 1272 } 1273 xmlFree(prop); 1274 } 1275 1276 elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements", 1277 NULL); 1278 if (elements != NULL) { 1279 if (style->cdataSection == NULL) 1280 style->cdataSection = xmlHashCreate(10); 1281 if (style->cdataSection == NULL) 1282 return; 1283 1284 element = elements; 1285 while (*element != 0) { 1286 while (IS_BLANK(*element)) 1287 element++; 1288 if (*element == 0) 1289 break; 1290 end = element; 1291 while ((*end != 0) && (!IS_BLANK(*end))) 1292 end++; 1293 element = xmlStrndup(element, end - element); 1294 if (element) { 1295#ifdef WITH_XSLT_DEBUG_PARSING 1296 xsltGenericDebug(xsltGenericDebugContext, 1297 "add cdata section output element %s\n", 1298 element); 1299#endif 1300 if (xmlValidateQName(BAD_CAST element, 0) != 0) { 1301 xsltTransformError(NULL, style, cur, 1302 "Attribute 'cdata-section-elements': The value " 1303 "'%s' is not a valid QName.\n", element); 1304 xmlFree(element); 1305 style->errors++; 1306 } else { 1307 const xmlChar *URI; 1308 1309 /* 1310 * TODO: Don't use xsltGetQNameURI(). 1311 */ 1312 URI = xsltGetQNameURI(cur, &element); 1313 if (element == NULL) { 1314 /* 1315 * TODO: We'll report additionally an error 1316 * via the stylesheet's error handling. 1317 */ 1318 xsltTransformError(NULL, style, cur, 1319 "Attribute 'cdata-section-elements': The value " 1320 "'%s' is not a valid QName.\n", element); 1321 style->errors++; 1322 } else { 1323 xmlNsPtr ns; 1324 1325 /* 1326 * XSLT-1.0 "Each QName is expanded into an 1327 * expanded-name using the namespace declarations in 1328 * effect on the xsl:output element in which the QName 1329 * occurs; if there is a default namespace, it is used 1330 * for QNames that do not have a prefix" 1331 * NOTE: Fix of bug #339570. 1332 */ 1333 if (URI == NULL) { 1334 ns = xmlSearchNs(style->doc, cur, NULL); 1335 if (ns != NULL) 1336 URI = ns->href; 1337 } 1338 xmlHashAddEntry2(style->cdataSection, element, URI, 1339 (void *) "cdata"); 1340 xmlFree(element); 1341 } 1342 } 1343 } 1344 element = end; 1345 } 1346 xmlFree(elements); 1347 } 1348 1349 prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL); 1350 if (prop != NULL) { 1351 if (style->mediaType) 1352 xmlFree(style->mediaType); 1353 style->mediaType = prop; 1354 } 1355 if (cur->children != NULL) { 1356 xsltParseContentError(style, cur->children); 1357 } 1358} 1359 1360/** 1361 * xsltParseStylesheetDecimalFormat: 1362 * @style: the XSLT stylesheet 1363 * @cur: the "decimal-format" element 1364 * 1365 * <!-- Category: top-level-element --> 1366 * <xsl:decimal-format 1367 * name = qname, decimal-separator = char, grouping-separator = char, 1368 * infinity = string, minus-sign = char, NaN = string, percent = char 1369 * per-mille = char, zero-digit = char, digit = char, 1370 * pattern-separator = char /> 1371 * 1372 * parse an XSLT stylesheet decimal-format element and 1373 * and record the formatting characteristics 1374 */ 1375static void 1376xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur) 1377{ 1378 xmlChar *prop; 1379 xsltDecimalFormatPtr format; 1380 xsltDecimalFormatPtr iter; 1381 1382 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1383 return; 1384 1385 format = style->decimalFormat; 1386 1387 prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL); 1388 if (prop != NULL) { 1389 format = xsltDecimalFormatGetByName(style, prop); 1390 if (format != NULL) { 1391 xsltTransformError(NULL, style, cur, 1392 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop); 1393 if (style != NULL) style->warnings++; 1394 return; 1395 } 1396 format = xsltNewDecimalFormat(prop); 1397 if (format == NULL) { 1398 xsltTransformError(NULL, style, cur, 1399 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n"); 1400 if (style != NULL) style->errors++; 1401 return; 1402 } 1403 /* Append new decimal-format structure */ 1404 for (iter = style->decimalFormat; iter->next; iter = iter->next) 1405 ; 1406 if (iter) 1407 iter->next = format; 1408 } 1409 1410 prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL); 1411 if (prop != NULL) { 1412 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint); 1413 format->decimalPoint = prop; 1414 } 1415 1416 prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL); 1417 if (prop != NULL) { 1418 if (format->grouping != NULL) xmlFree(format->grouping); 1419 format->grouping = prop; 1420 } 1421 1422 prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL); 1423 if (prop != NULL) { 1424 if (format->infinity != NULL) xmlFree(format->infinity); 1425 format->infinity = prop; 1426 } 1427 1428 prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL); 1429 if (prop != NULL) { 1430 if (format->minusSign != NULL) xmlFree(format->minusSign); 1431 format->minusSign = prop; 1432 } 1433 1434 prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL); 1435 if (prop != NULL) { 1436 if (format->noNumber != NULL) xmlFree(format->noNumber); 1437 format->noNumber = prop; 1438 } 1439 1440 prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL); 1441 if (prop != NULL) { 1442 if (format->percent != NULL) xmlFree(format->percent); 1443 format->percent = prop; 1444 } 1445 1446 prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL); 1447 if (prop != NULL) { 1448 if (format->permille != NULL) xmlFree(format->permille); 1449 format->permille = prop; 1450 } 1451 1452 prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL); 1453 if (prop != NULL) { 1454 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit); 1455 format->zeroDigit = prop; 1456 } 1457 1458 prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL); 1459 if (prop != NULL) { 1460 if (format->digit != NULL) xmlFree(format->digit); 1461 format->digit = prop; 1462 } 1463 1464 prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL); 1465 if (prop != NULL) { 1466 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator); 1467 format->patternSeparator = prop; 1468 } 1469 if (cur->children != NULL) { 1470 xsltParseContentError(style, cur->children); 1471 } 1472} 1473 1474/** 1475 * xsltParseStylesheetPreserveSpace: 1476 * @style: the XSLT stylesheet 1477 * @cur: the "preserve-space" element 1478 * 1479 * parse an XSLT stylesheet preserve-space element and record 1480 * elements needing preserving 1481 */ 1482 1483static void 1484xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { 1485 xmlChar *elements; 1486 xmlChar *element, *end; 1487 1488 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1489 return; 1490 1491 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); 1492 if (elements == NULL) { 1493 xsltTransformError(NULL, style, cur, 1494 "xsltParseStylesheetPreserveSpace: missing elements attribute\n"); 1495 if (style != NULL) style->warnings++; 1496 return; 1497 } 1498 1499 if (style->stripSpaces == NULL) 1500 style->stripSpaces = xmlHashCreate(10); 1501 if (style->stripSpaces == NULL) 1502 return; 1503 1504 element = elements; 1505 while (*element != 0) { 1506 while (IS_BLANK(*element)) element++; 1507 if (*element == 0) 1508 break; 1509 end = element; 1510 while ((*end != 0) && (!IS_BLANK(*end))) end++; 1511 element = xmlStrndup(element, end - element); 1512 if (element) { 1513#ifdef WITH_XSLT_DEBUG_PARSING 1514 xsltGenericDebug(xsltGenericDebugContext, 1515 "add preserved space element %s\n", element); 1516#endif 1517 if (xmlStrEqual(element, (const xmlChar *)"*")) { 1518 style->stripAll = -1; 1519 } else { 1520 const xmlChar *URI; 1521 1522 /* 1523 * TODO: Don't use xsltGetQNameURI(). 1524 */ 1525 URI = xsltGetQNameURI(cur, &element); 1526 1527 xmlHashAddEntry2(style->stripSpaces, element, URI, 1528 (xmlChar *) "preserve"); 1529 } 1530 xmlFree(element); 1531 } 1532 element = end; 1533 } 1534 xmlFree(elements); 1535 if (cur->children != NULL) { 1536 xsltParseContentError(style, cur->children); 1537 } 1538} 1539 1540#ifdef XSLT_REFACTORED 1541#else 1542/** 1543 * xsltParseStylesheetExtPrefix: 1544 * @style: the XSLT stylesheet 1545 * @template: the "extension-element-prefixes" prefix 1546 * 1547 * parse an XSLT stylesheet's "extension-element-prefix" attribute value 1548 * and register the namespaces of extension instruction. 1549 * SPEC "A namespace is designated as an extension namespace by using 1550 * an extension-element-prefixes attribute on: 1551 * 1) an xsl:stylesheet element 1552 * 2) an xsl:extension-element-prefixes attribute on a 1553 * literal result element 1554 * 3) an extension instruction." 1555 */ 1556static void 1557xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur, 1558 int isXsltElem) { 1559 xmlChar *prefixes; 1560 xmlChar *prefix, *end; 1561 1562 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1563 return; 1564 1565 if (isXsltElem) { 1566 /* For xsl:stylesheet/xsl:transform. */ 1567 prefixes = xmlGetNsProp(cur, 1568 (const xmlChar *)"extension-element-prefixes", NULL); 1569 } else { 1570 /* For literal result elements and extension instructions. */ 1571 prefixes = xmlGetNsProp(cur, 1572 (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE); 1573 } 1574 if (prefixes == NULL) { 1575 return; 1576 } 1577 1578 prefix = prefixes; 1579 while (*prefix != 0) { 1580 while (IS_BLANK(*prefix)) prefix++; 1581 if (*prefix == 0) 1582 break; 1583 end = prefix; 1584 while ((*end != 0) && (!IS_BLANK(*end))) end++; 1585 prefix = xmlStrndup(prefix, end - prefix); 1586 if (prefix) { 1587 xmlNsPtr ns; 1588 1589 if (xmlStrEqual(prefix, (const xmlChar *)"#default")) 1590 ns = xmlSearchNs(style->doc, cur, NULL); 1591 else 1592 ns = xmlSearchNs(style->doc, cur, prefix); 1593 if (ns == NULL) { 1594 xsltTransformError(NULL, style, cur, 1595 "xsl:extension-element-prefix : undefined namespace %s\n", 1596 prefix); 1597 if (style != NULL) style->warnings++; 1598 } else { 1599#ifdef WITH_XSLT_DEBUG_PARSING 1600 xsltGenericDebug(xsltGenericDebugContext, 1601 "add extension prefix %s\n", prefix); 1602#endif 1603 xsltRegisterExtPrefix(style, prefix, ns->href); 1604 } 1605 xmlFree(prefix); 1606 } 1607 prefix = end; 1608 } 1609 xmlFree(prefixes); 1610} 1611#endif /* else of XSLT_REFACTORED */ 1612 1613/** 1614 * xsltParseStylesheetStripSpace: 1615 * @style: the XSLT stylesheet 1616 * @cur: the "strip-space" element 1617 * 1618 * parse an XSLT stylesheet's strip-space element and record 1619 * the elements needing stripping 1620 */ 1621 1622static void 1623xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { 1624 xmlChar *elements; 1625 xmlChar *element, *end; 1626 1627 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1628 return; 1629 1630 elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); 1631 if (elements == NULL) { 1632 xsltTransformError(NULL, style, cur, 1633 "xsltParseStylesheetStripSpace: missing elements attribute\n"); 1634 if (style != NULL) style->warnings++; 1635 return; 1636 } 1637 1638 if (style->stripSpaces == NULL) 1639 style->stripSpaces = xmlHashCreate(10); 1640 if (style->stripSpaces == NULL) 1641 return; 1642 1643 element = elements; 1644 while (*element != 0) { 1645 while (IS_BLANK(*element)) element++; 1646 if (*element == 0) 1647 break; 1648 end = element; 1649 while ((*end != 0) && (!IS_BLANK(*end))) end++; 1650 element = xmlStrndup(element, end - element); 1651 if (element) { 1652#ifdef WITH_XSLT_DEBUG_PARSING 1653 xsltGenericDebug(xsltGenericDebugContext, 1654 "add stripped space element %s\n", element); 1655#endif 1656 if (xmlStrEqual(element, (const xmlChar *)"*")) { 1657 style->stripAll = 1; 1658 } else { 1659 const xmlChar *URI; 1660 1661 /* 1662 * TODO: Don't use xsltGetQNameURI(). 1663 */ 1664 URI = xsltGetQNameURI(cur, &element); 1665 1666 xmlHashAddEntry2(style->stripSpaces, element, URI, 1667 (xmlChar *) "strip"); 1668 } 1669 xmlFree(element); 1670 } 1671 element = end; 1672 } 1673 xmlFree(elements); 1674 if (cur->children != NULL) { 1675 xsltParseContentError(style, cur->children); 1676 } 1677} 1678 1679#ifdef XSLT_REFACTORED 1680#else 1681/** 1682 * xsltParseStylesheetExcludePrefix: 1683 * @style: the XSLT stylesheet 1684 * @cur: the current point in the stylesheet 1685 * 1686 * parse an XSLT stylesheet exclude prefix and record 1687 * namespaces needing stripping 1688 * 1689 * Returns the number of Excluded prefixes added at that level 1690 */ 1691 1692static int 1693xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur, 1694 int isXsltElem) 1695{ 1696 int nb = 0; 1697 xmlChar *prefixes; 1698 xmlChar *prefix, *end; 1699 1700 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) 1701 return(0); 1702 1703 if (isXsltElem) 1704 prefixes = xmlGetNsProp(cur, 1705 (const xmlChar *)"exclude-result-prefixes", NULL); 1706 else 1707 prefixes = xmlGetNsProp(cur, 1708 (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE); 1709 1710 if (prefixes == NULL) { 1711 return(0); 1712 } 1713 1714 prefix = prefixes; 1715 while (*prefix != 0) { 1716 while (IS_BLANK(*prefix)) prefix++; 1717 if (*prefix == 0) 1718 break; 1719 end = prefix; 1720 while ((*end != 0) && (!IS_BLANK(*end))) end++; 1721 prefix = xmlStrndup(prefix, end - prefix); 1722 if (prefix) { 1723 xmlNsPtr ns; 1724 1725 if (xmlStrEqual(prefix, (const xmlChar *)"#default")) 1726 ns = xmlSearchNs(style->doc, cur, NULL); 1727 else 1728 ns = xmlSearchNs(style->doc, cur, prefix); 1729 if (ns == NULL) { 1730 xsltTransformError(NULL, style, cur, 1731 "xsl:exclude-result-prefixes : undefined namespace %s\n", 1732 prefix); 1733 if (style != NULL) style->warnings++; 1734 } else { 1735 if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) { 1736#ifdef WITH_XSLT_DEBUG_PARSING 1737 xsltGenericDebug(xsltGenericDebugContext, 1738 "exclude result prefix %s\n", prefix); 1739#endif 1740 nb++; 1741 } 1742 } 1743 xmlFree(prefix); 1744 } 1745 prefix = end; 1746 } 1747 xmlFree(prefixes); 1748 return(nb); 1749} 1750#endif /* else of XSLT_REFACTORED */ 1751 1752#ifdef XSLT_REFACTORED 1753 1754/* 1755* xsltTreeEnsureXMLDecl: 1756* @doc: the doc 1757* 1758* BIG NOTE: 1759* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c". 1760* Ensures that there is an XML namespace declaration on the doc. 1761* 1762* Returns the XML ns-struct or NULL on API and internal errors. 1763*/ 1764static xmlNsPtr 1765xsltTreeEnsureXMLDecl(xmlDocPtr doc) 1766{ 1767 if (doc == NULL) 1768 return (NULL); 1769 if (doc->oldNs != NULL) 1770 return (doc->oldNs); 1771 { 1772 xmlNsPtr ns; 1773 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 1774 if (ns == NULL) { 1775 xmlGenericError(xmlGenericErrorContext, 1776 "xsltTreeEnsureXMLDecl: Failed to allocate " 1777 "the XML namespace.\n"); 1778 return (NULL); 1779 } 1780 memset(ns, 0, sizeof(xmlNs)); 1781 ns->type = XML_LOCAL_NAMESPACE; 1782 /* 1783 * URGENT TODO: revisit this. 1784 */ 1785#ifdef LIBXML_NAMESPACE_DICT 1786 if (doc->dict) 1787 ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1); 1788 else 1789 ns->href = xmlStrdup(XML_XML_NAMESPACE); 1790#else 1791 ns->href = xmlStrdup(XML_XML_NAMESPACE); 1792#endif 1793 ns->prefix = xmlStrdup((const xmlChar *)"xml"); 1794 doc->oldNs = ns; 1795 return (ns); 1796 } 1797} 1798 1799/* 1800* xsltTreeAcquireStoredNs: 1801* @doc: the doc 1802* @nsName: the namespace name 1803* @prefix: the prefix 1804* 1805* BIG NOTE: 1806* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c". 1807* Creates or reuses an xmlNs struct on doc->oldNs with 1808* the given prefix and namespace name. 1809* 1810* Returns the aquired ns struct or NULL in case of an API 1811* or internal error. 1812*/ 1813static xmlNsPtr 1814xsltTreeAcquireStoredNs(xmlDocPtr doc, 1815 const xmlChar *nsName, 1816 const xmlChar *prefix) 1817{ 1818 xmlNsPtr ns; 1819 1820 if (doc == NULL) 1821 return (NULL); 1822 if (doc->oldNs != NULL) 1823 ns = doc->oldNs; 1824 else 1825 ns = xsltTreeEnsureXMLDecl(doc); 1826 if (ns == NULL) 1827 return (NULL); 1828 if (ns->next != NULL) { 1829 /* Reuse. */ 1830 ns = ns->next; 1831 while (ns != NULL) { 1832 if ((ns->prefix == NULL) != (prefix == NULL)) { 1833 /* NOP */ 1834 } else if (prefix == NULL) { 1835 if (xmlStrEqual(ns->href, nsName)) 1836 return (ns); 1837 } else { 1838 if ((ns->prefix[0] == prefix[0]) && 1839 xmlStrEqual(ns->prefix, prefix) && 1840 xmlStrEqual(ns->href, nsName)) 1841 return (ns); 1842 1843 } 1844 if (ns->next == NULL) 1845 break; 1846 ns = ns->next; 1847 } 1848 } 1849 /* Create. */ 1850 ns->next = xmlNewNs(NULL, nsName, prefix); 1851 return (ns->next); 1852} 1853 1854/** 1855 * xsltLREBuildEffectiveNs: 1856 * 1857 * Apply ns-aliasing on the namespace of the given @elem and 1858 * its attributes. 1859 */ 1860static int 1861xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt, 1862 xmlNodePtr elem) 1863{ 1864 xmlNsPtr ns; 1865 xsltNsAliasPtr alias; 1866 1867 if ((cctxt == NULL) || (elem == NULL)) 1868 return(-1); 1869 if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases)) 1870 return(0); 1871 1872 alias = cctxt->nsAliases; 1873 while (alias != NULL) { 1874 if ( /* If both namespaces are NULL... */ 1875 ( (elem->ns == NULL) && 1876 ((alias->literalNs == NULL) || 1877 (alias->literalNs->href == NULL)) ) || 1878 /* ... or both namespace are equal */ 1879 ( (elem->ns != NULL) && 1880 (alias->literalNs != NULL) && 1881 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) 1882 { 1883 if ((alias->targetNs != NULL) && 1884 (alias->targetNs->href != NULL)) 1885 { 1886 /* 1887 * Convert namespace. 1888 */ 1889 if (elem->doc == alias->docOfTargetNs) { 1890 /* 1891 * This is the nice case: same docs. 1892 * This will eventually assign a ns-decl which 1893 * is shadowed, but this has no negative effect on 1894 * the generation of the result tree. 1895 */ 1896 elem->ns = alias->targetNs; 1897 } else { 1898 /* 1899 * This target xmlNs originates from a different 1900 * stylesheet tree. Try to locate it in the 1901 * in-scope namespaces. 1902 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs. 1903 */ 1904 ns = xmlSearchNs(elem->doc, elem, 1905 alias->targetNs->prefix); 1906 /* 1907 * If no matching ns-decl found, then assign a 1908 * ns-decl stored in xmlDoc. 1909 */ 1910 if ((ns == NULL) || 1911 (! xmlStrEqual(ns->href, alias->targetNs->href))) 1912 { 1913 /* 1914 * BIG NOTE: The use of xsltTreeAcquireStoredNs() 1915 * is not very efficient, but currently I don't 1916 * see an other way of *safely* changing a node's 1917 * namespace, since the xmlNs struct in 1918 * alias->targetNs might come from an other 1919 * stylesheet tree. So we need to anchor it in the 1920 * current document, without adding it to the tree, 1921 * which would otherwise change the in-scope-ns 1922 * semantic of the tree. 1923 */ 1924 ns = xsltTreeAcquireStoredNs(elem->doc, 1925 alias->targetNs->href, 1926 alias->targetNs->prefix); 1927 1928 if (ns == NULL) { 1929 xsltTransformError(NULL, cctxt->style, elem, 1930 "Internal error in " 1931 "xsltLREBuildEffectiveNs(): " 1932 "failed to acquire a stored " 1933 "ns-declaration.\n"); 1934 cctxt->style->errors++; 1935 return(-1); 1936 1937 } 1938 } 1939 elem->ns = ns; 1940 } 1941 } else { 1942 /* 1943 * Move into or leave in the NULL namespace. 1944 */ 1945 elem->ns = NULL; 1946 } 1947 break; 1948 } 1949 alias = alias->next; 1950 } 1951 /* 1952 * Same with attributes of literal result elements. 1953 */ 1954 if (elem->properties != NULL) { 1955 xmlAttrPtr attr = elem->properties; 1956 1957 while (attr != NULL) { 1958 if (attr->ns == NULL) { 1959 attr = attr->next; 1960 continue; 1961 } 1962 alias = cctxt->nsAliases; 1963 while (alias != NULL) { 1964 if ( /* If both namespaces are NULL... */ 1965 ( (elem->ns == NULL) && 1966 ((alias->literalNs == NULL) || 1967 (alias->literalNs->href == NULL)) ) || 1968 /* ... or both namespace are equal */ 1969 ( (elem->ns != NULL) && 1970 (alias->literalNs != NULL) && 1971 xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) 1972 { 1973 if ((alias->targetNs != NULL) && 1974 (alias->targetNs->href != NULL)) 1975 { 1976 if (elem->doc == alias->docOfTargetNs) { 1977 elem->ns = alias->targetNs; 1978 } else { 1979 ns = xmlSearchNs(elem->doc, elem, 1980 alias->targetNs->prefix); 1981 if ((ns == NULL) || 1982 (! xmlStrEqual(ns->href, alias->targetNs->href))) 1983 { 1984 ns = xsltTreeAcquireStoredNs(elem->doc, 1985 alias->targetNs->href, 1986 alias->targetNs->prefix); 1987 1988 if (ns == NULL) { 1989 xsltTransformError(NULL, cctxt->style, elem, 1990 "Internal error in " 1991 "xsltLREBuildEffectiveNs(): " 1992 "failed to acquire a stored " 1993 "ns-declaration.\n"); 1994 cctxt->style->errors++; 1995 return(-1); 1996 1997 } 1998 } 1999 elem->ns = ns; 2000 } 2001 } else { 2002 /* 2003 * Move into or leave in the NULL namespace. 2004 */ 2005 elem->ns = NULL; 2006 } 2007 break; 2008 } 2009 alias = alias->next; 2010 } 2011 2012 attr = attr->next; 2013 } 2014 } 2015 return(0); 2016} 2017 2018/** 2019 * xsltLREBuildEffectiveNsNodes: 2020 * 2021 * Computes the effective namespaces nodes for a literal result 2022 * element. 2023 * @effectiveNs is the set of effective ns-nodes 2024 * on the literal result element, which will be added to the result 2025 * element if not already existing in the result tree. 2026 * This means that excluded namespaces (via exclude-result-prefixes, 2027 * extension-element-prefixes and the XSLT namespace) not added 2028 * to the set. 2029 * Namespace-aliasing was applied on the @effectiveNs. 2030 */ 2031static int 2032xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt, 2033 xsltStyleItemLRElementInfoPtr item, 2034 xmlNodePtr elem, 2035 int isLRE) 2036{ 2037 xmlNsPtr ns, tmpns; 2038 xsltEffectiveNsPtr effNs, lastEffNs = NULL; 2039 int i, j, holdByElem; 2040 xsltPointerListPtr extElemNs = cctxt->inode->extElemNs; 2041 xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs; 2042 2043 if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) || 2044 (item == NULL) || (item->effectiveNs != NULL)) 2045 return(-1); 2046 2047 if (item->inScopeNs == NULL) 2048 return(0); 2049 2050 extElemNs = cctxt->inode->extElemNs; 2051 exclResultNs = cctxt->inode->exclResultNs; 2052 2053 for (i = 0; i < item->inScopeNs->totalNumber; i++) { 2054 ns = item->inScopeNs->list[i]; 2055 /* 2056 * Skip namespaces designated as excluded namespaces 2057 * ------------------------------------------------- 2058 * 2059 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces 2060 * which are target namespaces of namespace-aliases 2061 * regardless if designated as excluded. 2062 * 2063 * Exclude the XSLT namespace. 2064 */ 2065 if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) 2066 goto skip_ns; 2067 2068 /* 2069 * Apply namespace aliasing 2070 * ------------------------ 2071 * 2072 * SPEC XSLT 2.0 2073 * "- A namespace node whose string value is a literal namespace 2074 * URI is not copied to the result tree. 2075 * - A namespace node whose string value is a target namespace URI 2076 * is copied to the result tree, whether or not the URI 2077 * identifies an excluded namespace." 2078 * 2079 * NOTE: The ns-aliasing machanism is non-cascading. 2080 * (checked with Saxon, Xalan and MSXML .NET). 2081 * URGENT TODO: is style->nsAliases the effective list of 2082 * ns-aliases, or do we need to lookup the whole 2083 * import-tree? 2084 * TODO: Get rid of import-tree lookup. 2085 */ 2086 if (cctxt->hasNsAliases) { 2087 xsltNsAliasPtr alias; 2088 /* 2089 * First check for being a target namespace. 2090 */ 2091 alias = cctxt->nsAliases; 2092 do { 2093 /* 2094 * TODO: Is xmlns="" handled already? 2095 */ 2096 if ((alias->targetNs != NULL) && 2097 (xmlStrEqual(alias->targetNs->href, ns->href))) 2098 { 2099 /* 2100 * Recognized as a target namespace; use it regardless 2101 * if excluded otherwise. 2102 */ 2103 goto add_effective_ns; 2104 } 2105 alias = alias->next; 2106 } while (alias != NULL); 2107 2108 alias = cctxt->nsAliases; 2109 do { 2110 /* 2111 * TODO: Is xmlns="" handled already? 2112 */ 2113 if ((alias->literalNs != NULL) && 2114 (xmlStrEqual(alias->literalNs->href, ns->href))) 2115 { 2116 /* 2117 * Recognized as an namespace alias; do not use it. 2118 */ 2119 goto skip_ns; 2120 } 2121 alias = alias->next; 2122 } while (alias != NULL); 2123 } 2124 2125 /* 2126 * Exclude excluded result namespaces. 2127 */ 2128 if (exclResultNs) { 2129 for (j = 0; j < exclResultNs->number; j++) 2130 if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j])) 2131 goto skip_ns; 2132 } 2133 /* 2134 * Exclude extension-element namespaces. 2135 */ 2136 if (extElemNs) { 2137 for (j = 0; j < extElemNs->number; j++) 2138 if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j])) 2139 goto skip_ns; 2140 } 2141 2142add_effective_ns: 2143 /* 2144 * OPTIMIZE TODO: This information may not be needed. 2145 */ 2146 if (isLRE && (elem->nsDef != NULL)) { 2147 holdByElem = 0; 2148 tmpns = elem->nsDef; 2149 do { 2150 if (tmpns == ns) { 2151 holdByElem = 1; 2152 break; 2153 } 2154 tmpns = tmpns->next; 2155 } while (tmpns != NULL); 2156 } else 2157 holdByElem = 0; 2158 2159 2160 /* 2161 * Add the effective namespace declaration. 2162 */ 2163 effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs)); 2164 if (effNs == NULL) { 2165 xsltTransformError(NULL, cctxt->style, elem, 2166 "Internal error in xsltLREBuildEffectiveNs(): " 2167 "failed to allocate memory.\n"); 2168 cctxt->style->errors++; 2169 return(-1); 2170 } 2171 if (cctxt->psData->effectiveNs == NULL) { 2172 cctxt->psData->effectiveNs = effNs; 2173 effNs->nextInStore = NULL; 2174 } else { 2175 effNs->nextInStore = cctxt->psData->effectiveNs; 2176 cctxt->psData->effectiveNs = effNs; 2177 } 2178 2179 effNs->next = NULL; 2180 effNs->prefix = ns->prefix; 2181 effNs->nsName = ns->href; 2182 effNs->holdByElem = holdByElem; 2183 2184 if (lastEffNs == NULL) 2185 item->effectiveNs = effNs; 2186 else 2187 lastEffNs->next = effNs; 2188 lastEffNs = effNs; 2189 2190skip_ns: 2191 {} 2192 } 2193 return(0); 2194} 2195 2196 2197/** 2198 * xsltLREInfoCreate: 2199 * 2200 * @isLRE: indicates if the given @elem is a literal result element 2201 * 2202 * Creates a new info for a literal result element. 2203 */ 2204static int 2205xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt, 2206 xmlNodePtr elem, 2207 int isLRE) 2208{ 2209 xsltStyleItemLRElementInfoPtr item; 2210 2211 if ((cctxt == NULL) || (cctxt->inode == NULL)) 2212 return(-1); 2213 2214 item = (xsltStyleItemLRElementInfoPtr) 2215 xmlMalloc(sizeof(xsltStyleItemLRElementInfo)); 2216 if (item == NULL) { 2217 xsltTransformError(NULL, cctxt->style, NULL, 2218 "Internal error in xsltLREInfoCreate(): " 2219 "memory allocation failed.\n"); 2220 cctxt->style->errors++; 2221 return(-1); 2222 } 2223 memset(item, 0, sizeof(xsltStyleItemLRElementInfo)); 2224 item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT; 2225 /* 2226 * Store it in the stylesheet. 2227 */ 2228 item->next = cctxt->style->preComps; 2229 cctxt->style->preComps = (xsltElemPreCompPtr) item; 2230 /* 2231 * @inScopeNs are used for execution of XPath expressions 2232 * in AVTs. 2233 */ 2234 item->inScopeNs = cctxt->inode->inScopeNs; 2235 2236 if (elem) 2237 xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE); 2238 2239 cctxt->inode->litResElemInfo = item; 2240 cctxt->inode->nsChanged = 0; 2241 cctxt->maxLREs++; 2242 return(0); 2243} 2244 2245/** 2246 * xsltCompilerVarInfoPush: 2247 * @cctxt: the compilation context 2248 * 2249 * Pushes a new var/param info onto the stack. 2250 * 2251 * Returns the acquired variable info. 2252 */ 2253static xsltVarInfoPtr 2254xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt, 2255 xmlNodePtr inst, 2256 const xmlChar *name, 2257 const xmlChar *nsName) 2258{ 2259 xsltVarInfoPtr ivar; 2260 2261 if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) { 2262 ivar = cctxt->ivar->next; 2263 } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) { 2264 ivar = cctxt->ivars; 2265 } else { 2266 ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo)); 2267 if (ivar == NULL) { 2268 xsltTransformError(NULL, cctxt->style, inst, 2269 "xsltParseInScopeVarPush: xmlMalloc() failed!\n"); 2270 cctxt->style->errors++; 2271 return(NULL); 2272 } 2273 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */ 2274 if (cctxt->ivars == NULL) { 2275 cctxt->ivars = ivar; 2276 ivar->prev = NULL; 2277 } else { 2278 cctxt->ivar->next = ivar; 2279 ivar->prev = cctxt->ivar; 2280 } 2281 cctxt->ivar = ivar; 2282 ivar->next = NULL; 2283 } 2284 ivar->depth = cctxt->depth; 2285 ivar->name = name; 2286 ivar->nsName = nsName; 2287 return(ivar); 2288} 2289 2290/** 2291 * xsltCompilerVarInfoPop: 2292 * @cctxt: the compilation context 2293 * 2294 * Pops all var/param infos from the stack, which 2295 * have the current depth. 2296 */ 2297static void 2298xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt) 2299{ 2300 2301 while ((cctxt->ivar != NULL) && 2302 (cctxt->ivar->depth > cctxt->depth)) 2303 { 2304 cctxt->ivar = cctxt->ivar->prev; 2305 } 2306} 2307 2308/* 2309* xsltCompilerNodePush: 2310* 2311* @cctxt: the compilation context 2312* @node: the node to be pushed (this can also be the doc-node) 2313* 2314* 2315* 2316* Returns the current node info structure or 2317* NULL in case of an internal error. 2318*/ 2319static xsltCompilerNodeInfoPtr 2320xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 2321{ 2322 xsltCompilerNodeInfoPtr inode, iprev; 2323 2324 if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) { 2325 inode = cctxt->inode->next; 2326 } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) { 2327 inode = cctxt->inodeList; 2328 } else { 2329 /* 2330 * Create a new node-info. 2331 */ 2332 inode = (xsltCompilerNodeInfoPtr) 2333 xmlMalloc(sizeof(xsltCompilerNodeInfo)); 2334 if (inode == NULL) { 2335 xsltTransformError(NULL, cctxt->style, NULL, 2336 "xsltCompilerNodePush: malloc failed.\n"); 2337 return(NULL); 2338 } 2339 memset(inode, 0, sizeof(xsltCompilerNodeInfo)); 2340 if (cctxt->inodeList == NULL) 2341 cctxt->inodeList = inode; 2342 else { 2343 cctxt->inodeLast->next = inode; 2344 inode->prev = cctxt->inodeLast; 2345 } 2346 cctxt->inodeLast = inode; 2347 cctxt->maxNodeInfos++; 2348 if (cctxt->inode == NULL) { 2349 cctxt->inode = inode; 2350 /* 2351 * Create an initial literal result element info for 2352 * the root of the stylesheet. 2353 */ 2354 xsltLREInfoCreate(cctxt, NULL, 0); 2355 } 2356 } 2357 cctxt->depth++; 2358 cctxt->inode = inode; 2359 /* 2360 * REVISIT TODO: Keep the reset always complete. 2361 * NOTE: Be carefull with the @node, since it might be 2362 * a doc-node. 2363 */ 2364 inode->node = node; 2365 inode->depth = cctxt->depth; 2366 inode->templ = NULL; 2367 inode->category = XSLT_ELEMENT_CATEGORY_XSLT; 2368 inode->type = 0; 2369 inode->item = NULL; 2370 inode->curChildType = 0; 2371 inode->extContentHandled = 0; 2372 inode->isRoot = 0; 2373 2374 if (inode->prev != NULL) { 2375 iprev = inode->prev; 2376 /* 2377 * Inherit the following information: 2378 * --------------------------------- 2379 * 2380 * In-scope namespaces 2381 */ 2382 inode->inScopeNs = iprev->inScopeNs; 2383 /* 2384 * Info for literal result elements 2385 */ 2386 inode->litResElemInfo = iprev->litResElemInfo; 2387 inode->nsChanged = iprev->nsChanged; 2388 /* 2389 * Excluded result namespaces 2390 */ 2391 inode->exclResultNs = iprev->exclResultNs; 2392 /* 2393 * Extension instruction namespaces 2394 */ 2395 inode->extElemNs = iprev->extElemNs; 2396 /* 2397 * Whitespace preservation 2398 */ 2399 inode->preserveWhitespace = iprev->preserveWhitespace; 2400 /* 2401 * Forwards-compatible mode 2402 */ 2403 inode->forwardsCompat = iprev->forwardsCompat; 2404 } else { 2405 inode->inScopeNs = NULL; 2406 inode->exclResultNs = NULL; 2407 inode->extElemNs = NULL; 2408 inode->preserveWhitespace = 0; 2409 inode->forwardsCompat = 0; 2410 } 2411 2412 return(inode); 2413} 2414 2415/* 2416* xsltCompilerNodePop: 2417* 2418* @cctxt: the compilation context 2419* @node: the node to be pushed (this can also be the doc-node) 2420* 2421* Pops the current node info. 2422*/ 2423static void 2424xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 2425{ 2426 if (cctxt->inode == NULL) { 2427 xmlGenericError(xmlGenericErrorContext, 2428 "xsltCompilerNodePop: Top-node mismatch.\n"); 2429 return; 2430 } 2431 /* 2432 * NOTE: Be carefull with the @node, since it might be 2433 * a doc-node. 2434 */ 2435 if (cctxt->inode->node != node) { 2436 xmlGenericError(xmlGenericErrorContext, 2437 "xsltCompilerNodePop: Node mismatch.\n"); 2438 goto mismatch; 2439 } 2440 if (cctxt->inode->depth != cctxt->depth) { 2441 xmlGenericError(xmlGenericErrorContext, 2442 "xsltCompilerNodePop: Depth mismatch.\n"); 2443 goto mismatch; 2444 } 2445 cctxt->depth--; 2446 /* 2447 * Pop information of variables. 2448 */ 2449 if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth)) 2450 xsltCompilerVarInfoPop(cctxt); 2451 2452 cctxt->inode = cctxt->inode->prev; 2453 if (cctxt->inode != NULL) 2454 cctxt->inode->curChildType = 0; 2455 return; 2456 2457mismatch: 2458 { 2459 const xmlChar *nsName = NULL, *name = NULL; 2460 const xmlChar *infnsName = NULL, *infname = NULL; 2461 2462 if (node) { 2463 if (node->type == XML_ELEMENT_NODE) { 2464 name = node->name; 2465 if (node->ns != NULL) 2466 nsName = node->ns->href; 2467 else 2468 nsName = BAD_CAST ""; 2469 } else { 2470 name = BAD_CAST "#document"; 2471 nsName = BAD_CAST ""; 2472 } 2473 } else 2474 name = BAD_CAST "Not given"; 2475 2476 if (cctxt->inode->node) { 2477 if (node->type == XML_ELEMENT_NODE) { 2478 infname = cctxt->inode->node->name; 2479 if (cctxt->inode->node->ns != NULL) 2480 infnsName = cctxt->inode->node->ns->href; 2481 else 2482 infnsName = BAD_CAST ""; 2483 } else { 2484 infname = BAD_CAST "#document"; 2485 infnsName = BAD_CAST ""; 2486 } 2487 } else 2488 infname = BAD_CAST "Not given"; 2489 2490 2491 xmlGenericError(xmlGenericErrorContext, 2492 "xsltCompilerNodePop: Given : '%s' URI '%s'\n", 2493 name, nsName); 2494 xmlGenericError(xmlGenericErrorContext, 2495 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n", 2496 infname, infnsName); 2497 } 2498} 2499 2500/* 2501* xsltCompilerBuildInScopeNsList: 2502* 2503* Create and store the list of in-scope namespaces for the given 2504* node in the stylesheet. If there are no changes in the in-scope 2505* namespaces then the last ns-info of the ancestor axis will be returned. 2506* Compilation-time only. 2507* 2508* Returns the ns-info or NULL if there are no namespaces in scope. 2509*/ 2510static xsltNsListContainerPtr 2511xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 2512{ 2513 xsltNsListContainerPtr nsi = NULL; 2514 xmlNsPtr *list = NULL, ns; 2515 int i, maxns = 5; 2516 /* 2517 * Create a new ns-list for this position in the node-tree. 2518 * xmlGetNsList() will return NULL, if there are no ns-decls in the 2519 * tree. Note that the ns-decl for the XML namespace is not added 2520 * to the resulting list; the XPath module handles the XML namespace 2521 * internally. 2522 */ 2523 while (node != NULL) { 2524 if (node->type == XML_ELEMENT_NODE) { 2525 ns = node->nsDef; 2526 while (ns != NULL) { 2527 if (nsi == NULL) { 2528 nsi = (xsltNsListContainerPtr) 2529 xmlMalloc(sizeof(xsltNsListContainer)); 2530 if (nsi == NULL) { 2531 xsltTransformError(NULL, cctxt->style, NULL, 2532 "xsltCompilerBuildInScopeNsList: " 2533 "malloc failed!\n"); 2534 goto internal_err; 2535 } 2536 memset(nsi, 0, sizeof(xsltNsListContainer)); 2537 nsi->list = 2538 (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr)); 2539 if (nsi->list == NULL) { 2540 xsltTransformError(NULL, cctxt->style, NULL, 2541 "xsltCompilerBuildInScopeNsList: " 2542 "malloc failed!\n"); 2543 goto internal_err; 2544 } 2545 nsi->list[0] = NULL; 2546 } 2547 /* 2548 * Skip shadowed namespace bindings. 2549 */ 2550 for (i = 0; i < nsi->totalNumber; i++) { 2551 if ((ns->prefix == nsi->list[i]->prefix) || 2552 (xmlStrEqual(ns->prefix, nsi->list[i]->prefix))) 2553 break; 2554 } 2555 if (i >= nsi->totalNumber) { 2556 if (nsi->totalNumber +1 >= maxns) { 2557 maxns *= 2; 2558 nsi->list = 2559 (xmlNsPtr *) xmlRealloc(nsi->list, 2560 maxns * sizeof(xmlNsPtr)); 2561 if (nsi->list == NULL) { 2562 xsltTransformError(NULL, cctxt->style, NULL, 2563 "xsltCompilerBuildInScopeNsList: " 2564 "realloc failed!\n"); 2565 goto internal_err; 2566 } 2567 } 2568 nsi->list[nsi->totalNumber++] = ns; 2569 nsi->list[nsi->totalNumber] = NULL; 2570 } 2571 2572 ns = ns->next; 2573 } 2574 } 2575 node = node->parent; 2576 } 2577 if (nsi == NULL) 2578 return(NULL); 2579 /* 2580 * Move the default namespace to last position. 2581 */ 2582 nsi->xpathNumber = nsi->totalNumber; 2583 for (i = 0; i < nsi->totalNumber; i++) { 2584 if (nsi->list[i]->prefix == NULL) { 2585 ns = nsi->list[i]; 2586 nsi->list[i] = nsi->list[nsi->totalNumber-1]; 2587 nsi->list[nsi->totalNumber-1] = ns; 2588 nsi->xpathNumber--; 2589 break; 2590 } 2591 } 2592 /* 2593 * Store the ns-list in the stylesheet. 2594 */ 2595 if (xsltPointerListAddSize( 2596 (xsltPointerListPtr)cctxt->psData->inScopeNamespaces, 2597 (void *) nsi, 5) == -1) 2598 { 2599 xmlFree(nsi); 2600 nsi = NULL; 2601 xsltTransformError(NULL, cctxt->style, NULL, 2602 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n"); 2603 goto internal_err; 2604 } 2605 /* 2606 * Notify of change in status wrt namespaces. 2607 */ 2608 if (cctxt->inode != NULL) 2609 cctxt->inode->nsChanged = 1; 2610 2611 return(nsi); 2612 2613internal_err: 2614 if (list != NULL) 2615 xmlFree(list); 2616 cctxt->style->errors++; 2617 return(NULL); 2618} 2619 2620static int 2621xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt, 2622 xsltPointerListPtr list, 2623 xmlNodePtr node, 2624 const xmlChar *value) 2625{ 2626 xmlChar *cur, *end; 2627 xmlNsPtr ns; 2628 2629 if ((cctxt == NULL) || (value == NULL) || (list == NULL)) 2630 return(-1); 2631 2632 list->number = 0; 2633 2634 cur = (xmlChar *) value; 2635 while (*cur != 0) { 2636 while (IS_BLANK(*cur)) cur++; 2637 if (*cur == 0) 2638 break; 2639 end = cur; 2640 while ((*end != 0) && (!IS_BLANK(*end))) end++; 2641 cur = xmlStrndup(cur, end - cur); 2642 if (cur == NULL) { 2643 cur = end; 2644 continue; 2645 } 2646 /* 2647 * TODO: Export and use xmlSearchNsByPrefixStrict() 2648 * in Libxml2, tree.c, since xmlSearchNs() is in most 2649 * cases not efficient and in some cases not correct. 2650 * 2651 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value. 2652 */ 2653 if ((cur[0] == '#') && 2654 xmlStrEqual(cur, (const xmlChar *)"#default")) 2655 ns = xmlSearchNs(cctxt->style->doc, node, NULL); 2656 else 2657 ns = xmlSearchNs(cctxt->style->doc, node, cur); 2658 2659 if (ns == NULL) { 2660 /* 2661 * TODO: Better to report the attr-node, otherwise 2662 * the user won't know which attribute was invalid. 2663 */ 2664 xsltTransformError(NULL, cctxt->style, node, 2665 "No namespace binding in scope for prefix '%s'.\n", cur); 2666 /* 2667 * XSLT-1.0: "It is an error if there is no namespace 2668 * bound to the prefix on the element bearing the 2669 * exclude-result-prefixes or xsl:exclude-result-prefixes 2670 * attribute." 2671 */ 2672 cctxt->style->errors++; 2673 } else { 2674#ifdef WITH_XSLT_DEBUG_PARSING 2675 xsltGenericDebug(xsltGenericDebugContext, 2676 "resolved prefix '%s'\n", cur); 2677#endif 2678 /* 2679 * Note that we put the namespace name into the dict. 2680 */ 2681 if (xsltPointerListAddSize(list, 2682 (void *) xmlDictLookup(cctxt->style->dict, 2683 ns->href, -1), 5) == -1) 2684 { 2685 xmlFree(cur); 2686 goto internal_err; 2687 } 2688 } 2689 xmlFree(cur); 2690 2691 cur = end; 2692 } 2693 return(0); 2694 2695internal_err: 2696 cctxt->style->errors++; 2697 return(-1); 2698} 2699 2700/** 2701 * xsltCompilerUtilsCreateMergedList: 2702 * @dest: the destination list (optional) 2703 * @first: the first list 2704 * @second: the second list (optional) 2705 * 2706 * Appends the content of @second to @first into @destination. 2707 * If @destination is NULL a new list will be created. 2708 * 2709 * Returns the merged list of items or NULL if there's nothing to merge. 2710 */ 2711static xsltPointerListPtr 2712xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first, 2713 xsltPointerListPtr second) 2714{ 2715 xsltPointerListPtr ret; 2716 size_t num; 2717 2718 if (first) 2719 num = first->number; 2720 else 2721 num = 0; 2722 if (second) 2723 num += second->number; 2724 if (num == 0) 2725 return(NULL); 2726 ret = xsltPointerListCreate(num); 2727 if (ret == NULL) 2728 return(NULL); 2729 /* 2730 * Copy contents. 2731 */ 2732 if ((first != NULL) && (first->number != 0)) { 2733 memcpy(ret->items, first->items, 2734 first->number * sizeof(void *)); 2735 if ((second != NULL) && (second->number != 0)) 2736 memcpy(ret->items + first->number, second->items, 2737 second->number * sizeof(void *)); 2738 } else if ((second != NULL) && (second->number != 0)) 2739 memcpy(ret->items, (void *) second->items, 2740 second->number * sizeof(void *)); 2741 ret->number = num; 2742 return(ret); 2743} 2744 2745/* 2746* xsltParseExclResultPrefixes: 2747* 2748* Create and store the list of in-scope namespaces for the given 2749* node in the stylesheet. If there are no changes in the in-scope 2750* namespaces then the last ns-info of the ancestor axis will be returned. 2751* Compilation-time only. 2752* 2753* Returns the ns-info or NULL if there are no namespaces in scope. 2754*/ 2755static xsltPointerListPtr 2756xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, 2757 xsltPointerListPtr def, 2758 int instrCategory) 2759{ 2760 xsltPointerListPtr list = NULL; 2761 xmlChar *value; 2762 xmlAttrPtr attr; 2763 2764 if ((cctxt == NULL) || (node == NULL)) 2765 return(NULL); 2766 2767 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) 2768 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL); 2769 else 2770 attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", 2771 XSLT_NAMESPACE); 2772 if (attr == NULL) 2773 return(def); 2774 2775 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { 2776 /* 2777 * Mark the XSLT attr. 2778 */ 2779 attr->psvi = (void *) xsltXSLTAttrMarker; 2780 } 2781 2782 if ((attr->children != NULL) && 2783 (attr->children->content != NULL)) 2784 value = attr->children->content; 2785 else { 2786 xsltTransformError(NULL, cctxt->style, node, 2787 "Attribute 'exclude-result-prefixes': Invalid value.\n"); 2788 cctxt->style->errors++; 2789 return(def); 2790 } 2791 2792 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, 2793 BAD_CAST value) != 0) 2794 goto exit; 2795 if (cctxt->tmpList->number == 0) 2796 goto exit; 2797 /* 2798 * Merge the list with the inherited list. 2799 */ 2800 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); 2801 if (list == NULL) 2802 goto exit; 2803 /* 2804 * Store the list in the stylesheet/compiler context. 2805 */ 2806 if (xsltPointerListAddSize( 2807 cctxt->psData->exclResultNamespaces, list, 5) == -1) 2808 { 2809 xsltPointerListFree(list); 2810 list = NULL; 2811 goto exit; 2812 } 2813 /* 2814 * Notify of change in status wrt namespaces. 2815 */ 2816 if (cctxt->inode != NULL) 2817 cctxt->inode->nsChanged = 1; 2818 2819exit: 2820 if (list != NULL) 2821 return(list); 2822 else 2823 return(def); 2824} 2825 2826/* 2827* xsltParseExtElemPrefixes: 2828* 2829* Create and store the list of in-scope namespaces for the given 2830* node in the stylesheet. If there are no changes in the in-scope 2831* namespaces then the last ns-info of the ancestor axis will be returned. 2832* Compilation-time only. 2833* 2834* Returns the ns-info or NULL if there are no namespaces in scope. 2835*/ 2836static xsltPointerListPtr 2837xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, 2838 xsltPointerListPtr def, 2839 int instrCategory) 2840{ 2841 xsltPointerListPtr list = NULL; 2842 xmlAttrPtr attr; 2843 xmlChar *value; 2844 int i; 2845 2846 if ((cctxt == NULL) || (node == NULL)) 2847 return(NULL); 2848 2849 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) 2850 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL); 2851 else 2852 attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", 2853 XSLT_NAMESPACE); 2854 if (attr == NULL) 2855 return(def); 2856 2857 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { 2858 /* 2859 * Mark the XSLT attr. 2860 */ 2861 attr->psvi = (void *) xsltXSLTAttrMarker; 2862 } 2863 2864 if ((attr->children != NULL) && 2865 (attr->children->content != NULL)) 2866 value = attr->children->content; 2867 else { 2868 xsltTransformError(NULL, cctxt->style, node, 2869 "Attribute 'extension-element-prefixes': Invalid value.\n"); 2870 cctxt->style->errors++; 2871 return(def); 2872 } 2873 2874 2875 if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, 2876 BAD_CAST value) != 0) 2877 goto exit; 2878 2879 if (cctxt->tmpList->number == 0) 2880 goto exit; 2881 /* 2882 * REVISIT: Register the extension namespaces. 2883 */ 2884 for (i = 0; i < cctxt->tmpList->number; i++) 2885 xsltRegisterExtPrefix(cctxt->style, NULL, 2886 BAD_CAST cctxt->tmpList->items[i]); 2887 /* 2888 * Merge the list with the inherited list. 2889 */ 2890 list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); 2891 if (list == NULL) 2892 goto exit; 2893 /* 2894 * Store the list in the stylesheet. 2895 */ 2896 if (xsltPointerListAddSize( 2897 cctxt->psData->extElemNamespaces, list, 5) == -1) 2898 { 2899 xsltPointerListFree(list); 2900 list = NULL; 2901 goto exit; 2902 } 2903 /* 2904 * Notify of change in status wrt namespaces. 2905 */ 2906 if (cctxt->inode != NULL) 2907 cctxt->inode->nsChanged = 1; 2908 2909exit: 2910 if (list != NULL) 2911 return(list); 2912 else 2913 return(def); 2914} 2915 2916/* 2917* xsltParseAttrXSLTVersion: 2918* 2919* @cctxt: the compilation context 2920* @node: the element-node 2921* @isXsltElem: whether this is an XSLT element 2922* 2923* Parses the attribute xsl:version. 2924* 2925* Returns 1 if there was such an attribute, 0 if not and 2926* -1 if an internal or API error occured. 2927*/ 2928static int 2929xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, 2930 int instrCategory) 2931{ 2932 xmlChar *value; 2933 xmlAttrPtr attr; 2934 2935 if ((cctxt == NULL) || (node == NULL)) 2936 return(-1); 2937 2938 if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) 2939 attr = xmlHasNsProp(node, BAD_CAST "version", NULL); 2940 else 2941 attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE); 2942 2943 if (attr == NULL) 2944 return(0); 2945 2946 attr->psvi = (void *) xsltXSLTAttrMarker; 2947 2948 if ((attr->children != NULL) && 2949 (attr->children->content != NULL)) 2950 value = attr->children->content; 2951 else { 2952 xsltTransformError(NULL, cctxt->style, node, 2953 "Attribute 'version': Invalid value.\n"); 2954 cctxt->style->errors++; 2955 return(1); 2956 } 2957 2958 if (! xmlStrEqual(value, (const xmlChar *)"1.0")) { 2959 cctxt->inode->forwardsCompat = 1; 2960 /* 2961 * TODO: To what extent do we support the 2962 * forwards-compatible mode? 2963 */ 2964 /* 2965 * Report this only once per compilation episode. 2966 */ 2967 if (! cctxt->hasForwardsCompat) { 2968 cctxt->hasForwardsCompat = 1; 2969 cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING; 2970 xsltTransformError(NULL, cctxt->style, node, 2971 "Warning: the attribute xsl:version specifies a value " 2972 "different from '1.0'. Switching to forwards-compatible " 2973 "mode. Only features of XSLT 1.0 are supported by this " 2974 "processor.\n"); 2975 cctxt->style->warnings++; 2976 cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR; 2977 } 2978 } else { 2979 cctxt->inode->forwardsCompat = 0; 2980 } 2981 2982 if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { 2983 /* 2984 * Set a marker on XSLT attributes. 2985 */ 2986 attr->psvi = (void *) xsltXSLTAttrMarker; 2987 } 2988 return(1); 2989} 2990 2991static int 2992xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 2993{ 2994 xmlNodePtr deleteNode, cur, txt, textNode = NULL; 2995 xmlDocPtr doc; 2996 xsltStylesheetPtr style; 2997 int internalize = 0, findSpaceAttr; 2998 int xsltStylesheetElemDepth; 2999 xmlAttrPtr attr; 3000 xmlChar *value; 3001 const xmlChar *name, *nsNameXSLT = NULL; 3002 int strictWhitespace, inXSLText = 0; 3003#ifdef XSLT_REFACTORED_XSLT_NSCOMP 3004 xsltNsMapPtr nsMapItem; 3005#endif 3006 3007 if ((cctxt == NULL) || (cctxt->style == NULL) || 3008 (node == NULL) || (node->type != XML_ELEMENT_NODE)) 3009 return(-1); 3010 3011 doc = node->doc; 3012 if (doc == NULL) 3013 goto internal_err; 3014 3015 style = cctxt->style; 3016 if ((style->dict != NULL) && (doc->dict == style->dict)) 3017 internalize = 1; 3018 else 3019 style->internalized = 0; 3020 3021 /* 3022 * Init value of xml:space. Since this might be an embedded 3023 * stylesheet, this is needed to be performed on the element 3024 * where the stylesheet is rooted at, taking xml:space of 3025 * ancestors into account. 3026 */ 3027 if (! cctxt->simplified) 3028 xsltStylesheetElemDepth = cctxt->depth +1; 3029 else 3030 xsltStylesheetElemDepth = 0; 3031 3032 if (xmlNodeGetSpacePreserve(node) != 1) 3033 cctxt->inode->preserveWhitespace = 0; 3034 else 3035 cctxt->inode->preserveWhitespace = 1; 3036 3037 /* 3038 * Eval if we should keep the old incorrect behaviour. 3039 */ 3040 strictWhitespace = (cctxt->strict != 0) ? 1 : 0; 3041 3042 nsNameXSLT = xsltConstNamespaceNameXSLT; 3043 3044 deleteNode = NULL; 3045 cur = node; 3046 while (cur != NULL) { 3047 if (deleteNode != NULL) { 3048 3049#ifdef WITH_XSLT_DEBUG_BLANKS 3050 xsltGenericDebug(xsltGenericDebugContext, 3051 "xsltParsePreprocessStylesheetTree: removing node\n"); 3052#endif 3053 xmlUnlinkNode(deleteNode); 3054 xmlFreeNode(deleteNode); 3055 deleteNode = NULL; 3056 } 3057 if (cur->type == XML_ELEMENT_NODE) { 3058 3059 /* 3060 * Clear the PSVI field. 3061 */ 3062 cur->psvi = NULL; 3063 3064 xsltCompilerNodePush(cctxt, cur); 3065 3066 inXSLText = 0; 3067 textNode = NULL; 3068 findSpaceAttr = 1; 3069 cctxt->inode->stripWhitespace = 0; 3070 /* 3071 * TODO: I'd love to use a string pointer comparison here :-/ 3072 */ 3073 if (IS_XSLT_ELEM(cur)) { 3074#ifdef XSLT_REFACTORED_XSLT_NSCOMP 3075 if (cur->ns->href != nsNameXSLT) { 3076 nsMapItem = xsltNewNamespaceMapItem(cctxt, 3077 doc, cur->ns, cur); 3078 if (nsMapItem == NULL) 3079 goto internal_err; 3080 cur->ns->href = nsNameXSLT; 3081 } 3082#endif 3083 3084 if (cur->name == NULL) 3085 goto process_attributes; 3086 /* 3087 * Mark the XSLT element for later recognition. 3088 * TODO: Using the marker is still too dangerous, since if 3089 * the parsing mechanism leaves out an XSLT element, then 3090 * this might hit the transformation-mechanism, which 3091 * will break if it doesn't expect such a marker. 3092 */ 3093 /* cur->psvi = (void *) xsltXSLTElemMarker; */ 3094 3095 /* 3096 * XSLT 2.0: "Any whitespace text node whose parent is 3097 * one of the following elements is removed from the " 3098 * tree, regardless of any xml:space attributes:..." 3099 * xsl:apply-imports, 3100 * xsl:apply-templates, 3101 * xsl:attribute-set, 3102 * xsl:call-template, 3103 * xsl:choose, 3104 * xsl:stylesheet, xsl:transform. 3105 * XSLT 2.0: xsl:analyze-string, 3106 * xsl:character-map, 3107 * xsl:next-match 3108 * 3109 * TODO: I'd love to use a string pointer comparison here :-/ 3110 */ 3111 name = cur->name; 3112 switch (*name) { 3113 case 't': 3114 if ((name[0] == 't') && (name[1] == 'e') && 3115 (name[2] == 'x') && (name[3] == 't') && 3116 (name[4] == 0)) 3117 { 3118 /* 3119 * Process the xsl:text element. 3120 * ---------------------------- 3121 * Mark it for later recognition. 3122 */ 3123 cur->psvi = (void *) xsltXSLTTextMarker; 3124 /* 3125 * For stylesheets, the set of 3126 * whitespace-preserving element names 3127 * consists of just xsl:text. 3128 */ 3129 findSpaceAttr = 0; 3130 cctxt->inode->preserveWhitespace = 1; 3131 inXSLText = 1; 3132 } 3133 break; 3134 case 'c': 3135 if (xmlStrEqual(name, BAD_CAST "choose") || 3136 xmlStrEqual(name, BAD_CAST "call-template")) 3137 cctxt->inode->stripWhitespace = 1; 3138 break; 3139 case 'a': 3140 if (xmlStrEqual(name, BAD_CAST "apply-templates") || 3141 xmlStrEqual(name, BAD_CAST "apply-imports") || 3142 xmlStrEqual(name, BAD_CAST "attribute-set")) 3143 3144 cctxt->inode->stripWhitespace = 1; 3145 break; 3146 default: 3147 if (xsltStylesheetElemDepth == cctxt->depth) { 3148 /* 3149 * This is a xsl:stylesheet/xsl:transform. 3150 */ 3151 cctxt->inode->stripWhitespace = 1; 3152 break; 3153 } 3154 3155 if ((cur->prev != NULL) && 3156 (cur->prev->type == XML_TEXT_NODE)) 3157 { 3158 /* 3159 * XSLT 2.0 : "Any whitespace text node whose 3160 * following-sibling node is an xsl:param or 3161 * xsl:sort element is removed from the tree, 3162 * regardless of any xml:space attributes." 3163 */ 3164 if (((*name == 'p') || (*name == 's')) && 3165 (xmlStrEqual(name, BAD_CAST "param") || 3166 xmlStrEqual(name, BAD_CAST "sort"))) 3167 { 3168 do { 3169 if (IS_BLANK_NODE(cur->prev)) { 3170 txt = cur->prev; 3171 xmlUnlinkNode(txt); 3172 xmlFreeNode(txt); 3173 } else { 3174 /* 3175 * This will result in a content 3176 * error, when hitting the parsing 3177 * functions. 3178 */ 3179 break; 3180 } 3181 } while (cur->prev); 3182 } 3183 } 3184 break; 3185 } 3186 } 3187 3188process_attributes: 3189 /* 3190 * Process attributes. 3191 * ------------------ 3192 */ 3193 if (cur->properties != NULL) { 3194 if (cur->children == NULL) 3195 findSpaceAttr = 0; 3196 attr = cur->properties; 3197 do { 3198#ifdef XSLT_REFACTORED_XSLT_NSCOMP 3199 if ((attr->ns) && (attr->ns->href != nsNameXSLT) && 3200 xmlStrEqual(attr->ns->href, nsNameXSLT)) 3201 { 3202 nsMapItem = xsltNewNamespaceMapItem(cctxt, 3203 doc, attr->ns, cur); 3204 if (nsMapItem == NULL) 3205 goto internal_err; 3206 attr->ns->href = nsNameXSLT; 3207 } 3208#endif 3209 if (internalize) { 3210 /* 3211 * Internalize the attribute's value; the goal is to 3212 * speed up operations and minimize used space by 3213 * compiled stylesheets. 3214 */ 3215 txt = attr->children; 3216 /* 3217 * NOTE that this assumes only one 3218 * text-node in the attribute's content. 3219 */ 3220 if ((txt != NULL) && (txt->content != NULL) && 3221 (!xmlDictOwns(style->dict, txt->content))) 3222 { 3223 value = (xmlChar *) xmlDictLookup(style->dict, 3224 txt->content, -1); 3225 xmlNodeSetContent(txt, NULL); 3226 txt->content = value; 3227 } 3228 } 3229 /* 3230 * Process xml:space attributes. 3231 * ---------------------------- 3232 */ 3233 if ((findSpaceAttr != 0) && 3234 (attr->ns != NULL) && 3235 (attr->name != NULL) && 3236 (attr->name[0] == 's') && 3237 (attr->ns->prefix != NULL) && 3238 (attr->ns->prefix[0] == 'x') && 3239 (attr->ns->prefix[1] == 'm') && 3240 (attr->ns->prefix[2] == 'l') && 3241 (attr->ns->prefix[3] == 0)) 3242 { 3243 value = xmlGetNsProp(cur, BAD_CAST "space", 3244 XML_XML_NAMESPACE); 3245 if (value != NULL) { 3246 if (xmlStrEqual(value, BAD_CAST "preserve")) { 3247 cctxt->inode->preserveWhitespace = 1; 3248 } else if (xmlStrEqual(value, BAD_CAST "default")) { 3249 cctxt->inode->preserveWhitespace = 0; 3250 } else { 3251 /* Invalid value for xml:space. */ 3252 xsltTransformError(NULL, style, cur, 3253 "Attribute xml:space: Invalid value.\n"); 3254 cctxt->style->warnings++; 3255 } 3256 findSpaceAttr = 0; 3257 xmlFree(value); 3258 } 3259 3260 } 3261 attr = attr->next; 3262 } while (attr != NULL); 3263 } 3264 /* 3265 * We'll descend into the children of element nodes only. 3266 */ 3267 if (cur->children != NULL) { 3268 cur = cur->children; 3269 continue; 3270 } 3271 } else if ((cur->type == XML_TEXT_NODE) || 3272 (cur->type == XML_CDATA_SECTION_NODE)) 3273 { 3274 /* 3275 * Merge adjacent text/CDATA-section-nodes 3276 * --------------------------------------- 3277 * In order to avoid breaking of existing stylesheets, 3278 * if the old behaviour is wanted (strictWhitespace == 0), 3279 * then we *won't* merge adjacent text-nodes 3280 * (except in xsl:text); this will ensure that whitespace-only 3281 * text nodes are (incorrectly) not stripped in some cases. 3282 * 3283 * Example: : <foo> <!-- bar -->zoo</foo> 3284 * Corrent (strict) result: <foo> zoo</foo> 3285 * Incorrect (old) result : <foo>zoo</foo> 3286 * 3287 * NOTE that we *will* merge adjacent text-nodes if 3288 * they are in xsl:text. 3289 * Example, the following: 3290 * <xsl:text> <!-- bar -->zoo<xsl:text> 3291 * will result in both cases in: 3292 * <xsl:text> zoo<xsl:text> 3293 */ 3294 cur->type = XML_TEXT_NODE; 3295 if ((strictWhitespace != 0) || (inXSLText != 0)) { 3296 /* 3297 * New behaviour; merge nodes. 3298 */ 3299 if (textNode == NULL) 3300 textNode = cur; 3301 else { 3302 if (cur->content != NULL) 3303 xmlNodeAddContent(textNode, cur->content); 3304 deleteNode = cur; 3305 } 3306 if ((cur->next == NULL) || 3307 (cur->next->type == XML_ELEMENT_NODE)) 3308 goto end_of_text; 3309 else 3310 goto next_sibling; 3311 } else { 3312 /* 3313 * Old behaviour. 3314 */ 3315 if (textNode == NULL) 3316 textNode = cur; 3317 goto end_of_text; 3318 } 3319 } else if ((cur->type == XML_COMMENT_NODE) || 3320 (cur->type == XML_PI_NODE)) 3321 { 3322 /* 3323 * Remove processing instructions and comments. 3324 */ 3325 deleteNode = cur; 3326 if ((cur->next == NULL) || 3327 (cur->next->type == XML_ELEMENT_NODE)) 3328 goto end_of_text; 3329 else 3330 goto next_sibling; 3331 } else { 3332 textNode = NULL; 3333 /* 3334 * Invalid node-type for this data-model. 3335 */ 3336 xsltTransformError(NULL, style, cur, 3337 "Invalid type of node for the XSLT data model.\n"); 3338 cctxt->style->errors++; 3339 goto next_sibling; 3340 } 3341 3342end_of_text: 3343 if (textNode) { 3344 value = textNode->content; 3345 /* 3346 * At this point all adjacent text/CDATA-section nodes 3347 * have been merged. 3348 * 3349 * Strip whitespace-only text-nodes. 3350 * (cctxt->inode->stripWhitespace) 3351 */ 3352 if ((value == NULL) || (*value == 0) || 3353 (((cctxt->inode->stripWhitespace) || 3354 (! cctxt->inode->preserveWhitespace)) && 3355 IS_BLANK(*value) && 3356 xsltIsBlank(value))) 3357 { 3358 if (textNode != cur) { 3359 xmlUnlinkNode(textNode); 3360 xmlFreeNode(textNode); 3361 } else 3362 deleteNode = textNode; 3363 textNode = NULL; 3364 goto next_sibling; 3365 } 3366 /* 3367 * Convert CDATA-section nodes to text-nodes. 3368 * TODO: Can this produce problems? 3369 */ 3370 if (textNode->type != XML_TEXT_NODE) { 3371 textNode->type = XML_TEXT_NODE; 3372 textNode->name = xmlStringText; 3373 } 3374 if (internalize && 3375 (textNode->content != NULL) && 3376 (!xmlDictOwns(style->dict, textNode->content))) 3377 { 3378 /* 3379 * Internalize the string. 3380 */ 3381 value = (xmlChar *) xmlDictLookup(style->dict, 3382 textNode->content, -1); 3383 xmlNodeSetContent(textNode, NULL); 3384 textNode->content = value; 3385 } 3386 textNode = NULL; 3387 /* 3388 * Note that "disable-output-escaping" of the xsl:text 3389 * element will be applied at a later level, when 3390 * XSLT elements are processed. 3391 */ 3392 } 3393 3394next_sibling: 3395 if (cur->type == XML_ELEMENT_NODE) { 3396 xsltCompilerNodePop(cctxt, cur); 3397 } 3398 if (cur == node) 3399 break; 3400 if (cur->next != NULL) { 3401 cur = cur->next; 3402 } else { 3403 cur = cur->parent; 3404 inXSLText = 0; 3405 goto next_sibling; 3406 }; 3407 } 3408 if (deleteNode != NULL) { 3409#ifdef WITH_XSLT_DEBUG_PARSING 3410 xsltGenericDebug(xsltGenericDebugContext, 3411 "xsltParsePreprocessStylesheetTree: removing node\n"); 3412#endif 3413 xmlUnlinkNode(deleteNode); 3414 xmlFreeNode(deleteNode); 3415 } 3416 return(0); 3417 3418internal_err: 3419 return(-1); 3420} 3421 3422#endif /* XSLT_REFACTORED */ 3423 3424#ifdef XSLT_REFACTORED 3425#else 3426static void 3427xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) 3428{ 3429 xmlNodePtr deleteNode, styleelem; 3430 int internalize = 0; 3431 3432 if ((style == NULL) || (cur == NULL)) 3433 return; 3434 3435 if ((cur->doc != NULL) && (style->dict != NULL) && 3436 (cur->doc->dict == style->dict)) 3437 internalize = 1; 3438 else 3439 style->internalized = 0; 3440 3441 if ((cur != NULL) && (IS_XSLT_ELEM(cur)) && 3442 (IS_XSLT_NAME(cur, "stylesheet"))) { 3443 styleelem = cur; 3444 } else { 3445 styleelem = NULL; 3446 } 3447 3448 /* 3449 * This content comes from the stylesheet 3450 * For stylesheets, the set of whitespace-preserving 3451 * element names consists of just xsl:text. 3452 */ 3453 deleteNode = NULL; 3454 while (cur != NULL) { 3455 if (deleteNode != NULL) { 3456#ifdef WITH_XSLT_DEBUG_BLANKS 3457 xsltGenericDebug(xsltGenericDebugContext, 3458 "xsltPrecomputeStylesheet: removing ignorable blank node\n"); 3459#endif 3460 xmlUnlinkNode(deleteNode); 3461 xmlFreeNode(deleteNode); 3462 deleteNode = NULL; 3463 } 3464 if (cur->type == XML_ELEMENT_NODE) { 3465 int exclPrefixes; 3466 /* 3467 * Internalize attributes values. 3468 */ 3469 if ((internalize) && (cur->properties != NULL)) { 3470 xmlAttrPtr attr = cur->properties; 3471 xmlNodePtr txt; 3472 3473 while (attr != NULL) { 3474 txt = attr->children; 3475 if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && 3476 (txt->content != NULL) && 3477 (!xmlDictOwns(style->dict, txt->content))) 3478 { 3479 xmlChar *tmp; 3480 3481 /* 3482 * internalize the text string, goal is to speed 3483 * up operations and minimize used space by compiled 3484 * stylesheets. 3485 */ 3486 tmp = (xmlChar *) xmlDictLookup(style->dict, 3487 txt->content, -1); 3488 if (tmp != txt->content) { 3489 xmlNodeSetContent(txt, NULL); 3490 txt->content = tmp; 3491 } 3492 } 3493 attr = attr->next; 3494 } 3495 } 3496 if (IS_XSLT_ELEM(cur)) { 3497 exclPrefixes = 0; 3498 xsltStylePreCompute(style, cur); 3499 if (IS_XSLT_NAME(cur, "text")) { 3500 for (;exclPrefixes > 0;exclPrefixes--) 3501 exclPrefixPop(style); 3502 goto skip_children; 3503 } 3504 } else { 3505 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0); 3506 } 3507 3508 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) { 3509 xmlNsPtr ns = cur->nsDef, prev = NULL, next; 3510 xmlNodePtr root = NULL; 3511 int i, moved; 3512 3513 root = xmlDocGetRootElement(cur->doc); 3514 if ((root != NULL) && (root != cur)) { 3515 while (ns != NULL) { 3516 moved = 0; 3517 next = ns->next; 3518 for (i = 0;i < style->exclPrefixNr;i++) { 3519 if ((ns->prefix != NULL) && 3520 (xmlStrEqual(ns->href, 3521 style->exclPrefixTab[i]))) { 3522 /* 3523 * Move the namespace definition on the root 3524 * element to avoid duplicating it without 3525 * loosing it. 3526 */ 3527 if (prev == NULL) { 3528 cur->nsDef = ns->next; 3529 } else { 3530 prev->next = ns->next; 3531 } 3532 ns->next = root->nsDef; 3533 root->nsDef = ns; 3534 moved = 1; 3535 break; 3536 } 3537 } 3538 if (moved == 0) 3539 prev = ns; 3540 ns = next; 3541 } 3542 } 3543 } 3544 /* 3545 * If we have prefixes locally, recurse and pop them up when 3546 * going back 3547 */ 3548 if (exclPrefixes > 0) { 3549 xsltPrecomputeStylesheet(style, cur->children); 3550 for (;exclPrefixes > 0;exclPrefixes--) 3551 exclPrefixPop(style); 3552 goto skip_children; 3553 } 3554 } else if (cur->type == XML_TEXT_NODE) { 3555 if (IS_BLANK_NODE(cur)) { 3556 if (xmlNodeGetSpacePreserve(cur) != 1) { 3557 deleteNode = cur; 3558 } 3559 } else if ((cur->content != NULL) && (internalize) && 3560 (!xmlDictOwns(style->dict, cur->content))) { 3561 xmlChar *tmp; 3562 3563 /* 3564 * internalize the text string, goal is to speed 3565 * up operations and minimize used space by compiled 3566 * stylesheets. 3567 */ 3568 tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1); 3569 xmlNodeSetContent(cur, NULL); 3570 cur->content = tmp; 3571 } 3572 } else if ((cur->type != XML_ELEMENT_NODE) && 3573 (cur->type != XML_CDATA_SECTION_NODE)) { 3574 deleteNode = cur; 3575 goto skip_children; 3576 } 3577 3578 /* 3579 * Skip to next node. In case of a namespaced element children of 3580 * the stylesheet and not in the XSLT namespace and not an extension 3581 * element, ignore its content. 3582 */ 3583 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) && 3584 (styleelem != NULL) && (cur->parent == styleelem) && 3585 (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) && 3586 (!xsltCheckExtURI(style, cur->ns->href))) { 3587 goto skip_children; 3588 } else if (cur->children != NULL) { 3589 if ((cur->children->type != XML_ENTITY_DECL) && 3590 (cur->children->type != XML_ENTITY_REF_NODE) && 3591 (cur->children->type != XML_ENTITY_NODE)) { 3592 cur = cur->children; 3593 continue; 3594 } 3595 } 3596 3597skip_children: 3598 if (cur->next != NULL) { 3599 cur = cur->next; 3600 continue; 3601 } 3602 do { 3603 3604 cur = cur->parent; 3605 if (cur == NULL) 3606 break; 3607 if (cur == (xmlNodePtr) style->doc) { 3608 cur = NULL; 3609 break; 3610 } 3611 if (cur->next != NULL) { 3612 cur = cur->next; 3613 break; 3614 } 3615 } while (cur != NULL); 3616 } 3617 if (deleteNode != NULL) { 3618#ifdef WITH_XSLT_DEBUG_PARSING 3619 xsltGenericDebug(xsltGenericDebugContext, 3620 "xsltPrecomputeStylesheet: removing ignorable blank node\n"); 3621#endif 3622 xmlUnlinkNode(deleteNode); 3623 xmlFreeNode(deleteNode); 3624 } 3625} 3626#endif /* end of else XSLT_REFACTORED */ 3627 3628/** 3629 * xsltGatherNamespaces: 3630 * @style: the XSLT stylesheet 3631 * 3632 * Browse the stylesheet and build the namspace hash table which 3633 * will be used for XPath interpretation. If needed do a bit of normalization 3634 */ 3635 3636static void 3637xsltGatherNamespaces(xsltStylesheetPtr style) { 3638 xmlNodePtr cur; 3639 const xmlChar *URI; 3640 3641 if (style == NULL) 3642 return; 3643 /* 3644 * TODO: basically if the stylesheet uses the same prefix for different 3645 * patterns, well they may be in problem, hopefully they will get 3646 * a warning first. 3647 */ 3648 /* 3649 * TODO: Eliminate the use of the hash for XPath expressions. 3650 * An expression should be evaluated in the context of the in-scope 3651 * namespaces; eliminate the restriction of an XML document to contain 3652 * no duplicate prefixes for different namespace names. 3653 * 3654 */ 3655 cur = xmlDocGetRootElement(style->doc); 3656 while (cur != NULL) { 3657 if (cur->type == XML_ELEMENT_NODE) { 3658 xmlNsPtr ns = cur->nsDef; 3659 while (ns != NULL) { 3660 if (ns->prefix != NULL) { 3661 if (style->nsHash == NULL) { 3662 style->nsHash = xmlHashCreate(10); 3663 if (style->nsHash == NULL) { 3664 xsltTransformError(NULL, style, cur, 3665 "xsltGatherNamespaces: failed to create hash table\n"); 3666 style->errors++; 3667 return; 3668 } 3669 } 3670 URI = xmlHashLookup(style->nsHash, ns->prefix); 3671 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) { 3672 xsltTransformError(NULL, style, cur, 3673 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix); 3674 style->warnings++; 3675 } else if (URI == NULL) { 3676 xmlHashUpdateEntry(style->nsHash, ns->prefix, 3677 (void *) ns->href, (xmlHashDeallocator)xmlFree); 3678 3679#ifdef WITH_XSLT_DEBUG_PARSING 3680 xsltGenericDebug(xsltGenericDebugContext, 3681 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href); 3682#endif 3683 } 3684 } 3685 ns = ns->next; 3686 } 3687 } 3688 3689 /* 3690 * Skip to next node 3691 */ 3692 if (cur->children != NULL) { 3693 if (cur->children->type != XML_ENTITY_DECL) { 3694 cur = cur->children; 3695 continue; 3696 } 3697 } 3698 if (cur->next != NULL) { 3699 cur = cur->next; 3700 continue; 3701 } 3702 3703 do { 3704 cur = cur->parent; 3705 if (cur == NULL) 3706 break; 3707 if (cur == (xmlNodePtr) style->doc) { 3708 cur = NULL; 3709 break; 3710 } 3711 if (cur->next != NULL) { 3712 cur = cur->next; 3713 break; 3714 } 3715 } while (cur != NULL); 3716 } 3717} 3718 3719#ifdef XSLT_REFACTORED 3720 3721static xsltStyleType 3722xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt, 3723 xmlNodePtr node) 3724{ 3725 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || 3726 (node->name == NULL)) 3727 return(0); 3728 3729 if (node->name[0] == 'a') { 3730 if (IS_XSLT_NAME(node, "apply-templates")) 3731 return(XSLT_FUNC_APPLYTEMPLATES); 3732 else if (IS_XSLT_NAME(node, "attribute")) 3733 return(XSLT_FUNC_ATTRIBUTE); 3734 else if (IS_XSLT_NAME(node, "apply-imports")) 3735 return(XSLT_FUNC_APPLYIMPORTS); 3736 else if (IS_XSLT_NAME(node, "attribute-set")) 3737 return(0); 3738 3739 } else if (node->name[0] == 'c') { 3740 if (IS_XSLT_NAME(node, "choose")) 3741 return(XSLT_FUNC_CHOOSE); 3742 else if (IS_XSLT_NAME(node, "copy")) 3743 return(XSLT_FUNC_COPY); 3744 else if (IS_XSLT_NAME(node, "copy-of")) 3745 return(XSLT_FUNC_COPYOF); 3746 else if (IS_XSLT_NAME(node, "call-template")) 3747 return(XSLT_FUNC_CALLTEMPLATE); 3748 else if (IS_XSLT_NAME(node, "comment")) 3749 return(XSLT_FUNC_COMMENT); 3750 3751 } else if (node->name[0] == 'd') { 3752 if (IS_XSLT_NAME(node, "document")) 3753 return(XSLT_FUNC_DOCUMENT); 3754 else if (IS_XSLT_NAME(node, "decimal-format")) 3755 return(0); 3756 3757 } else if (node->name[0] == 'e') { 3758 if (IS_XSLT_NAME(node, "element")) 3759 return(XSLT_FUNC_ELEMENT); 3760 3761 } else if (node->name[0] == 'f') { 3762 if (IS_XSLT_NAME(node, "for-each")) 3763 return(XSLT_FUNC_FOREACH); 3764 else if (IS_XSLT_NAME(node, "fallback")) 3765 return(XSLT_FUNC_FALLBACK); 3766 3767 } else if (*(node->name) == 'i') { 3768 if (IS_XSLT_NAME(node, "if")) 3769 return(XSLT_FUNC_IF); 3770 else if (IS_XSLT_NAME(node, "include")) 3771 return(0); 3772 else if (IS_XSLT_NAME(node, "import")) 3773 return(0); 3774 3775 } else if (*(node->name) == 'k') { 3776 if (IS_XSLT_NAME(node, "key")) 3777 return(0); 3778 3779 } else if (*(node->name) == 'm') { 3780 if (IS_XSLT_NAME(node, "message")) 3781 return(XSLT_FUNC_MESSAGE); 3782 3783 } else if (*(node->name) == 'n') { 3784 if (IS_XSLT_NAME(node, "number")) 3785 return(XSLT_FUNC_NUMBER); 3786 else if (IS_XSLT_NAME(node, "namespace-alias")) 3787 return(0); 3788 3789 } else if (*(node->name) == 'o') { 3790 if (IS_XSLT_NAME(node, "otherwise")) 3791 return(XSLT_FUNC_OTHERWISE); 3792 else if (IS_XSLT_NAME(node, "output")) 3793 return(0); 3794 3795 } else if (*(node->name) == 'p') { 3796 if (IS_XSLT_NAME(node, "param")) 3797 return(XSLT_FUNC_PARAM); 3798 else if (IS_XSLT_NAME(node, "processing-instruction")) 3799 return(XSLT_FUNC_PI); 3800 else if (IS_XSLT_NAME(node, "preserve-space")) 3801 return(0); 3802 3803 } else if (*(node->name) == 's') { 3804 if (IS_XSLT_NAME(node, "sort")) 3805 return(XSLT_FUNC_SORT); 3806 else if (IS_XSLT_NAME(node, "strip-space")) 3807 return(0); 3808 else if (IS_XSLT_NAME(node, "stylesheet")) 3809 return(0); 3810 3811 } else if (node->name[0] == 't') { 3812 if (IS_XSLT_NAME(node, "text")) 3813 return(XSLT_FUNC_TEXT); 3814 else if (IS_XSLT_NAME(node, "template")) 3815 return(0); 3816 else if (IS_XSLT_NAME(node, "transform")) 3817 return(0); 3818 3819 } else if (*(node->name) == 'v') { 3820 if (IS_XSLT_NAME(node, "value-of")) 3821 return(XSLT_FUNC_VALUEOF); 3822 else if (IS_XSLT_NAME(node, "variable")) 3823 return(XSLT_FUNC_VARIABLE); 3824 3825 } else if (*(node->name) == 'w') { 3826 if (IS_XSLT_NAME(node, "when")) 3827 return(XSLT_FUNC_WHEN); 3828 if (IS_XSLT_NAME(node, "with-param")) 3829 return(XSLT_FUNC_WITHPARAM); 3830 } 3831 return(0); 3832} 3833 3834/** 3835 * xsltParseAnyXSLTElem: 3836 * 3837 * @cctxt: the compilation context 3838 * @elem: the element node of the XSLT instruction 3839 * 3840 * Parses, validates the content models and compiles XSLT instructions. 3841 * 3842 * Returns 0 if everything's fine; 3843 * -1 on API or internal errors. 3844 */ 3845int 3846xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem) 3847{ 3848 if ((cctxt == NULL) || (elem == NULL) || 3849 (elem->type != XML_ELEMENT_NODE)) 3850 return(-1); 3851 3852 elem->psvi = NULL; 3853 3854 if (! (IS_XSLT_ELEM_FAST(elem))) 3855 return(-1); 3856 /* 3857 * Detection of handled content of extension instructions. 3858 */ 3859 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { 3860 cctxt->inode->extContentHandled = 1; 3861 } 3862 3863 xsltCompilerNodePush(cctxt, elem); 3864 /* 3865 * URGENT TODO: Find a way to speed up this annoying redundant 3866 * textual node-name and namespace comparison. 3867 */ 3868 if (cctxt->inode->prev->curChildType != 0) 3869 cctxt->inode->type = cctxt->inode->prev->curChildType; 3870 else 3871 cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem); 3872 /* 3873 * Update the in-scope namespaces if needed. 3874 */ 3875 if (elem->nsDef != NULL) 3876 cctxt->inode->inScopeNs = 3877 xsltCompilerBuildInScopeNsList(cctxt, elem); 3878 /* 3879 * xsltStylePreCompute(): 3880 * This will compile the information found on the current 3881 * element's attributes. NOTE that this won't process the 3882 * children of the instruction. 3883 */ 3884 xsltStylePreCompute(cctxt->style, elem); 3885 /* 3886 * TODO: How to react on errors in xsltStylePreCompute() ? 3887 */ 3888 3889 /* 3890 * Validate the content model of the XSLT-element. 3891 */ 3892 switch (cctxt->inode->type) { 3893 case XSLT_FUNC_APPLYIMPORTS: 3894 /* EMPTY */ 3895 goto empty_content; 3896 case XSLT_FUNC_APPLYTEMPLATES: 3897 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */ 3898 goto apply_templates; 3899 case XSLT_FUNC_ATTRIBUTE: 3900 /* <!-- Content: template --> */ 3901 goto sequence_constructor; 3902 case XSLT_FUNC_CALLTEMPLATE: 3903 /* <!-- Content: xsl:with-param* --> */ 3904 goto call_template; 3905 case XSLT_FUNC_CHOOSE: 3906 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */ 3907 goto choose; 3908 case XSLT_FUNC_COMMENT: 3909 /* <!-- Content: template --> */ 3910 goto sequence_constructor; 3911 case XSLT_FUNC_COPY: 3912 /* <!-- Content: template --> */ 3913 goto sequence_constructor; 3914 case XSLT_FUNC_COPYOF: 3915 /* EMPTY */ 3916 goto empty_content; 3917 case XSLT_FUNC_DOCUMENT: /* Extra one */ 3918 /* ?? template ?? */ 3919 goto sequence_constructor; 3920 case XSLT_FUNC_ELEMENT: 3921 /* <!-- Content: template --> */ 3922 goto sequence_constructor; 3923 case XSLT_FUNC_FALLBACK: 3924 /* <!-- Content: template --> */ 3925 goto sequence_constructor; 3926 case XSLT_FUNC_FOREACH: 3927 /* <!-- Content: (xsl:sort*, template) --> */ 3928 goto for_each; 3929 case XSLT_FUNC_IF: 3930 /* <!-- Content: template --> */ 3931 goto sequence_constructor; 3932 case XSLT_FUNC_OTHERWISE: 3933 /* <!-- Content: template --> */ 3934 goto sequence_constructor; 3935 case XSLT_FUNC_MESSAGE: 3936 /* <!-- Content: template --> */ 3937 goto sequence_constructor; 3938 case XSLT_FUNC_NUMBER: 3939 /* EMPTY */ 3940 goto empty_content; 3941 case XSLT_FUNC_PARAM: 3942 /* 3943 * Check for redefinition. 3944 */ 3945 if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { 3946 xsltVarInfoPtr ivar = cctxt->ivar; 3947 3948 do { 3949 if ((ivar->name == 3950 ((xsltStyleItemParamPtr) elem->psvi)->name) && 3951 (ivar->nsName == 3952 ((xsltStyleItemParamPtr) elem->psvi)->ns)) 3953 { 3954 elem->psvi = NULL; 3955 xsltTransformError(NULL, cctxt->style, elem, 3956 "Redefinition of variable or parameter '%s'.\n", 3957 ivar->name); 3958 cctxt->style->errors++; 3959 goto error; 3960 } 3961 ivar = ivar->prev; 3962 } while (ivar != NULL); 3963 } 3964 /* <!-- Content: template --> */ 3965 goto sequence_constructor; 3966 case XSLT_FUNC_PI: 3967 /* <!-- Content: template --> */ 3968 goto sequence_constructor; 3969 case XSLT_FUNC_SORT: 3970 /* EMPTY */ 3971 goto empty_content; 3972 case XSLT_FUNC_TEXT: 3973 /* <!-- Content: #PCDATA --> */ 3974 goto text; 3975 case XSLT_FUNC_VALUEOF: 3976 /* EMPTY */ 3977 goto empty_content; 3978 case XSLT_FUNC_VARIABLE: 3979 /* 3980 * Check for redefinition. 3981 */ 3982 if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { 3983 xsltVarInfoPtr ivar = cctxt->ivar; 3984 3985 do { 3986 if ((ivar->name == 3987 ((xsltStyleItemVariablePtr) elem->psvi)->name) && 3988 (ivar->nsName == 3989 ((xsltStyleItemVariablePtr) elem->psvi)->ns)) 3990 { 3991 elem->psvi = NULL; 3992 xsltTransformError(NULL, cctxt->style, elem, 3993 "Redefinition of variable or parameter '%s'.\n", 3994 ivar->name); 3995 cctxt->style->errors++; 3996 goto error; 3997 } 3998 ivar = ivar->prev; 3999 } while (ivar != NULL); 4000 } 4001 /* <!-- Content: template --> */ 4002 goto sequence_constructor; 4003 case XSLT_FUNC_WHEN: 4004 /* <!-- Content: template --> */ 4005 goto sequence_constructor; 4006 case XSLT_FUNC_WITHPARAM: 4007 /* <!-- Content: template --> */ 4008 goto sequence_constructor; 4009 default: 4010#ifdef WITH_XSLT_DEBUG_PARSING 4011 xsltGenericDebug(xsltGenericDebugContext, 4012 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n", 4013 elem->name); 4014#endif 4015 xsltTransformError(NULL, cctxt->style, elem, 4016 "xsltParseXSLTNode: Internal error; " 4017 "unhandled XSLT element '%s'.\n", elem->name); 4018 cctxt->style->errors++; 4019 goto internal_err; 4020 } 4021 4022apply_templates: 4023 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */ 4024 if (elem->children != NULL) { 4025 xmlNodePtr child = elem->children; 4026 do { 4027 if (child->type == XML_ELEMENT_NODE) { 4028 if (IS_XSLT_ELEM_FAST(child)) { 4029 if (xmlStrEqual(child->name, BAD_CAST "with-param")) { 4030 cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; 4031 xsltParseAnyXSLTElem(cctxt, child); 4032 } else if (xmlStrEqual(child->name, BAD_CAST "sort")) { 4033 cctxt->inode->curChildType = XSLT_FUNC_SORT; 4034 xsltParseAnyXSLTElem(cctxt, child); 4035 } else 4036 xsltParseContentError(cctxt->style, child); 4037 } else 4038 xsltParseContentError(cctxt->style, child); 4039 } 4040 child = child->next; 4041 } while (child != NULL); 4042 } 4043 goto exit; 4044 4045call_template: 4046 /* <!-- Content: xsl:with-param* --> */ 4047 if (elem->children != NULL) { 4048 xmlNodePtr child = elem->children; 4049 do { 4050 if (child->type == XML_ELEMENT_NODE) { 4051 if (IS_XSLT_ELEM_FAST(child)) { 4052 xsltStyleType type; 4053 4054 type = xsltGetXSLTElementTypeByNode(cctxt, child); 4055 if (type == XSLT_FUNC_WITHPARAM) { 4056 cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; 4057 xsltParseAnyXSLTElem(cctxt, child); 4058 } else { 4059 xsltParseContentError(cctxt->style, child); 4060 } 4061 } else 4062 xsltParseContentError(cctxt->style, child); 4063 } 4064 child = child->next; 4065 } while (child != NULL); 4066 } 4067 goto exit; 4068 4069text: 4070 if (elem->children != NULL) { 4071 xmlNodePtr child = elem->children; 4072 do { 4073 if ((child->type != XML_TEXT_NODE) && 4074 (child->type != XML_CDATA_SECTION_NODE)) 4075 { 4076 xsltTransformError(NULL, cctxt->style, elem, 4077 "The XSLT 'text' element must have only character " 4078 "data as content.\n"); 4079 } 4080 child = child->next; 4081 } while (child != NULL); 4082 } 4083 goto exit; 4084 4085empty_content: 4086 if (elem->children != NULL) { 4087 xmlNodePtr child = elem->children; 4088 /* 4089 * Relaxed behaviour: we will allow whitespace-only text-nodes. 4090 */ 4091 do { 4092 if (((child->type != XML_TEXT_NODE) && 4093 (child->type != XML_CDATA_SECTION_NODE)) || 4094 (! IS_BLANK_NODE(child))) 4095 { 4096 xsltTransformError(NULL, cctxt->style, elem, 4097 "This XSLT element must have no content.\n"); 4098 cctxt->style->errors++; 4099 break; 4100 } 4101 child = child->next; 4102 } while (child != NULL); 4103 } 4104 goto exit; 4105 4106choose: 4107 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */ 4108 /* 4109 * TODO: text-nodes in between are *not* allowed in XSLT 1.0. 4110 * The old behaviour did not check this. 4111 * NOTE: In XSLT 2.0 they are stripped beforehand 4112 * if whitespace-only (regardless of xml:space). 4113 */ 4114 if (elem->children != NULL) { 4115 xmlNodePtr child = elem->children; 4116 int nbWhen = 0, nbOtherwise = 0, err = 0; 4117 do { 4118 if (child->type == XML_ELEMENT_NODE) { 4119 if (IS_XSLT_ELEM_FAST(child)) { 4120 xsltStyleType type; 4121 4122 type = xsltGetXSLTElementTypeByNode(cctxt, child); 4123 if (type == XSLT_FUNC_WHEN) { 4124 nbWhen++; 4125 if (nbOtherwise) { 4126 xsltParseContentError(cctxt->style, child); 4127 err = 1; 4128 break; 4129 } 4130 cctxt->inode->curChildType = XSLT_FUNC_WHEN; 4131 xsltParseAnyXSLTElem(cctxt, child); 4132 } else if (type == XSLT_FUNC_OTHERWISE) { 4133 if (! nbWhen) { 4134 xsltParseContentError(cctxt->style, child); 4135 err = 1; 4136 break; 4137 } 4138 if (nbOtherwise) { 4139 xsltTransformError(NULL, cctxt->style, elem, 4140 "The XSLT 'choose' element must not contain " 4141 "more than one XSLT 'otherwise' element.\n"); 4142 cctxt->style->errors++; 4143 err = 1; 4144 break; 4145 } 4146 nbOtherwise++; 4147 cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE; 4148 xsltParseAnyXSLTElem(cctxt, child); 4149 } else 4150 xsltParseContentError(cctxt->style, child); 4151 } else 4152 xsltParseContentError(cctxt->style, child); 4153 } 4154 /* 4155 else 4156 xsltParseContentError(cctxt, child); 4157 */ 4158 child = child->next; 4159 } while (child != NULL); 4160 if ((! err) && (! nbWhen)) { 4161 xsltTransformError(NULL, cctxt->style, elem, 4162 "The XSLT element 'choose' must contain at least one " 4163 "XSLT element 'when'.\n"); 4164 cctxt->style->errors++; 4165 } 4166 } 4167 goto exit; 4168 4169for_each: 4170 /* <!-- Content: (xsl:sort*, template) --> */ 4171 /* 4172 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0. 4173 * The old behaviour did not allow this, but it catched this 4174 * only at transformation-time. 4175 * In XSLT 2.0 they are stripped beforehand if whitespace-only 4176 * (regardless of xml:space). 4177 */ 4178 if (elem->children != NULL) { 4179 xmlNodePtr child = elem->children; 4180 /* 4181 * Parse xsl:sort first. 4182 */ 4183 do { 4184 if ((child->type == XML_ELEMENT_NODE) && 4185 IS_XSLT_ELEM_FAST(child)) 4186 { 4187 if (xsltGetXSLTElementTypeByNode(cctxt, child) == 4188 XSLT_FUNC_SORT) 4189 { 4190 cctxt->inode->curChildType = XSLT_FUNC_SORT; 4191 xsltParseAnyXSLTElem(cctxt, child); 4192 } else 4193 break; 4194 } else 4195 break; 4196 child = child->next; 4197 } while (child != NULL); 4198 /* 4199 * Parse the sequece constructor. 4200 */ 4201 if (child != NULL) 4202 xsltParseSequenceConstructor(cctxt, child); 4203 } 4204 goto exit; 4205 4206sequence_constructor: 4207 /* 4208 * Parse the sequence constructor. 4209 */ 4210 if (elem->children != NULL) 4211 xsltParseSequenceConstructor(cctxt, elem->children); 4212 4213 /* 4214 * Register information for vars/params. Only needed if there 4215 * are any following siblings. 4216 */ 4217 if ((elem->next != NULL) && 4218 ((cctxt->inode->type == XSLT_FUNC_VARIABLE) || 4219 (cctxt->inode->type == XSLT_FUNC_PARAM))) 4220 { 4221 if ((elem->psvi != NULL) && 4222 (((xsltStyleBasicItemVariablePtr) elem->psvi)->name)) 4223 { 4224 xsltCompilerVarInfoPush(cctxt, elem, 4225 ((xsltStyleBasicItemVariablePtr) elem->psvi)->name, 4226 ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns); 4227 } 4228 } 4229 4230error: 4231exit: 4232 xsltCompilerNodePop(cctxt, elem); 4233 return(0); 4234 4235internal_err: 4236 xsltCompilerNodePop(cctxt, elem); 4237 return(-1); 4238} 4239 4240/** 4241 * xsltForwardsCompatUnkownItemCreate: 4242 * 4243 * @cctxt: the compilation context 4244 * 4245 * Creates a compiled representation of the unknown 4246 * XSLT instruction. 4247 * 4248 * Returns the compiled representation. 4249 */ 4250static xsltStyleItemUknownPtr 4251xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt) 4252{ 4253 xsltStyleItemUknownPtr item; 4254 4255 item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown)); 4256 if (item == NULL) { 4257 xsltTransformError(NULL, cctxt->style, NULL, 4258 "Internal error in xsltForwardsCompatUnkownItemCreate(): " 4259 "Failed to allocate memory.\n"); 4260 cctxt->style->errors++; 4261 return(NULL); 4262 } 4263 memset(item, 0, sizeof(xsltStyleItemUknown)); 4264 item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT; 4265 /* 4266 * Store it in the stylesheet. 4267 */ 4268 item->next = cctxt->style->preComps; 4269 cctxt->style->preComps = (xsltElemPreCompPtr) item; 4270 return(item); 4271} 4272 4273/** 4274 * xsltParseUnknownXSLTElem: 4275 * 4276 * @cctxt: the compilation context 4277 * @node: the element of the unknown XSLT instruction 4278 * 4279 * Parses an unknown XSLT element. 4280 * If forwards compatible mode is enabled this will allow 4281 * such an unknown XSLT and; otherwise it is rejected. 4282 * 4283 * Returns 1 in the unknown XSLT instruction is rejected, 4284 * 0 if everything's fine and 4285 * -1 on API or internal errors. 4286 */ 4287static int 4288xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt, 4289 xmlNodePtr node) 4290{ 4291 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) 4292 return(-1); 4293 4294 /* 4295 * Detection of handled content of extension instructions. 4296 */ 4297 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { 4298 cctxt->inode->extContentHandled = 1; 4299 } 4300 if (cctxt->inode->forwardsCompat == 0) { 4301 /* 4302 * We are not in forwards-compatible mode, so raise an error. 4303 */ 4304 xsltTransformError(NULL, cctxt->style, node, 4305 "Unknown XSLT element '%s'.\n", node->name); 4306 cctxt->style->errors++; 4307 return(1); 4308 } 4309 /* 4310 * Forwards-compatible mode. 4311 * ------------------------ 4312 * 4313 * Parse/compile xsl:fallback elements. 4314 * 4315 * QUESTION: Do we have to raise an error if there's no xsl:fallback? 4316 * ANSWER: No, since in the stylesheet the fallback behaviour might 4317 * also be provided by using the XSLT function "element-available". 4318 */ 4319 if (cctxt->unknownItem == NULL) { 4320 /* 4321 * Create a singleton for all unknown XSLT instructions. 4322 */ 4323 cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt); 4324 if (cctxt->unknownItem == NULL) { 4325 node->psvi = NULL; 4326 return(-1); 4327 } 4328 } 4329 node->psvi = cctxt->unknownItem; 4330 if (node->children == NULL) 4331 return(0); 4332 else { 4333 xmlNodePtr child = node->children; 4334 4335 xsltCompilerNodePush(cctxt, node); 4336 /* 4337 * Update the in-scope namespaces if needed. 4338 */ 4339 if (node->nsDef != NULL) 4340 cctxt->inode->inScopeNs = 4341 xsltCompilerBuildInScopeNsList(cctxt, node); 4342 /* 4343 * Parse all xsl:fallback children. 4344 */ 4345 do { 4346 if ((child->type == XML_ELEMENT_NODE) && 4347 IS_XSLT_ELEM_FAST(child) && 4348 IS_XSLT_NAME(child, "fallback")) 4349 { 4350 cctxt->inode->curChildType = XSLT_FUNC_FALLBACK; 4351 xsltParseAnyXSLTElem(cctxt, child); 4352 } 4353 child = child->next; 4354 } while (child != NULL); 4355 4356 xsltCompilerNodePop(cctxt, node); 4357 } 4358 return(0); 4359} 4360 4361/** 4362 * xsltParseSequenceConstructor: 4363 * 4364 * @cctxt: the compilation context 4365 * @cur: the start-node of the content to be parsed 4366 * 4367 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms). 4368 * This will additionally remove xsl:text elements from the tree. 4369 */ 4370void 4371xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur) 4372{ 4373 xsltStyleType type; 4374 xmlNodePtr deleteNode = NULL; 4375 4376 if (cctxt == NULL) { 4377 xmlGenericError(xmlGenericErrorContext, 4378 "xsltParseSequenceConstructor: Bad arguments\n"); 4379 cctxt->style->errors++; 4380 return; 4381 } 4382 /* 4383 * Detection of handled content of extension instructions. 4384 */ 4385 if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { 4386 cctxt->inode->extContentHandled = 1; 4387 } 4388 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 4389 return; 4390 /* 4391 * This is the content reffered to as a "template". 4392 * E.g. an xsl:element has such content model: 4393 * <xsl:element 4394 * name = { qname } 4395 * namespace = { uri-reference } 4396 * use-attribute-sets = qnames> 4397 * <!-- Content: template --> 4398 * 4399 * NOTE that in XSLT-2 the term "template" was abandoned due to 4400 * confusion with xsl:template and the term "sequence constructor" 4401 * was introduced instead. 4402 * 4403 * The following XSLT-instructions are allowed to appear: 4404 * xsl:apply-templates, xsl:call-template, xsl:apply-imports, 4405 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number, 4406 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable, 4407 * xsl:message, xsl:fallback, 4408 * xsl:processing-instruction, xsl:comment, xsl:element 4409 * xsl:attribute. 4410 * Additional allowed content: 4411 * 1) extension instructions 4412 * 2) literal result elements 4413 * 3) PCDATA 4414 * 4415 * NOTE that this content model does *not* allow xsl:param. 4416 */ 4417 while (cur != NULL) { 4418 if (deleteNode != NULL) { 4419#ifdef WITH_XSLT_DEBUG_BLANKS 4420 xsltGenericDebug(xsltGenericDebugContext, 4421 "xsltParseSequenceConstructor: removing xsl:text element\n"); 4422#endif 4423 xmlUnlinkNode(deleteNode); 4424 xmlFreeNode(deleteNode); 4425 deleteNode = NULL; 4426 } 4427 if (cur->type == XML_ELEMENT_NODE) { 4428 4429 if (cur->psvi == xsltXSLTTextMarker) { 4430 /* 4431 * xsl:text elements 4432 * -------------------------------------------------------- 4433 */ 4434 xmlNodePtr tmp; 4435 4436 cur->psvi = NULL; 4437 /* 4438 * Mark the xsl:text element for later deletion. 4439 */ 4440 deleteNode = cur; 4441 /* 4442 * Validate content. 4443 */ 4444 tmp = cur->children; 4445 if (tmp) { 4446 /* 4447 * We don't expect more than one text-node in the 4448 * content, since we already merged adjacent 4449 * text/CDATA-nodes and eliminated PI/comment-nodes. 4450 */ 4451 if ((tmp->type == XML_TEXT_NODE) || 4452 (tmp->next == NULL)) 4453 { 4454 /* 4455 * Leave the contained text-node in the tree. 4456 */ 4457 xmlUnlinkNode(tmp); 4458 xmlAddPrevSibling(cur, tmp); 4459 } else { 4460 tmp = NULL; 4461 xsltTransformError(NULL, cctxt->style, cur, 4462 "Element 'xsl:text': Invalid type " 4463 "of node found in content.\n"); 4464 cctxt->style->errors++; 4465 } 4466 } 4467 if (cur->properties) { 4468 xmlAttrPtr attr; 4469 /* 4470 * TODO: We need to report errors for 4471 * invalid attrs. 4472 */ 4473 attr = cur->properties; 4474 do { 4475 if ((attr->ns == NULL) && 4476 (attr->name != NULL) && 4477 (attr->name[0] == 'd') && 4478 xmlStrEqual(attr->name, 4479 BAD_CAST "disable-output-escaping")) 4480 { 4481 /* 4482 * Attr "disable-output-escaping". 4483 * XSLT-2: This attribute is deprecated. 4484 */ 4485 if ((attr->children != NULL) && 4486 xmlStrEqual(attr->children->content, 4487 BAD_CAST "yes")) 4488 { 4489 /* 4490 * Disable output escaping for this 4491 * text node. 4492 */ 4493 if (tmp) 4494 tmp->name = xmlStringTextNoenc; 4495 } else if ((attr->children == NULL) || 4496 (attr->children->content == NULL) || 4497 (!xmlStrEqual(attr->children->content, 4498 BAD_CAST "no"))) 4499 { 4500 xsltTransformError(NULL, cctxt->style, 4501 cur, 4502 "Attribute 'disable-output-escaping': " 4503 "Invalid value. Expected is " 4504 "'yes' or 'no'.\n"); 4505 cctxt->style->errors++; 4506 } 4507 break; 4508 } 4509 attr = attr->next; 4510 } while (attr != NULL); 4511 } 4512 } else if (IS_XSLT_ELEM_FAST(cur)) { 4513 /* 4514 * TODO: Using the XSLT-marker is still not stable yet. 4515 */ 4516 /* if (cur->psvi == xsltXSLTElemMarker) { */ 4517 /* 4518 * XSLT instructions 4519 * -------------------------------------------------------- 4520 */ 4521 cur->psvi = NULL; 4522 type = xsltGetXSLTElementTypeByNode(cctxt, cur); 4523 switch (type) { 4524 case XSLT_FUNC_APPLYIMPORTS: 4525 case XSLT_FUNC_APPLYTEMPLATES: 4526 case XSLT_FUNC_ATTRIBUTE: 4527 case XSLT_FUNC_CALLTEMPLATE: 4528 case XSLT_FUNC_CHOOSE: 4529 case XSLT_FUNC_COMMENT: 4530 case XSLT_FUNC_COPY: 4531 case XSLT_FUNC_COPYOF: 4532 case XSLT_FUNC_DOCUMENT: /* Extra one */ 4533 case XSLT_FUNC_ELEMENT: 4534 case XSLT_FUNC_FALLBACK: 4535 case XSLT_FUNC_FOREACH: 4536 case XSLT_FUNC_IF: 4537 case XSLT_FUNC_MESSAGE: 4538 case XSLT_FUNC_NUMBER: 4539 case XSLT_FUNC_PI: 4540 case XSLT_FUNC_TEXT: 4541 case XSLT_FUNC_VALUEOF: 4542 case XSLT_FUNC_VARIABLE: 4543 /* 4544 * Parse the XSLT element. 4545 */ 4546 cctxt->inode->curChildType = type; 4547 xsltParseAnyXSLTElem(cctxt, cur); 4548 break; 4549 default: 4550 xsltParseUnknownXSLTElem(cctxt, cur); 4551 cur = cur->next; 4552 continue; 4553 } 4554 } else { 4555 /* 4556 * Non-XSLT elements 4557 * ----------------- 4558 */ 4559 xsltCompilerNodePush(cctxt, cur); 4560 /* 4561 * Update the in-scope namespaces if needed. 4562 */ 4563 if (cur->nsDef != NULL) 4564 cctxt->inode->inScopeNs = 4565 xsltCompilerBuildInScopeNsList(cctxt, cur); 4566 /* 4567 * The current element is either a literal result element 4568 * or an extension instruction. 4569 * 4570 * Process attr "xsl:extension-element-prefixes". 4571 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be 4572 * processed by the implementor of the extension function; 4573 * i.e., it won't be handled by the XSLT processor. 4574 */ 4575 /* SPEC 1.0: 4576 * "exclude-result-prefixes" is only allowed on literal 4577 * result elements and "xsl:exclude-result-prefixes" 4578 * on xsl:stylesheet/xsl:transform. 4579 * SPEC 2.0: 4580 * "There are a number of standard attributes 4581 * that may appear on any XSLT element: specifically 4582 * version, exclude-result-prefixes, 4583 * extension-element-prefixes, xpath-default-namespace, 4584 * default-collation, and use-when." 4585 * 4586 * SPEC 2.0: 4587 * For literal result elements: 4588 * "xsl:version, xsl:exclude-result-prefixes, 4589 * xsl:extension-element-prefixes, 4590 * xsl:xpath-default-namespace, 4591 * xsl:default-collation, or xsl:use-when." 4592 */ 4593 if (cur->properties) 4594 cctxt->inode->extElemNs = 4595 xsltParseExtElemPrefixes(cctxt, 4596 cur, cctxt->inode->extElemNs, 4597 XSLT_ELEMENT_CATEGORY_LRE); 4598 /* 4599 * Eval if we have an extension instruction here. 4600 */ 4601 if ((cur->ns != NULL) && 4602 (cctxt->inode->extElemNs != NULL) && 4603 (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1)) 4604 { 4605 /* 4606 * Extension instructions 4607 * ---------------------------------------------------- 4608 * Mark the node information. 4609 */ 4610 cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION; 4611 cctxt->inode->extContentHandled = 0; 4612 if (cur->psvi != NULL) { 4613 cur->psvi = NULL; 4614 /* 4615 * TODO: Temporary sanity check. 4616 */ 4617 xsltTransformError(NULL, cctxt->style, cur, 4618 "Internal error in xsltParseSequenceConstructor(): " 4619 "Occupied PSVI field.\n"); 4620 cctxt->style->errors++; 4621 cur = cur->next; 4622 continue; 4623 } 4624 cur->psvi = (void *) 4625 xsltPreComputeExtModuleElement(cctxt->style, cur); 4626 4627 if (cur->psvi == NULL) { 4628 /* 4629 * OLD COMMENT: "Unknown element, maybe registered 4630 * at the context level. Mark it for later 4631 * recognition." 4632 * QUESTION: What does the xsltExtMarker mean? 4633 * ANSWER: It is used in 4634 * xsltApplySequenceConstructor() at 4635 * transformation-time to look out for extension 4636 * registered in the transformation context. 4637 */ 4638 cur->psvi = (void *) xsltExtMarker; 4639 } 4640 /* 4641 * BIG NOTE: Now the ugly part. In previous versions 4642 * of Libxslt (until 1.1.16), all the content of an 4643 * extension instruction was processed and compiled without 4644 * the need of the extension-author to explicitely call 4645 * such a processing;.We now need to mimic this old 4646 * behaviour in order to avoid breaking old code 4647 * on the extension-author's side. 4648 * The mechanism: 4649 * 1) If the author does *not* set the 4650 * compile-time-flag @extContentHandled, then we'll 4651 * parse the content assuming that it's a "template" 4652 * (or "sequence constructor in XSLT 2.0 terms). 4653 * NOTE: If the extension is registered at 4654 * transformation-time only, then there's no way of 4655 * knowing that content shall be valid, and we'll 4656 * process the content the same way. 4657 * 2) If the author *does* set the flag, then we'll assume 4658 * that the author has handled the parsing him/herself 4659 * (e.g. called xsltParseSequenceConstructor(), etc. 4660 * explicitely in his/her code). 4661 */ 4662 if ((cur->children != NULL) && 4663 (cctxt->inode->extContentHandled == 0)) 4664 { 4665 /* 4666 * Default parsing of the content using the 4667 * sequence-constructor model. 4668 */ 4669 xsltParseSequenceConstructor(cctxt, cur->children); 4670 } 4671 } else { 4672 /* 4673 * Literal result element 4674 * ---------------------------------------------------- 4675 * Allowed XSLT attributes: 4676 * xsl:extension-element-prefixes CDATA #IMPLIED 4677 * xsl:exclude-result-prefixes CDATA #IMPLIED 4678 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED 4679 * xsl:version NMTOKEN #IMPLIED 4680 */ 4681 cur->psvi = NULL; 4682 cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE; 4683 if (cur->properties != NULL) { 4684 xmlAttrPtr attr = cur->properties; 4685 /* 4686 * Attribute "xsl:exclude-result-prefixes". 4687 */ 4688 cctxt->inode->exclResultNs = 4689 xsltParseExclResultPrefixes(cctxt, cur, 4690 cctxt->inode->exclResultNs, 4691 XSLT_ELEMENT_CATEGORY_LRE); 4692 /* 4693 * Attribute "xsl:version". 4694 */ 4695 xsltParseAttrXSLTVersion(cctxt, cur, 4696 XSLT_ELEMENT_CATEGORY_LRE); 4697 /* 4698 * Report invalid XSLT attributes. 4699 * For XSLT 1.0 only xsl:use-attribute-sets is allowed 4700 * next to xsl:version, xsl:exclude-result-prefixes and 4701 * xsl:extension-element-prefixes. 4702 * 4703 * Mark all XSLT attributes, in order to skip such 4704 * attributes when instantiating the LRE. 4705 */ 4706 do { 4707 if ((attr->psvi != xsltXSLTAttrMarker) && 4708 IS_XSLT_ATTR_FAST(attr)) 4709 { 4710 if (! xmlStrEqual(attr->name, 4711 BAD_CAST "use-attribute-sets")) 4712 { 4713 xsltTransformError(NULL, cctxt->style, 4714 cur, 4715 "Unknown XSLT attribute '%s'.\n", 4716 attr->name); 4717 cctxt->style->errors++; 4718 } else { 4719 /* 4720 * XSLT attr marker. 4721 */ 4722 attr->psvi = (void *) xsltXSLTAttrMarker; 4723 } 4724 } 4725 attr = attr->next; 4726 } while (attr != NULL); 4727 } 4728 /* 4729 * Create/reuse info for the literal result element. 4730 */ 4731 if (cctxt->inode->nsChanged) 4732 xsltLREInfoCreate(cctxt, cur, 1); 4733 cur->psvi = cctxt->inode->litResElemInfo; 4734 /* 4735 * Apply ns-aliasing on the element and on its attributes. 4736 */ 4737 if (cctxt->hasNsAliases) 4738 xsltLREBuildEffectiveNs(cctxt, cur); 4739 /* 4740 * Compile attribute value templates (AVT). 4741 */ 4742 if (cur->properties) { 4743 xmlAttrPtr attr = cur->properties; 4744 4745 while (attr != NULL) { 4746 xsltCompileAttr(cctxt->style, attr); 4747 attr = attr->next; 4748 } 4749 } 4750 /* 4751 * Parse the content, which is defined to be a "template" 4752 * (or "sequence constructor" in XSLT 2.0 terms). 4753 */ 4754 if (cur->children != NULL) { 4755 xsltParseSequenceConstructor(cctxt, cur->children); 4756 } 4757 } 4758 /* 4759 * Leave the non-XSLT element. 4760 */ 4761 xsltCompilerNodePop(cctxt, cur); 4762 } 4763 } 4764 cur = cur->next; 4765 } 4766 if (deleteNode != NULL) { 4767#ifdef WITH_XSLT_DEBUG_BLANKS 4768 xsltGenericDebug(xsltGenericDebugContext, 4769 "xsltParseSequenceConstructor: removing xsl:text element\n"); 4770#endif 4771 xmlUnlinkNode(deleteNode); 4772 xmlFreeNode(deleteNode); 4773 deleteNode = NULL; 4774 } 4775} 4776 4777/** 4778 * xsltParseTemplateContent: 4779 * @style: the XSLT stylesheet 4780 * @templ: the node containing the content to be parsed 4781 * 4782 * Parses and compiles the content-model of an xsl:template element. 4783 * Note that this is *not* the "template" content model (or "sequence 4784 * constructor" in XSLT 2.0); it it allows addional xsl:param 4785 * elements as immediate children of @templ. 4786 * 4787 * Called by: 4788 * exsltFuncFunctionComp() (EXSLT, functions.c) 4789 * So this is intended to be called from extension functions. 4790 */ 4791void 4792xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { 4793 if ((style == NULL) || (templ == NULL) || 4794 (templ->type == XML_NAMESPACE_DECL)) 4795 return; 4796 4797 /* 4798 * Detection of handled content of extension instructions. 4799 */ 4800 if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { 4801 XSLT_CCTXT(style)->inode->extContentHandled = 1; 4802 } 4803 4804 if (templ->children != NULL) { 4805 xmlNodePtr child = templ->children; 4806 /* 4807 * Process xsl:param elements, which can only occur as the 4808 * immediate children of xsl:template (well, and of any 4809 * user-defined extension instruction if needed). 4810 */ 4811 do { 4812 if ((child->type == XML_ELEMENT_NODE) && 4813 IS_XSLT_ELEM_FAST(child) && 4814 IS_XSLT_NAME(child, "param")) 4815 { 4816 XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM; 4817 xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); 4818 } else 4819 break; 4820 child = child->next; 4821 } while (child != NULL); 4822 /* 4823 * Parse the content and register the pattern. 4824 */ 4825 xsltParseSequenceConstructor(XSLT_CCTXT(style), child); 4826 } 4827} 4828 4829#else /* XSLT_REFACTORED */ 4830 4831/** 4832 * xsltParseTemplateContent: 4833 * @style: the XSLT stylesheet 4834 * @templ: the container node (can be a document for literal results) 4835 * 4836 * parse a template content-model 4837 * Clean-up the template content from unwanted ignorable blank nodes 4838 * and process xslt:text 4839 */ 4840void 4841xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { 4842 xmlNodePtr cur, delete; 4843 4844 if ((style == NULL) || (templ == NULL) || 4845 (templ->type == XML_NAMESPACE_DECL)) return; 4846 4847 /* 4848 * This content comes from the stylesheet 4849 * For stylesheets, the set of whitespace-preserving 4850 * element names consists of just xsl:text. 4851 */ 4852 cur = templ->children; 4853 delete = NULL; 4854 while (cur != NULL) { 4855 if (delete != NULL) { 4856#ifdef WITH_XSLT_DEBUG_BLANKS 4857 xsltGenericDebug(xsltGenericDebugContext, 4858 "xsltParseTemplateContent: removing text\n"); 4859#endif 4860 xmlUnlinkNode(delete); 4861 xmlFreeNode(delete); 4862 delete = NULL; 4863 } 4864 if (IS_XSLT_ELEM(cur)) { 4865 if (IS_XSLT_NAME(cur, "text")) { 4866 /* 4867 * TODO: Processing of xsl:text should be moved to 4868 * xsltPrecomputeStylesheet(), since otherwise this 4869 * will be performed for every multiply included 4870 * stylesheet; i.e. this here is not skipped with 4871 * the use of the style->nopreproc flag. 4872 */ 4873 if (cur->children != NULL) { 4874 xmlChar *prop; 4875 xmlNodePtr text = cur->children, next; 4876 int noesc = 0; 4877 4878 prop = xmlGetNsProp(cur, 4879 (const xmlChar *)"disable-output-escaping", 4880 NULL); 4881 if (prop != NULL) { 4882#ifdef WITH_XSLT_DEBUG_PARSING 4883 xsltGenericDebug(xsltGenericDebugContext, 4884 "Disable escaping: %s\n", text->content); 4885#endif 4886 if (xmlStrEqual(prop, (const xmlChar *)"yes")) { 4887 noesc = 1; 4888 } else if (!xmlStrEqual(prop, 4889 (const xmlChar *)"no")){ 4890 xsltTransformError(NULL, style, cur, 4891 "xsl:text: disable-output-escaping allows only yes or no\n"); 4892 style->warnings++; 4893 4894 } 4895 xmlFree(prop); 4896 } 4897 4898 while (text != NULL) { 4899 if (text->type == XML_COMMENT_NODE) { 4900 text = text->next; 4901 continue; 4902 } 4903 if ((text->type != XML_TEXT_NODE) && 4904 (text->type != XML_CDATA_SECTION_NODE)) { 4905 xsltTransformError(NULL, style, cur, 4906 "xsltParseTemplateContent: xslt:text content problem\n"); 4907 style->errors++; 4908 break; 4909 } 4910 if ((noesc) && (text->type != XML_CDATA_SECTION_NODE)) 4911 text->name = xmlStringTextNoenc; 4912 text = text->next; 4913 } 4914 4915 /* 4916 * replace xsl:text by the list of childs 4917 */ 4918 if (text == NULL) { 4919 text = cur->children; 4920 while (text != NULL) { 4921 if ((style->internalized) && 4922 (text->content != NULL) && 4923 (!xmlDictOwns(style->dict, text->content))) { 4924 4925 /* 4926 * internalize the text string 4927 */ 4928 if (text->doc->dict != NULL) { 4929 const xmlChar *tmp; 4930 4931 tmp = xmlDictLookup(text->doc->dict, 4932 text->content, -1); 4933 if (tmp != text->content) { 4934 xmlNodeSetContent(text, NULL); 4935 text->content = (xmlChar *) tmp; 4936 } 4937 } 4938 } 4939 4940 next = text->next; 4941 xmlUnlinkNode(text); 4942 xmlAddPrevSibling(cur, text); 4943 text = next; 4944 } 4945 } 4946 } 4947 delete = cur; 4948 goto skip_children; 4949 } 4950 } 4951 else if ((cur->ns != NULL) && (style->nsDefs != NULL) && 4952 (xsltCheckExtPrefix(style, cur->ns->prefix))) 4953 { 4954 /* 4955 * okay this is an extension element compile it too 4956 */ 4957 xsltStylePreCompute(style, cur); 4958 } 4959 else if (cur->type == XML_ELEMENT_NODE) 4960 { 4961 /* 4962 * This is an element which will be output as part of the 4963 * template exectution, precompile AVT if found. 4964 */ 4965 if ((cur->ns == NULL) && (style->defaultAlias != NULL)) { 4966 cur->ns = xmlSearchNsByHref(cur->doc, cur, 4967 style->defaultAlias); 4968 } 4969 if (cur->properties != NULL) { 4970 xmlAttrPtr attr = cur->properties; 4971 4972 while (attr != NULL) { 4973 xsltCompileAttr(style, attr); 4974 attr = attr->next; 4975 } 4976 } 4977 } 4978 /* 4979 * Skip to next node 4980 */ 4981 if (cur->children != NULL) { 4982 if (cur->children->type != XML_ENTITY_DECL) { 4983 cur = cur->children; 4984 continue; 4985 } 4986 } 4987skip_children: 4988 if (cur->next != NULL) { 4989 cur = cur->next; 4990 continue; 4991 } 4992 4993 do { 4994 cur = cur->parent; 4995 if (cur == NULL) 4996 break; 4997 if (cur == templ) { 4998 cur = NULL; 4999 break; 5000 } 5001 if (cur->next != NULL) { 5002 cur = cur->next; 5003 break; 5004 } 5005 } while (cur != NULL); 5006 } 5007 if (delete != NULL) { 5008#ifdef WITH_XSLT_DEBUG_PARSING 5009 xsltGenericDebug(xsltGenericDebugContext, 5010 "xsltParseTemplateContent: removing text\n"); 5011#endif 5012 xmlUnlinkNode(delete); 5013 xmlFreeNode(delete); 5014 delete = NULL; 5015 } 5016 5017 /* 5018 * Skip the first params 5019 */ 5020 cur = templ->children; 5021 while (cur != NULL) { 5022 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param")))) 5023 break; 5024 cur = cur->next; 5025 } 5026 5027 /* 5028 * Browse the remainder of the template 5029 */ 5030 while (cur != NULL) { 5031 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { 5032 xmlNodePtr param = cur; 5033 5034 xsltTransformError(NULL, style, cur, 5035 "xsltParseTemplateContent: ignoring misplaced param element\n"); 5036 if (style != NULL) style->warnings++; 5037 cur = cur->next; 5038 xmlUnlinkNode(param); 5039 xmlFreeNode(param); 5040 } else 5041 break; 5042 } 5043} 5044 5045#endif /* else XSLT_REFACTORED */ 5046 5047/** 5048 * xsltParseStylesheetKey: 5049 * @style: the XSLT stylesheet 5050 * @key: the "key" element 5051 * 5052 * <!-- Category: top-level-element --> 5053 * <xsl:key name = qname, match = pattern, use = expression /> 5054 * 5055 * parse an XSLT stylesheet key definition and register it 5056 */ 5057 5058static void 5059xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) { 5060 xmlChar *prop = NULL; 5061 xmlChar *use = NULL; 5062 xmlChar *match = NULL; 5063 xmlChar *name = NULL; 5064 xmlChar *nameURI = NULL; 5065 5066 if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE)) 5067 return; 5068 5069 /* 5070 * Get arguments 5071 */ 5072 prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL); 5073 if (prop != NULL) { 5074 const xmlChar *URI; 5075 5076 /* 5077 * TODO: Don't use xsltGetQNameURI(). 5078 */ 5079 URI = xsltGetQNameURI(key, &prop); 5080 if (prop == NULL) { 5081 if (style != NULL) style->errors++; 5082 goto error; 5083 } else { 5084 name = prop; 5085 if (URI != NULL) 5086 nameURI = xmlStrdup(URI); 5087 } 5088#ifdef WITH_XSLT_DEBUG_PARSING 5089 xsltGenericDebug(xsltGenericDebugContext, 5090 "xsltParseStylesheetKey: name %s\n", name); 5091#endif 5092 } else { 5093 xsltTransformError(NULL, style, key, 5094 "xsl:key : error missing name\n"); 5095 if (style != NULL) style->errors++; 5096 goto error; 5097 } 5098 5099 match = xmlGetNsProp(key, (const xmlChar *)"match", NULL); 5100 if (match == NULL) { 5101 xsltTransformError(NULL, style, key, 5102 "xsl:key : error missing match\n"); 5103 if (style != NULL) style->errors++; 5104 goto error; 5105 } 5106 5107 use = xmlGetNsProp(key, (const xmlChar *)"use", NULL); 5108 if (use == NULL) { 5109 xsltTransformError(NULL, style, key, 5110 "xsl:key : error missing use\n"); 5111 if (style != NULL) style->errors++; 5112 goto error; 5113 } 5114 5115 /* 5116 * register the keys 5117 */ 5118 xsltAddKey(style, name, nameURI, match, use, key); 5119 5120 5121error: 5122 if (use != NULL) 5123 xmlFree(use); 5124 if (match != NULL) 5125 xmlFree(match); 5126 if (name != NULL) 5127 xmlFree(name); 5128 if (nameURI != NULL) 5129 xmlFree(nameURI); 5130 5131 if (key->children != NULL) { 5132 xsltParseContentError(style, key->children); 5133 } 5134} 5135 5136#ifdef XSLT_REFACTORED 5137/** 5138 * xsltParseXSLTTemplate: 5139 * @style: the XSLT stylesheet 5140 * @template: the "template" element 5141 * 5142 * parse an XSLT stylesheet template building the associated structures 5143 * TODO: Is @style ever expected to be NULL? 5144 * 5145 * Called from: 5146 * xsltParseXSLTStylesheet() 5147 * xsltParseStylesheetTop() 5148 */ 5149 5150static void 5151xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) { 5152 xsltTemplatePtr templ; 5153 xmlChar *prop; 5154 double priority; 5155 5156 if ((cctxt == NULL) || (templNode == NULL) || 5157 (templNode->type != XML_ELEMENT_NODE)) 5158 return; 5159 5160 /* 5161 * Create and link the structure 5162 */ 5163 templ = xsltNewTemplate(); 5164 if (templ == NULL) 5165 return; 5166 5167 xsltCompilerNodePush(cctxt, templNode); 5168 if (templNode->nsDef != NULL) 5169 cctxt->inode->inScopeNs = 5170 xsltCompilerBuildInScopeNsList(cctxt, templNode); 5171 5172 templ->next = cctxt->style->templates; 5173 cctxt->style->templates = templ; 5174 templ->style = cctxt->style; 5175 5176 /* 5177 * Attribute "mode". 5178 */ 5179 prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL); 5180 if (prop != NULL) { 5181 const xmlChar *modeURI; 5182 5183 /* 5184 * TODO: We need a standardized function for extraction 5185 * of namespace names and local names from QNames. 5186 * Don't use xsltGetQNameURI() as it cannot channe� 5187 * reports through the context. 5188 */ 5189 modeURI = xsltGetQNameURI(templNode, &prop); 5190 if (prop == NULL) { 5191 cctxt->style->errors++; 5192 goto error; 5193 } 5194 templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1); 5195 xmlFree(prop); 5196 prop = NULL; 5197 if (xmlValidateNCName(templ->mode, 0)) { 5198 xsltTransformError(NULL, cctxt->style, templNode, 5199 "xsl:template: Attribute 'mode': The local part '%s' " 5200 "of the value is not a valid NCName.\n", templ->name); 5201 cctxt->style->errors++; 5202 goto error; 5203 } 5204 if (modeURI != NULL) 5205 templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1); 5206#ifdef WITH_XSLT_DEBUG_PARSING 5207 xsltGenericDebug(xsltGenericDebugContext, 5208 "xsltParseXSLTTemplate: mode %s\n", templ->mode); 5209#endif 5210 } 5211 /* 5212 * Attribute "match". 5213 */ 5214 prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL); 5215 if (prop != NULL) { 5216 templ->match = prop; 5217 prop = NULL; 5218 } 5219 /* 5220 * Attribute "priority". 5221 */ 5222 prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL); 5223 if (prop != NULL) { 5224 priority = xmlXPathStringEvalNumber(prop); 5225 templ->priority = (float) priority; 5226 xmlFree(prop); 5227 prop = NULL; 5228 } 5229 /* 5230 * Attribute "name". 5231 */ 5232 prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL); 5233 if (prop != NULL) { 5234 const xmlChar *nameURI; 5235 xsltTemplatePtr curTempl; 5236 5237 /* 5238 * TODO: Don't use xsltGetQNameURI(). 5239 */ 5240 nameURI = xsltGetQNameURI(templNode, &prop); 5241 if (prop == NULL) { 5242 cctxt->style->errors++; 5243 goto error; 5244 } 5245 templ->name = xmlDictLookup(cctxt->style->dict, prop, -1); 5246 xmlFree(prop); 5247 prop = NULL; 5248 if (xmlValidateNCName(templ->name, 0)) { 5249 xsltTransformError(NULL, cctxt->style, templNode, 5250 "xsl:template: Attribute 'name': The local part '%s' of " 5251 "the value is not a valid NCName.\n", templ->name); 5252 cctxt->style->errors++; 5253 goto error; 5254 } 5255 if (nameURI != NULL) 5256 templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1); 5257 curTempl = templ->next; 5258 while (curTempl != NULL) { 5259 if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) && 5260 xmlStrEqual(curTempl->nameURI, nameURI) ) || 5261 (nameURI == NULL && curTempl->nameURI == NULL && 5262 xmlStrEqual(curTempl->name, templ->name))) 5263 { 5264 xsltTransformError(NULL, cctxt->style, templNode, 5265 "xsl:template: error duplicate name '%s'\n", templ->name); 5266 cctxt->style->errors++; 5267 goto error; 5268 } 5269 curTempl = curTempl->next; 5270 } 5271 } 5272 if (templNode->children != NULL) { 5273 xsltParseTemplateContent(cctxt->style, templNode); 5274 /* 5275 * MAYBE TODO: Custom behaviour: In order to stay compatible with 5276 * Xalan and MSXML(.NET), we could allow whitespace 5277 * to appear before an xml:param element; this whitespace 5278 * will additionally become part of the "template". 5279 * NOTE that this is totally deviates from the spec, but 5280 * is the de facto behaviour of Xalan and MSXML(.NET). 5281 * Personally I wouldn't allow this, since if we have: 5282 * <xsl:template ...xml:space="preserve"> 5283 * <xsl:param name="foo"/> 5284 * <xsl:param name="bar"/> 5285 * <xsl:param name="zoo"/> 5286 * ... the whitespace between every xsl:param would be 5287 * added to the result tree. 5288 */ 5289 } 5290 5291 templ->elem = templNode; 5292 templ->content = templNode->children; 5293 xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI); 5294 5295error: 5296 xsltCompilerNodePop(cctxt, templNode); 5297 return; 5298} 5299 5300#else /* XSLT_REFACTORED */ 5301 5302/** 5303 * xsltParseStylesheetTemplate: 5304 * @style: the XSLT stylesheet 5305 * @template: the "template" element 5306 * 5307 * parse an XSLT stylesheet template building the associated structures 5308 */ 5309 5310static void 5311xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { 5312 xsltTemplatePtr ret; 5313 xmlChar *prop; 5314 xmlChar *mode = NULL; 5315 xmlChar *modeURI = NULL; 5316 double priority; 5317 5318 if ((style == NULL) || (template == NULL) || 5319 (template->type != XML_ELEMENT_NODE)) 5320 return; 5321 5322 /* 5323 * Create and link the structure 5324 */ 5325 ret = xsltNewTemplate(); 5326 if (ret == NULL) 5327 return; 5328 ret->next = style->templates; 5329 style->templates = ret; 5330 ret->style = style; 5331 5332 /* 5333 * Get inherited namespaces 5334 */ 5335 /* 5336 * TODO: Apply the optimized in-scope-namespace mechanism 5337 * as for the other XSLT instructions. 5338 */ 5339 xsltGetInheritedNsList(style, ret, template); 5340 5341 /* 5342 * Get arguments 5343 */ 5344 prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL); 5345 if (prop != NULL) { 5346 const xmlChar *URI; 5347 5348 /* 5349 * TODO: Don't use xsltGetQNameURI(). 5350 */ 5351 URI = xsltGetQNameURI(template, &prop); 5352 if (prop == NULL) { 5353 if (style != NULL) style->errors++; 5354 goto error; 5355 } else { 5356 mode = prop; 5357 if (URI != NULL) 5358 modeURI = xmlStrdup(URI); 5359 } 5360 ret->mode = xmlDictLookup(style->dict, mode, -1); 5361 ret->modeURI = xmlDictLookup(style->dict, modeURI, -1); 5362#ifdef WITH_XSLT_DEBUG_PARSING 5363 xsltGenericDebug(xsltGenericDebugContext, 5364 "xsltParseStylesheetTemplate: mode %s\n", mode); 5365#endif 5366 if (mode != NULL) xmlFree(mode); 5367 if (modeURI != NULL) xmlFree(modeURI); 5368 } 5369 prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL); 5370 if (prop != NULL) { 5371 if (ret->match != NULL) xmlFree(ret->match); 5372 ret->match = prop; 5373 } 5374 5375 prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL); 5376 if (prop != NULL) { 5377 priority = xmlXPathStringEvalNumber(prop); 5378 ret->priority = (float) priority; 5379 xmlFree(prop); 5380 } 5381 5382 prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL); 5383 if (prop != NULL) { 5384 const xmlChar *URI; 5385 xsltTemplatePtr cur; 5386 5387 /* 5388 * TODO: Don't use xsltGetQNameURI(). 5389 */ 5390 URI = xsltGetQNameURI(template, &prop); 5391 if (prop == NULL) { 5392 if (style != NULL) style->errors++; 5393 goto error; 5394 } else { 5395 if (xmlValidateNCName(prop,0)) { 5396 xsltTransformError(NULL, style, template, 5397 "xsl:template : error invalid name '%s'\n", prop); 5398 if (style != NULL) style->errors++; 5399 goto error; 5400 } 5401 ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1); 5402 xmlFree(prop); 5403 prop = NULL; 5404 if (URI != NULL) 5405 ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1); 5406 else 5407 ret->nameURI = NULL; 5408 cur = ret->next; 5409 while (cur != NULL) { 5410 if ((URI != NULL && xmlStrEqual(cur->name, ret->name) && 5411 xmlStrEqual(cur->nameURI, URI) ) || 5412 (URI == NULL && cur->nameURI == NULL && 5413 xmlStrEqual(cur->name, ret->name))) { 5414 xsltTransformError(NULL, style, template, 5415 "xsl:template: error duplicate name '%s'\n", ret->name); 5416 style->errors++; 5417 goto error; 5418 } 5419 cur = cur->next; 5420 } 5421 } 5422 } 5423 5424 /* 5425 * parse the content and register the pattern 5426 */ 5427 xsltParseTemplateContent(style, template); 5428 ret->elem = template; 5429 ret->content = template->children; 5430 xsltAddTemplate(style, ret, ret->mode, ret->modeURI); 5431 5432error: 5433 return; 5434} 5435 5436#endif /* else XSLT_REFACTORED */ 5437 5438#ifdef XSLT_REFACTORED 5439 5440/** 5441 * xsltIncludeComp: 5442 * @cctxt: the compilation contenxt 5443 * @node: the xsl:include node 5444 * 5445 * Process the xslt include node on the source node 5446 */ 5447static xsltStyleItemIncludePtr 5448xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { 5449 xsltStyleItemIncludePtr item; 5450 5451 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) 5452 return(NULL); 5453 5454 node->psvi = NULL; 5455 item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude)); 5456 if (item == NULL) { 5457 xsltTransformError(NULL, cctxt->style, node, 5458 "xsltIncludeComp : malloc failed\n"); 5459 cctxt->style->errors++; 5460 return(NULL); 5461 } 5462 memset(item, 0, sizeof(xsltStyleItemInclude)); 5463 5464 node->psvi = item; 5465 item->inst = node; 5466 item->type = XSLT_FUNC_INCLUDE; 5467 5468 item->next = cctxt->style->preComps; 5469 cctxt->style->preComps = (xsltElemPreCompPtr) item; 5470 5471 return(item); 5472} 5473 5474/** 5475 * xsltParseFindTopLevelElem: 5476 */ 5477static int 5478xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt, 5479 xmlNodePtr cur, 5480 const xmlChar *name, 5481 const xmlChar *namespaceURI, 5482 int breakOnOtherElem, 5483 xmlNodePtr *resultNode) 5484{ 5485 if (name == NULL) 5486 return(-1); 5487 5488 *resultNode = NULL; 5489 while (cur != NULL) { 5490 if (cur->type == XML_ELEMENT_NODE) { 5491 if ((cur->ns != NULL) && (cur->name != NULL)) { 5492 if ((*(cur->name) == *name) && 5493 xmlStrEqual(cur->name, name) && 5494 xmlStrEqual(cur->ns->href, namespaceURI)) 5495 { 5496 *resultNode = cur; 5497 return(1); 5498 } 5499 } 5500 if (breakOnOtherElem) 5501 break; 5502 } 5503 cur = cur->next; 5504 } 5505 *resultNode = cur; 5506 return(0); 5507} 5508 5509static int 5510xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt, 5511 xmlNodePtr node, 5512 xsltStyleType type) 5513{ 5514 int ret = 0; 5515 5516 /* 5517 * TODO: The reason why this function exists: 5518 * due to historical reasons some of the 5519 * top-level declarations are processed by functions 5520 * in other files. Since we need still to set 5521 * up the node-info and generate information like 5522 * in-scope namespaces, this is a wrapper around 5523 * those old parsing functions. 5524 */ 5525 xsltCompilerNodePush(cctxt, node); 5526 if (node->nsDef != NULL) 5527 cctxt->inode->inScopeNs = 5528 xsltCompilerBuildInScopeNsList(cctxt, node); 5529 cctxt->inode->type = type; 5530 5531 switch (type) { 5532 case XSLT_FUNC_INCLUDE: 5533 { 5534 int oldIsInclude; 5535 5536 if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL) 5537 goto exit; 5538 /* 5539 * Mark this stylesheet tree as being currently included. 5540 */ 5541 oldIsInclude = cctxt->isInclude; 5542 cctxt->isInclude = 1; 5543 5544 if (xsltParseStylesheetInclude(cctxt->style, node) != 0) { 5545 cctxt->style->errors++; 5546 } 5547 cctxt->isInclude = oldIsInclude; 5548 } 5549 break; 5550 case XSLT_FUNC_PARAM: 5551 xsltStylePreCompute(cctxt->style, node); 5552 xsltParseGlobalParam(cctxt->style, node); 5553 break; 5554 case XSLT_FUNC_VARIABLE: 5555 xsltStylePreCompute(cctxt->style, node); 5556 xsltParseGlobalVariable(cctxt->style, node); 5557 break; 5558 case XSLT_FUNC_ATTRSET: 5559 xsltParseStylesheetAttributeSet(cctxt->style, node); 5560 break; 5561 default: 5562 xsltTransformError(NULL, cctxt->style, node, 5563 "Internal error: (xsltParseTopLevelXSLTElem) " 5564 "Cannot handle this top-level declaration.\n"); 5565 cctxt->style->errors++; 5566 ret = -1; 5567 } 5568 5569exit: 5570 xsltCompilerNodePop(cctxt, node); 5571 5572 return(ret); 5573} 5574 5575#if 0 5576static int 5577xsltParseRemoveWhitespace(xmlNodePtr node) 5578{ 5579 if ((node == NULL) || (node->children == NULL)) 5580 return(0); 5581 else { 5582 xmlNodePtr delNode = NULL, child = node->children; 5583 5584 do { 5585 if (delNode) { 5586 xmlUnlinkNode(delNode); 5587 xmlFreeNode(delNode); 5588 delNode = NULL; 5589 } 5590 if (((child->type == XML_TEXT_NODE) || 5591 (child->type == XML_CDATA_SECTION_NODE)) && 5592 (IS_BLANK_NODE(child))) 5593 delNode = child; 5594 child = child->next; 5595 } while (child != NULL); 5596 if (delNode) { 5597 xmlUnlinkNode(delNode); 5598 xmlFreeNode(delNode); 5599 delNode = NULL; 5600 } 5601 } 5602 return(0); 5603} 5604#endif 5605 5606static int 5607xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 5608{ 5609#ifdef WITH_XSLT_DEBUG_PARSING 5610 int templates = 0; 5611#endif 5612 xmlNodePtr cur, start = NULL; 5613 xsltStylesheetPtr style; 5614 5615 if ((cctxt == NULL) || (node == NULL) || 5616 (node->type != XML_ELEMENT_NODE)) 5617 return(-1); 5618 5619 style = cctxt->style; 5620 /* 5621 * At this stage all import declarations of all stylesheet modules 5622 * with the same stylesheet level have been processed. 5623 * Now we can safely parse the rest of the declarations. 5624 */ 5625 if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include")) 5626 { 5627 xsltDocumentPtr include; 5628 /* 5629 * URGENT TODO: Make this work with simplified stylesheets! 5630 * I.e., when we won't find an xsl:stylesheet element. 5631 */ 5632 /* 5633 * This is as include declaration. 5634 */ 5635 include = ((xsltStyleItemIncludePtr) node->psvi)->include; 5636 if (include == NULL) { 5637 /* TODO: raise error? */ 5638 return(-1); 5639 } 5640 /* 5641 * TODO: Actually an xsl:include should locate an embedded 5642 * stylesheet as well; so the document-element won't always 5643 * be the element where the actual stylesheet is rooted at. 5644 * But such embedded stylesheets are not supported by Libxslt yet. 5645 */ 5646 node = xmlDocGetRootElement(include->doc); 5647 if (node == NULL) { 5648 return(-1); 5649 } 5650 } 5651 5652 if (node->children == NULL) 5653 return(0); 5654 /* 5655 * Push the xsl:stylesheet/xsl:transform element. 5656 */ 5657 xsltCompilerNodePush(cctxt, node); 5658 cctxt->inode->isRoot = 1; 5659 cctxt->inode->nsChanged = 0; 5660 /* 5661 * Start with the naked dummy info for literal result elements. 5662 */ 5663 cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo; 5664 5665 /* 5666 * In every case, we need to have 5667 * the in-scope namespaces of the element, where the 5668 * stylesheet is rooted at, regardless if it's an XSLT 5669 * instruction or a literal result instruction (or if 5670 * this is an embedded stylesheet). 5671 */ 5672 cctxt->inode->inScopeNs = 5673 xsltCompilerBuildInScopeNsList(cctxt, node); 5674 5675 /* 5676 * Process attributes of xsl:stylesheet/xsl:transform. 5677 * -------------------------------------------------- 5678 * Allowed are: 5679 * id = id 5680 * extension-element-prefixes = tokens 5681 * exclude-result-prefixes = tokens 5682 * version = number (mandatory) 5683 */ 5684 if (xsltParseAttrXSLTVersion(cctxt, node, 5685 XSLT_ELEMENT_CATEGORY_XSLT) == 0) 5686 { 5687 /* 5688 * Attribute "version". 5689 * XSLT 1.0: "An xsl:stylesheet element *must* have a version 5690 * attribute, indicating the version of XSLT that the 5691 * stylesheet requires". 5692 * The root element of a simplified stylesheet must also have 5693 * this attribute. 5694 */ 5695#ifdef XSLT_REFACTORED_MANDATORY_VERSION 5696 if (isXsltElem) 5697 xsltTransformError(NULL, cctxt->style, node, 5698 "The attribute 'version' is missing.\n"); 5699 cctxt->style->errors++; 5700#else 5701 /* OLD behaviour. */ 5702 xsltTransformError(NULL, cctxt->style, node, 5703 "xsl:version is missing: document may not be a stylesheet\n"); 5704 cctxt->style->warnings++; 5705#endif 5706 } 5707 /* 5708 * The namespaces declared by the attributes 5709 * "extension-element-prefixes" and 5710 * "exclude-result-prefixes" are local to *this* 5711 * stylesheet tree; i.e., they are *not* visible to 5712 * other stylesheet-modules, whether imported or included. 5713 * 5714 * Attribute "extension-element-prefixes". 5715 */ 5716 cctxt->inode->extElemNs = 5717 xsltParseExtElemPrefixes(cctxt, node, NULL, 5718 XSLT_ELEMENT_CATEGORY_XSLT); 5719 /* 5720 * Attribute "exclude-result-prefixes". 5721 */ 5722 cctxt->inode->exclResultNs = 5723 xsltParseExclResultPrefixes(cctxt, node, NULL, 5724 XSLT_ELEMENT_CATEGORY_XSLT); 5725 /* 5726 * Create/reuse info for the literal result element. 5727 */ 5728 if (cctxt->inode->nsChanged) 5729 xsltLREInfoCreate(cctxt, node, 0); 5730 /* 5731 * Processed top-level elements: 5732 * ---------------------------- 5733 * xsl:variable, xsl:param (QName, in-scope ns, 5734 * expression (vars allowed)) 5735 * xsl:attribute-set (QName, in-scope ns) 5736 * xsl:strip-space, xsl:preserve-space (XPath NameTests, 5737 * in-scope ns) 5738 * I *think* global scope, merge with includes 5739 * xsl:output (QName, in-scope ns) 5740 * xsl:key (QName, in-scope ns, pattern, 5741 * expression (vars *not* allowed)) 5742 * xsl:decimal-format (QName, needs in-scope ns) 5743 * xsl:namespace-alias (in-scope ns) 5744 * global scope, merge with includes 5745 * xsl:template (last, QName, pattern) 5746 * 5747 * (whitespace-only text-nodes have *not* been removed 5748 * yet; this will be done in xsltParseSequenceConstructor) 5749 * 5750 * Report misplaced child-nodes first. 5751 */ 5752 cur = node->children; 5753 while (cur != NULL) { 5754 if (cur->type == XML_TEXT_NODE) { 5755 xsltTransformError(NULL, style, cur, 5756 "Misplaced text node (content: '%s').\n", 5757 (cur->content != NULL) ? cur->content : BAD_CAST ""); 5758 style->errors++; 5759 } else if (cur->type != XML_ELEMENT_NODE) { 5760 xsltTransformError(NULL, style, cur, "Misplaced node.\n"); 5761 style->errors++; 5762 } 5763 cur = cur->next; 5764 } 5765 /* 5766 * Skip xsl:import elements; they have been processed 5767 * already. 5768 */ 5769 cur = node->children; 5770 while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, 5771 BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) 5772 cur = cur->next; 5773 if (cur == NULL) 5774 goto exit; 5775 5776 start = cur; 5777 /* 5778 * Process all top-level xsl:param elements. 5779 */ 5780 while ((cur != NULL) && 5781 xsltParseFindTopLevelElem(cctxt, cur, 5782 BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1) 5783 { 5784 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); 5785 cur = cur->next; 5786 } 5787 /* 5788 * Process all top-level xsl:variable elements. 5789 */ 5790 cur = start; 5791 while ((cur != NULL) && 5792 xsltParseFindTopLevelElem(cctxt, cur, 5793 BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1) 5794 { 5795 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE); 5796 cur = cur->next; 5797 } 5798 /* 5799 * Process all the rest of top-level elements. 5800 */ 5801 cur = start; 5802 while (cur != NULL) { 5803 /* 5804 * Process element nodes. 5805 */ 5806 if (cur->type == XML_ELEMENT_NODE) { 5807 if (cur->ns == NULL) { 5808 xsltTransformError(NULL, style, cur, 5809 "Unexpected top-level element in no namespace.\n"); 5810 style->errors++; 5811 cur = cur->next; 5812 continue; 5813 } 5814 /* 5815 * Process all XSLT elements. 5816 */ 5817 if (IS_XSLT_ELEM_FAST(cur)) { 5818 /* 5819 * xsl:import is only allowed at the beginning. 5820 */ 5821 if (IS_XSLT_NAME(cur, "import")) { 5822 xsltTransformError(NULL, style, cur, 5823 "Misplaced xsl:import element.\n"); 5824 style->errors++; 5825 cur = cur->next; 5826 continue; 5827 } 5828 /* 5829 * TODO: Change the return type of the parsing functions 5830 * to int. 5831 */ 5832 if (IS_XSLT_NAME(cur, "template")) { 5833#ifdef WITH_XSLT_DEBUG_PARSING 5834 templates++; 5835#endif 5836 /* 5837 * TODO: Is the position of xsl:template in the 5838 * tree significant? If not it would be easier to 5839 * parse them at a later stage. 5840 */ 5841 xsltParseXSLTTemplate(cctxt, cur); 5842 } else if (IS_XSLT_NAME(cur, "variable")) { 5843 /* NOP; done already */ 5844 } else if (IS_XSLT_NAME(cur, "param")) { 5845 /* NOP; done already */ 5846 } else if (IS_XSLT_NAME(cur, "include")) { 5847 if (cur->psvi != NULL) 5848 xsltParseXSLTStylesheetElemCore(cctxt, cur); 5849 else { 5850 xsltTransformError(NULL, style, cur, 5851 "Internal error: " 5852 "(xsltParseXSLTStylesheetElemCore) " 5853 "The xsl:include element was not compiled.\n"); 5854 style->errors++; 5855 } 5856 } else if (IS_XSLT_NAME(cur, "strip-space")) { 5857 /* No node info needed. */ 5858 xsltParseStylesheetStripSpace(style, cur); 5859 } else if (IS_XSLT_NAME(cur, "preserve-space")) { 5860 /* No node info needed. */ 5861 xsltParseStylesheetPreserveSpace(style, cur); 5862 } else if (IS_XSLT_NAME(cur, "output")) { 5863 /* No node-info needed. */ 5864 xsltParseStylesheetOutput(style, cur); 5865 } else if (IS_XSLT_NAME(cur, "key")) { 5866 /* TODO: node-info needed for expressions ? */ 5867 xsltParseStylesheetKey(style, cur); 5868 } else if (IS_XSLT_NAME(cur, "decimal-format")) { 5869 /* No node-info needed. */ 5870 xsltParseStylesheetDecimalFormat(style, cur); 5871 } else if (IS_XSLT_NAME(cur, "attribute-set")) { 5872 xsltParseTopLevelXSLTElem(cctxt, cur, 5873 XSLT_FUNC_ATTRSET); 5874 } else if (IS_XSLT_NAME(cur, "namespace-alias")) { 5875 /* NOP; done already */ 5876 } else { 5877 if (cctxt->inode->forwardsCompat) { 5878 /* 5879 * Forwards-compatible mode: 5880 * 5881 * XSLT-1: "if it is a top-level element and 5882 * XSLT 1.0 does not allow such elements as top-level 5883 * elements, then the element must be ignored along 5884 * with its content;" 5885 */ 5886 /* 5887 * TODO: I don't think we should generate a warning. 5888 */ 5889 xsltTransformError(NULL, style, cur, 5890 "Forwards-compatible mode: Ignoring unknown XSLT " 5891 "element '%s'.\n", cur->name); 5892 style->warnings++; 5893 } else { 5894 xsltTransformError(NULL, style, cur, 5895 "Unknown XSLT element '%s'.\n", cur->name); 5896 style->errors++; 5897 } 5898 } 5899 } else { 5900 xsltTopLevelFunction function; 5901 5902 /* 5903 * Process non-XSLT elements, which are in a 5904 * non-NULL namespace. 5905 */ 5906 /* 5907 * QUESTION: What does xsltExtModuleTopLevelLookup() 5908 * do exactly? 5909 */ 5910 function = xsltExtModuleTopLevelLookup(cur->name, 5911 cur->ns->href); 5912 if (function != NULL) 5913 function(style, cur); 5914#ifdef WITH_XSLT_DEBUG_PARSING 5915 xsltGenericDebug(xsltGenericDebugContext, 5916 "xsltParseXSLTStylesheetElemCore : User-defined " 5917 "data element '%s'.\n", cur->name); 5918#endif 5919 } 5920 } 5921 cur = cur->next; 5922 } 5923 5924exit: 5925 5926#ifdef WITH_XSLT_DEBUG_PARSING 5927 xsltGenericDebug(xsltGenericDebugContext, 5928 "### END of parsing top-level elements of doc '%s'.\n", 5929 node->doc->URL); 5930 xsltGenericDebug(xsltGenericDebugContext, 5931 "### Templates: %d\n", templates); 5932#ifdef XSLT_REFACTORED 5933 xsltGenericDebug(xsltGenericDebugContext, 5934 "### Max inodes: %d\n", cctxt->maxNodeInfos); 5935 xsltGenericDebug(xsltGenericDebugContext, 5936 "### Max LREs : %d\n", cctxt->maxLREs); 5937#endif /* XSLT_REFACTORED */ 5938#endif /* WITH_XSLT_DEBUG_PARSING */ 5939 5940 xsltCompilerNodePop(cctxt, node); 5941 return(0); 5942} 5943 5944/** 5945 * xsltParseXSLTStylesheet: 5946 * @cctxt: the compiler context 5947 * @node: the xsl:stylesheet/xsl:transform element-node 5948 * 5949 * Parses the xsl:stylesheet and xsl:transform element. 5950 * 5951 * <xsl:stylesheet 5952 * id = id 5953 * extension-element-prefixes = tokens 5954 * exclude-result-prefixes = tokens 5955 * version = number> 5956 * <!-- Content: (xsl:import*, top-level-elements) --> 5957 * </xsl:stylesheet> 5958 * 5959 * BIG TODO: The xsl:include stuff. 5960 * 5961 * Called by xsltParseStylesheetTree() 5962 * 5963 * Returns 0 on success, a positive result on errors and 5964 * -1 on API or internal errors. 5965 */ 5966static int 5967xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) 5968{ 5969 xmlNodePtr cur, start; 5970 5971 if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) 5972 return(-1); 5973 5974 if (node->children == NULL) 5975 goto exit; 5976 5977 /* 5978 * Process top-level elements: 5979 * xsl:import (must be first) 5980 * xsl:include (this is just a pre-processing) 5981 */ 5982 cur = node->children; 5983 /* 5984 * Process xsl:import elements. 5985 * XSLT 1.0: "The xsl:import element children must precede all 5986 * other element children of an xsl:stylesheet element, 5987 * including any xsl:include element children." 5988 */ 5989 while ((cur != NULL) && 5990 xsltParseFindTopLevelElem(cctxt, cur, 5991 BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) 5992 { 5993 if (xsltParseStylesheetImport(cctxt->style, cur) != 0) { 5994 cctxt->style->errors++; 5995 } 5996 cur = cur->next; 5997 } 5998 if (cur == NULL) 5999 goto exit; 6000 start = cur; 6001 /* 6002 * Pre-process all xsl:include elements. 6003 */ 6004 cur = start; 6005 while ((cur != NULL) && 6006 xsltParseFindTopLevelElem(cctxt, cur, 6007 BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1) 6008 { 6009 xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE); 6010 cur = cur->next; 6011 } 6012 /* 6013 * Pre-process all xsl:namespace-alias elements. 6014 * URGENT TODO: This won't work correctly: the order of included 6015 * aliases and aliases defined here is significant. 6016 */ 6017 cur = start; 6018 while ((cur != NULL) && 6019 xsltParseFindTopLevelElem(cctxt, cur, 6020 BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1) 6021 { 6022 xsltNamespaceAlias(cctxt->style, cur); 6023 cur = cur->next; 6024 } 6025 6026 if (cctxt->isInclude) { 6027 /* 6028 * If this stylesheet is intended for inclusion, then 6029 * we will process only imports and includes. 6030 */ 6031 goto exit; 6032 } 6033 /* 6034 * Now parse the rest of the top-level elements. 6035 */ 6036 xsltParseXSLTStylesheetElemCore(cctxt, node); 6037exit: 6038 6039 return(0); 6040} 6041 6042#else /* XSLT_REFACTORED */ 6043 6044/** 6045 * xsltParseStylesheetTop: 6046 * @style: the XSLT stylesheet 6047 * @top: the top level "stylesheet" or "transform" element 6048 * 6049 * scan the top level elements of an XSL stylesheet 6050 */ 6051static void 6052xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { 6053 xmlNodePtr cur; 6054 xmlChar *prop; 6055#ifdef WITH_XSLT_DEBUG_PARSING 6056 int templates = 0; 6057#endif 6058 6059 if ((top == NULL) || (top->type != XML_ELEMENT_NODE)) 6060 return; 6061 6062 prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL); 6063 if (prop == NULL) { 6064 xsltTransformError(NULL, style, top, 6065 "xsl:version is missing: document may not be a stylesheet\n"); 6066 if (style != NULL) style->warnings++; 6067 } else { 6068 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) && 6069 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) { 6070 xsltTransformError(NULL, style, top, 6071 "xsl:version: only 1.0 features are supported\n"); 6072 if (style != NULL) { 6073 style->forwards_compatible = 1; 6074 style->warnings++; 6075 } 6076 } 6077 xmlFree(prop); 6078 } 6079 6080 /* 6081 * process xsl:import elements 6082 */ 6083 cur = top->children; 6084 while (cur != NULL) { 6085 if (IS_BLANK_NODE(cur)) { 6086 cur = cur->next; 6087 continue; 6088 } 6089 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) { 6090 if (xsltParseStylesheetImport(style, cur) != 0) 6091 if (style != NULL) style->errors++; 6092 } else 6093 break; 6094 cur = cur->next; 6095 } 6096 6097 /* 6098 * process other top-level elements 6099 */ 6100 while (cur != NULL) { 6101 if (IS_BLANK_NODE(cur)) { 6102 cur = cur->next; 6103 continue; 6104 } 6105 if (cur->type == XML_TEXT_NODE) { 6106 if (cur->content != NULL) { 6107 xsltTransformError(NULL, style, cur, 6108 "misplaced text node: '%s'\n", cur->content); 6109 } 6110 if (style != NULL) style->errors++; 6111 cur = cur->next; 6112 continue; 6113 } 6114 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) { 6115 xsltGenericError(xsltGenericErrorContext, 6116 "Found a top-level element %s with null namespace URI\n", 6117 cur->name); 6118 if (style != NULL) style->errors++; 6119 cur = cur->next; 6120 continue; 6121 } 6122 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) { 6123 xsltTopLevelFunction function; 6124 6125 function = xsltExtModuleTopLevelLookup(cur->name, 6126 cur->ns->href); 6127 if (function != NULL) 6128 function(style, cur); 6129 6130#ifdef WITH_XSLT_DEBUG_PARSING 6131 xsltGenericDebug(xsltGenericDebugContext, 6132 "xsltParseStylesheetTop : found foreign element %s\n", 6133 cur->name); 6134#endif 6135 cur = cur->next; 6136 continue; 6137 } 6138 if (IS_XSLT_NAME(cur, "import")) { 6139 xsltTransformError(NULL, style, cur, 6140 "xsltParseStylesheetTop: ignoring misplaced import element\n"); 6141 if (style != NULL) style->errors++; 6142 } else if (IS_XSLT_NAME(cur, "include")) { 6143 if (xsltParseStylesheetInclude(style, cur) != 0) 6144 if (style != NULL) style->errors++; 6145 } else if (IS_XSLT_NAME(cur, "strip-space")) { 6146 xsltParseStylesheetStripSpace(style, cur); 6147 } else if (IS_XSLT_NAME(cur, "preserve-space")) { 6148 xsltParseStylesheetPreserveSpace(style, cur); 6149 } else if (IS_XSLT_NAME(cur, "output")) { 6150 xsltParseStylesheetOutput(style, cur); 6151 } else if (IS_XSLT_NAME(cur, "key")) { 6152 xsltParseStylesheetKey(style, cur); 6153 } else if (IS_XSLT_NAME(cur, "decimal-format")) { 6154 xsltParseStylesheetDecimalFormat(style, cur); 6155 } else if (IS_XSLT_NAME(cur, "attribute-set")) { 6156 xsltParseStylesheetAttributeSet(style, cur); 6157 } else if (IS_XSLT_NAME(cur, "variable")) { 6158 xsltParseGlobalVariable(style, cur); 6159 } else if (IS_XSLT_NAME(cur, "param")) { 6160 xsltParseGlobalParam(style, cur); 6161 } else if (IS_XSLT_NAME(cur, "template")) { 6162#ifdef WITH_XSLT_DEBUG_PARSING 6163 templates++; 6164#endif 6165 xsltParseStylesheetTemplate(style, cur); 6166 } else if (IS_XSLT_NAME(cur, "namespace-alias")) { 6167 xsltNamespaceAlias(style, cur); 6168 } else { 6169 if ((style != NULL) && (style->forwards_compatible == 0)) { 6170 xsltTransformError(NULL, style, cur, 6171 "xsltParseStylesheetTop: unknown %s element\n", 6172 cur->name); 6173 if (style != NULL) style->errors++; 6174 } 6175 else { 6176 /* do Forwards-Compatible Processing */ 6177 xsltTransformError(NULL, style, cur, 6178 "xsltParseStylesheetTop: ignoring unknown %s element\n", 6179 cur->name); 6180 if (style != NULL) style->warnings++; 6181 } 6182 } 6183 cur = cur->next; 6184 } 6185#ifdef WITH_XSLT_DEBUG_PARSING 6186 xsltGenericDebug(xsltGenericDebugContext, 6187 "parsed %d templates\n", templates); 6188#endif 6189} 6190 6191#endif /* else of XSLT_REFACTORED */ 6192 6193#ifdef XSLT_REFACTORED 6194/** 6195 * xsltParseSimplifiedStylesheetTree: 6196 * 6197 * @style: the stylesheet (TODO: Change this to the compiler context) 6198 * @doc: the document containing the stylesheet. 6199 * @node: the node where the stylesheet is rooted at 6200 * 6201 * Returns 0 in case of success, a positive result if an error occurred 6202 * and -1 on API and internal errors. 6203 */ 6204static int 6205xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt, 6206 xmlDocPtr doc, 6207 xmlNodePtr node) 6208{ 6209 xsltTemplatePtr templ; 6210 6211 if ((cctxt == NULL) || (node == NULL)) 6212 return(-1); 6213 6214 if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE) 6215 { 6216 /* 6217 * TODO: Adjust report, since this might be an 6218 * embedded stylesheet. 6219 */ 6220 xsltTransformError(NULL, cctxt->style, node, 6221 "The attribute 'xsl:version' is missing; cannot identify " 6222 "this document as an XSLT stylesheet document.\n"); 6223 cctxt->style->errors++; 6224 return(1); 6225 } 6226 6227#ifdef WITH_XSLT_DEBUG_PARSING 6228 xsltGenericDebug(xsltGenericDebugContext, 6229 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n"); 6230#endif 6231 6232 /* 6233 * Create and link the template 6234 */ 6235 templ = xsltNewTemplate(); 6236 if (templ == NULL) { 6237 return(-1); 6238 } 6239 templ->next = cctxt->style->templates; 6240 cctxt->style->templates = templ; 6241 templ->match = xmlStrdup(BAD_CAST "/"); 6242 6243 /* 6244 * Note that we push the document-node in this special case. 6245 */ 6246 xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); 6247 /* 6248 * In every case, we need to have 6249 * the in-scope namespaces of the element, where the 6250 * stylesheet is rooted at, regardless if it's an XSLT 6251 * instruction or a literal result instruction (or if 6252 * this is an embedded stylesheet). 6253 */ 6254 cctxt->inode->inScopeNs = 6255 xsltCompilerBuildInScopeNsList(cctxt, node); 6256 /* 6257 * Parse the content and register the match-pattern. 6258 */ 6259 xsltParseSequenceConstructor(cctxt, node); 6260 xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); 6261 6262 templ->elem = (xmlNodePtr) doc; 6263 templ->content = node; 6264 xsltAddTemplate(cctxt->style, templ, NULL, NULL); 6265 cctxt->style->literal_result = 1; 6266 return(0); 6267} 6268 6269#ifdef XSLT_REFACTORED_XSLT_NSCOMP 6270/** 6271 * xsltRestoreDocumentNamespaces: 6272 * @ns: map of namespaces 6273 * @doc: the document 6274 * 6275 * Restore the namespaces for the document 6276 * 6277 * Returns 0 in case of success, -1 in case of failure 6278 */ 6279int 6280xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc) 6281{ 6282 if (doc == NULL) 6283 return(-1); 6284 /* 6285 * Revert the changes we have applied to the namespace-URIs of 6286 * ns-decls. 6287 */ 6288 while (ns != NULL) { 6289 if ((ns->doc == doc) && (ns->ns != NULL)) { 6290 ns->ns->href = ns->origNsName; 6291 ns->origNsName = NULL; 6292 ns->ns = NULL; 6293 } 6294 ns = ns->next; 6295 } 6296 return(0); 6297} 6298#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ 6299 6300/** 6301 * xsltParseStylesheetProcess: 6302 * @style: the XSLT stylesheet (the current stylesheet-level) 6303 * @doc: and xmlDoc parsed XML 6304 * 6305 * Parses an XSLT stylesheet, adding the associated structures. 6306 * Called by: 6307 * xsltParseStylesheetImportedDoc() (xslt.c) 6308 * xsltParseStylesheetInclude() (imports.c) 6309 * 6310 * Returns the value of the @style parameter if everything 6311 * went right, NULL if something went amiss. 6312 */ 6313xsltStylesheetPtr 6314xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc) 6315{ 6316 xsltCompilerCtxtPtr cctxt; 6317 xmlNodePtr cur; 6318 int oldIsSimplifiedStylesheet; 6319 6320 xsltInitGlobals(); 6321 6322 if ((style == NULL) || (doc == NULL)) 6323 return(NULL); 6324 6325 cctxt = XSLT_CCTXT(style); 6326 6327 cur = xmlDocGetRootElement(doc); 6328 if (cur == NULL) { 6329 xsltTransformError(NULL, style, (xmlNodePtr) doc, 6330 "xsltParseStylesheetProcess : empty stylesheet\n"); 6331 return(NULL); 6332 } 6333 oldIsSimplifiedStylesheet = cctxt->simplified; 6334 6335 if ((IS_XSLT_ELEM(cur)) && 6336 ((IS_XSLT_NAME(cur, "stylesheet")) || 6337 (IS_XSLT_NAME(cur, "transform")))) { 6338#ifdef WITH_XSLT_DEBUG_PARSING 6339 xsltGenericDebug(xsltGenericDebugContext, 6340 "xsltParseStylesheetProcess : found stylesheet\n"); 6341#endif 6342 cctxt->simplified = 0; 6343 style->literal_result = 0; 6344 } else { 6345 cctxt->simplified = 1; 6346 style->literal_result = 1; 6347 } 6348 /* 6349 * Pre-process the stylesheet if not already done before. 6350 * This will remove PIs and comments, merge adjacent 6351 * text nodes, internalize strings, etc. 6352 */ 6353 if (! style->nopreproc) 6354 xsltParsePreprocessStylesheetTree(cctxt, cur); 6355 /* 6356 * Parse and compile the stylesheet. 6357 */ 6358 if (style->literal_result == 0) { 6359 if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0) 6360 return(NULL); 6361 } else { 6362 if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0) 6363 return(NULL); 6364 } 6365 6366 cctxt->simplified = oldIsSimplifiedStylesheet; 6367 6368 return(style); 6369} 6370 6371#else /* XSLT_REFACTORED */ 6372 6373/** 6374 * xsltParseStylesheetProcess: 6375 * @ret: the XSLT stylesheet (the current stylesheet-level) 6376 * @doc: and xmlDoc parsed XML 6377 * 6378 * Parses an XSLT stylesheet, adding the associated structures. 6379 * Called by: 6380 * xsltParseStylesheetImportedDoc() (xslt.c) 6381 * xsltParseStylesheetInclude() (imports.c) 6382 * 6383 * Returns the value of the @style parameter if everything 6384 * went right, NULL if something went amiss. 6385 */ 6386xsltStylesheetPtr 6387xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { 6388 xmlNodePtr cur; 6389 6390 xsltInitGlobals(); 6391 6392 if (doc == NULL) 6393 return(NULL); 6394 if (ret == NULL) 6395 return(ret); 6396 6397 /* 6398 * First steps, remove blank nodes, 6399 * locate the xsl:stylesheet element and the 6400 * namespace declaration. 6401 */ 6402 cur = xmlDocGetRootElement(doc); 6403 if (cur == NULL) { 6404 xsltTransformError(NULL, ret, (xmlNodePtr) doc, 6405 "xsltParseStylesheetProcess : empty stylesheet\n"); 6406 return(NULL); 6407 } 6408 6409 if ((IS_XSLT_ELEM(cur)) && 6410 ((IS_XSLT_NAME(cur, "stylesheet")) || 6411 (IS_XSLT_NAME(cur, "transform")))) { 6412#ifdef WITH_XSLT_DEBUG_PARSING 6413 xsltGenericDebug(xsltGenericDebugContext, 6414 "xsltParseStylesheetProcess : found stylesheet\n"); 6415#endif 6416 ret->literal_result = 0; 6417 xsltParseStylesheetExcludePrefix(ret, cur, 1); 6418 xsltParseStylesheetExtPrefix(ret, cur, 1); 6419 } else { 6420 xsltParseStylesheetExcludePrefix(ret, cur, 0); 6421 xsltParseStylesheetExtPrefix(ret, cur, 0); 6422 ret->literal_result = 1; 6423 } 6424 if (!ret->nopreproc) { 6425 xsltPrecomputeStylesheet(ret, cur); 6426 } 6427 if (ret->literal_result == 0) { 6428 xsltParseStylesheetTop(ret, cur); 6429 } else { 6430 xmlChar *prop; 6431 xsltTemplatePtr template; 6432 6433 /* 6434 * the document itself might be the template, check xsl:version 6435 */ 6436 prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); 6437 if (prop == NULL) { 6438 xsltTransformError(NULL, ret, cur, 6439 "xsltParseStylesheetProcess : document is not a stylesheet\n"); 6440 return(NULL); 6441 } 6442 6443#ifdef WITH_XSLT_DEBUG_PARSING 6444 xsltGenericDebug(xsltGenericDebugContext, 6445 "xsltParseStylesheetProcess : document is stylesheet\n"); 6446#endif 6447 6448 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) { 6449 xsltTransformError(NULL, ret, cur, 6450 "xsl:version: only 1.0 features are supported\n"); 6451 /* TODO set up compatibility when not XSLT 1.0 */ 6452 ret->warnings++; 6453 } 6454 xmlFree(prop); 6455 6456 /* 6457 * Create and link the template 6458 */ 6459 template = xsltNewTemplate(); 6460 if (template == NULL) { 6461 return(NULL); 6462 } 6463 template->next = ret->templates; 6464 ret->templates = template; 6465 template->match = xmlStrdup((const xmlChar *)"/"); 6466 6467 /* 6468 * parse the content and register the pattern 6469 */ 6470 xsltParseTemplateContent(ret, (xmlNodePtr) doc); 6471 template->elem = (xmlNodePtr) doc; 6472 template->content = doc->children; 6473 xsltAddTemplate(ret, template, NULL, NULL); 6474 ret->literal_result = 1; 6475 } 6476 6477 return(ret); 6478} 6479 6480#endif /* else of XSLT_REFACTORED */ 6481 6482/** 6483 * xsltParseStylesheetImportedDoc: 6484 * @doc: an xmlDoc parsed XML 6485 * @parentStyle: pointer to the parent stylesheet (if it exists) 6486 * 6487 * parse an XSLT stylesheet building the associated structures 6488 * except the processing not needed for imported documents. 6489 * 6490 * Returns a new XSLT stylesheet structure. 6491 */ 6492 6493xsltStylesheetPtr 6494xsltParseStylesheetImportedDoc(xmlDocPtr doc, 6495 xsltStylesheetPtr parentStyle) { 6496 xsltStylesheetPtr retStyle; 6497 6498 if (doc == NULL) 6499 return(NULL); 6500 6501 retStyle = xsltNewStylesheet(); 6502 if (retStyle == NULL) 6503 return(NULL); 6504 /* 6505 * Set the importing stylesheet module; also used to detect recursion. 6506 */ 6507 retStyle->parent = parentStyle; 6508 /* 6509 * Adjust the string dict. 6510 */ 6511 if (doc->dict != NULL) { 6512 xmlDictFree(retStyle->dict); 6513 retStyle->dict = doc->dict; 6514#ifdef WITH_XSLT_DEBUG 6515 xsltGenericDebug(xsltGenericDebugContext, 6516 "reusing dictionary from %s for stylesheet\n", 6517 doc->URL); 6518#endif 6519 xmlDictReference(retStyle->dict); 6520 } 6521 6522 /* 6523 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict 6524 * the stylesheet to containt distinct namespace prefixes. 6525 */ 6526 xsltGatherNamespaces(retStyle); 6527 6528#ifdef XSLT_REFACTORED 6529 { 6530 xsltCompilerCtxtPtr cctxt; 6531 xsltStylesheetPtr oldCurSheet; 6532 6533 if (parentStyle == NULL) { 6534 xsltPrincipalStylesheetDataPtr principalData; 6535 /* 6536 * Principal stylesheet 6537 * -------------------- 6538 */ 6539 retStyle->principal = retStyle; 6540 /* 6541 * Create extra data for the principal stylesheet. 6542 */ 6543 principalData = xsltNewPrincipalStylesheetData(); 6544 if (principalData == NULL) { 6545 xsltFreeStylesheet(retStyle); 6546 return(NULL); 6547 } 6548 retStyle->principalData = principalData; 6549 /* 6550 * Create the compilation context 6551 * ------------------------------ 6552 * (only once; for the principal stylesheet). 6553 * This is currently the only function where the 6554 * compilation context is created. 6555 */ 6556 cctxt = xsltCompilationCtxtCreate(retStyle); 6557 if (cctxt == NULL) { 6558 xsltFreeStylesheet(retStyle); 6559 return(NULL); 6560 } 6561 retStyle->compCtxt = (void *) cctxt; 6562 cctxt->style = retStyle; 6563 cctxt->dict = retStyle->dict; 6564 cctxt->psData = principalData; 6565 /* 6566 * Push initial dummy node info. 6567 */ 6568 cctxt->depth = -1; 6569 xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); 6570 } else { 6571 /* 6572 * Imported stylesheet. 6573 */ 6574 retStyle->principal = parentStyle->principal; 6575 cctxt = parentStyle->compCtxt; 6576 retStyle->compCtxt = cctxt; 6577 } 6578 /* 6579 * Save the old and set the current stylesheet structure in the 6580 * compilation context. 6581 */ 6582 oldCurSheet = cctxt->style; 6583 cctxt->style = retStyle; 6584 6585 retStyle->doc = doc; 6586 xsltParseStylesheetProcess(retStyle, doc); 6587 6588 cctxt->style = oldCurSheet; 6589 if (parentStyle == NULL) { 6590 /* 6591 * Pop the initial dummy node info. 6592 */ 6593 xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); 6594 } else { 6595 /* 6596 * Clear the compilation context of imported 6597 * stylesheets. 6598 * TODO: really? 6599 */ 6600 /* retStyle->compCtxt = NULL; */ 6601 } 6602 /* 6603 * Free the stylesheet if there were errors. 6604 */ 6605 if (retStyle != NULL) { 6606 if (retStyle->errors != 0) { 6607#ifdef XSLT_REFACTORED_XSLT_NSCOMP 6608 /* 6609 * Restore all changes made to namespace URIs of ns-decls. 6610 */ 6611 if (cctxt->psData->nsMap) 6612 xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc); 6613#endif 6614 /* 6615 * Detach the doc from the stylesheet; otherwise the doc 6616 * will be freed in xsltFreeStylesheet(). 6617 */ 6618 retStyle->doc = NULL; 6619 /* 6620 * Cleanup the doc if its the main stylesheet. 6621 */ 6622 if (parentStyle == NULL) { 6623 xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc)); 6624 if (retStyle->compCtxt != NULL) { 6625 xsltCompilationCtxtFree(retStyle->compCtxt); 6626 retStyle->compCtxt = NULL; 6627 } 6628 } 6629 6630 xsltFreeStylesheet(retStyle); 6631 retStyle = NULL; 6632 } 6633 } 6634 } 6635 6636#else /* XSLT_REFACTORED */ 6637 /* 6638 * Old behaviour. 6639 */ 6640 retStyle->doc = doc; 6641 if (xsltParseStylesheetProcess(retStyle, doc) == NULL) { 6642 retStyle->doc = NULL; 6643 xsltFreeStylesheet(retStyle); 6644 retStyle = NULL; 6645 } 6646 if (retStyle != NULL) { 6647 if (retStyle->errors != 0) { 6648 retStyle->doc = NULL; 6649 if (parentStyle == NULL) 6650 xsltCleanupStylesheetTree(doc, 6651 xmlDocGetRootElement(doc)); 6652 xsltFreeStylesheet(retStyle); 6653 retStyle = NULL; 6654 } 6655 } 6656#endif /* else of XSLT_REFACTORED */ 6657 6658 return(retStyle); 6659} 6660 6661/** 6662 * xsltParseStylesheetDoc: 6663 * @doc: and xmlDoc parsed XML 6664 * 6665 * parse an XSLT stylesheet, building the associated structures. doc 6666 * is kept as a reference within the returned stylesheet, so changes 6667 * to doc after the parsing will be reflected when the stylesheet 6668 * is applied, and the doc is automatically freed when the 6669 * stylesheet is closed. 6670 * 6671 * Returns a new XSLT stylesheet structure. 6672 */ 6673 6674xsltStylesheetPtr 6675xsltParseStylesheetDoc(xmlDocPtr doc) { 6676 xsltStylesheetPtr ret; 6677 6678 xsltInitGlobals(); 6679 6680 ret = xsltParseStylesheetImportedDoc(doc, NULL); 6681 if (ret == NULL) 6682 return(NULL); 6683 6684 xsltResolveStylesheetAttributeSet(ret); 6685#ifdef XSLT_REFACTORED 6686 /* 6687 * Free the compilation context. 6688 * TODO: Check if it's better to move this cleanup to 6689 * xsltParseStylesheetImportedDoc(). 6690 */ 6691 if (ret->compCtxt != NULL) { 6692 xsltCompilationCtxtFree(XSLT_CCTXT(ret)); 6693 ret->compCtxt = NULL; 6694 } 6695#endif 6696 return(ret); 6697} 6698 6699/** 6700 * xsltParseStylesheetFile: 6701 * @filename: the filename/URL to the stylesheet 6702 * 6703 * Load and parse an XSLT stylesheet 6704 * 6705 * Returns a new XSLT stylesheet structure. 6706 */ 6707 6708xsltStylesheetPtr 6709xsltParseStylesheetFile(const xmlChar* filename) { 6710 xsltSecurityPrefsPtr sec; 6711 xsltStylesheetPtr ret; 6712 xmlDocPtr doc; 6713 6714 xsltInitGlobals(); 6715 6716 if (filename == NULL) 6717 return(NULL); 6718 6719#ifdef WITH_XSLT_DEBUG_PARSING 6720 xsltGenericDebug(xsltGenericDebugContext, 6721 "xsltParseStylesheetFile : parse %s\n", filename); 6722#endif 6723 6724 /* 6725 * Security framework check 6726 */ 6727 sec = xsltGetDefaultSecurityPrefs(); 6728 if (sec != NULL) { 6729 int res; 6730 6731 res = xsltCheckRead(sec, NULL, filename); 6732 if (res == 0) { 6733 xsltTransformError(NULL, NULL, NULL, 6734 "xsltParseStylesheetFile: read rights for %s denied\n", 6735 filename); 6736 return(NULL); 6737 } 6738 } 6739 6740 doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS, 6741 NULL, XSLT_LOAD_START); 6742 if (doc == NULL) { 6743 xsltTransformError(NULL, NULL, NULL, 6744 "xsltParseStylesheetFile : cannot parse %s\n", filename); 6745 return(NULL); 6746 } 6747 ret = xsltParseStylesheetDoc(doc); 6748 if (ret == NULL) { 6749 xmlFreeDoc(doc); 6750 return(NULL); 6751 } 6752 6753 return(ret); 6754} 6755 6756/************************************************************************ 6757 * * 6758 * Handling of Stylesheet PI * 6759 * * 6760 ************************************************************************/ 6761 6762#define CUR (*cur) 6763#define SKIP(val) cur += (val) 6764#define NXT(val) cur[(val)] 6765#define SKIP_BLANKS \ 6766 while (IS_BLANK(CUR)) NEXT 6767#define NEXT ((*cur) ? cur++ : cur) 6768 6769/** 6770 * xsltParseStylesheetPI: 6771 * @value: the value of the PI 6772 * 6773 * This function checks that the type is text/xml and extracts 6774 * the URI-Reference for the stylesheet 6775 * 6776 * Returns the URI-Reference for the stylesheet or NULL (it need to 6777 * be freed by the caller) 6778 */ 6779static xmlChar * 6780xsltParseStylesheetPI(const xmlChar *value) { 6781 const xmlChar *cur; 6782 const xmlChar *start; 6783 xmlChar *val; 6784 xmlChar tmp; 6785 xmlChar *href = NULL; 6786 int isXml = 0; 6787 6788 if (value == NULL) 6789 return(NULL); 6790 6791 cur = value; 6792 while (CUR != 0) { 6793 SKIP_BLANKS; 6794 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') && 6795 (NXT(3) == 'e')) { 6796 SKIP(4); 6797 SKIP_BLANKS; 6798 if (CUR != '=') 6799 continue; 6800 NEXT; 6801 if ((CUR != '\'') && (CUR != '"')) 6802 continue; 6803 tmp = CUR; 6804 NEXT; 6805 start = cur; 6806 while ((CUR != 0) && (CUR != tmp)) 6807 NEXT; 6808 if (CUR != tmp) 6809 continue; 6810 val = xmlStrndup(start, cur - start); 6811 NEXT; 6812 if (val == NULL) 6813 return(NULL); 6814 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) && 6815 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) { 6816 xmlFree(val); 6817 break; 6818 } 6819 isXml = 1; 6820 xmlFree(val); 6821 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') && 6822 (NXT(3) == 'f')) { 6823 SKIP(4); 6824 SKIP_BLANKS; 6825 if (CUR != '=') 6826 continue; 6827 NEXT; 6828 if ((CUR != '\'') && (CUR != '"')) 6829 continue; 6830 tmp = CUR; 6831 NEXT; 6832 start = cur; 6833 while ((CUR != 0) && (CUR != tmp)) 6834 NEXT; 6835 if (CUR != tmp) 6836 continue; 6837 if (href == NULL) 6838 href = xmlStrndup(start, cur - start); 6839 NEXT; 6840 } else { 6841 while ((CUR != 0) && (!IS_BLANK(CUR))) 6842 NEXT; 6843 } 6844 6845 } 6846 6847 if (!isXml) { 6848 if (href != NULL) 6849 xmlFree(href); 6850 href = NULL; 6851 } 6852 return(href); 6853} 6854 6855/** 6856 * xsltLoadStylesheetPI: 6857 * @doc: a document to process 6858 * 6859 * This function tries to locate the stylesheet PI in the given document 6860 * If found, and if contained within the document, it will extract 6861 * that subtree to build the stylesheet to process @doc (doc itself will 6862 * be modified). If found but referencing an external document it will 6863 * attempt to load it and generate a stylesheet from it. In both cases, 6864 * the resulting stylesheet and the document need to be freed once the 6865 * transformation is done. 6866 * 6867 * Returns a new XSLT stylesheet structure or NULL if not found. 6868 */ 6869xsltStylesheetPtr 6870xsltLoadStylesheetPI(xmlDocPtr doc) { 6871 xmlNodePtr child; 6872 xsltStylesheetPtr ret = NULL; 6873 xmlChar *href = NULL; 6874 xmlURIPtr URI; 6875 6876 xsltInitGlobals(); 6877 6878 if (doc == NULL) 6879 return(NULL); 6880 6881 /* 6882 * Find the text/xml stylesheet PI id any before the root 6883 */ 6884 child = doc->children; 6885 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) { 6886 if ((child->type == XML_PI_NODE) && 6887 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) { 6888 href = xsltParseStylesheetPI(child->content); 6889 if (href != NULL) 6890 break; 6891 } 6892 child = child->next; 6893 } 6894 6895 /* 6896 * If found check the href to select processing 6897 */ 6898 if (href != NULL) { 6899#ifdef WITH_XSLT_DEBUG_PARSING 6900 xsltGenericDebug(xsltGenericDebugContext, 6901 "xsltLoadStylesheetPI : found PI href=%s\n", href); 6902#endif 6903 URI = xmlParseURI((const char *) href); 6904 if (URI == NULL) { 6905 xsltTransformError(NULL, NULL, child, 6906 "xml-stylesheet : href %s is not valid\n", href); 6907 xmlFree(href); 6908 return(NULL); 6909 } 6910 if ((URI->fragment != NULL) && (URI->scheme == NULL) && 6911 (URI->opaque == NULL) && (URI->authority == NULL) && 6912 (URI->server == NULL) && (URI->user == NULL) && 6913 (URI->path == NULL) && (URI->query == NULL)) { 6914 xmlAttrPtr ID; 6915 6916#ifdef WITH_XSLT_DEBUG_PARSING 6917 xsltGenericDebug(xsltGenericDebugContext, 6918 "xsltLoadStylesheetPI : Reference to ID %s\n", href); 6919#endif 6920 if (URI->fragment[0] == '#') 6921 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1])); 6922 else 6923 ID = xmlGetID(doc, (const xmlChar *) URI->fragment); 6924 if (ID == NULL) { 6925 xsltTransformError(NULL, NULL, child, 6926 "xml-stylesheet : no ID %s found\n", URI->fragment); 6927 } else { 6928 xmlDocPtr fake; 6929 xmlNodePtr subtree, newtree; 6930 xmlNsPtr ns; 6931 6932#ifdef WITH_XSLT_DEBUG 6933 xsltGenericDebug(xsltGenericDebugContext, 6934 "creating new document from %s for embedded stylesheet\n", 6935 doc->URL); 6936#endif 6937 /* 6938 * move the subtree in a new document passed to 6939 * the stylesheet analyzer 6940 */ 6941 subtree = ID->parent; 6942 fake = xmlNewDoc(NULL); 6943 if (fake != NULL) { 6944 /* 6945 * Should the dictionary still be shared even though 6946 * the nodes are being copied rather than moved? 6947 */ 6948 fake->dict = doc->dict; 6949 xmlDictReference(doc->dict); 6950#ifdef WITH_XSLT_DEBUG 6951 xsltGenericDebug(xsltGenericDebugContext, 6952 "reusing dictionary from %s for embedded stylesheet\n", 6953 doc->URL); 6954#endif 6955 6956 newtree = xmlDocCopyNode(subtree, fake, 1); 6957 6958 fake->URL = xmlNodeGetBase(doc, subtree->parent); 6959#ifdef WITH_XSLT_DEBUG 6960 xsltGenericDebug(xsltGenericDebugContext, 6961 "set base URI for embedded stylesheet as %s\n", 6962 fake->URL); 6963#endif 6964 6965 /* 6966 * Add all namespaces in scope of embedded stylesheet to 6967 * root element of newly created stylesheet document 6968 */ 6969 while ((subtree = subtree->parent) != (xmlNodePtr)doc) { 6970 for (ns = subtree->ns; ns; ns = ns->next) { 6971 xmlNewNs(newtree, ns->href, ns->prefix); 6972 } 6973 } 6974 6975 xmlAddChild((xmlNodePtr)fake, newtree); 6976 ret = xsltParseStylesheetDoc(fake); 6977 if (ret == NULL) 6978 xmlFreeDoc(fake); 6979 } 6980 } 6981 } else { 6982 xmlChar *URL, *base; 6983 6984 /* 6985 * Reference to an external stylesheet 6986 */ 6987 6988 base = xmlNodeGetBase(doc, (xmlNodePtr) doc); 6989 URL = xmlBuildURI(href, base); 6990 if (URL != NULL) { 6991#ifdef WITH_XSLT_DEBUG_PARSING 6992 xsltGenericDebug(xsltGenericDebugContext, 6993 "xsltLoadStylesheetPI : fetching %s\n", URL); 6994#endif 6995 ret = xsltParseStylesheetFile(URL); 6996 xmlFree(URL); 6997 } else { 6998#ifdef WITH_XSLT_DEBUG_PARSING 6999 xsltGenericDebug(xsltGenericDebugContext, 7000 "xsltLoadStylesheetPI : fetching %s\n", href); 7001#endif 7002 ret = xsltParseStylesheetFile(href); 7003 } 7004 if (base != NULL) 7005 xmlFree(base); 7006 } 7007 xmlFreeURI(URI); 7008 xmlFree(href); 7009 } 7010 return(ret); 7011} 7012