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