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 */