1 /* 2 * preproc.c: Preprocessing of style operations 3 * 4 * References: 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 6 * 7 * Michael Kay "XSLT Programmer's Reference" pp 637-643 8 * Writing Multiple Output Files 9 * 10 * XSLT-1.1 Working Draft 11 * http://www.w3.org/TR/xslt11#multiple-output 12 * 13 * See Copyright for the status of this software. 14 * 15 * daniel@veillard.com 16 */ 17 18 #define IN_LIBXSLT 19 #include "libxslt.h" 20 21 #include <string.h> 22 23 #include <libxml/xmlmemory.h> 24 #include <libxml/parser.h> 25 #include <libxml/tree.h> 26 #include <libxml/valid.h> 27 #include <libxml/hash.h> 28 #include <libxml/uri.h> 29 #include <libxml/encoding.h> 30 #include <libxml/xmlerror.h> 31 #include "xslt.h" 32 #include "xsltutils.h" 33 #include "xsltInternals.h" 34 #include "transform.h" 35 #include "templates.h" 36 #include "variables.h" 37 #include "numbersInternals.h" 38 #include "preproc.h" 39 #include "extra.h" 40 #include "imports.h" 41 #include "extensions.h" 42 #include "pattern.h" 43 44 #ifdef WITH_XSLT_DEBUG 45 #define WITH_XSLT_DEBUG_PREPROC 46 #endif 47 48 const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; 49 50 /************************************************************************ 51 * * 52 * Grammar checks * 53 * * 54 ************************************************************************/ 55 56 #ifdef XSLT_REFACTORED 57 /* 58 * Grammar checks are now performed in xslt.c. 59 */ 60 #else 61 /** 62 * xsltCheckTopLevelElement: 63 * @style: the XSLT stylesheet 64 * @inst: the XSLT instruction 65 * @err: raise an error or not 66 * 67 * Check that the instruction is instanciated as a top level element. 68 * 69 * Returns -1 in case of error, 0 if failed and 1 in case of success 70 */ 71 static int 72 xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) { 73 xmlNodePtr parent; 74 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL)) 75 return(-1); 76 77 parent = inst->parent; 78 if (parent == NULL) { 79 if (err) { 80 xsltTransformError(NULL, style, inst, 81 "internal problem: element has no parent\n"); 82 style->errors++; 83 } 84 return(0); 85 } 86 if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) || 87 ((parent->ns != inst->ns) && 88 (!xmlStrEqual(parent->ns->href, inst->ns->href))) || 89 ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) && 90 (!xmlStrEqual(parent->name, BAD_CAST "transform")))) { 91 if (err) { 92 xsltTransformError(NULL, style, inst, 93 "element %s only allowed as child of stylesheet\n", 94 inst->name); 95 style->errors++; 96 } 97 return(0); 98 } 99 return(1); 100 } 101 102 /** 103 * xsltCheckInstructionElement: 104 * @style: the XSLT stylesheet 105 * @inst: the XSLT instruction 106 * 107 * Check that the instruction is instanciated as an instruction element. 108 */ 109 static void 110 xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) { 111 xmlNodePtr parent; 112 int has_ext; 113 114 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || 115 (style->literal_result)) 116 return; 117 118 has_ext = (style->extInfos != NULL); 119 120 parent = inst->parent; 121 if (parent == NULL) { 122 xsltTransformError(NULL, style, inst, 123 "internal problem: element has no parent\n"); 124 style->errors++; 125 return; 126 } 127 while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { 128 if (((parent->ns == inst->ns) || 129 ((parent->ns != NULL) && 130 (xmlStrEqual(parent->ns->href, inst->ns->href)))) && 131 ((xmlStrEqual(parent->name, BAD_CAST "template")) || 132 (xmlStrEqual(parent->name, BAD_CAST "param")) || 133 (xmlStrEqual(parent->name, BAD_CAST "attribute")) || 134 (xmlStrEqual(parent->name, BAD_CAST "variable")))) { 135 return; 136 } 137 138 /* 139 * if we are within an extension element all bets are off 140 * about the semantic there e.g. xsl:param within func:function 141 */ 142 if ((has_ext) && (parent->ns != NULL) && 143 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) 144 return; 145 146 parent = parent->parent; 147 } 148 xsltTransformError(NULL, style, inst, 149 "element %s only allowed within a template, variable or param\n", 150 inst->name); 151 style->errors++; 152 } 153 154 /** 155 * xsltCheckParentElement: 156 * @style: the XSLT stylesheet 157 * @inst: the XSLT instruction 158 * @allow1: allowed parent1 159 * @allow2: allowed parent2 160 * 161 * Check that the instruction is instanciated as the childre of one of the 162 * possible parents. 163 */ 164 static void 165 xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, 166 const xmlChar *allow1, const xmlChar *allow2) { 167 xmlNodePtr parent; 168 169 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || 170 (style->literal_result)) 171 return; 172 173 parent = inst->parent; 174 if (parent == NULL) { 175 xsltTransformError(NULL, style, inst, 176 "internal problem: element has no parent\n"); 177 style->errors++; 178 return; 179 } 180 if (((parent->ns == inst->ns) || 181 ((parent->ns != NULL) && 182 (xmlStrEqual(parent->ns->href, inst->ns->href)))) && 183 ((xmlStrEqual(parent->name, allow1)) || 184 (xmlStrEqual(parent->name, allow2)))) { 185 return; 186 } 187 188 if (style->extInfos != NULL) { 189 while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { 190 /* 191 * if we are within an extension element all bets are off 192 * about the semantic there e.g. xsl:param within func:function 193 */ 194 if ((parent->ns != NULL) && 195 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) 196 return; 197 198 parent = parent->parent; 199 } 200 } 201 xsltTransformError(NULL, style, inst, 202 "element %s is not allowed within that context\n", 203 inst->name); 204 style->errors++; 205 } 206 #endif 207 208 /************************************************************************ 209 * * 210 * handling of precomputed data * 211 * * 212 ************************************************************************/ 213 214 /** 215 * xsltNewStylePreComp: 216 * @style: the XSLT stylesheet 217 * @type: the construct type 218 * 219 * Create a new XSLT Style precomputed block 220 * 221 * Returns the newly allocated specialized structure 222 * or NULL in case of error 223 */ 224 static xsltStylePreCompPtr 225 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) { 226 xsltStylePreCompPtr cur; 227 #ifdef XSLT_REFACTORED 228 size_t size; 229 #endif 230 231 if (style == NULL) 232 return(NULL); 233 234 #ifdef XSLT_REFACTORED 235 /* 236 * URGENT TODO: Use specialized factory functions in order 237 * to avoid this ugliness. 238 */ 239 switch (type) { 240 case XSLT_FUNC_COPY: 241 size = sizeof(xsltStyleItemCopy); break; 242 case XSLT_FUNC_SORT: 243 size = sizeof(xsltStyleItemSort); break; 244 case XSLT_FUNC_TEXT: 245 size = sizeof(xsltStyleItemText); break; 246 case XSLT_FUNC_ELEMENT: 247 size = sizeof(xsltStyleItemElement); break; 248 case XSLT_FUNC_ATTRIBUTE: 249 size = sizeof(xsltStyleItemAttribute); break; 250 case XSLT_FUNC_COMMENT: 251 size = sizeof(xsltStyleItemComment); break; 252 case XSLT_FUNC_PI: 253 size = sizeof(xsltStyleItemPI); break; 254 case XSLT_FUNC_COPYOF: 255 size = sizeof(xsltStyleItemCopyOf); break; 256 case XSLT_FUNC_VALUEOF: 257 size = sizeof(xsltStyleItemValueOf); break;; 258 case XSLT_FUNC_NUMBER: 259 size = sizeof(xsltStyleItemNumber); break; 260 case XSLT_FUNC_APPLYIMPORTS: 261 size = sizeof(xsltStyleItemApplyImports); break; 262 case XSLT_FUNC_CALLTEMPLATE: 263 size = sizeof(xsltStyleItemCallTemplate); break; 264 case XSLT_FUNC_APPLYTEMPLATES: 265 size = sizeof(xsltStyleItemApplyTemplates); break; 266 case XSLT_FUNC_CHOOSE: 267 size = sizeof(xsltStyleItemChoose); break; 268 case XSLT_FUNC_IF: 269 size = sizeof(xsltStyleItemIf); break; 270 case XSLT_FUNC_FOREACH: 271 size = sizeof(xsltStyleItemForEach); break; 272 case XSLT_FUNC_DOCUMENT: 273 size = sizeof(xsltStyleItemDocument); break; 274 case XSLT_FUNC_WITHPARAM: 275 size = sizeof(xsltStyleItemWithParam); break; 276 case XSLT_FUNC_PARAM: 277 size = sizeof(xsltStyleItemParam); break; 278 case XSLT_FUNC_VARIABLE: 279 size = sizeof(xsltStyleItemVariable); break; 280 case XSLT_FUNC_WHEN: 281 size = sizeof(xsltStyleItemWhen); break; 282 case XSLT_FUNC_OTHERWISE: 283 size = sizeof(xsltStyleItemOtherwise); break; 284 default: 285 xsltTransformError(NULL, style, NULL, 286 "xsltNewStylePreComp : invalid type %d\n", type); 287 style->errors++; 288 return(NULL); 289 } 290 /* 291 * Create the structure. 292 */ 293 cur = (xsltStylePreCompPtr) xmlMalloc(size); 294 if (cur == NULL) { 295 xsltTransformError(NULL, style, NULL, 296 "xsltNewStylePreComp : malloc failed\n"); 297 style->errors++; 298 return(NULL); 299 } 300 memset(cur, 0, size); 301 302 #else /* XSLT_REFACTORED */ 303 /* 304 * Old behaviour. 305 */ 306 cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp)); 307 if (cur == NULL) { 308 xsltTransformError(NULL, style, NULL, 309 "xsltNewStylePreComp : malloc failed\n"); 310 style->errors++; 311 return(NULL); 312 } 313 memset(cur, 0, sizeof(xsltStylePreComp)); 314 #endif /* XSLT_REFACTORED */ 315 316 /* 317 * URGENT TODO: Better to move this to spezialized factory functions. 318 */ 319 cur->type = type; 320 switch (cur->type) { 321 case XSLT_FUNC_COPY: 322 cur->func = (xsltTransformFunction) xsltCopy;break; 323 case XSLT_FUNC_SORT: 324 cur->func = (xsltTransformFunction) xsltSort;break; 325 case XSLT_FUNC_TEXT: 326 cur->func = (xsltTransformFunction) xsltText;break; 327 case XSLT_FUNC_ELEMENT: 328 cur->func = (xsltTransformFunction) xsltElement;break; 329 case XSLT_FUNC_ATTRIBUTE: 330 cur->func = (xsltTransformFunction) xsltAttribute;break; 331 case XSLT_FUNC_COMMENT: 332 cur->func = (xsltTransformFunction) xsltComment;break; 333 case XSLT_FUNC_PI: 334 cur->func = (xsltTransformFunction) xsltProcessingInstruction; 335 break; 336 case XSLT_FUNC_COPYOF: 337 cur->func = (xsltTransformFunction) xsltCopyOf;break; 338 case XSLT_FUNC_VALUEOF: 339 cur->func = (xsltTransformFunction) xsltValueOf;break; 340 case XSLT_FUNC_NUMBER: 341 cur->func = (xsltTransformFunction) xsltNumber;break; 342 case XSLT_FUNC_APPLYIMPORTS: 343 cur->func = (xsltTransformFunction) xsltApplyImports;break; 344 case XSLT_FUNC_CALLTEMPLATE: 345 cur->func = (xsltTransformFunction) xsltCallTemplate;break; 346 case XSLT_FUNC_APPLYTEMPLATES: 347 cur->func = (xsltTransformFunction) xsltApplyTemplates;break; 348 case XSLT_FUNC_CHOOSE: 349 cur->func = (xsltTransformFunction) xsltChoose;break; 350 case XSLT_FUNC_IF: 351 cur->func = (xsltTransformFunction) xsltIf;break; 352 case XSLT_FUNC_FOREACH: 353 cur->func = (xsltTransformFunction) xsltForEach;break; 354 case XSLT_FUNC_DOCUMENT: 355 cur->func = (xsltTransformFunction) xsltDocumentElem;break; 356 case XSLT_FUNC_WITHPARAM: 357 case XSLT_FUNC_PARAM: 358 case XSLT_FUNC_VARIABLE: 359 case XSLT_FUNC_WHEN: 360 break; 361 default: 362 if (cur->func == NULL) { 363 xsltTransformError(NULL, style, NULL, 364 "xsltNewStylePreComp : no function for type %d\n", type); 365 style->errors++; 366 } 367 } 368 cur->next = style->preComps; 369 style->preComps = (xsltElemPreCompPtr) cur; 370 371 return(cur); 372 } 373 374 /** 375 * xsltFreeStylePreComp: 376 * @comp: an XSLT Style precomputed block 377 * 378 * Free up the memory allocated by @comp 379 */ 380 static void 381 xsltFreeStylePreComp(xsltStylePreCompPtr comp) { 382 if (comp == NULL) 383 return; 384 #ifdef XSLT_REFACTORED 385 /* 386 * URGENT TODO: Implement destructors. 387 */ 388 switch (comp->type) { 389 case XSLT_FUNC_LITERAL_RESULT_ELEMENT: 390 break; 391 case XSLT_FUNC_COPY: 392 break; 393 case XSLT_FUNC_SORT: { 394 xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; 395 if (item->locale != (xsltLocale)0) 396 xsltFreeLocale(item->locale); 397 if (item->comp != NULL) 398 xmlXPathFreeCompExpr(item->comp); 399 } 400 break; 401 case XSLT_FUNC_TEXT: 402 break; 403 case XSLT_FUNC_ELEMENT: 404 break; 405 case XSLT_FUNC_ATTRIBUTE: 406 break; 407 case XSLT_FUNC_COMMENT: 408 break; 409 case XSLT_FUNC_PI: 410 break; 411 case XSLT_FUNC_COPYOF: { 412 xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp; 413 if (item->comp != NULL) 414 xmlXPathFreeCompExpr(item->comp); 415 } 416 break; 417 case XSLT_FUNC_VALUEOF: { 418 xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp; 419 if (item->comp != NULL) 420 xmlXPathFreeCompExpr(item->comp); 421 } 422 break; 423 case XSLT_FUNC_NUMBER: { 424 xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp; 425 if (item->numdata.countPat != NULL) 426 xsltFreeCompMatchList(item->numdata.countPat); 427 if (item->numdata.fromPat != NULL) 428 xsltFreeCompMatchList(item->numdata.fromPat); 429 } 430 break; 431 case XSLT_FUNC_APPLYIMPORTS: 432 break; 433 case XSLT_FUNC_CALLTEMPLATE: 434 break; 435 case XSLT_FUNC_APPLYTEMPLATES: { 436 xsltStyleItemApplyTemplatesPtr item = 437 (xsltStyleItemApplyTemplatesPtr) comp; 438 if (item->comp != NULL) 439 xmlXPathFreeCompExpr(item->comp); 440 } 441 break; 442 case XSLT_FUNC_CHOOSE: 443 break; 444 case XSLT_FUNC_IF: { 445 xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp; 446 if (item->comp != NULL) 447 xmlXPathFreeCompExpr(item->comp); 448 } 449 break; 450 case XSLT_FUNC_FOREACH: { 451 xsltStyleItemForEachPtr item = 452 (xsltStyleItemForEachPtr) comp; 453 if (item->comp != NULL) 454 xmlXPathFreeCompExpr(item->comp); 455 } 456 break; 457 case XSLT_FUNC_DOCUMENT: 458 break; 459 case XSLT_FUNC_WITHPARAM: { 460 xsltStyleItemWithParamPtr item = 461 (xsltStyleItemWithParamPtr) comp; 462 if (item->comp != NULL) 463 xmlXPathFreeCompExpr(item->comp); 464 } 465 break; 466 case XSLT_FUNC_PARAM: { 467 xsltStyleItemParamPtr item = 468 (xsltStyleItemParamPtr) comp; 469 if (item->comp != NULL) 470 xmlXPathFreeCompExpr(item->comp); 471 } 472 break; 473 case XSLT_FUNC_VARIABLE: { 474 xsltStyleItemVariablePtr item = 475 (xsltStyleItemVariablePtr) comp; 476 if (item->comp != NULL) 477 xmlXPathFreeCompExpr(item->comp); 478 } 479 break; 480 case XSLT_FUNC_WHEN: { 481 xsltStyleItemWhenPtr item = 482 (xsltStyleItemWhenPtr) comp; 483 if (item->comp != NULL) 484 xmlXPathFreeCompExpr(item->comp); 485 } 486 break; 487 case XSLT_FUNC_OTHERWISE: 488 case XSLT_FUNC_FALLBACK: 489 case XSLT_FUNC_MESSAGE: 490 case XSLT_FUNC_INCLUDE: 491 case XSLT_FUNC_ATTRSET: 492 493 break; 494 default: 495 /* TODO: Raise error. */ 496 break; 497 } 498 #else 499 if (comp->locale != (xsltLocale)0) 500 xsltFreeLocale(comp->locale); 501 if (comp->comp != NULL) 502 xmlXPathFreeCompExpr(comp->comp); 503 if (comp->numdata.countPat != NULL) 504 xsltFreeCompMatchList(comp->numdata.countPat); 505 if (comp->numdata.fromPat != NULL) 506 xsltFreeCompMatchList(comp->numdata.fromPat); 507 if (comp->nsList != NULL) 508 xmlFree(comp->nsList); 509 #endif 510 511 xmlFree(comp); 512 } 513 514 515 /************************************************************************ 516 * * 517 * XSLT-1.1 extensions * 518 * * 519 ************************************************************************/ 520 521 /** 522 * xsltDocumentComp: 523 * @style: the XSLT stylesheet 524 * @inst: the instruction in the stylesheet 525 * @function: unused 526 * 527 * Pre process an XSLT-1.1 document element 528 * 529 * Returns a precompiled data structure for the element 530 */ 531 xsltElemPreCompPtr 532 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, 533 xsltTransformFunction function ATTRIBUTE_UNUSED) { 534 #ifdef XSLT_REFACTORED 535 xsltStyleItemDocumentPtr comp; 536 #else 537 xsltStylePreCompPtr comp; 538 #endif 539 const xmlChar *filename = NULL; 540 541 /* 542 * As of 2006-03-30, this function is currently defined in Libxslt 543 * to be used for: 544 * (in libxslt/extra.c) 545 * "output" in XSLT_SAXON_NAMESPACE 546 * "write" XSLT_XALAN_NAMESPACE 547 * "document" XSLT_XT_NAMESPACE 548 * "document" XSLT_NAMESPACE (from the abandoned old working 549 * draft of XSLT 1.1) 550 * (in libexslt/common.c) 551 * "document" in EXSLT_COMMON_NAMESPACE 552 */ 553 #ifdef XSLT_REFACTORED 554 comp = (xsltStyleItemDocumentPtr) 555 xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); 556 #else 557 comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); 558 #endif 559 560 if (comp == NULL) 561 return (NULL); 562 comp->inst = inst; 563 comp->ver11 = 0; 564 565 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { 566 #ifdef WITH_XSLT_DEBUG_EXTRA 567 xsltGenericDebug(xsltGenericDebugContext, 568 "Found saxon:output extension\n"); 569 #endif 570 /* 571 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE 572 * (http://icl.com/saxon) 573 * The @file is in no namespace; it is an AVT. 574 * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output) 575 * 576 * TODO: Do we need not to check the namespace here? 577 */ 578 filename = xsltEvalStaticAttrValueTemplate(style, inst, 579 (const xmlChar *)"file", 580 NULL, &comp->has_filename); 581 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { 582 #ifdef WITH_XSLT_DEBUG_EXTRA 583 xsltGenericDebug(xsltGenericDebugContext, 584 "Found xalan:write extension\n"); 585 #endif 586 /* the filename need to be interpreted */ 587 /* 588 * TODO: Is "filename need to be interpreted" meant to be a todo? 589 * Where will be the filename of xalan:write be processed? 590 * 591 * TODO: Do we need not to check the namespace here? 592 * The extension ns is "http://xml.apache.org/xalan/redirect". 593 * See http://xml.apache.org/xalan-j/extensionslib.html. 594 */ 595 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { 596 if (inst->ns != NULL) { 597 if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) { 598 /* 599 * Mark the instruction as being of 600 * XSLT version 1.1 (abandoned). 601 */ 602 comp->ver11 = 1; 603 #ifdef WITH_XSLT_DEBUG_EXTRA 604 xsltGenericDebug(xsltGenericDebugContext, 605 "Found xslt11:document construct\n"); 606 #endif 607 } else { 608 if (xmlStrEqual(inst->ns->href, 609 (const xmlChar *)"http://exslt.org/common")) { 610 /* EXSLT. */ 611 #ifdef WITH_XSLT_DEBUG_EXTRA 612 xsltGenericDebug(xsltGenericDebugContext, 613 "Found exslt:document extension\n"); 614 #endif 615 } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) { 616 /* James Clark's XT. */ 617 #ifdef WITH_XSLT_DEBUG_EXTRA 618 xsltGenericDebug(xsltGenericDebugContext, 619 "Found xt:document extension\n"); 620 #endif 621 } 622 } 623 } 624 /* 625 * The element "document" is used in conjunction with the 626 * following namespaces: 627 * 628 * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1) 629 * <!ELEMENT xsl:document %template;> 630 * <!ATTLIST xsl:document 631 * href %avt; #REQUIRED 632 * @href is an AVT 633 * IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft, 634 * it was removed and isn't available in XSLT 1.1 anymore. 635 * In XSLT 2.0 it was renamed to xsl:result-document. 636 * 637 * All other attributes are identical to the attributes 638 * on xsl:output 639 * 640 * 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common) 641 * <exsl:document 642 * href = { uri-reference } 643 * TODO: is @href is an AVT? 644 * 645 * 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt) 646 * Example: <xt:document method="xml" href="myFile.xml"> 647 * TODO: is @href is an AVT? 648 * 649 * In all cases @href is in no namespace. 650 */ 651 filename = xsltEvalStaticAttrValueTemplate(style, inst, 652 (const xmlChar *)"href", NULL, &comp->has_filename); 653 } 654 if (!comp->has_filename) { 655 goto error; 656 } 657 comp->filename = filename; 658 659 error: 660 return ((xsltElemPreCompPtr) comp); 661 } 662 663 /************************************************************************ 664 * * 665 * Most of the XSLT-1.0 transformations * 666 * * 667 ************************************************************************/ 668 669 /** 670 * xsltSortComp: 671 * @style: the XSLT stylesheet 672 * @inst: the xslt sort node 673 * 674 * Process the xslt sort node on the source node 675 */ 676 static void 677 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { 678 #ifdef XSLT_REFACTORED 679 xsltStyleItemSortPtr comp; 680 #else 681 xsltStylePreCompPtr comp; 682 #endif 683 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 684 return; 685 686 #ifdef XSLT_REFACTORED 687 comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT); 688 #else 689 comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT); 690 #endif 691 692 if (comp == NULL) 693 return; 694 inst->psvi = comp; 695 comp->inst = inst; 696 697 comp->stype = xsltEvalStaticAttrValueTemplate(style, inst, 698 (const xmlChar *)"data-type", 699 NULL, &comp->has_stype); 700 if (comp->stype != NULL) { 701 if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) 702 comp->number = 0; 703 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) 704 comp->number = 1; 705 else { 706 xsltTransformError(NULL, style, inst, 707 "xsltSortComp: no support for data-type = %s\n", comp->stype); 708 comp->number = 0; /* use default */ 709 if (style != NULL) style->warnings++; 710 } 711 } 712 comp->order = xsltEvalStaticAttrValueTemplate(style, inst, 713 (const xmlChar *)"order", 714 NULL, &comp->has_order); 715 if (comp->order != NULL) { 716 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) 717 comp->descending = 0; 718 else if (xmlStrEqual(comp->order, (const xmlChar *) "descending")) 719 comp->descending = 1; 720 else { 721 xsltTransformError(NULL, style, inst, 722 "xsltSortComp: invalid value %s for order\n", comp->order); 723 comp->descending = 0; /* use default */ 724 if (style != NULL) style->warnings++; 725 } 726 } 727 comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst, 728 (const xmlChar *)"case-order", 729 NULL, &comp->has_use); 730 if (comp->case_order != NULL) { 731 if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first")) 732 comp->lower_first = 0; 733 else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first")) 734 comp->lower_first = 1; 735 else { 736 xsltTransformError(NULL, style, inst, 737 "xsltSortComp: invalid value %s for order\n", comp->order); 738 comp->lower_first = 0; /* use default */ 739 if (style != NULL) style->warnings++; 740 } 741 } 742 743 comp->lang = xsltEvalStaticAttrValueTemplate(style, inst, 744 (const xmlChar *)"lang", 745 NULL, &comp->has_lang); 746 if (comp->lang != NULL) { 747 comp->locale = xsltNewLocale(comp->lang); 748 } 749 else { 750 comp->locale = (xsltLocale)0; 751 } 752 753 comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE); 754 if (comp->select == NULL) { 755 /* 756 * The default value of the select attribute is ., which will 757 * cause the string-value of the current node to be used as 758 * the sort key. 759 */ 760 comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1); 761 } 762 comp->comp = xsltXPathCompile(style, comp->select); 763 if (comp->comp == NULL) { 764 xsltTransformError(NULL, style, inst, 765 "xsltSortComp: could not compile select expression '%s'\n", 766 comp->select); 767 if (style != NULL) style->errors++; 768 } 769 if (inst->children != NULL) { 770 xsltTransformError(NULL, style, inst, 771 "xsl:sort : is not empty\n"); 772 if (style != NULL) style->errors++; 773 } 774 } 775 776 /** 777 * xsltCopyComp: 778 * @style: the XSLT stylesheet 779 * @inst: the xslt copy node 780 * 781 * Process the xslt copy node on the source node 782 */ 783 static void 784 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { 785 #ifdef XSLT_REFACTORED 786 xsltStyleItemCopyPtr comp; 787 #else 788 xsltStylePreCompPtr comp; 789 #endif 790 791 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 792 return; 793 #ifdef XSLT_REFACTORED 794 comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY); 795 #else 796 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY); 797 #endif 798 799 if (comp == NULL) 800 return; 801 inst->psvi = comp; 802 comp->inst = inst; 803 804 805 comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets", 806 XSLT_NAMESPACE); 807 if (comp->use == NULL) 808 comp->has_use = 0; 809 else 810 comp->has_use = 1; 811 } 812 813 #ifdef XSLT_REFACTORED 814 /* Enable if ever needed for xsl:text. */ 815 #else 816 /** 817 * xsltTextComp: 818 * @style: an XSLT compiled stylesheet 819 * @inst: the xslt text node 820 * 821 * TODO: This function is obsolete, since xsl:text won't 822 * be compiled, but removed from the tree. 823 * 824 * Process the xslt text node on the source node 825 */ 826 static void 827 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { 828 #ifdef XSLT_REFACTORED 829 xsltStyleItemTextPtr comp; 830 #else 831 xsltStylePreCompPtr comp; 832 #endif 833 const xmlChar *prop; 834 835 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 836 return; 837 838 #ifdef XSLT_REFACTORED 839 comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT); 840 #else 841 comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT); 842 #endif 843 if (comp == NULL) 844 return; 845 inst->psvi = comp; 846 comp->inst = inst; 847 comp->noescape = 0; 848 849 prop = xsltGetCNsProp(style, inst, 850 (const xmlChar *)"disable-output-escaping", 851 XSLT_NAMESPACE); 852 if (prop != NULL) { 853 if (xmlStrEqual(prop, (const xmlChar *)"yes")) { 854 comp->noescape = 1; 855 } else if (!xmlStrEqual(prop, 856 (const xmlChar *)"no")){ 857 xsltTransformError(NULL, style, inst, 858 "xsl:text: disable-output-escaping allows only yes or no\n"); 859 if (style != NULL) style->warnings++; 860 } 861 } 862 } 863 #endif /* else of XSLT_REFACTORED */ 864 865 /** 866 * xsltElementComp: 867 * @style: an XSLT compiled stylesheet 868 * @inst: the xslt element node 869 * 870 * Process the xslt element node on the source node 871 */ 872 static void 873 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { 874 #ifdef XSLT_REFACTORED 875 xsltStyleItemElementPtr comp; 876 #else 877 xsltStylePreCompPtr comp; 878 #endif 879 880 /* 881 * <xsl:element 882 * name = { qname } 883 * namespace = { uri-reference } 884 * use-attribute-sets = qnames> 885 * <!-- Content: template --> 886 * </xsl:element> 887 */ 888 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 889 return; 890 891 #ifdef XSLT_REFACTORED 892 comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); 893 #else 894 comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); 895 #endif 896 897 if (comp == NULL) 898 return; 899 inst->psvi = comp; 900 comp->inst = inst; 901 902 /* 903 * Attribute "name". 904 */ 905 /* 906 * TODO: Precompile the AVT. See bug #344894. 907 */ 908 comp->name = xsltEvalStaticAttrValueTemplate(style, inst, 909 (const xmlChar *)"name", NULL, &comp->has_name); 910 if (! comp->has_name) { 911 xsltTransformError(NULL, style, inst, 912 "xsl:element: The attribute 'name' is missing.\n"); 913 style->errors++; 914 goto error; 915 } 916 /* 917 * Attribute "namespace". 918 */ 919 /* 920 * TODO: Precompile the AVT. See bug #344894. 921 */ 922 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, 923 (const xmlChar *)"namespace", NULL, &comp->has_ns); 924 925 if (comp->name != NULL) { 926 if (xmlValidateQName(comp->name, 0)) { 927 xsltTransformError(NULL, style, inst, 928 "xsl:element: The value '%s' of the attribute 'name' is " 929 "not a valid QName.\n", comp->name); 930 style->errors++; 931 } else { 932 const xmlChar *prefix = NULL, *name; 933 934 name = xsltSplitQName(style->dict, comp->name, &prefix); 935 if (comp->has_ns == 0) { 936 xmlNsPtr ns; 937 938 /* 939 * SPEC XSLT 1.0: 940 * "If the namespace attribute is not present, then the QName is 941 * expanded into an expanded-name using the namespace declarations 942 * in effect for the xsl:element element, including any default 943 * namespace declaration. 944 */ 945 ns = xmlSearchNs(inst->doc, inst, prefix); 946 if (ns != NULL) { 947 comp->ns = xmlDictLookup(style->dict, ns->href, -1); 948 comp->has_ns = 1; 949 #ifdef XSLT_REFACTORED 950 comp->nsPrefix = prefix; 951 comp->name = name; 952 #endif 953 } else if (prefix != NULL) { 954 xsltTransformError(NULL, style, inst, 955 "xsl:element: The prefixed QName '%s' " 956 "has no namespace binding in scope in the " 957 "stylesheet; this is an error, since the namespace was " 958 "not specified by the instruction itself.\n", comp->name); 959 style->errors++; 960 } 961 } 962 if ((prefix != NULL) && 963 (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) 964 { 965 /* 966 * Mark is to be skipped. 967 */ 968 comp->has_name = 0; 969 } 970 } 971 } 972 /* 973 * Attribute "use-attribute-sets", 974 */ 975 comp->use = xsltEvalStaticAttrValueTemplate(style, inst, 976 (const xmlChar *)"use-attribute-sets", 977 NULL, &comp->has_use); 978 979 error: 980 return; 981 } 982 983 /** 984 * xsltAttributeComp: 985 * @style: an XSLT compiled stylesheet 986 * @inst: the xslt attribute node 987 * 988 * Process the xslt attribute node on the source node 989 */ 990 static void 991 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { 992 #ifdef XSLT_REFACTORED 993 xsltStyleItemAttributePtr comp; 994 #else 995 xsltStylePreCompPtr comp; 996 #endif 997 998 /* 999 * <xsl:attribute 1000 * name = { qname } 1001 * namespace = { uri-reference }> 1002 * <!-- Content: template --> 1003 * </xsl:attribute> 1004 */ 1005 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1006 return; 1007 1008 #ifdef XSLT_REFACTORED 1009 comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, 1010 XSLT_FUNC_ATTRIBUTE); 1011 #else 1012 comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE); 1013 #endif 1014 1015 if (comp == NULL) 1016 return; 1017 inst->psvi = comp; 1018 comp->inst = inst; 1019 1020 /* 1021 * Attribute "name". 1022 */ 1023 /* 1024 * TODO: Precompile the AVT. See bug #344894. 1025 */ 1026 comp->name = xsltEvalStaticAttrValueTemplate(style, inst, 1027 (const xmlChar *)"name", 1028 NULL, &comp->has_name); 1029 if (! comp->has_name) { 1030 xsltTransformError(NULL, style, inst, 1031 "XSLT-attribute: The attribute 'name' is missing.\n"); 1032 style->errors++; 1033 return; 1034 } 1035 /* 1036 * Attribute "namespace". 1037 */ 1038 /* 1039 * TODO: Precompile the AVT. See bug #344894. 1040 */ 1041 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, 1042 (const xmlChar *)"namespace", 1043 NULL, &comp->has_ns); 1044 1045 if (comp->name != NULL) { 1046 if (xmlValidateQName(comp->name, 0)) { 1047 xsltTransformError(NULL, style, inst, 1048 "xsl:attribute: The value '%s' of the attribute 'name' is " 1049 "not a valid QName.\n", comp->name); 1050 style->errors++; 1051 } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) { 1052 xsltTransformError(NULL, style, inst, 1053 "xsl:attribute: The attribute name 'xmlns' is not allowed.\n"); 1054 style->errors++; 1055 } else { 1056 const xmlChar *prefix = NULL, *name; 1057 1058 name = xsltSplitQName(style->dict, comp->name, &prefix); 1059 if (prefix != NULL) { 1060 if (comp->has_ns == 0) { 1061 xmlNsPtr ns; 1062 1063 /* 1064 * SPEC XSLT 1.0: 1065 * "If the namespace attribute is not present, then the 1066 * QName is expanded into an expanded-name using the 1067 * namespace declarations in effect for the xsl:element 1068 * element, including any default namespace declaration. 1069 */ 1070 ns = xmlSearchNs(inst->doc, inst, prefix); 1071 if (ns != NULL) { 1072 comp->ns = xmlDictLookup(style->dict, ns->href, -1); 1073 comp->has_ns = 1; 1074 #ifdef XSLT_REFACTORED 1075 comp->nsPrefix = prefix; 1076 comp->name = name; 1077 #endif 1078 } else { 1079 xsltTransformError(NULL, style, inst, 1080 "xsl:attribute: The prefixed QName '%s' " 1081 "has no namespace binding in scope in the " 1082 "stylesheet; this is an error, since the " 1083 "namespace was not specified by the instruction " 1084 "itself.\n", comp->name); 1085 style->errors++; 1086 } 1087 } 1088 } 1089 } 1090 } 1091 } 1092 1093 /** 1094 * xsltCommentComp: 1095 * @style: an XSLT compiled stylesheet 1096 * @inst: the xslt comment node 1097 * 1098 * Process the xslt comment node on the source node 1099 */ 1100 static void 1101 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1102 #ifdef XSLT_REFACTORED 1103 xsltStyleItemCommentPtr comp; 1104 #else 1105 xsltStylePreCompPtr comp; 1106 #endif 1107 1108 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1109 return; 1110 1111 #ifdef XSLT_REFACTORED 1112 comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); 1113 #else 1114 comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); 1115 #endif 1116 1117 if (comp == NULL) 1118 return; 1119 inst->psvi = comp; 1120 comp->inst = inst; 1121 } 1122 1123 /** 1124 * xsltProcessingInstructionComp: 1125 * @style: an XSLT compiled stylesheet 1126 * @inst: the xslt processing-instruction node 1127 * 1128 * Process the xslt processing-instruction node on the source node 1129 */ 1130 static void 1131 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1132 #ifdef XSLT_REFACTORED 1133 xsltStyleItemPIPtr comp; 1134 #else 1135 xsltStylePreCompPtr comp; 1136 #endif 1137 1138 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1139 return; 1140 1141 #ifdef XSLT_REFACTORED 1142 comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI); 1143 #else 1144 comp = xsltNewStylePreComp(style, XSLT_FUNC_PI); 1145 #endif 1146 1147 if (comp == NULL) 1148 return; 1149 inst->psvi = comp; 1150 comp->inst = inst; 1151 1152 comp->name = xsltEvalStaticAttrValueTemplate(style, inst, 1153 (const xmlChar *)"name", 1154 XSLT_NAMESPACE, &comp->has_name); 1155 } 1156 1157 /** 1158 * xsltCopyOfComp: 1159 * @style: an XSLT compiled stylesheet 1160 * @inst: the xslt copy-of node 1161 * 1162 * Process the xslt copy-of node on the source node 1163 */ 1164 static void 1165 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1166 #ifdef XSLT_REFACTORED 1167 xsltStyleItemCopyOfPtr comp; 1168 #else 1169 xsltStylePreCompPtr comp; 1170 #endif 1171 1172 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1173 return; 1174 1175 #ifdef XSLT_REFACTORED 1176 comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); 1177 #else 1178 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); 1179 #endif 1180 1181 if (comp == NULL) 1182 return; 1183 inst->psvi = comp; 1184 comp->inst = inst; 1185 1186 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1187 XSLT_NAMESPACE); 1188 if (comp->select == NULL) { 1189 xsltTransformError(NULL, style, inst, 1190 "xsl:copy-of : select is missing\n"); 1191 if (style != NULL) style->errors++; 1192 return; 1193 } 1194 comp->comp = xsltXPathCompile(style, comp->select); 1195 if (comp->comp == NULL) { 1196 xsltTransformError(NULL, style, inst, 1197 "xsl:copy-of : could not compile select expression '%s'\n", 1198 comp->select); 1199 if (style != NULL) style->errors++; 1200 } 1201 } 1202 1203 /** 1204 * xsltValueOfComp: 1205 * @style: an XSLT compiled stylesheet 1206 * @inst: the xslt value-of node 1207 * 1208 * Process the xslt value-of node on the source node 1209 */ 1210 static void 1211 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1212 #ifdef XSLT_REFACTORED 1213 xsltStyleItemValueOfPtr comp; 1214 #else 1215 xsltStylePreCompPtr comp; 1216 #endif 1217 const xmlChar *prop; 1218 1219 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1220 return; 1221 1222 #ifdef XSLT_REFACTORED 1223 comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); 1224 #else 1225 comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); 1226 #endif 1227 1228 if (comp == NULL) 1229 return; 1230 inst->psvi = comp; 1231 comp->inst = inst; 1232 1233 prop = xsltGetCNsProp(style, inst, 1234 (const xmlChar *)"disable-output-escaping", 1235 XSLT_NAMESPACE); 1236 if (prop != NULL) { 1237 if (xmlStrEqual(prop, (const xmlChar *)"yes")) { 1238 comp->noescape = 1; 1239 } else if (!xmlStrEqual(prop, 1240 (const xmlChar *)"no")){ 1241 xsltTransformError(NULL, style, inst, 1242 "xsl:value-of : disable-output-escaping allows only yes or no\n"); 1243 if (style != NULL) style->warnings++; 1244 } 1245 } 1246 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1247 XSLT_NAMESPACE); 1248 if (comp->select == NULL) { 1249 xsltTransformError(NULL, style, inst, 1250 "xsl:value-of : select is missing\n"); 1251 if (style != NULL) style->errors++; 1252 return; 1253 } 1254 comp->comp = xsltXPathCompile(style, comp->select); 1255 if (comp->comp == NULL) { 1256 xsltTransformError(NULL, style, inst, 1257 "xsl:value-of : could not compile select expression '%s'\n", 1258 comp->select); 1259 if (style != NULL) style->errors++; 1260 } 1261 } 1262 1263 static void 1264 xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst, 1265 const xmlChar *propName, 1266 int mandatory, 1267 int *hasProp, const xmlChar **nsName, 1268 const xmlChar** localName) 1269 { 1270 const xmlChar *prop; 1271 1272 if (nsName) 1273 *nsName = NULL; 1274 if (localName) 1275 *localName = NULL; 1276 if (hasProp) 1277 *hasProp = 0; 1278 1279 prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE); 1280 if (prop == NULL) { 1281 if (mandatory) { 1282 xsltTransformError(NULL, style, inst, 1283 "The attribute '%s' is missing.\n", propName); 1284 style->errors++; 1285 return; 1286 } 1287 } else { 1288 const xmlChar *URI; 1289 1290 if (xmlValidateQName(prop, 0)) { 1291 xsltTransformError(NULL, style, inst, 1292 "The value '%s' of the attribute " 1293 "'%s' is not a valid QName.\n", prop, propName); 1294 style->errors++; 1295 return; 1296 } else { 1297 /* 1298 * @prop will be in the string dict afterwards, @URI not. 1299 */ 1300 URI = xsltGetQNameURI2(style, inst, &prop); 1301 if (prop == NULL) { 1302 style->errors++; 1303 } else { 1304 *localName = prop; 1305 if (hasProp) 1306 *hasProp = 1; 1307 if (URI != NULL) { 1308 /* 1309 * Fixes bug #308441: Put the ns-name in the dict 1310 * in order to pointer compare names during XPath's 1311 * variable lookup. 1312 */ 1313 if (nsName) 1314 *nsName = xmlDictLookup(style->dict, URI, -1); 1315 /* comp->has_ns = 1; */ 1316 } 1317 } 1318 } 1319 } 1320 return; 1321 } 1322 1323 /** 1324 * xsltWithParamComp: 1325 * @style: an XSLT compiled stylesheet 1326 * @inst: the xslt with-param node 1327 * 1328 * Process the xslt with-param node on the source node 1329 * Allowed parents: xsl:call-template, xsl:apply-templates. 1330 * <xsl:with-param 1331 * name = qname 1332 * select = expression> 1333 * <!-- Content: template --> 1334 * </xsl:with-param> 1335 */ 1336 static void 1337 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1338 #ifdef XSLT_REFACTORED 1339 xsltStyleItemWithParamPtr comp; 1340 #else 1341 xsltStylePreCompPtr comp; 1342 #endif 1343 1344 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1345 return; 1346 1347 #ifdef XSLT_REFACTORED 1348 comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); 1349 #else 1350 comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); 1351 #endif 1352 1353 if (comp == NULL) 1354 return; 1355 inst->psvi = comp; 1356 comp->inst = inst; 1357 1358 /* 1359 * Attribute "name". 1360 */ 1361 xsltGetQNameProperty(style, inst, BAD_CAST "name", 1362 1, &(comp->has_name), &(comp->ns), &(comp->name)); 1363 if (comp->ns) 1364 comp->has_ns = 1; 1365 /* 1366 * Attribute "select". 1367 */ 1368 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1369 XSLT_NAMESPACE); 1370 if (comp->select != NULL) { 1371 comp->comp = xsltXPathCompile(style, comp->select); 1372 if (comp->comp == NULL) { 1373 xsltTransformError(NULL, style, inst, 1374 "XSLT-with-param: Failed to compile select " 1375 "expression '%s'\n", comp->select); 1376 style->errors++; 1377 } 1378 if (inst->children != NULL) { 1379 xsltTransformError(NULL, style, inst, 1380 "XSLT-with-param: The content should be empty since " 1381 "the attribute select is present.\n"); 1382 style->warnings++; 1383 } 1384 } 1385 } 1386 1387 /** 1388 * xsltNumberComp: 1389 * @style: an XSLT compiled stylesheet 1390 * @cur: the xslt number node 1391 * 1392 * Process the xslt number node on the source node 1393 */ 1394 static void 1395 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { 1396 #ifdef XSLT_REFACTORED 1397 xsltStyleItemNumberPtr comp; 1398 #else 1399 xsltStylePreCompPtr comp; 1400 #endif 1401 const xmlChar *prop; 1402 1403 if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) 1404 return; 1405 1406 #ifdef XSLT_REFACTORED 1407 comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); 1408 #else 1409 comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); 1410 #endif 1411 1412 if (comp == NULL) 1413 return; 1414 cur->psvi = comp; 1415 1416 if ((style == NULL) || (cur == NULL)) 1417 return; 1418 1419 comp->numdata.doc = cur->doc; 1420 comp->numdata.node = cur; 1421 comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", 1422 XSLT_NAMESPACE); 1423 1424 prop = xsltEvalStaticAttrValueTemplate(style, cur, 1425 (const xmlChar *)"format", 1426 XSLT_NAMESPACE, &comp->numdata.has_format); 1427 if (comp->numdata.has_format == 0) { 1428 comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0); 1429 } else { 1430 comp->numdata.format = prop; 1431 } 1432 1433 comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count", 1434 XSLT_NAMESPACE); 1435 comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from", 1436 XSLT_NAMESPACE); 1437 1438 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE); 1439 if (prop != NULL) { 1440 comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style, 1441 NULL); 1442 } 1443 1444 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE); 1445 if (prop != NULL) { 1446 comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style, 1447 NULL); 1448 } 1449 1450 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE); 1451 if (prop != NULL) { 1452 if (xmlStrEqual(prop, BAD_CAST("single")) || 1453 xmlStrEqual(prop, BAD_CAST("multiple")) || 1454 xmlStrEqual(prop, BAD_CAST("any"))) { 1455 comp->numdata.level = prop; 1456 } else { 1457 xsltTransformError(NULL, style, cur, 1458 "xsl:number : invalid value %s for level\n", prop); 1459 if (style != NULL) style->warnings++; 1460 } 1461 } 1462 1463 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE); 1464 if (prop != NULL) { 1465 xsltTransformError(NULL, style, cur, 1466 "xsl:number : lang attribute not implemented\n"); 1467 XSLT_TODO; /* xsl:number lang attribute */ 1468 } 1469 1470 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); 1471 if (prop != NULL) { 1472 if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) { 1473 xsltTransformError(NULL, style, cur, 1474 "xsl:number : letter-value 'alphabetic' not implemented\n"); 1475 if (style != NULL) style->warnings++; 1476 XSLT_TODO; /* xsl:number letter-value attribute alphabetic */ 1477 } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) { 1478 xsltTransformError(NULL, style, cur, 1479 "xsl:number : letter-value 'traditional' not implemented\n"); 1480 if (style != NULL) style->warnings++; 1481 XSLT_TODO; /* xsl:number letter-value attribute traditional */ 1482 } else { 1483 xsltTransformError(NULL, style, cur, 1484 "xsl:number : invalid value %s for letter-value\n", prop); 1485 if (style != NULL) style->warnings++; 1486 } 1487 } 1488 1489 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator", 1490 XSLT_NAMESPACE); 1491 if (prop != NULL) { 1492 comp->numdata.groupingCharacterLen = xmlStrlen(prop); 1493 comp->numdata.groupingCharacter = 1494 xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen)); 1495 } 1496 1497 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); 1498 if (prop != NULL) { 1499 sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup); 1500 } else { 1501 comp->numdata.groupingCharacter = 0; 1502 } 1503 1504 /* Set default values */ 1505 if (comp->numdata.value == NULL) { 1506 if (comp->numdata.level == NULL) { 1507 comp->numdata.level = xmlDictLookup(style->dict, 1508 BAD_CAST"single", 6); 1509 } 1510 } 1511 1512 } 1513 1514 /** 1515 * xsltApplyImportsComp: 1516 * @style: an XSLT compiled stylesheet 1517 * @inst: the xslt apply-imports node 1518 * 1519 * Process the xslt apply-imports node on the source node 1520 */ 1521 static void 1522 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1523 #ifdef XSLT_REFACTORED 1524 xsltStyleItemApplyImportsPtr comp; 1525 #else 1526 xsltStylePreCompPtr comp; 1527 #endif 1528 1529 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1530 return; 1531 1532 #ifdef XSLT_REFACTORED 1533 comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); 1534 #else 1535 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); 1536 #endif 1537 1538 if (comp == NULL) 1539 return; 1540 inst->psvi = comp; 1541 comp->inst = inst; 1542 } 1543 1544 /** 1545 * xsltCallTemplateComp: 1546 * @style: an XSLT compiled stylesheet 1547 * @inst: the xslt call-template node 1548 * 1549 * Process the xslt call-template node on the source node 1550 */ 1551 static void 1552 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1553 #ifdef XSLT_REFACTORED 1554 xsltStyleItemCallTemplatePtr comp; 1555 #else 1556 xsltStylePreCompPtr comp; 1557 #endif 1558 1559 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1560 return; 1561 1562 #ifdef XSLT_REFACTORED 1563 comp = (xsltStyleItemCallTemplatePtr) 1564 xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); 1565 #else 1566 comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); 1567 #endif 1568 1569 if (comp == NULL) 1570 return; 1571 inst->psvi = comp; 1572 comp->inst = inst; 1573 1574 /* 1575 * Attribute "name". 1576 */ 1577 xsltGetQNameProperty(style, inst, BAD_CAST "name", 1578 1, &(comp->has_name), &(comp->ns), &(comp->name)); 1579 if (comp->ns) 1580 comp->has_ns = 1; 1581 } 1582 1583 /** 1584 * xsltApplyTemplatesComp: 1585 * @style: an XSLT compiled stylesheet 1586 * @inst: the apply-templates node 1587 * 1588 * Process the apply-templates node on the source node 1589 */ 1590 static void 1591 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1592 #ifdef XSLT_REFACTORED 1593 xsltStyleItemApplyTemplatesPtr comp; 1594 #else 1595 xsltStylePreCompPtr comp; 1596 #endif 1597 1598 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1599 return; 1600 1601 #ifdef XSLT_REFACTORED 1602 comp = (xsltStyleItemApplyTemplatesPtr) 1603 xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); 1604 #else 1605 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); 1606 #endif 1607 1608 if (comp == NULL) 1609 return; 1610 inst->psvi = comp; 1611 comp->inst = inst; 1612 1613 /* 1614 * Attribute "mode". 1615 */ 1616 xsltGetQNameProperty(style, inst, BAD_CAST "mode", 1617 0, NULL, &(comp->modeURI), &(comp->mode)); 1618 /* 1619 * Attribute "select". 1620 */ 1621 comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select", 1622 XSLT_NAMESPACE); 1623 if (comp->select != NULL) { 1624 comp->comp = xsltXPathCompile(style, comp->select); 1625 if (comp->comp == NULL) { 1626 xsltTransformError(NULL, style, inst, 1627 "XSLT-apply-templates: could not compile select " 1628 "expression '%s'\n", comp->select); 1629 style->errors++; 1630 } 1631 } 1632 /* TODO: handle (or skip) the xsl:sort and xsl:with-param */ 1633 } 1634 1635 /** 1636 * xsltChooseComp: 1637 * @style: an XSLT compiled stylesheet 1638 * @inst: the xslt choose node 1639 * 1640 * Process the xslt choose node on the source node 1641 */ 1642 static void 1643 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1644 #ifdef XSLT_REFACTORED 1645 xsltStyleItemChoosePtr comp; 1646 #else 1647 xsltStylePreCompPtr comp; 1648 #endif 1649 1650 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1651 return; 1652 1653 #ifdef XSLT_REFACTORED 1654 comp = (xsltStyleItemChoosePtr) 1655 xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); 1656 #else 1657 comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); 1658 #endif 1659 1660 if (comp == NULL) 1661 return; 1662 inst->psvi = comp; 1663 comp->inst = inst; 1664 } 1665 1666 /** 1667 * xsltIfComp: 1668 * @style: an XSLT compiled stylesheet 1669 * @inst: the xslt if node 1670 * 1671 * Process the xslt if node on the source node 1672 */ 1673 static void 1674 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1675 #ifdef XSLT_REFACTORED 1676 xsltStyleItemIfPtr comp; 1677 #else 1678 xsltStylePreCompPtr comp; 1679 #endif 1680 1681 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1682 return; 1683 1684 #ifdef XSLT_REFACTORED 1685 comp = (xsltStyleItemIfPtr) 1686 xsltNewStylePreComp(style, XSLT_FUNC_IF); 1687 #else 1688 comp = xsltNewStylePreComp(style, XSLT_FUNC_IF); 1689 #endif 1690 1691 if (comp == NULL) 1692 return; 1693 inst->psvi = comp; 1694 comp->inst = inst; 1695 1696 comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); 1697 if (comp->test == NULL) { 1698 xsltTransformError(NULL, style, inst, 1699 "xsl:if : test is not defined\n"); 1700 if (style != NULL) style->errors++; 1701 return; 1702 } 1703 comp->comp = xsltXPathCompile(style, comp->test); 1704 if (comp->comp == NULL) { 1705 xsltTransformError(NULL, style, inst, 1706 "xsl:if : could not compile test expression '%s'\n", 1707 comp->test); 1708 if (style != NULL) style->errors++; 1709 } 1710 } 1711 1712 /** 1713 * xsltWhenComp: 1714 * @style: an XSLT compiled stylesheet 1715 * @inst: the xslt if node 1716 * 1717 * Process the xslt if node on the source node 1718 */ 1719 static void 1720 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1721 #ifdef XSLT_REFACTORED 1722 xsltStyleItemWhenPtr comp; 1723 #else 1724 xsltStylePreCompPtr comp; 1725 #endif 1726 1727 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1728 return; 1729 1730 #ifdef XSLT_REFACTORED 1731 comp = (xsltStyleItemWhenPtr) 1732 xsltNewStylePreComp(style, XSLT_FUNC_WHEN); 1733 #else 1734 comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN); 1735 #endif 1736 1737 if (comp == NULL) 1738 return; 1739 inst->psvi = comp; 1740 comp->inst = inst; 1741 1742 comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); 1743 if (comp->test == NULL) { 1744 xsltTransformError(NULL, style, inst, 1745 "xsl:when : test is not defined\n"); 1746 if (style != NULL) style->errors++; 1747 return; 1748 } 1749 comp->comp = xsltXPathCompile(style, comp->test); 1750 if (comp->comp == NULL) { 1751 xsltTransformError(NULL, style, inst, 1752 "xsl:when : could not compile test expression '%s'\n", 1753 comp->test); 1754 if (style != NULL) style->errors++; 1755 } 1756 } 1757 1758 /** 1759 * xsltForEachComp: 1760 * @style: an XSLT compiled stylesheet 1761 * @inst: the xslt for-each node 1762 * 1763 * Process the xslt for-each node on the source node 1764 */ 1765 static void 1766 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1767 #ifdef XSLT_REFACTORED 1768 xsltStyleItemForEachPtr comp; 1769 #else 1770 xsltStylePreCompPtr comp; 1771 #endif 1772 1773 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1774 return; 1775 1776 #ifdef XSLT_REFACTORED 1777 comp = (xsltStyleItemForEachPtr) 1778 xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); 1779 #else 1780 comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); 1781 #endif 1782 1783 if (comp == NULL) 1784 return; 1785 inst->psvi = comp; 1786 comp->inst = inst; 1787 1788 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1789 XSLT_NAMESPACE); 1790 if (comp->select == NULL) { 1791 xsltTransformError(NULL, style, inst, 1792 "xsl:for-each : select is missing\n"); 1793 if (style != NULL) style->errors++; 1794 } else { 1795 comp->comp = xsltXPathCompile(style, comp->select); 1796 if (comp->comp == NULL) { 1797 xsltTransformError(NULL, style, inst, 1798 "xsl:for-each : could not compile select expression '%s'\n", 1799 comp->select); 1800 if (style != NULL) style->errors++; 1801 } 1802 } 1803 /* TODO: handle and skip the xsl:sort */ 1804 } 1805 1806 /** 1807 * xsltVariableComp: 1808 * @style: an XSLT compiled stylesheet 1809 * @inst: the xslt variable node 1810 * 1811 * Process the xslt variable node on the source node 1812 */ 1813 static void 1814 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1815 #ifdef XSLT_REFACTORED 1816 xsltStyleItemVariablePtr comp; 1817 #else 1818 xsltStylePreCompPtr comp; 1819 #endif 1820 1821 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1822 return; 1823 1824 #ifdef XSLT_REFACTORED 1825 comp = (xsltStyleItemVariablePtr) 1826 xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); 1827 #else 1828 comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); 1829 #endif 1830 1831 if (comp == NULL) 1832 return; 1833 1834 inst->psvi = comp; 1835 comp->inst = inst; 1836 /* 1837 * The full template resolution can be done statically 1838 */ 1839 1840 /* 1841 * Attribute "name". 1842 */ 1843 xsltGetQNameProperty(style, inst, BAD_CAST "name", 1844 1, &(comp->has_name), &(comp->ns), &(comp->name)); 1845 if (comp->ns) 1846 comp->has_ns = 1; 1847 /* 1848 * Attribute "select". 1849 */ 1850 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1851 XSLT_NAMESPACE); 1852 if (comp->select != NULL) { 1853 #ifndef XSLT_REFACTORED 1854 xmlNodePtr cur; 1855 #endif 1856 comp->comp = xsltXPathCompile(style, comp->select); 1857 if (comp->comp == NULL) { 1858 xsltTransformError(NULL, style, inst, 1859 "XSLT-variable: Failed to compile the XPath expression '%s'.\n", 1860 comp->select); 1861 style->errors++; 1862 } 1863 #ifdef XSLT_REFACTORED 1864 if (inst->children != NULL) { 1865 xsltTransformError(NULL, style, inst, 1866 "XSLT-variable: There must be no child nodes, since the " 1867 "attribute 'select' was specified.\n"); 1868 style->errors++; 1869 } 1870 #else 1871 for (cur = inst->children; cur != NULL; cur = cur->next) { 1872 if (cur->type != XML_COMMENT_NODE && 1873 (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content))) 1874 { 1875 xsltTransformError(NULL, style, inst, 1876 "XSLT-variable: There must be no child nodes, since the " 1877 "attribute 'select' was specified.\n"); 1878 style->errors++; 1879 } 1880 } 1881 #endif 1882 } 1883 } 1884 1885 /** 1886 * xsltParamComp: 1887 * @style: an XSLT compiled stylesheet 1888 * @inst: the xslt param node 1889 * 1890 * Process the xslt param node on the source node 1891 */ 1892 static void 1893 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { 1894 #ifdef XSLT_REFACTORED 1895 xsltStyleItemParamPtr comp; 1896 #else 1897 xsltStylePreCompPtr comp; 1898 #endif 1899 1900 if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) 1901 return; 1902 1903 #ifdef XSLT_REFACTORED 1904 comp = (xsltStyleItemParamPtr) 1905 xsltNewStylePreComp(style, XSLT_FUNC_PARAM); 1906 #else 1907 comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM); 1908 #endif 1909 1910 if (comp == NULL) 1911 return; 1912 inst->psvi = comp; 1913 comp->inst = inst; 1914 1915 /* 1916 * Attribute "name". 1917 */ 1918 xsltGetQNameProperty(style, inst, BAD_CAST "name", 1919 1, &(comp->has_name), &(comp->ns), &(comp->name)); 1920 if (comp->ns) 1921 comp->has_ns = 1; 1922 /* 1923 * Attribute "select". 1924 */ 1925 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", 1926 XSLT_NAMESPACE); 1927 if (comp->select != NULL) { 1928 comp->comp = xsltXPathCompile(style, comp->select); 1929 if (comp->comp == NULL) { 1930 xsltTransformError(NULL, style, inst, 1931 "XSLT-param: could not compile select expression '%s'.\n", 1932 comp->select); 1933 style->errors++; 1934 } 1935 if (inst->children != NULL) { 1936 xsltTransformError(NULL, style, inst, 1937 "XSLT-param: The content should be empty since the " 1938 "attribute 'select' is present.\n"); 1939 style->warnings++; 1940 } 1941 } 1942 } 1943 1944 /************************************************************************ 1945 * * 1946 * Generic interface * 1947 * * 1948 ************************************************************************/ 1949 1950 /** 1951 * xsltFreeStylePreComps: 1952 * @style: an XSLT transformation context 1953 * 1954 * Free up the memory allocated by all precomputed blocks 1955 */ 1956 void 1957 xsltFreeStylePreComps(xsltStylesheetPtr style) { 1958 xsltElemPreCompPtr cur, next; 1959 1960 if (style == NULL) 1961 return; 1962 1963 cur = style->preComps; 1964 while (cur != NULL) { 1965 next = cur->next; 1966 if (cur->type == XSLT_FUNC_EXTENSION) 1967 cur->free(cur); 1968 else 1969 xsltFreeStylePreComp((xsltStylePreCompPtr) cur); 1970 cur = next; 1971 } 1972 } 1973 1974 #ifdef XSLT_REFACTORED 1975 1976 /** 1977 * xsltStylePreCompute: 1978 * @style: the XSLT stylesheet 1979 * @node: the element in the XSLT namespace 1980 * 1981 * Precompute an XSLT element. 1982 * This expects the type of the element to be already 1983 * set in style->compCtxt->inode->type; 1984 */ 1985 void 1986 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) { 1987 /* 1988 * The xsltXSLTElemMarker marker was set beforehand by 1989 * the parsing mechanism for all elements in the XSLT namespace. 1990 */ 1991 if (style == NULL) { 1992 if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) 1993 node->psvi = NULL; 1994 return; 1995 } 1996 if (node == NULL) 1997 return; 1998 if (! IS_XSLT_ELEM_FAST(node)) 1999 return; 2000 2001 node->psvi = NULL; 2002 if (XSLT_CCTXT(style)->inode->type != 0) { 2003 switch (XSLT_CCTXT(style)->inode->type) { 2004 case XSLT_FUNC_APPLYTEMPLATES: 2005 xsltApplyTemplatesComp(style, node); 2006 break; 2007 case XSLT_FUNC_WITHPARAM: 2008 xsltWithParamComp(style, node); 2009 break; 2010 case XSLT_FUNC_VALUEOF: 2011 xsltValueOfComp(style, node); 2012 break; 2013 case XSLT_FUNC_COPY: 2014 xsltCopyComp(style, node); 2015 break; 2016 case XSLT_FUNC_COPYOF: 2017 xsltCopyOfComp(style, node); 2018 break; 2019 case XSLT_FUNC_IF: 2020 xsltIfComp(style, node); 2021 break; 2022 case XSLT_FUNC_CHOOSE: 2023 xsltChooseComp(style, node); 2024 break; 2025 case XSLT_FUNC_WHEN: 2026 xsltWhenComp(style, node); 2027 break; 2028 case XSLT_FUNC_OTHERWISE: 2029 /* NOP yet */ 2030 return; 2031 case XSLT_FUNC_FOREACH: 2032 xsltForEachComp(style, node); 2033 break; 2034 case XSLT_FUNC_APPLYIMPORTS: 2035 xsltApplyImportsComp(style, node); 2036 break; 2037 case XSLT_FUNC_ATTRIBUTE: 2038 xsltAttributeComp(style, node); 2039 break; 2040 case XSLT_FUNC_ELEMENT: 2041 xsltElementComp(style, node); 2042 break; 2043 case XSLT_FUNC_SORT: 2044 xsltSortComp(style, node); 2045 break; 2046 case XSLT_FUNC_COMMENT: 2047 xsltCommentComp(style, node); 2048 break; 2049 case XSLT_FUNC_NUMBER: 2050 xsltNumberComp(style, node); 2051 break; 2052 case XSLT_FUNC_PI: 2053 xsltProcessingInstructionComp(style, node); 2054 break; 2055 case XSLT_FUNC_CALLTEMPLATE: 2056 xsltCallTemplateComp(style, node); 2057 break; 2058 case XSLT_FUNC_PARAM: 2059 xsltParamComp(style, node); 2060 break; 2061 case XSLT_FUNC_VARIABLE: 2062 xsltVariableComp(style, node); 2063 break; 2064 case XSLT_FUNC_FALLBACK: 2065 /* NOP yet */ 2066 return; 2067 case XSLT_FUNC_DOCUMENT: 2068 /* The extra one */ 2069 node->psvi = (void *) xsltDocumentComp(style, node, 2070 (xsltTransformFunction) xsltDocumentElem); 2071 break; 2072 case XSLT_FUNC_MESSAGE: 2073 /* NOP yet */ 2074 return; 2075 default: 2076 /* 2077 * NOTE that xsl:text, xsl:template, xsl:stylesheet, 2078 * xsl:transform, xsl:import, xsl:include are not expected 2079 * to be handed over to this function. 2080 */ 2081 xsltTransformError(NULL, style, node, 2082 "Internal error: (xsltStylePreCompute) cannot handle " 2083 "the XSLT element '%s'.\n", node->name); 2084 style->errors++; 2085 return; 2086 } 2087 } else { 2088 /* 2089 * Fallback to string comparison. 2090 */ 2091 if (IS_XSLT_NAME(node, "apply-templates")) { 2092 xsltApplyTemplatesComp(style, node); 2093 } else if (IS_XSLT_NAME(node, "with-param")) { 2094 xsltWithParamComp(style, node); 2095 } else if (IS_XSLT_NAME(node, "value-of")) { 2096 xsltValueOfComp(style, node); 2097 } else if (IS_XSLT_NAME(node, "copy")) { 2098 xsltCopyComp(style, node); 2099 } else if (IS_XSLT_NAME(node, "copy-of")) { 2100 xsltCopyOfComp(style, node); 2101 } else if (IS_XSLT_NAME(node, "if")) { 2102 xsltIfComp(style, node); 2103 } else if (IS_XSLT_NAME(node, "choose")) { 2104 xsltChooseComp(style, node); 2105 } else if (IS_XSLT_NAME(node, "when")) { 2106 xsltWhenComp(style, node); 2107 } else if (IS_XSLT_NAME(node, "otherwise")) { 2108 /* NOP yet */ 2109 return; 2110 } else if (IS_XSLT_NAME(node, "for-each")) { 2111 xsltForEachComp(style, node); 2112 } else if (IS_XSLT_NAME(node, "apply-imports")) { 2113 xsltApplyImportsComp(style, node); 2114 } else if (IS_XSLT_NAME(node, "attribute")) { 2115 xsltAttributeComp(style, node); 2116 } else if (IS_XSLT_NAME(node, "element")) { 2117 xsltElementComp(style, node); 2118 } else if (IS_XSLT_NAME(node, "sort")) { 2119 xsltSortComp(style, node); 2120 } else if (IS_XSLT_NAME(node, "comment")) { 2121 xsltCommentComp(style, node); 2122 } else if (IS_XSLT_NAME(node, "number")) { 2123 xsltNumberComp(style, node); 2124 } else if (IS_XSLT_NAME(node, "processing-instruction")) { 2125 xsltProcessingInstructionComp(style, node); 2126 } else if (IS_XSLT_NAME(node, "call-template")) { 2127 xsltCallTemplateComp(style, node); 2128 } else if (IS_XSLT_NAME(node, "param")) { 2129 xsltParamComp(style, node); 2130 } else if (IS_XSLT_NAME(node, "variable")) { 2131 xsltVariableComp(style, node); 2132 } else if (IS_XSLT_NAME(node, "fallback")) { 2133 /* NOP yet */ 2134 return; 2135 } else if (IS_XSLT_NAME(node, "document")) { 2136 /* The extra one */ 2137 node->psvi = (void *) xsltDocumentComp(style, node, 2138 (xsltTransformFunction) xsltDocumentElem); 2139 } else if (IS_XSLT_NAME(node, "output")) { 2140 /* Top-level */ 2141 return; 2142 } else if (IS_XSLT_NAME(node, "preserve-space")) { 2143 /* Top-level */ 2144 return; 2145 } else if (IS_XSLT_NAME(node, "strip-space")) { 2146 /* Top-level */ 2147 return; 2148 } else if (IS_XSLT_NAME(node, "key")) { 2149 /* Top-level */ 2150 return; 2151 } else if (IS_XSLT_NAME(node, "message")) { 2152 return; 2153 } else if (IS_XSLT_NAME(node, "attribute-set")) { 2154 /* Top-level */ 2155 return; 2156 } else if (IS_XSLT_NAME(node, "namespace-alias")) { 2157 /* Top-level */ 2158 return; 2159 } else if (IS_XSLT_NAME(node, "decimal-format")) { 2160 /* Top-level */ 2161 return; 2162 } else if (IS_XSLT_NAME(node, "include")) { 2163 /* Top-level */ 2164 } else { 2165 /* 2166 * NOTE that xsl:text, xsl:template, xsl:stylesheet, 2167 * xsl:transform, xsl:import, xsl:include are not expected 2168 * to be handed over to this function. 2169 */ 2170 xsltTransformError(NULL, style, node, 2171 "Internal error: (xsltStylePreCompute) cannot handle " 2172 "the XSLT element '%s'.\n", node->name); 2173 style->errors++; 2174 return; 2175 } 2176 } 2177 /* 2178 * Assign the current list of in-scope namespaces to the 2179 * item. This is needed for XPath expressions. 2180 */ 2181 if (node->psvi != NULL) { 2182 ((xsltStylePreCompPtr) node->psvi)->inScopeNs = 2183 XSLT_CCTXT(style)->inode->inScopeNs; 2184 } 2185 } 2186 2187 #else 2188 2189 /** 2190 * xsltStylePreCompute: 2191 * @style: the XSLT stylesheet 2192 * @inst: the instruction in the stylesheet 2193 * 2194 * Precompute an XSLT stylesheet element 2195 */ 2196 void 2197 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { 2198 /* 2199 * URGENT TODO: Normally inst->psvi Should never be reserved here, 2200 * BUT: since if we include the same stylesheet from 2201 * multiple imports, then the stylesheet will be parsed 2202 * again. We simply must not try to compute the stylesheet again. 2203 * TODO: Get to the point where we don't need to query the 2204 * namespace- and local-name of the node, but can evaluate this 2205 * using cctxt->style->inode->category; 2206 */ 2207 if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) || 2208 (inst->psvi != NULL)) 2209 return; 2210 2211 if (IS_XSLT_ELEM(inst)) { 2212 xsltStylePreCompPtr cur; 2213 2214 if (IS_XSLT_NAME(inst, "apply-templates")) { 2215 xsltCheckInstructionElement(style, inst); 2216 xsltApplyTemplatesComp(style, inst); 2217 } else if (IS_XSLT_NAME(inst, "with-param")) { 2218 xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", 2219 BAD_CAST "call-template"); 2220 xsltWithParamComp(style, inst); 2221 } else if (IS_XSLT_NAME(inst, "value-of")) { 2222 xsltCheckInstructionElement(style, inst); 2223 xsltValueOfComp(style, inst); 2224 } else if (IS_XSLT_NAME(inst, "copy")) { 2225 xsltCheckInstructionElement(style, inst); 2226 xsltCopyComp(style, inst); 2227 } else if (IS_XSLT_NAME(inst, "copy-of")) { 2228 xsltCheckInstructionElement(style, inst); 2229 xsltCopyOfComp(style, inst); 2230 } else if (IS_XSLT_NAME(inst, "if")) { 2231 xsltCheckInstructionElement(style, inst); 2232 xsltIfComp(style, inst); 2233 } else if (IS_XSLT_NAME(inst, "when")) { 2234 xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); 2235 xsltWhenComp(style, inst); 2236 } else if (IS_XSLT_NAME(inst, "choose")) { 2237 xsltCheckInstructionElement(style, inst); 2238 xsltChooseComp(style, inst); 2239 } else if (IS_XSLT_NAME(inst, "for-each")) { 2240 xsltCheckInstructionElement(style, inst); 2241 xsltForEachComp(style, inst); 2242 } else if (IS_XSLT_NAME(inst, "apply-imports")) { 2243 xsltCheckInstructionElement(style, inst); 2244 xsltApplyImportsComp(style, inst); 2245 } else if (IS_XSLT_NAME(inst, "attribute")) { 2246 xmlNodePtr parent = inst->parent; 2247 2248 if ((parent == NULL) || 2249 (parent->type != XML_ELEMENT_NODE) || (parent->ns == NULL) || 2250 ((parent->ns != inst->ns) && 2251 (!xmlStrEqual(parent->ns->href, inst->ns->href))) || 2252 (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) { 2253 xsltCheckInstructionElement(style, inst); 2254 } 2255 xsltAttributeComp(style, inst); 2256 } else if (IS_XSLT_NAME(inst, "element")) { 2257 xsltCheckInstructionElement(style, inst); 2258 xsltElementComp(style, inst); 2259 } else if (IS_XSLT_NAME(inst, "text")) { 2260 xsltCheckInstructionElement(style, inst); 2261 xsltTextComp(style, inst); 2262 } else if (IS_XSLT_NAME(inst, "sort")) { 2263 xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", 2264 BAD_CAST "for-each"); 2265 xsltSortComp(style, inst); 2266 } else if (IS_XSLT_NAME(inst, "comment")) { 2267 xsltCheckInstructionElement(style, inst); 2268 xsltCommentComp(style, inst); 2269 } else if (IS_XSLT_NAME(inst, "number")) { 2270 xsltCheckInstructionElement(style, inst); 2271 xsltNumberComp(style, inst); 2272 } else if (IS_XSLT_NAME(inst, "processing-instruction")) { 2273 xsltCheckInstructionElement(style, inst); 2274 xsltProcessingInstructionComp(style, inst); 2275 } else if (IS_XSLT_NAME(inst, "call-template")) { 2276 xsltCheckInstructionElement(style, inst); 2277 xsltCallTemplateComp(style, inst); 2278 } else if (IS_XSLT_NAME(inst, "param")) { 2279 if (xsltCheckTopLevelElement(style, inst, 0) == 0) 2280 xsltCheckInstructionElement(style, inst); 2281 xsltParamComp(style, inst); 2282 } else if (IS_XSLT_NAME(inst, "variable")) { 2283 if (xsltCheckTopLevelElement(style, inst, 0) == 0) 2284 xsltCheckInstructionElement(style, inst); 2285 xsltVariableComp(style, inst); 2286 } else if (IS_XSLT_NAME(inst, "otherwise")) { 2287 xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); 2288 xsltCheckInstructionElement(style, inst); 2289 return; 2290 } else if (IS_XSLT_NAME(inst, "template")) { 2291 xsltCheckTopLevelElement(style, inst, 1); 2292 return; 2293 } else if (IS_XSLT_NAME(inst, "output")) { 2294 xsltCheckTopLevelElement(style, inst, 1); 2295 return; 2296 } else if (IS_XSLT_NAME(inst, "preserve-space")) { 2297 xsltCheckTopLevelElement(style, inst, 1); 2298 return; 2299 } else if (IS_XSLT_NAME(inst, "strip-space")) { 2300 xsltCheckTopLevelElement(style, inst, 1); 2301 return; 2302 } else if ((IS_XSLT_NAME(inst, "stylesheet")) || 2303 (IS_XSLT_NAME(inst, "transform"))) { 2304 xmlNodePtr parent = inst->parent; 2305 2306 if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) { 2307 xsltTransformError(NULL, style, inst, 2308 "element %s only allowed only as root element\n", 2309 inst->name); 2310 style->errors++; 2311 } 2312 return; 2313 } else if (IS_XSLT_NAME(inst, "key")) { 2314 xsltCheckTopLevelElement(style, inst, 1); 2315 return; 2316 } else if (IS_XSLT_NAME(inst, "message")) { 2317 xsltCheckInstructionElement(style, inst); 2318 return; 2319 } else if (IS_XSLT_NAME(inst, "attribute-set")) { 2320 xsltCheckTopLevelElement(style, inst, 1); 2321 return; 2322 } else if (IS_XSLT_NAME(inst, "namespace-alias")) { 2323 xsltCheckTopLevelElement(style, inst, 1); 2324 return; 2325 } else if (IS_XSLT_NAME(inst, "include")) { 2326 xsltCheckTopLevelElement(style, inst, 1); 2327 return; 2328 } else if (IS_XSLT_NAME(inst, "import")) { 2329 xsltCheckTopLevelElement(style, inst, 1); 2330 return; 2331 } else if (IS_XSLT_NAME(inst, "decimal-format")) { 2332 xsltCheckTopLevelElement(style, inst, 1); 2333 return; 2334 } else if (IS_XSLT_NAME(inst, "fallback")) { 2335 xsltCheckInstructionElement(style, inst); 2336 return; 2337 } else if (IS_XSLT_NAME(inst, "document")) { 2338 xsltCheckInstructionElement(style, inst); 2339 inst->psvi = (void *) xsltDocumentComp(style, inst, 2340 (xsltTransformFunction) xsltDocumentElem); 2341 } else { 2342 xsltTransformError(NULL, style, inst, 2343 "xsltStylePreCompute: unknown xsl:%s\n", inst->name); 2344 if (style != NULL) style->warnings++; 2345 } 2346 2347 cur = (xsltStylePreCompPtr) inst->psvi; 2348 /* 2349 * A ns-list is build for every XSLT item in the 2350 * node-tree. This is needed for XPath expressions. 2351 */ 2352 if (cur != NULL) { 2353 int i = 0; 2354 2355 cur->nsList = xmlGetNsList(inst->doc, inst); 2356 if (cur->nsList != NULL) { 2357 while (cur->nsList[i] != NULL) 2358 i++; 2359 } 2360 cur->nsNr = i; 2361 } 2362 } else { 2363 inst->psvi = 2364 (void *) xsltPreComputeExtModuleElement(style, inst); 2365 2366 /* 2367 * Unknown element, maybe registered at the context 2368 * level. Mark it for later recognition. 2369 */ 2370 if (inst->psvi == NULL) 2371 inst->psvi = (void *) xsltExtMarker; 2372 } 2373 } 2374 #endif /* XSLT_REFACTORED */