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