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