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