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