ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

xslt.c
Go to the documentation of this file.
00001 /*
00002  * xslt.c: Implemetation of an XSL Transformation 1.0 engine
00003  *
00004  * Reference:
00005  *   XSLT specification
00006  *   http://www.w3.org/TR/1999/REC-xslt-19991116
00007  *
00008  *   Associating Style Sheets with XML documents
00009  *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
00010  *
00011  * See Copyright for the status of this software.
00012  *
00013  * daniel@veillard.com
00014  */
00015 
00016 #define IN_LIBXSLT
00017 #include "libxslt.h"
00018 
00019 #include <string.h>
00020 
00021 #include <libxml/xmlmemory.h>
00022 #include <libxml/parser.h>
00023 #include <libxml/tree.h>
00024 #include <libxml/valid.h>
00025 #include <libxml/hash.h>
00026 #include <libxml/uri.h>
00027 #include <libxml/xmlerror.h>
00028 #include <libxml/parserInternals.h>
00029 #include <libxml/xpathInternals.h>
00030 #include <libxml/xpath.h>
00031 #include "xslt.h"
00032 #include "xsltInternals.h"
00033 #include "pattern.h"
00034 #include "variables.h"
00035 #include "namespaces.h"
00036 #include "attributes.h"
00037 #include "xsltutils.h"
00038 #include "imports.h"
00039 #include "keys.h"
00040 #include "documents.h"
00041 #include "extensions.h"
00042 #include "preproc.h"
00043 #include "extra.h"
00044 #include "security.h"
00045 
00046 #ifdef WITH_XSLT_DEBUG
00047 #define WITH_XSLT_DEBUG_PARSING
00048 /* #define WITH_XSLT_DEBUG_BLANKS */
00049 #endif
00050 
00051 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
00052 const int xsltLibxsltVersion = LIBXSLT_VERSION;
00053 const int xsltLibxmlVersion = LIBXML_VERSION;
00054 
00055 #ifdef XSLT_REFACTORED
00056 
00057 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
00058 
00059 #define XSLT_ELEMENT_CATEGORY_XSLT 0
00060 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
00061 #define XSLT_ELEMENT_CATEGORY_LRE 2
00062 
00063 /*
00064 * xsltLiteralResultMarker:
00065 * Marker for Literal result elements, in order to avoid multiple attempts
00066 * to recognize such elements in the stylesheet's tree.
00067 * This marker is set on node->psvi during the initial traversal
00068 * of a stylesheet's node tree.
00069 *
00070 const xmlChar *xsltLiteralResultMarker =
00071     (const xmlChar *) "Literal Result Element";
00072 */
00073 
00074 /*
00075 * xsltXSLTTextMarker:
00076 * Marker for xsl:text elements. Used to recognize xsl:text elements
00077 * for post-processing of the stylesheet's tree, where those
00078 * elements are removed from the tree.
00079 */
00080 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
00081 
00082 /*
00083 * xsltXSLTAttrMarker:
00084 * Marker for XSLT attribute on Literal Result Elements.
00085 */
00086 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
00087 
00088 #endif
00089 
00090 #ifdef XSLT_LOCALE_WINAPI
00091 extern xmlRMutexPtr xsltLocaleMutex;
00092 #endif
00093 /*
00094  * Harmless but avoiding a problem when compiling against a
00095  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
00096  */
00097 #ifndef LIBXML_DEBUG_ENABLED
00098 double xmlXPathStringEvalNumber(const xmlChar *str);
00099 #endif
00100 /*
00101  * Useful macros
00102  */
00103 
00104 #ifdef  IS_BLANK
00105 #undef  IS_BLANK
00106 #endif
00107 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||  \
00108                      ((c) == 0x0D))
00109 
00110 #ifdef  IS_BLANK_NODE
00111 #undef  IS_BLANK_NODE
00112 #endif
00113 #define IS_BLANK_NODE(n)                        \
00114     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
00115 
00124 static void
00125 xsltParseContentError(xsltStylesheetPtr style,
00126                xmlNodePtr node)
00127 {
00128     if ((style == NULL) || (node == NULL))
00129     return;
00130 
00131     if (IS_XSLT_ELEM(node))
00132     xsltTransformError(NULL, style, node,
00133         "The XSLT-element '%s' is not allowed at this position.\n",
00134         node->name);
00135     else
00136     xsltTransformError(NULL, style, node,
00137         "The element '%s' is not allowed at this position.\n",
00138         node->name);
00139     style->errors++;
00140 }
00141 
00142 #ifdef XSLT_REFACTORED
00143 #else
00144 
00154 static int
00155 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
00156 {
00157     int i;
00158 
00159     if (style->exclPrefixMax == 0) {
00160         style->exclPrefixMax = 4;
00161         style->exclPrefixTab =
00162             (xmlChar * *)xmlMalloc(style->exclPrefixMax *
00163                                    sizeof(style->exclPrefixTab[0]));
00164         if (style->exclPrefixTab == NULL) {
00165             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
00166             return (-1);
00167         }
00168     }
00169     /* do not push duplicates */
00170     for (i = 0;i < style->exclPrefixNr;i++) {
00171         if (xmlStrEqual(style->exclPrefixTab[i], value))
00172         return(-1);
00173     }
00174     if (style->exclPrefixNr >= style->exclPrefixMax) {
00175         style->exclPrefixMax *= 2;
00176         style->exclPrefixTab =
00177             (xmlChar * *)xmlRealloc(style->exclPrefixTab,
00178                                     style->exclPrefixMax *
00179                                     sizeof(style->exclPrefixTab[0]));
00180         if (style->exclPrefixTab == NULL) {
00181             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
00182             return (-1);
00183         }
00184     }
00185     style->exclPrefixTab[style->exclPrefixNr] = value;
00186     style->exclPrefix = value;
00187     return (style->exclPrefixNr++);
00188 }
00197 static xmlChar *
00198 exclPrefixPop(xsltStylesheetPtr style)
00199 {
00200     xmlChar *ret;
00201 
00202     if (style->exclPrefixNr <= 0)
00203         return (0);
00204     style->exclPrefixNr--;
00205     if (style->exclPrefixNr > 0)
00206         style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
00207     else
00208         style->exclPrefix = NULL;
00209     ret = style->exclPrefixTab[style->exclPrefixNr];
00210     style->exclPrefixTab[style->exclPrefixNr] = 0;
00211     return (ret);
00212 }
00213 #endif
00214 
00215 /************************************************************************
00216  *                                  *
00217  *          Helper functions                *
00218  *                                  *
00219  ************************************************************************/
00220 
00221 static int initialized = 0;
00228 void
00229 xsltInit (void) {
00230     if (initialized == 0) {
00231     initialized = 1;
00232 #ifdef XSLT_LOCALE_WINAPI
00233     xsltLocaleMutex = xmlNewRMutex();
00234 #endif
00235         xsltRegisterAllExtras();
00236     }
00237 }
00238 
00244 void
00245 xsltUninit (void) {
00246     initialized = 0;
00247 }
00248 
00257 int
00258 xsltIsBlank(xmlChar *str) {
00259     if (str == NULL)
00260     return(1);
00261     while (*str != 0) {
00262     if (!(IS_BLANK(*str))) return(0);
00263     str++;
00264     }
00265     return(1);
00266 }
00267 
00268 /************************************************************************
00269  *                                  *
00270  *      Routines to handle XSLT data structures         *
00271  *                                  *
00272  ************************************************************************/
00273 static xsltDecimalFormatPtr
00274 xsltNewDecimalFormat(xmlChar *name)
00275 {
00276     xsltDecimalFormatPtr self;
00277     /* UTF-8 for 0x2030 */
00278     static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
00279 
00280     self = xmlMalloc(sizeof(xsltDecimalFormat));
00281     if (self != NULL) {
00282     self->next = NULL;
00283     self->name = name;
00284     
00285     /* Default values */
00286     self->digit = xmlStrdup(BAD_CAST("#"));
00287     self->patternSeparator = xmlStrdup(BAD_CAST(";"));
00288     self->decimalPoint = xmlStrdup(BAD_CAST("."));
00289     self->grouping = xmlStrdup(BAD_CAST(","));
00290     self->percent = xmlStrdup(BAD_CAST("%"));
00291     self->permille = xmlStrdup(BAD_CAST(permille));
00292     self->zeroDigit = xmlStrdup(BAD_CAST("0"));
00293     self->minusSign = xmlStrdup(BAD_CAST("-"));
00294     self->infinity = xmlStrdup(BAD_CAST("Infinity"));
00295     self->noNumber = xmlStrdup(BAD_CAST("NaN"));
00296     }
00297     return self;
00298 }
00299 
00300 static void
00301 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
00302 {
00303     if (self != NULL) {
00304     if (self->digit)
00305         xmlFree(self->digit);
00306     if (self->patternSeparator)
00307         xmlFree(self->patternSeparator);
00308     if (self->decimalPoint)
00309         xmlFree(self->decimalPoint);
00310     if (self->grouping)
00311         xmlFree(self->grouping);
00312     if (self->percent)
00313         xmlFree(self->percent);
00314     if (self->permille)
00315         xmlFree(self->permille);
00316     if (self->zeroDigit)
00317         xmlFree(self->zeroDigit);
00318     if (self->minusSign)
00319         xmlFree(self->minusSign);
00320     if (self->infinity)
00321         xmlFree(self->infinity);
00322     if (self->noNumber)
00323         xmlFree(self->noNumber);
00324     if (self->name)
00325         xmlFree(self->name);
00326     xmlFree(self);
00327     }
00328 }
00329 
00330 static void
00331 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
00332 {
00333     xsltDecimalFormatPtr iter;
00334     xsltDecimalFormatPtr tmp;
00335 
00336     if (self == NULL)
00337     return;
00338     
00339     iter = self->decimalFormat;
00340     while (iter != NULL) {
00341     tmp = iter->next;
00342     xsltFreeDecimalFormat(iter);
00343     iter = tmp;
00344     }
00345 }
00346 
00356 xsltDecimalFormatPtr
00357 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
00358 {
00359     xsltDecimalFormatPtr result = NULL;
00360 
00361     if (name == NULL)
00362     return style->decimalFormat;
00363 
00364     while (style != NULL) {
00365     for (result = style->decimalFormat->next;
00366          result != NULL;
00367          result = result->next) {
00368         if (xmlStrEqual(name, result->name))
00369         return result;
00370     }
00371     style = xsltNextImport(style);
00372     }
00373     return result;
00374 }
00375 
00376 
00384 static xsltTemplatePtr
00385 xsltNewTemplate(void) {
00386     xsltTemplatePtr cur;
00387 
00388     cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
00389     if (cur == NULL) {
00390     xsltTransformError(NULL, NULL, NULL,
00391         "xsltNewTemplate : malloc failed\n");
00392     return(NULL);
00393     }
00394     memset(cur, 0, sizeof(xsltTemplate));
00395     cur->priority = XSLT_PAT_NO_PRIORITY;
00396     return(cur);
00397 }
00398 
00405 static void
00406 xsltFreeTemplate(xsltTemplatePtr template) {
00407     if (template == NULL)
00408     return;
00409     if (template->match) xmlFree(template->match);
00410 /*
00411 *   NOTE: @name and @nameURI are put into the string dict now.
00412 *   if (template->name) xmlFree(template->name);
00413 *   if (template->nameURI) xmlFree(template->nameURI);
00414 */
00415 /*
00416     if (template->mode) xmlFree(template->mode);
00417     if (template->modeURI) xmlFree(template->modeURI);
00418  */
00419     if (template->inheritedNs) xmlFree(template->inheritedNs);
00420     memset(template, -1, sizeof(xsltTemplate));
00421     xmlFree(template);
00422 }
00423 
00430 static void
00431 xsltFreeTemplateList(xsltTemplatePtr template) {
00432     xsltTemplatePtr cur;
00433 
00434     while (template != NULL) {
00435     cur = template;
00436     template = template->next;
00437     xsltFreeTemplate(cur);
00438     }
00439 }
00440 
00441 #ifdef XSLT_REFACTORED
00442 
00443 static void
00444 xsltFreeNsAliasList(xsltNsAliasPtr item)
00445 {
00446     xsltNsAliasPtr tmp;
00447     
00448     while (item) {
00449     tmp = item;
00450     item = item->next;
00451     xmlFree(tmp);
00452     } 
00453     return;
00454 }
00455 
00456 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
00457 static void
00458 xsltFreeNamespaceMap(xsltNsMapPtr item)
00459 {
00460     xsltNsMapPtr tmp;
00461     
00462     while (item) {
00463     tmp = item;
00464     item = item->next;
00465     xmlFree(tmp);
00466     } 
00467     return;
00468 }
00469 
00470 static xsltNsMapPtr
00471 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
00472             xmlDocPtr doc,
00473             xmlNsPtr ns,
00474             xmlNodePtr elem)
00475 {
00476     xsltNsMapPtr ret;
00477 
00478     if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
00479     return(NULL);
00480 
00481     ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
00482     if (ret == NULL) {
00483     xsltTransformError(NULL, cctxt->style, elem,
00484         "Internal error: (xsltNewNamespaceMapItem) "
00485         "memory allocation failed.\n");
00486     return(NULL);
00487     }
00488     memset(ret, 0, sizeof(xsltNsMap));
00489     ret->doc = doc;
00490     ret->ns = ns;
00491     ret->origNsName = ns->href;
00492     /*
00493     * Store the item at current stylesheet-level.
00494     */
00495     if (cctxt->psData->nsMap != NULL)
00496     ret->next = cctxt->psData->nsMap;
00497     cctxt->psData->nsMap = ret;
00498 
00499     return(ret);
00500 }
00501 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
00502 
00509 static void
00510 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
00511 {
00512     xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;    
00513 
00514     while (ivar) {
00515     ivartmp = ivar;
00516     ivar = ivar->next;
00517     xmlFree(ivartmp);
00518     }
00519 }
00520 
00526 static void
00527 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
00528 {    
00529     if (cctxt == NULL)
00530     return;
00531 #ifdef WITH_XSLT_DEBUG_PARSING
00532     xsltGenericDebug(xsltGenericDebugContext,
00533     "Freeing compilation context\n");
00534     xsltGenericDebug(xsltGenericDebugContext,
00535     "### Max inodes: %d\n", cctxt->maxNodeInfos);
00536     xsltGenericDebug(xsltGenericDebugContext,
00537     "### Max LREs  : %d\n", cctxt->maxLREs);
00538 #endif
00539     /*
00540     * Free node-infos.
00541     */
00542     if (cctxt->inodeList != NULL) {
00543     xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
00544     while (cur != NULL) {
00545         tmp = cur;
00546         cur = cur->next;
00547         xmlFree(tmp);
00548     }
00549     }
00550     if (cctxt->tmpList != NULL)
00551     xsltPointerListFree(cctxt->tmpList);
00552 #ifdef XSLT_REFACTORED_XPATHCOMP
00553     if (cctxt->xpathCtxt != NULL)
00554     xmlXPathFreeContext(cctxt->xpathCtxt);
00555 #endif
00556     if (cctxt->nsAliases != NULL)
00557     xsltFreeNsAliasList(cctxt->nsAliases);
00558 
00559     if (cctxt->ivars)
00560     xsltCompilerVarInfoFree(cctxt);
00561 
00562     xmlFree(cctxt);
00563 }
00564 
00573 static xsltCompilerCtxtPtr
00574 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
00575     xsltCompilerCtxtPtr ret;
00576 
00577     ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
00578     if (ret == NULL) {
00579     xsltTransformError(NULL, style, NULL,
00580         "xsltCompilerCreate: allocation of compiler "
00581         "context failed.\n");
00582     return(NULL);
00583     }
00584     memset(ret, 0, sizeof(xsltCompilerCtxt));
00585 
00586     ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
00587     ret->tmpList = xsltPointerListCreate(20);
00588     if (ret->tmpList == NULL) {
00589     goto internal_err;
00590     }
00591 #ifdef XSLT_REFACTORED_XPATHCOMP
00592     /*
00593     * Create the XPath compilation context in order
00594     * to speed up precompilation of XPath expressions.
00595     */
00596     ret->xpathCtxt = xmlXPathNewContext(NULL);
00597     if (ret->xpathCtxt == NULL)
00598     goto internal_err;
00599 #endif
00600     
00601     return(ret);
00602 
00603 internal_err:
00604     xsltCompilationCtxtFree(ret);
00605     return(NULL);
00606 }
00607 
00608 static void
00609 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
00610 {
00611     xsltEffectiveNsPtr tmp;
00612 
00613     while (first != NULL) {
00614     tmp = first;
00615     first = first->nextInStore;
00616     xmlFree(tmp);
00617     }
00618 }
00619 
00620 static void
00621 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
00622 {
00623     if (data == NULL)
00624     return;
00625 
00626     if (data->inScopeNamespaces != NULL) {
00627     int i;
00628     xsltNsListContainerPtr nsi;
00629     xsltPointerListPtr list =
00630         (xsltPointerListPtr) data->inScopeNamespaces;
00631 
00632     for (i = 0; i < list->number; i++) {
00633         /*
00634         * REVISIT TODO: Free info of in-scope namespaces.
00635         */
00636         nsi = (xsltNsListContainerPtr) list->items[i];
00637         if (nsi->list != NULL)
00638         xmlFree(nsi->list);
00639         xmlFree(nsi);
00640     }
00641     xsltPointerListFree(list);
00642     data->inScopeNamespaces = NULL;
00643     }
00644 
00645     if (data->exclResultNamespaces != NULL) {
00646     int i;
00647     xsltPointerListPtr list = (xsltPointerListPtr)
00648         data->exclResultNamespaces; 
00649     
00650     for (i = 0; i < list->number; i++)
00651         xsltPointerListFree((xsltPointerListPtr) list->items[i]);
00652     
00653     xsltPointerListFree(list);
00654     data->exclResultNamespaces = NULL;
00655     }
00656 
00657     if (data->extElemNamespaces != NULL) {
00658     xsltPointerListPtr list = (xsltPointerListPtr)
00659         data->extElemNamespaces;
00660     int i;
00661 
00662     for (i = 0; i < list->number; i++)
00663         xsltPointerListFree((xsltPointerListPtr) list->items[i]);
00664 
00665     xsltPointerListFree(list);
00666     data->extElemNamespaces = NULL;
00667     }
00668     if (data->effectiveNs) {
00669     xsltLREEffectiveNsNodesFree(data->effectiveNs);
00670     data->effectiveNs = NULL;
00671     }
00672 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
00673     xsltFreeNamespaceMap(data->nsMap);
00674 #endif
00675     xmlFree(data);
00676 }
00677 
00678 static xsltPrincipalStylesheetDataPtr
00679 xsltNewPrincipalStylesheetData(void)
00680 {
00681     xsltPrincipalStylesheetDataPtr ret;
00682 
00683     ret = (xsltPrincipalStylesheetDataPtr)
00684     xmlMalloc(sizeof(xsltPrincipalStylesheetData));
00685     if (ret == NULL) {
00686     xsltTransformError(NULL, NULL, NULL,
00687         "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
00688     return(NULL);
00689     }
00690     memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
00691     
00692     /*
00693     * Global list of in-scope namespaces.
00694     */    
00695     ret->inScopeNamespaces = xsltPointerListCreate(-1);
00696     if (ret->inScopeNamespaces == NULL)
00697     goto internal_err;
00698     /*
00699     * Global list of excluded result ns-decls.
00700     */
00701     ret->exclResultNamespaces = xsltPointerListCreate(-1);
00702     if (ret->exclResultNamespaces == NULL)
00703     goto internal_err;
00704     /*
00705     * Global list of extension instruction namespace names.
00706     */    
00707     ret->extElemNamespaces = xsltPointerListCreate(-1);
00708     if (ret->extElemNamespaces == NULL)
00709     goto internal_err;
00710 
00711     return(ret);
00712 
00713 internal_err:
00714 
00715     return(NULL);
00716 }
00717 
00718 #endif
00719 
00727 xsltStylesheetPtr
00728 xsltNewStylesheet(void) {
00729     xsltStylesheetPtr ret = NULL;    
00730 
00731     ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
00732     if (ret == NULL) {
00733     xsltTransformError(NULL, NULL, NULL,
00734         "xsltNewStylesheet : malloc failed\n");
00735     goto internal_err;
00736     }
00737     memset(ret, 0, sizeof(xsltStylesheet));
00738 
00739     ret->omitXmlDeclaration = -1;
00740     ret->standalone = -1;
00741     ret->decimalFormat = xsltNewDecimalFormat(NULL);
00742     ret->indent = -1;
00743     ret->errors = 0;
00744     ret->warnings = 0;
00745     ret->exclPrefixNr = 0;
00746     ret->exclPrefixMax = 0;
00747     ret->exclPrefixTab = NULL;
00748     ret->extInfos = NULL;
00749     ret->extrasNr = 0;
00750     ret->internalized = 1;
00751     ret->literal_result = 0;
00752     ret->dict = xmlDictCreate();
00753 #ifdef WITH_XSLT_DEBUG
00754     xsltGenericDebug(xsltGenericDebugContext,
00755     "creating dictionary for stylesheet\n");
00756 #endif
00757 
00758     xsltInit();
00759 
00760     return(ret);
00761 
00762 internal_err:
00763     if (ret != NULL)
00764     xsltFreeStylesheet(ret);
00765     return(NULL);
00766 }
00767 
00777 int
00778 xsltAllocateExtra(xsltStylesheetPtr style)
00779 {
00780     return(style->extrasNr++);
00781 }
00782 
00793 int
00794 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
00795 {
00796     if (ctxt->extrasNr >= ctxt->extrasMax) {
00797     int i;
00798     if (ctxt->extrasNr == 0) {
00799         ctxt->extrasMax = 20;
00800         ctxt->extras = (xsltRuntimeExtraPtr)
00801         xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
00802         if (ctxt->extras == NULL) {
00803         xmlGenericError(xmlGenericErrorContext,
00804             "xsltAllocateExtraCtxt: out of memory\n");
00805         ctxt->state = XSLT_STATE_ERROR;
00806         return(0);
00807         }
00808         for (i = 0;i < ctxt->extrasMax;i++) {
00809         ctxt->extras[i].info = NULL;
00810         ctxt->extras[i].deallocate = NULL;
00811         ctxt->extras[i].val.ptr = NULL;
00812         }
00813 
00814     } else {
00815         xsltRuntimeExtraPtr tmp;
00816 
00817         ctxt->extrasMax += 100;
00818         tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
00819                     ctxt->extrasMax * sizeof(xsltRuntimeExtra));
00820         if (tmp == NULL) {
00821         xmlGenericError(xmlGenericErrorContext,
00822             "xsltAllocateExtraCtxt: out of memory\n");
00823         ctxt->state = XSLT_STATE_ERROR;
00824         return(0);
00825         }
00826         ctxt->extras = tmp;
00827         for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
00828         ctxt->extras[i].info = NULL;
00829         ctxt->extras[i].deallocate = NULL;
00830         ctxt->extras[i].val.ptr = NULL;
00831         }
00832     }
00833     }
00834     return(ctxt->extrasNr++);
00835 }
00836 
00843 static void
00844 xsltFreeStylesheetList(xsltStylesheetPtr style) {
00845     xsltStylesheetPtr next;
00846 
00847     while (style != NULL) {
00848     next = style->next;
00849     xsltFreeStylesheet(style);
00850     style = next;
00851     }
00852 }
00853 
00865 static int
00866 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
00867               xmlNodePtr rootElem ATTRIBUTE_UNUSED)
00868 {    
00869 #if 0 /* TODO: Currently disabled, since probably not needed. */
00870     xmlNodePtr cur;
00871 
00872     if ((doc == NULL) || (rootElem == NULL) ||
00873     (rootElem->type != XML_ELEMENT_NODE) ||
00874     (doc != rootElem->doc))
00875     return(-1);
00876 
00877     /*
00878     * Cleanup was suggested by Aleksey Sanin:
00879     * Clear the PSVI field to avoid problems if the
00880     * node-tree of the stylesheet is intended to be used for
00881     * further processing by the user (e.g. for compiling it
00882     * once again - although not recommended).
00883     */
00884 
00885     cur = rootElem;
00886     while (cur != NULL) {
00887     if (cur->type == XML_ELEMENT_NODE) {
00888         /*
00889         * Clear the PSVI field.
00890         */
00891         cur->psvi = NULL;
00892         if (cur->children) {
00893         cur = cur->children;
00894         continue;
00895         }
00896     }
00897 
00898 leave_node:
00899     if (cur == rootElem)
00900         break;
00901     if (cur->next != NULL)
00902         cur = cur->next;
00903     else {
00904         cur = cur->parent;
00905         if (cur == NULL)
00906         break;
00907         goto leave_node;
00908     }
00909     }
00910 #endif /* #if 0 */
00911     return(0);
00912 }
00913 
00920 void
00921 xsltFreeStylesheet(xsltStylesheetPtr style)
00922 {
00923     if (style == NULL)
00924         return;
00925     
00926 #ifdef XSLT_REFACTORED
00927     /*
00928     * Start with a cleanup of the main stylesheet's doc.
00929     */
00930     if ((style->principal == style) && (style->doc))
00931     xsltCleanupStylesheetTree(style->doc,
00932         xmlDocGetRootElement(style->doc));
00933 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
00934     /*
00935     * Restore changed ns-decls before freeing the document.
00936     */
00937     if ((style->doc != NULL) &&
00938     XSLT_HAS_INTERNAL_NSMAP(style))
00939     {
00940     xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
00941         style->doc);    
00942     }
00943 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
00944 #else
00945     /*
00946     * Start with a cleanup of the main stylesheet's doc.
00947     */
00948     if ((style->parent == NULL) && (style->doc))
00949     xsltCleanupStylesheetTree(style->doc,
00950         xmlDocGetRootElement(style->doc));
00951 #endif /* XSLT_REFACTORED */
00952 
00953     xsltFreeKeys(style);
00954     xsltFreeExts(style);
00955     xsltFreeTemplateHashes(style);
00956     xsltFreeDecimalFormatList(style);
00957     xsltFreeTemplateList(style->templates);
00958     xsltFreeAttributeSetsHashes(style);
00959     xsltFreeNamespaceAliasHashes(style);
00960     xsltFreeStylePreComps(style);
00961     /*
00962     * Free documents of all included stylsheet modules of this
00963     * stylesheet level.
00964     */
00965     xsltFreeStyleDocuments(style);
00966     /*
00967     * TODO: Best time to shutdown extension stuff?
00968     */
00969     xsltShutdownExts(style);
00970        
00971     if (style->variables != NULL)
00972         xsltFreeStackElemList(style->variables);
00973     if (style->cdataSection != NULL)
00974         xmlHashFree(style->cdataSection, NULL);
00975     if (style->stripSpaces != NULL)
00976         xmlHashFree(style->stripSpaces, NULL);
00977     if (style->nsHash != NULL)
00978         xmlHashFree(style->nsHash, NULL);
00979     if (style->exclPrefixTab != NULL)
00980         xmlFree(style->exclPrefixTab);
00981     if (style->method != NULL)
00982         xmlFree(style->method);
00983     if (style->methodURI != NULL)
00984         xmlFree(style->methodURI);
00985     if (style->version != NULL)
00986         xmlFree(style->version);
00987     if (style->encoding != NULL)
00988         xmlFree(style->encoding);
00989     if (style->doctypePublic != NULL)
00990         xmlFree(style->doctypePublic);
00991     if (style->doctypeSystem != NULL)
00992         xmlFree(style->doctypeSystem);
00993     if (style->mediaType != NULL)
00994         xmlFree(style->mediaType);
00995     if (style->attVTs)
00996         xsltFreeAVTList(style->attVTs);
00997     if (style->imports != NULL)
00998         xsltFreeStylesheetList(style->imports);
00999 
01000 #ifdef XSLT_REFACTORED
01001     /*
01002     * If this is the principal stylesheet, then
01003     * free its internal data.
01004     */
01005     if (style->principal == style) {
01006     if (style->principalData) {
01007         xsltFreePrincipalStylesheetData(style->principalData);
01008         style->principalData = NULL;
01009     }
01010     }    
01011 #endif
01012     /*
01013     * Better to free the main document of this stylesheet level
01014     * at the end - so here.
01015     */
01016     if (style->doc != NULL) {   
01017         xmlFreeDoc(style->doc);
01018     }
01019 
01020 #ifdef WITH_XSLT_DEBUG
01021     xsltGenericDebug(xsltGenericDebugContext,
01022                      "freeing dictionary from stylesheet\n");
01023 #endif
01024     xmlDictFree(style->dict);
01025 
01026     memset(style, -1, sizeof(xsltStylesheet));
01027     xmlFree(style);
01028 }
01029 
01030 /************************************************************************
01031  *                                  *
01032  *      Parsing of an XSLT Stylesheet               *
01033  *                                  *
01034  ************************************************************************/
01035 
01036 #ifdef XSLT_REFACTORED
01037     /*
01038     * This is now performed in an optimized way in xsltParseXSLTTemplate.
01039     */
01040 #else
01041 
01053 static int
01054 xsltGetInheritedNsList(xsltStylesheetPtr style,
01055                    xsltTemplatePtr template,
01056                    xmlNodePtr node)
01057 {
01058     xmlNsPtr cur;
01059     xmlNsPtr *ret = NULL;
01060     int nbns = 0;
01061     int maxns = 10;
01062     int i;    
01063 
01064     if ((style == NULL) || (template == NULL) || (node == NULL) ||
01065     (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
01066     return(0);
01067     while (node != NULL) {
01068         if (node->type == XML_ELEMENT_NODE) {
01069             cur = node->nsDef;
01070             while (cur != NULL) {
01071         if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
01072             goto skip_ns;
01073 
01074         if ((cur->prefix != NULL) &&
01075             (xsltCheckExtPrefix(style, cur->prefix)))
01076             goto skip_ns;
01077         /*
01078         * Check if this namespace was excluded.
01079         * Note that at this point only the exclusions defined
01080         * on the topmost stylesheet element are in the exclusion-list.
01081         */
01082         for (i = 0;i < style->exclPrefixNr;i++) {
01083             if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
01084             goto skip_ns;
01085         }
01086                 if (ret == NULL) {
01087                     ret =
01088                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
01089                                                sizeof(xmlNsPtr));
01090                     if (ret == NULL) {
01091                         xmlGenericError(xmlGenericErrorContext,
01092                                         "xsltGetInheritedNsList : out of memory!\n");
01093                         return(0);
01094                     }
01095                     ret[nbns] = NULL;
01096                 }
01097         /*
01098         * Skip shadowed namespace bindings.
01099         */
01100                 for (i = 0; i < nbns; i++) {
01101                     if ((cur->prefix == ret[i]->prefix) ||
01102                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
01103                         break;
01104                 }
01105                 if (i >= nbns) {
01106                     if (nbns >= maxns) {
01107                         maxns *= 2;
01108                         ret = (xmlNsPtr *) xmlRealloc(ret,
01109                                                       (maxns +
01110                                                        1) *
01111                                                       sizeof(xmlNsPtr));
01112                         if (ret == NULL) {
01113                             xmlGenericError(xmlGenericErrorContext,
01114                                             "xsltGetInheritedNsList : realloc failed!\n");
01115                             return(0);
01116                         }
01117                     }
01118                     ret[nbns++] = cur;
01119                     ret[nbns] = NULL;
01120                 }
01121 skip_ns:
01122                 cur = cur->next;
01123             }
01124         }
01125         node = node->parent;
01126     }
01127     if (nbns != 0) {
01128 #ifdef WITH_XSLT_DEBUG_PARSING
01129         xsltGenericDebug(xsltGenericDebugContext,
01130                          "template has %d inherited namespaces\n", nbns);
01131 #endif
01132     template->inheritedNsNr = nbns;
01133     template->inheritedNs = ret;
01134     }
01135     return (nbns);
01136 }
01137 #endif /* else of XSLT_REFACTORED */
01138 
01148 void
01149 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
01150 {
01151     xmlChar *elements,
01152      *prop;
01153     xmlChar *element,
01154      *end;
01155 
01156     if ((cur == NULL) || (style == NULL))
01157         return;
01158    
01159     prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
01160     if (prop != NULL) {
01161         if (style->version != NULL)
01162             xmlFree(style->version);
01163         style->version = prop;
01164     }
01165 
01166     prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
01167     if (prop != NULL) {
01168         if (style->encoding != NULL)
01169             xmlFree(style->encoding);
01170         style->encoding = prop;
01171     }
01172 
01173     /* relaxed to support xt:document
01174     * TODO KB: What does "relaxed to support xt:document" mean?
01175     */
01176     prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
01177     if (prop != NULL) {
01178         const xmlChar *URI;
01179 
01180         if (style->method != NULL)
01181             xmlFree(style->method);
01182         style->method = NULL;
01183         if (style->methodURI != NULL)
01184             xmlFree(style->methodURI);
01185         style->methodURI = NULL;
01186 
01187     /*
01188     * TODO: Don't use xsltGetQNameURI().
01189     */
01190     URI = xsltGetQNameURI(cur, &prop);
01191     if (prop == NULL) {
01192         if (style != NULL) style->errors++;
01193     } else if (URI == NULL) {
01194             if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
01195                 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
01196                 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
01197                 style->method = prop;
01198             } else {
01199         xsltTransformError(NULL, style, cur,
01200                                  "invalid value for method: %s\n", prop);
01201                 if (style != NULL) style->warnings++;
01202             }
01203     } else {
01204         style->method = prop;
01205         style->methodURI = xmlStrdup(URI);
01206     }
01207     }
01208 
01209     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
01210     if (prop != NULL) {
01211         if (style->doctypeSystem != NULL)
01212             xmlFree(style->doctypeSystem);
01213         style->doctypeSystem = prop;
01214     }
01215 
01216     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
01217     if (prop != NULL) {
01218         if (style->doctypePublic != NULL)
01219             xmlFree(style->doctypePublic);
01220         style->doctypePublic = prop;
01221     }
01222 
01223     prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
01224     if (prop != NULL) {
01225         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
01226             style->standalone = 1;
01227         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
01228             style->standalone = 0;
01229         } else {
01230         xsltTransformError(NULL, style, cur,
01231                              "invalid value for standalone: %s\n", prop);
01232             style->errors++;
01233         }
01234         xmlFree(prop);
01235     }
01236 
01237     prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
01238     if (prop != NULL) {
01239         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
01240             style->indent = 1;
01241         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
01242             style->indent = 0;
01243         } else {
01244         xsltTransformError(NULL, style, cur,
01245                              "invalid value for indent: %s\n", prop);
01246             style->errors++;
01247         }
01248         xmlFree(prop);
01249     }
01250 
01251     prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
01252     if (prop != NULL) {
01253         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
01254             style->omitXmlDeclaration = 1;
01255         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
01256             style->omitXmlDeclaration = 0;
01257         } else {
01258         xsltTransformError(NULL, style, cur,
01259                              "invalid value for omit-xml-declaration: %s\n",
01260                              prop);
01261             style->errors++;
01262         }
01263         xmlFree(prop);
01264     }
01265 
01266     elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
01267     NULL);
01268     if (elements != NULL) {
01269         if (style->cdataSection == NULL)
01270             style->cdataSection = xmlHashCreate(10);
01271         if (style->cdataSection == NULL)
01272             return;
01273 
01274         element = elements;
01275         while (*element != 0) {
01276             while (IS_BLANK(*element))
01277                 element++;
01278             if (*element == 0)
01279                 break;
01280             end = element;
01281             while ((*end != 0) && (!IS_BLANK(*end)))
01282                 end++;
01283             element = xmlStrndup(element, end - element);
01284             if (element) {      
01285 #ifdef WITH_XSLT_DEBUG_PARSING
01286                 xsltGenericDebug(xsltGenericDebugContext,
01287                                  "add cdata section output element %s\n",
01288                                  element);
01289 #endif
01290         if (xmlValidateQName(BAD_CAST element, 0) != 0) {
01291             xsltTransformError(NULL, style, cur,
01292             "Attribute 'cdata-section-elements': The value "
01293             "'%s' is not a valid QName.\n", element);
01294             xmlFree(element);
01295             style->errors++;
01296         } else {
01297             const xmlChar *URI;
01298 
01299             /*
01300             * TODO: Don't use xsltGetQNameURI().
01301             */
01302             URI = xsltGetQNameURI(cur, &element);
01303             if (element == NULL) {
01304             /*
01305             * TODO: We'll report additionally an error
01306             *  via the stylesheet's error handling.         
01307             */
01308             xsltTransformError(NULL, style, cur,
01309                 "Attribute 'cdata-section-elements': The value "
01310                 "'%s' is not a valid QName.\n", element);
01311             style->errors++;
01312             } else {
01313             xmlNsPtr ns;
01314             
01315             /*
01316             * XSLT-1.0 "Each QName is expanded into an
01317             *  expanded-name using the namespace declarations in
01318             *  effect on the xsl:output element in which the QName
01319             *  occurs; if there is a default namespace, it is used
01320             *  for QNames that do not have a prefix"
01321             * NOTE: Fix of bug #339570.
01322             */
01323             if (URI == NULL) {
01324                 ns = xmlSearchNs(style->doc, cur, NULL);
01325                 if (ns != NULL)
01326                 URI = ns->href;
01327             }          
01328             xmlHashAddEntry2(style->cdataSection, element, URI,
01329                 (void *) "cdata");
01330             xmlFree(element);
01331             }
01332         }
01333             }
01334             element = end;
01335         }
01336         xmlFree(elements);
01337     }
01338 
01339     prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
01340     if (prop != NULL) {
01341     if (style->mediaType)
01342         xmlFree(style->mediaType);
01343     style->mediaType = prop;
01344     }
01345     if (cur->children != NULL) {
01346     xsltParseContentError(style, cur->children);
01347     }
01348 }
01349 
01365 static void
01366 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
01367 {
01368     xmlChar *prop;
01369     xsltDecimalFormatPtr format;
01370     xsltDecimalFormatPtr iter;
01371     
01372     if ((cur == NULL) || (style == NULL))
01373     return;
01374 
01375     format = style->decimalFormat;
01376     
01377     prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
01378     if (prop != NULL) {
01379     format = xsltDecimalFormatGetByName(style, prop);
01380     if (format != NULL) {
01381         xsltTransformError(NULL, style, cur,
01382      "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
01383         if (style != NULL) style->warnings++;
01384         return;
01385     }
01386     format = xsltNewDecimalFormat(prop);
01387     if (format == NULL) {
01388         xsltTransformError(NULL, style, cur,
01389      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
01390         if (style != NULL) style->errors++;
01391         return;
01392     }
01393     /* Append new decimal-format structure */
01394     for (iter = style->decimalFormat; iter->next; iter = iter->next)
01395         ;
01396     if (iter)
01397         iter->next = format;
01398     }
01399 
01400     prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
01401     if (prop != NULL) {
01402     if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
01403     format->decimalPoint  = prop;
01404     }
01405     
01406     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
01407     if (prop != NULL) {
01408     if (format->grouping != NULL) xmlFree(format->grouping);
01409     format->grouping  = prop;
01410     }
01411 
01412     prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
01413     if (prop != NULL) {
01414     if (format->infinity != NULL) xmlFree(format->infinity);
01415     format->infinity  = prop;
01416     }
01417     
01418     prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
01419     if (prop != NULL) {
01420     if (format->minusSign != NULL) xmlFree(format->minusSign);
01421     format->minusSign  = prop;
01422     }
01423     
01424     prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
01425     if (prop != NULL) {
01426     if (format->noNumber != NULL) xmlFree(format->noNumber);
01427     format->noNumber  = prop;
01428     }
01429     
01430     prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
01431     if (prop != NULL) {
01432     if (format->percent != NULL) xmlFree(format->percent);
01433     format->percent  = prop;
01434     }
01435     
01436     prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
01437     if (prop != NULL) {
01438     if (format->permille != NULL) xmlFree(format->permille);
01439     format->permille  = prop;
01440     }
01441     
01442     prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
01443     if (prop != NULL) {
01444     if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
01445     format->zeroDigit  = prop;
01446     }
01447     
01448     prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
01449     if (prop != NULL) {
01450     if (format->digit != NULL) xmlFree(format->digit);
01451     format->digit  = prop;
01452     }
01453     
01454     prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
01455     if (prop != NULL) {
01456     if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
01457     format->patternSeparator  = prop;
01458     }
01459     if (cur->children != NULL) {
01460     xsltParseContentError(style, cur->children);
01461     }
01462 }
01463 
01473 static void
01474 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
01475     xmlChar *elements;
01476     xmlChar *element, *end;
01477 
01478     if ((cur == NULL) || (style == NULL))
01479     return;
01480 
01481     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
01482     if (elements == NULL) {
01483     xsltTransformError(NULL, style, cur,
01484         "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
01485     if (style != NULL) style->warnings++;
01486     return;
01487     }
01488 
01489     if (style->stripSpaces == NULL)
01490     style->stripSpaces = xmlHashCreate(10);
01491     if (style->stripSpaces == NULL)
01492     return;
01493 
01494     element = elements;
01495     while (*element != 0) {
01496     while (IS_BLANK(*element)) element++;
01497     if (*element == 0)
01498         break;
01499         end = element;
01500     while ((*end != 0) && (!IS_BLANK(*end))) end++;
01501     element = xmlStrndup(element, end - element);
01502     if (element) {
01503 #ifdef WITH_XSLT_DEBUG_PARSING
01504         xsltGenericDebug(xsltGenericDebugContext,
01505         "add preserved space element %s\n", element);
01506 #endif
01507         if (xmlStrEqual(element, (const xmlChar *)"*")) {
01508         style->stripAll = -1;
01509         } else {
01510         const xmlChar *URI;
01511 
01512         /*
01513         * TODO: Don't use xsltGetQNameURI().
01514         */
01515                 URI = xsltGetQNameURI(cur, &element);
01516 
01517         xmlHashAddEntry2(style->stripSpaces, element, URI,
01518                 (xmlChar *) "preserve");
01519         }
01520         xmlFree(element);
01521     }
01522     element = end;
01523     }
01524     xmlFree(elements);
01525     if (cur->children != NULL) {
01526     xsltParseContentError(style, cur->children);
01527     }
01528 }
01529 
01530 #ifdef XSLT_REFACTORED
01531 #else
01532 
01546 static void
01547 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
01548                  int isXsltElem) {
01549     xmlChar *prefixes;
01550     xmlChar *prefix, *end;
01551 
01552     if ((cur == NULL) || (style == NULL))
01553     return;
01554 
01555     if (isXsltElem) {
01556     /* For xsl:stylesheet/xsl:transform. */
01557     prefixes = xmlGetNsProp(cur,
01558         (const xmlChar *)"extension-element-prefixes", NULL);
01559     } else {
01560     /* For literal result elements and extension instructions. */
01561     prefixes = xmlGetNsProp(cur,
01562         (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
01563     }
01564     if (prefixes == NULL) {
01565     return;
01566     }
01567 
01568     prefix = prefixes;
01569     while (*prefix != 0) {
01570     while (IS_BLANK(*prefix)) prefix++;
01571     if (*prefix == 0)
01572         break;
01573         end = prefix;
01574     while ((*end != 0) && (!IS_BLANK(*end))) end++;
01575     prefix = xmlStrndup(prefix, end - prefix);
01576     if (prefix) {
01577         xmlNsPtr ns;
01578 
01579         if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
01580         ns = xmlSearchNs(style->doc, cur, NULL);
01581         else
01582         ns = xmlSearchNs(style->doc, cur, prefix);
01583         if (ns == NULL) {
01584         xsltTransformError(NULL, style, cur,
01585         "xsl:extension-element-prefix : undefined namespace %s\n",
01586                              prefix);
01587         if (style != NULL) style->warnings++;
01588         } else {
01589 #ifdef WITH_XSLT_DEBUG_PARSING
01590         xsltGenericDebug(xsltGenericDebugContext,
01591             "add extension prefix %s\n", prefix);
01592 #endif
01593         xsltRegisterExtPrefix(style, prefix, ns->href);
01594         }
01595         xmlFree(prefix);
01596     }
01597     prefix = end;
01598     }
01599     xmlFree(prefixes);
01600 }
01601 #endif /* else of XSLT_REFACTORED */
01602 
01612 static void
01613 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
01614     xmlChar *elements;
01615     xmlChar *element, *end;
01616 
01617     if ((cur == NULL) || (style == NULL))
01618     return;
01619 
01620     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
01621     if (elements == NULL) {
01622     xsltTransformError(NULL, style, cur,
01623         "xsltParseStylesheetStripSpace: missing elements attribute\n");
01624     if (style != NULL) style->warnings++;
01625     return;
01626     }
01627 
01628     if (style->stripSpaces == NULL)
01629     style->stripSpaces = xmlHashCreate(10);
01630     if (style->stripSpaces == NULL)
01631     return;
01632 
01633     element = elements;
01634     while (*element != 0) {
01635     while (IS_BLANK(*element)) element++;
01636     if (*element == 0)
01637         break;
01638         end = element;
01639     while ((*end != 0) && (!IS_BLANK(*end))) end++;
01640     element = xmlStrndup(element, end - element);
01641     if (element) {
01642 #ifdef WITH_XSLT_DEBUG_PARSING
01643         xsltGenericDebug(xsltGenericDebugContext,
01644         "add stripped space element %s\n", element);
01645 #endif
01646         if (xmlStrEqual(element, (const xmlChar *)"*")) {
01647         style->stripAll = 1;
01648         } else {
01649         const xmlChar *URI;
01650 
01651         /*
01652         * TODO: Don't use xsltGetQNameURI().
01653         */
01654                 URI = xsltGetQNameURI(cur, &element);
01655 
01656         xmlHashAddEntry2(style->stripSpaces, element, URI,
01657                     (xmlChar *) "strip");
01658         }
01659         xmlFree(element);
01660     }
01661     element = end;
01662     }
01663     xmlFree(elements);
01664     if (cur->children != NULL) {
01665     xsltParseContentError(style, cur->children);
01666     }
01667 }
01668 
01669 #ifdef XSLT_REFACTORED
01670 #else
01671 
01682 static int
01683 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
01684                  int isXsltElem)
01685 {
01686     int nb = 0;
01687     xmlChar *prefixes;
01688     xmlChar *prefix, *end;
01689 
01690     if ((cur == NULL) || (style == NULL))
01691     return(0);
01692 
01693     if (isXsltElem)
01694     prefixes = xmlGetNsProp(cur,
01695         (const xmlChar *)"exclude-result-prefixes", NULL);
01696     else
01697     prefixes = xmlGetNsProp(cur,
01698         (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
01699 
01700     if (prefixes == NULL) {
01701     return(0);
01702     }
01703 
01704     prefix = prefixes;
01705     while (*prefix != 0) {
01706     while (IS_BLANK(*prefix)) prefix++;
01707     if (*prefix == 0)
01708         break;
01709         end = prefix;
01710     while ((*end != 0) && (!IS_BLANK(*end))) end++;
01711     prefix = xmlStrndup(prefix, end - prefix);
01712     if (prefix) {
01713         xmlNsPtr ns;
01714 
01715         if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
01716         ns = xmlSearchNs(style->doc, cur, NULL);
01717         else
01718         ns = xmlSearchNs(style->doc, cur, prefix);
01719         if (ns == NULL) {
01720         xsltTransformError(NULL, style, cur,
01721         "xsl:exclude-result-prefixes : undefined namespace %s\n",
01722                              prefix);
01723         if (style != NULL) style->warnings++;
01724         } else {
01725         if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
01726 #ifdef WITH_XSLT_DEBUG_PARSING
01727             xsltGenericDebug(xsltGenericDebugContext,
01728             "exclude result prefix %s\n", prefix);
01729 #endif
01730             nb++;
01731         }
01732         }
01733         xmlFree(prefix);
01734     }
01735     prefix = end;
01736     }
01737     xmlFree(prefixes);
01738     return(nb);
01739 }
01740 #endif /* else of XSLT_REFACTORED */
01741 
01742 #ifdef XSLT_REFACTORED
01743 
01744 /*
01745 * xsltTreeEnsureXMLDecl:
01746 * @doc: the doc
01747 * 
01748 * BIG NOTE:
01749 *  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
01750 * Ensures that there is an XML namespace declaration on the doc.
01751 * 
01752 * Returns the XML ns-struct or NULL on API and internal errors.
01753 */
01754 static xmlNsPtr
01755 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
01756 {
01757     if (doc == NULL)
01758     return (NULL);
01759     if (doc->oldNs != NULL)
01760     return (doc->oldNs);
01761     {
01762     xmlNsPtr ns;
01763     ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
01764     if (ns == NULL) {
01765         xmlGenericError(xmlGenericErrorContext,
01766         "xsltTreeEnsureXMLDecl: Failed to allocate "
01767         "the XML namespace.\n");    
01768         return (NULL);
01769     }
01770     memset(ns, 0, sizeof(xmlNs));
01771     ns->type = XML_LOCAL_NAMESPACE;
01772     /*
01773     * URGENT TODO: revisit this.
01774     */
01775 #ifdef LIBXML_NAMESPACE_DICT
01776     if (doc->dict)
01777         ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
01778     else
01779         ns->href = xmlStrdup(XML_XML_NAMESPACE);
01780 #else
01781     ns->href = xmlStrdup(XML_XML_NAMESPACE); 
01782 #endif
01783     ns->prefix = xmlStrdup((const xmlChar *)"xml");
01784     doc->oldNs = ns;
01785     return (ns);
01786     }
01787 }
01788 
01789 /*
01790 * xsltTreeAcquireStoredNs:
01791 * @doc: the doc
01792 * @nsName: the namespace name
01793 * @prefix: the prefix
01794 * 
01795 * BIG NOTE:
01796 *  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
01797 * Creates or reuses an xmlNs struct on doc->oldNs with
01798 * the given prefix and namespace name.
01799 * 
01800 * Returns the aquired ns struct or NULL in case of an API
01801 *         or internal error.
01802 */
01803 static xmlNsPtr
01804 xsltTreeAcquireStoredNs(xmlDocPtr doc,
01805             const xmlChar *nsName,
01806             const xmlChar *prefix)
01807 {
01808     xmlNsPtr ns;
01809 
01810     if (doc == NULL)
01811     return (NULL);
01812     if (doc->oldNs != NULL)
01813     ns = doc->oldNs;
01814     else
01815     ns = xsltTreeEnsureXMLDecl(doc);
01816     if (ns == NULL)
01817     return (NULL);
01818     if (ns->next != NULL) {
01819     /* Reuse. */
01820     ns = ns->next;
01821     while (ns != NULL) {
01822         if ((ns->prefix == NULL) != (prefix == NULL)) {
01823         /* NOP */
01824         } else if (prefix == NULL) {
01825         if (xmlStrEqual(ns->href, nsName))
01826             return (ns);
01827         } else {
01828         if ((ns->prefix[0] == prefix[0]) &&
01829              xmlStrEqual(ns->prefix, prefix) &&
01830              xmlStrEqual(ns->href, nsName))
01831             return (ns);
01832         
01833         }
01834         if (ns->next == NULL)
01835         break;
01836         ns = ns->next;
01837     }
01838     }
01839     /* Create. */
01840     ns->next = xmlNewNs(NULL, nsName, prefix);
01841     return (ns->next);
01842 }
01843 
01850 static int
01851 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
01852             xmlNodePtr elem)
01853 {
01854     xmlNsPtr ns;
01855     xsltNsAliasPtr alias;
01856 
01857     if ((cctxt == NULL) || (elem == NULL))
01858     return(-1);
01859     if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
01860     return(0);
01861 
01862     alias = cctxt->nsAliases;           
01863     while (alias != NULL) {
01864     if ( /* If both namespaces are NULL... */
01865         ( (elem->ns == NULL) &&
01866         ((alias->literalNs == NULL) ||
01867         (alias->literalNs->href == NULL)) ) ||
01868         /* ... or both namespace are equal */
01869         ( (elem->ns != NULL) &&
01870         (alias->literalNs != NULL) &&
01871         xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
01872     {
01873         if ((alias->targetNs != NULL) &&
01874         (alias->targetNs->href != NULL))
01875         {
01876         /*
01877         * Convert namespace.
01878         */
01879         if (elem->doc == alias->docOfTargetNs) {
01880             /*
01881             * This is the nice case: same docs.
01882             * This will eventually assign a ns-decl which
01883             * is shadowed, but this has no negative effect on
01884             * the generation of the result tree.
01885             */
01886             elem->ns = alias->targetNs;
01887         } else {
01888             /*
01889             * This target xmlNs originates from a different
01890             * stylesheet tree. Try to locate it in the
01891             * in-scope namespaces.
01892             * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
01893             */
01894             ns = xmlSearchNs(elem->doc, elem,
01895             alias->targetNs->prefix);           
01896             /*
01897             * If no matching ns-decl found, then assign a
01898             * ns-decl stored in xmlDoc.
01899             */
01900             if ((ns == NULL) ||
01901             (! xmlStrEqual(ns->href, alias->targetNs->href)))
01902             {
01903             /*
01904             * BIG NOTE: The use of xsltTreeAcquireStoredNs()
01905             *  is not very efficient, but currently I don't
01906             *  see an other way of *safely* changing a node's
01907             *  namespace, since the xmlNs struct in
01908             *  alias->targetNs might come from an other
01909             *  stylesheet tree. So we need to anchor it in the
01910             *  current document, without adding it to the tree,
01911             *  which would otherwise change the in-scope-ns
01912             *  semantic of the tree.
01913             */
01914             ns = xsltTreeAcquireStoredNs(elem->doc,
01915                 alias->targetNs->href,
01916                 alias->targetNs->prefix);
01917             
01918             if (ns == NULL) {
01919                 xsltTransformError(NULL, cctxt->style, elem,
01920                 "Internal error in "
01921                 "xsltLREBuildEffectiveNs(): "
01922                 "failed to acquire a stored "
01923                 "ns-declaration.\n");
01924                 cctxt->style->errors++;
01925                 return(-1);
01926                 
01927             }
01928             }
01929             elem->ns = ns;
01930         }          
01931         } else {
01932         /*
01933         * Move into or leave in the NULL namespace.
01934         */
01935         elem->ns = NULL;
01936         }
01937         break;
01938     }
01939     alias = alias->next;
01940     }
01941     /*
01942     * Same with attributes of literal result elements.
01943     */
01944     if (elem->properties != NULL) {
01945     xmlAttrPtr attr = elem->properties;
01946     
01947     while (attr != NULL) {
01948         if (attr->ns == NULL) {
01949         attr = attr->next;
01950         continue;
01951         }
01952         alias = cctxt->nsAliases;
01953         while (alias != NULL) {
01954         if ( /* If both namespaces are NULL... */
01955             ( (elem->ns == NULL) &&
01956             ((alias->literalNs == NULL) ||
01957             (alias->literalNs->href == NULL)) ) ||
01958             /* ... or both namespace are equal */
01959             ( (elem->ns != NULL) &&
01960             (alias->literalNs != NULL) &&
01961             xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
01962         {
01963             if ((alias->targetNs != NULL) &&
01964             (alias->targetNs->href != NULL))
01965             {           
01966             if (elem->doc == alias->docOfTargetNs) {
01967                 elem->ns = alias->targetNs;
01968             } else {
01969                 ns = xmlSearchNs(elem->doc, elem,
01970                 alias->targetNs->prefix);
01971                 if ((ns == NULL) ||
01972                 (! xmlStrEqual(ns->href, alias->targetNs->href)))
01973                 {
01974                 ns = xsltTreeAcquireStoredNs(elem->doc,
01975                     alias->targetNs->href,
01976                     alias->targetNs->prefix);
01977                 
01978                 if (ns == NULL) {
01979                     xsltTransformError(NULL, cctxt->style, elem,
01980                     "Internal error in "
01981                     "xsltLREBuildEffectiveNs(): "
01982                     "failed to acquire a stored "
01983                     "ns-declaration.\n");
01984                     cctxt->style->errors++;
01985                     return(-1);
01986                     
01987                 }
01988                 }
01989                 elem->ns = ns;
01990             }
01991             } else {
01992             /*
01993             * Move into or leave in the NULL namespace.
01994             */
01995             elem->ns = NULL;
01996             }
01997             break;
01998         }
01999         alias = alias->next;
02000         }
02001         
02002         attr = attr->next;
02003     }
02004     }
02005     return(0);
02006 }
02007 
02021 static int
02022 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
02023                  xsltStyleItemLRElementInfoPtr item,
02024                  xmlNodePtr elem,
02025                  int isLRE)
02026 {
02027     xmlNsPtr ns, tmpns;
02028     xsltEffectiveNsPtr effNs, lastEffNs = NULL;
02029     int i, j, holdByElem;
02030     xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
02031     xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
02032 
02033     if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
02034     (item == NULL) || (item->effectiveNs != NULL))
02035     return(-1);
02036 
02037     if (item->inScopeNs == NULL)    
02038     return(0);
02039 
02040     extElemNs = cctxt->inode->extElemNs;
02041     exclResultNs = cctxt->inode->exclResultNs;
02042 
02043     for (i = 0; i < item->inScopeNs->totalNumber; i++) {
02044     ns = item->inScopeNs->list[i];
02045     /*
02046     * Skip namespaces designated as excluded namespaces
02047     * -------------------------------------------------
02048     *
02049     * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
02050     *  which are target namespaces of namespace-aliases
02051     *  regardless if designated as excluded.
02052     *
02053     * Exclude the XSLT namespace.
02054     */
02055     if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
02056         goto skip_ns;
02057 
02058     /*
02059     * Apply namespace aliasing
02060     * ------------------------
02061     *
02062     * SPEC XSLT 2.0
02063     *  "- A namespace node whose string value is a literal namespace
02064     *     URI is not copied to the result tree.
02065     *   - A namespace node whose string value is a target namespace URI
02066     *     is copied to the result tree, whether or not the URI
02067     *     identifies an excluded namespace."
02068     * 
02069     * NOTE: The ns-aliasing machanism is non-cascading.
02070     *  (checked with Saxon, Xalan and MSXML .NET).
02071     * URGENT TODO: is style->nsAliases the effective list of
02072     *  ns-aliases, or do we need to lookup the whole
02073     *  import-tree?
02074     * TODO: Get rid of import-tree lookup.
02075     */
02076     if (cctxt->hasNsAliases) {
02077         xsltNsAliasPtr alias;
02078         /*
02079         * First check for being a target namespace.
02080         */
02081         alias = cctxt->nsAliases;
02082         do {
02083         /*
02084         * TODO: Is xmlns="" handled already?
02085         */
02086         if ((alias->targetNs != NULL) &&
02087             (xmlStrEqual(alias->targetNs->href, ns->href)))
02088         {
02089             /*
02090             * Recognized as a target namespace; use it regardless
02091             * if excluded otherwise.
02092             */
02093             goto add_effective_ns;
02094         }
02095         alias = alias->next;
02096         } while (alias != NULL);
02097 
02098         alias = cctxt->nsAliases;
02099         do {
02100         /*
02101         * TODO: Is xmlns="" handled already?
02102         */
02103         if ((alias->literalNs != NULL) &&
02104             (xmlStrEqual(alias->literalNs->href, ns->href)))
02105         {
02106             /*
02107             * Recognized as an namespace alias; do not use it.
02108             */
02109             goto skip_ns;
02110         }
02111         alias = alias->next;
02112         } while (alias != NULL);
02113     }
02114     
02115     /*
02116     * Exclude excluded result namespaces.
02117     */
02118     if (exclResultNs) {
02119         for (j = 0; j < exclResultNs->number; j++)
02120         if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
02121             goto skip_ns;
02122     }
02123     /*
02124     * Exclude extension-element namespaces.
02125     */
02126     if (extElemNs) {
02127         for (j = 0; j < extElemNs->number; j++)
02128         if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
02129             goto skip_ns;
02130     }
02131 
02132 add_effective_ns:
02133     /*
02134     * OPTIMIZE TODO: This information may not be needed.
02135     */
02136     if (isLRE && (elem->nsDef != NULL)) {
02137         holdByElem = 0;
02138         tmpns = elem->nsDef;
02139         do {
02140         if (tmpns == ns) {
02141             holdByElem = 1;
02142             break;
02143         }
02144         tmpns = tmpns->next;
02145         } while (tmpns != NULL);        
02146     } else
02147         holdByElem = 0;
02148     
02149     
02150     /*
02151     * Add the effective namespace declaration.
02152     */
02153     effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
02154     if (effNs == NULL) {
02155         xsltTransformError(NULL, cctxt->style, elem,
02156         "Internal error in xsltLREBuildEffectiveNs(): "
02157         "failed to allocate memory.\n");
02158         cctxt->style->errors++;
02159         return(-1);
02160     }
02161     if (cctxt->psData->effectiveNs == NULL) {
02162         cctxt->psData->effectiveNs = effNs;
02163         effNs->nextInStore = NULL;   
02164     } else {
02165         effNs->nextInStore = cctxt->psData->effectiveNs;
02166         cctxt->psData->effectiveNs = effNs;
02167     }
02168 
02169     effNs->next = NULL;
02170     effNs->prefix = ns->prefix;
02171     effNs->nsName = ns->href;
02172     effNs->holdByElem = holdByElem;
02173     
02174     if (lastEffNs == NULL)
02175         item->effectiveNs = effNs;
02176     else
02177         lastEffNs->next = effNs;
02178     lastEffNs = effNs;
02179     
02180 skip_ns:
02181     {}
02182     }
02183     return(0);
02184 }
02185 
02186 
02194 static int
02195 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
02196           xmlNodePtr elem,
02197           int isLRE)
02198 {
02199     xsltStyleItemLRElementInfoPtr item;
02200 
02201     if ((cctxt == NULL) || (cctxt->inode == NULL))
02202     return(-1);
02203 
02204     item = (xsltStyleItemLRElementInfoPtr)
02205     xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
02206     if (item == NULL) {
02207     xsltTransformError(NULL, cctxt->style, NULL,
02208         "Internal error in xsltLREInfoCreate(): "
02209         "memory allocation failed.\n");
02210     cctxt->style->errors++;
02211     return(-1);
02212     }
02213     memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
02214     item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
02215     /*
02216     * Store it in the stylesheet.
02217     */
02218     item->next = cctxt->style->preComps;
02219     cctxt->style->preComps = (xsltElemPreCompPtr) item;
02220     /*
02221     * @inScopeNs are used for execution of XPath expressions
02222     *  in AVTs.
02223     */
02224     item->inScopeNs = cctxt->inode->inScopeNs;
02225     
02226     if (elem)
02227     xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
02228 
02229     cctxt->inode->litResElemInfo = item;
02230     cctxt->inode->nsChanged = 0;
02231     cctxt->maxLREs++;
02232     return(0);
02233 }
02234 
02243 static xsltVarInfoPtr
02244 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
02245                   xmlNodePtr inst,
02246                   const xmlChar *name,
02247                   const xmlChar *nsName)
02248 {
02249     xsltVarInfoPtr ivar;
02250 
02251     if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
02252     ivar = cctxt->ivar->next;
02253     } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
02254     ivar = cctxt->ivars;
02255     } else {
02256     ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
02257     if (ivar == NULL) {
02258         xsltTransformError(NULL, cctxt->style, inst,
02259         "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
02260         cctxt->style->errors++;
02261         return(NULL);
02262     }
02263     /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
02264     if (cctxt->ivars == NULL) {
02265         cctxt->ivars = ivar;
02266         ivar->prev = NULL;
02267     } else {
02268         cctxt->ivar->next = ivar;
02269         ivar->prev = cctxt->ivar;
02270     }
02271     cctxt->ivar = ivar;
02272     ivar->next = NULL;
02273     }
02274     ivar->depth = cctxt->depth;
02275     ivar->name = name;
02276     ivar->nsName = nsName;
02277     return(ivar);
02278 }
02279 
02287 static void
02288 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
02289 {
02290 
02291     while ((cctxt->ivar != NULL) &&
02292     (cctxt->ivar->depth > cctxt->depth))
02293     {
02294     cctxt->ivar = cctxt->ivar->prev;
02295     }
02296 }
02297 
02298 /*
02299 * xsltCompilerNodePush:
02300 *
02301 * @cctxt: the compilation context
02302 * @node: the node to be pushed (this can also be the doc-node)
02303 *
02304 * 
02305 *
02306 * Returns the current node info structure or
02307 *         NULL in case of an internal error.
02308 */
02309 static xsltCompilerNodeInfoPtr
02310 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
02311 {    
02312     xsltCompilerNodeInfoPtr inode, iprev;
02313 
02314     if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {   
02315     inode = cctxt->inode->next;
02316     } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
02317     inode = cctxt->inodeList;   
02318     } else {
02319     /*
02320     * Create a new node-info.
02321     */
02322     inode = (xsltCompilerNodeInfoPtr)
02323         xmlMalloc(sizeof(xsltCompilerNodeInfo));
02324     if (inode == NULL) {
02325         xsltTransformError(NULL, cctxt->style, NULL,
02326         "xsltCompilerNodePush: malloc failed.\n");
02327         return(NULL);
02328     }
02329     memset(inode, 0, sizeof(xsltCompilerNodeInfo));
02330     if (cctxt->inodeList == NULL)
02331         cctxt->inodeList = inode;
02332     else {
02333         cctxt->inodeLast->next = inode;
02334         inode->prev = cctxt->inodeLast;
02335     }
02336     cctxt->inodeLast = inode;
02337     cctxt->maxNodeInfos++;  
02338     if (cctxt->inode == NULL) {
02339         cctxt->inode = inode;
02340         /*
02341         * Create an initial literal result element info for
02342         * the root of the stylesheet.
02343         */
02344         xsltLREInfoCreate(cctxt, NULL, 0);
02345     } 
02346     }       
02347     cctxt->depth++;
02348     cctxt->inode = inode;
02349     /*
02350     * REVISIT TODO: Keep the reset always complete.    
02351     * NOTE: Be carefull with the @node, since it might be
02352     *  a doc-node.
02353     */
02354     inode->node = node;
02355     inode->depth = cctxt->depth;
02356     inode->templ = NULL;
02357     inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
02358     inode->type = 0;
02359     inode->item = NULL;
02360     inode->curChildType = 0;
02361     inode->extContentHandled = 0;
02362     inode->isRoot = 0;
02363     
02364     if (inode->prev != NULL) {
02365     iprev = inode->prev;
02366     /*
02367     * Inherit the following information:
02368     * ---------------------------------
02369     *
02370     * In-scope namespaces
02371     */
02372     inode->inScopeNs = iprev->inScopeNs;
02373     /*
02374     * Info for literal result elements
02375     */
02376     inode->litResElemInfo = iprev->litResElemInfo;
02377     inode->nsChanged = iprev->nsChanged;
02378     /*
02379     * Excluded result namespaces
02380     */
02381     inode->exclResultNs = iprev->exclResultNs;
02382     /*
02383     * Extension instruction namespaces
02384     */
02385     inode->extElemNs = iprev->extElemNs;
02386     /*
02387     * Whitespace preservation
02388     */
02389     inode->preserveWhitespace = iprev->preserveWhitespace;
02390     /*
02391     * Forwards-compatible mode
02392     */
02393     inode->forwardsCompat = iprev->forwardsCompat;  
02394     } else {
02395     inode->inScopeNs = NULL;
02396     inode->exclResultNs = NULL;
02397     inode->extElemNs = NULL;
02398     inode->preserveWhitespace = 0;
02399     inode->forwardsCompat = 0;
02400     }
02401     
02402     return(inode);
02403 }
02404 
02405 /*
02406 * xsltCompilerNodePop:
02407 *
02408 * @cctxt: the compilation context
02409 * @node: the node to be pushed (this can also be the doc-node)
02410 *
02411 * Pops the current node info.
02412 */
02413 static void
02414 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
02415 {    
02416     if (cctxt->inode == NULL) {
02417     xmlGenericError(xmlGenericErrorContext,
02418         "xsltCompilerNodePop: Top-node mismatch.\n");
02419     return;
02420     }
02421     /*
02422     * NOTE: Be carefull with the @node, since it might be
02423     *  a doc-node.
02424     */
02425     if (cctxt->inode->node != node) {
02426     xmlGenericError(xmlGenericErrorContext,
02427     "xsltCompilerNodePop: Node mismatch.\n");
02428     goto mismatch;
02429     }
02430     if (cctxt->inode->depth != cctxt->depth) {
02431     xmlGenericError(xmlGenericErrorContext,
02432     "xsltCompilerNodePop: Depth mismatch.\n");
02433     goto mismatch;
02434     }
02435     /*
02436     * Pop information of variables.
02437     */
02438     if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
02439     xsltCompilerVarInfoPop(cctxt);
02440 
02441     cctxt->depth--;
02442     cctxt->inode = cctxt->inode->prev;
02443     if (cctxt->inode != NULL)
02444     cctxt->inode->curChildType = 0;
02445     return;
02446 
02447 mismatch:
02448     {
02449     const xmlChar *nsName = NULL, *name = NULL;
02450     const xmlChar *infnsName = NULL, *infname = NULL;
02451     
02452     if (node) {
02453         if (node->type == XML_ELEMENT_NODE) {
02454         name = node->name;
02455         if (node->ns != NULL)
02456             nsName = node->ns->href;
02457         else
02458             nsName = BAD_CAST "";
02459         } else {
02460         name = BAD_CAST "#document";
02461         nsName = BAD_CAST "";
02462         }
02463     } else
02464         name = BAD_CAST "Not given";
02465 
02466     if (cctxt->inode->node) {
02467         if (node->type == XML_ELEMENT_NODE) {
02468         infname = cctxt->inode->node->name;
02469         if (cctxt->inode->node->ns != NULL)
02470             infnsName = cctxt->inode->node->ns->href;
02471         else
02472             infnsName = BAD_CAST "";
02473         } else {
02474         infname = BAD_CAST "#document";
02475         infnsName = BAD_CAST "";
02476         }
02477     } else
02478         infname = BAD_CAST "Not given";
02479 
02480     
02481     xmlGenericError(xmlGenericErrorContext,
02482         "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
02483         name, nsName);
02484     xmlGenericError(xmlGenericErrorContext,
02485         "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
02486         infname, infnsName);
02487     }
02488 }
02489 
02490 /*
02491 * xsltCompilerBuildInScopeNsList:
02492 *
02493 * Create and store the list of in-scope namespaces for the given
02494 * node in the stylesheet. If there are no changes in the in-scope
02495 * namespaces then the last ns-info of the ancestor axis will be returned.
02496 * Compilation-time only.
02497 *
02498 * Returns the ns-info or NULL if there are no namespaces in scope.
02499 */
02500 static xsltNsListContainerPtr
02501 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
02502 {
02503     xsltNsListContainerPtr nsi = NULL;
02504     xmlNsPtr *list = NULL, ns;
02505     int i, maxns = 5;
02506     /*
02507     * Create a new ns-list for this position in the node-tree.
02508     * xmlGetNsList() will return NULL, if there are no ns-decls in the
02509     * tree. Note that the ns-decl for the XML namespace is not added
02510     * to the resulting list; the XPath module handles the XML namespace
02511     * internally.
02512     */
02513     while (node != NULL) {
02514         if (node->type == XML_ELEMENT_NODE) {
02515             ns = node->nsDef;
02516             while (ns != NULL) {
02517                 if (nsi == NULL) {
02518             nsi = (xsltNsListContainerPtr)
02519             xmlMalloc(sizeof(xsltNsListContainer));
02520             if (nsi == NULL) {
02521             xsltTransformError(NULL, cctxt->style, NULL,
02522                 "xsltCompilerBuildInScopeNsList: "
02523                 "malloc failed!\n");
02524             goto internal_err;
02525             }
02526             memset(nsi, 0, sizeof(xsltNsListContainer));
02527                     nsi->list =
02528                         (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
02529                     if (nsi->list == NULL) {
02530             xsltTransformError(NULL, cctxt->style, NULL,
02531                 "xsltCompilerBuildInScopeNsList: "
02532                 "malloc failed!\n");
02533             goto internal_err;
02534                     }
02535                     nsi->list[0] = NULL;
02536                 }
02537         /*
02538         * Skip shadowed namespace bindings.
02539         */
02540                 for (i = 0; i < nsi->totalNumber; i++) {
02541                     if ((ns->prefix == nsi->list[i]->prefix) ||
02542                         (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
02543             break;
02544                 }
02545                 if (i >= nsi->totalNumber) {
02546                     if (nsi->totalNumber +1 >= maxns) {
02547                         maxns *= 2;
02548             nsi->list =
02549                 (xmlNsPtr *) xmlRealloc(nsi->list,
02550                 maxns * sizeof(xmlNsPtr));
02551                         if (nsi->list == NULL) {
02552                             xsltTransformError(NULL, cctxt->style, NULL,
02553                 "xsltCompilerBuildInScopeNsList: "
02554                 "realloc failed!\n");
02555                 goto internal_err;
02556                         }
02557                     }
02558                     nsi->list[nsi->totalNumber++] = ns;
02559                     nsi->list[nsi->totalNumber] = NULL;
02560                 }
02561 
02562                 ns = ns->next;
02563             }
02564         }
02565         node = node->parent;
02566     }
02567     if (nsi == NULL)
02568     return(NULL);
02569     /*
02570     * Move the default namespace to last position.
02571     */
02572     nsi->xpathNumber = nsi->totalNumber;
02573     for (i = 0; i < nsi->totalNumber; i++) {
02574     if (nsi->list[i]->prefix == NULL) {
02575         ns = nsi->list[i];
02576         nsi->list[i] = nsi->list[nsi->totalNumber-1];
02577         nsi->list[nsi->totalNumber-1] = ns;
02578         nsi->xpathNumber--;
02579         break;
02580     }
02581     }
02582     /*
02583     * Store the ns-list in the stylesheet.
02584     */
02585     if (xsltPointerListAddSize(
02586     (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
02587     (void *) nsi, 5) == -1)
02588     {   
02589     xmlFree(nsi);
02590     nsi = NULL;
02591     xsltTransformError(NULL, cctxt->style, NULL,
02592         "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
02593     goto internal_err;
02594     }
02595     /*
02596     * Notify of change in status wrt namespaces.
02597     */
02598     if (cctxt->inode != NULL)
02599     cctxt->inode->nsChanged = 1;
02600 
02601     return(nsi);
02602 
02603 internal_err:
02604     if (list != NULL)
02605     xmlFree(list);    
02606     cctxt->style->errors++;
02607     return(NULL);
02608 }
02609 
02610 static int
02611 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
02612               xsltPointerListPtr list,
02613               xmlNodePtr node,
02614               const xmlChar *value)
02615 {
02616     xmlChar *cur, *end;
02617     xmlNsPtr ns;
02618     
02619     if ((cctxt == NULL) || (value == NULL) || (list == NULL))
02620     return(-1);
02621 
02622     list->number = 0;
02623 
02624     cur = (xmlChar *) value;
02625     while (*cur != 0) {
02626     while (IS_BLANK(*cur)) cur++;
02627     if (*cur == 0)
02628         break;
02629     end = cur;
02630     while ((*end != 0) && (!IS_BLANK(*end))) end++;
02631     cur = xmlStrndup(cur, end - cur);
02632     if (cur == NULL) {
02633         cur = end;
02634         continue;
02635     }       
02636     /*
02637     * TODO: Export and use xmlSearchNsByPrefixStrict()
02638     *   in Libxml2, tree.c, since xmlSearchNs() is in most
02639     *   cases not efficient and in some cases not correct.
02640     *
02641     * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
02642     */
02643     if ((cur[0] == '#') &&
02644         xmlStrEqual(cur, (const xmlChar *)"#default"))
02645         ns = xmlSearchNs(cctxt->style->doc, node, NULL);
02646     else
02647         ns = xmlSearchNs(cctxt->style->doc, node, cur);     
02648 
02649     if (ns == NULL) {
02650         /*
02651         * TODO: Better to report the attr-node, otherwise
02652         *  the user won't know which attribute was invalid.
02653         */
02654         xsltTransformError(NULL, cctxt->style, node,
02655         "No namespace binding in scope for prefix '%s'.\n", cur);
02656         /*
02657         * XSLT-1.0: "It is an error if there is no namespace
02658         *  bound to the prefix on the element bearing the
02659         *  exclude-result-prefixes or xsl:exclude-result-prefixes
02660         *  attribute."
02661         */
02662         cctxt->style->errors++;
02663     } else {
02664 #ifdef WITH_XSLT_DEBUG_PARSING
02665         xsltGenericDebug(xsltGenericDebugContext,
02666         "resolved prefix '%s'\n", cur);
02667 #endif
02668         /*
02669         * Note that we put the namespace name into the dict.
02670         */
02671         if (xsltPointerListAddSize(list,
02672         (void *) xmlDictLookup(cctxt->style->dict,
02673         ns->href, -1), 5) == -1)
02674         {
02675         xmlFree(cur);
02676         goto internal_err;
02677         }
02678     }
02679     xmlFree(cur);
02680         
02681     cur = end;
02682     }
02683     return(0);
02684 
02685 internal_err:
02686     cctxt->style->errors++;
02687     return(-1);
02688 }
02689 
02701 static xsltPointerListPtr
02702 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
02703                 xsltPointerListPtr second)
02704 {
02705     xsltPointerListPtr ret;
02706     size_t num;
02707 
02708     if (first)
02709     num = first->number;
02710     else
02711     num = 0;
02712     if (second)
02713     num += second->number;    
02714     if (num == 0)
02715     return(NULL);
02716     ret = xsltPointerListCreate(num);
02717     if (ret == NULL)
02718     return(NULL);
02719     /*
02720     * Copy contents.
02721     */
02722     if ((first != NULL) &&  (first->number != 0)) {
02723     memcpy(ret->items, first->items,
02724         first->number * sizeof(void *));
02725     if ((second != NULL) && (second->number != 0))
02726         memcpy(ret->items + first->number, second->items,
02727         second->number * sizeof(void *));
02728     } else if ((second != NULL) && (second->number != 0))
02729     memcpy(ret->items, (void *) second->items,
02730         second->number * sizeof(void *));
02731     ret->number = num;
02732     return(ret);
02733 }
02734 
02735 /*
02736 * xsltParseExclResultPrefixes:
02737 *
02738 * Create and store the list of in-scope namespaces for the given
02739 * node in the stylesheet. If there are no changes in the in-scope
02740 * namespaces then the last ns-info of the ancestor axis will be returned.
02741 * Compilation-time only.
02742 *
02743 * Returns the ns-info or NULL if there are no namespaces in scope.
02744 */
02745 static xsltPointerListPtr
02746 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
02747                 xsltPointerListPtr def,
02748                 int instrCategory)
02749 {    
02750     xsltPointerListPtr list = NULL;
02751     xmlChar *value;
02752     xmlAttrPtr attr;
02753 
02754     if ((cctxt == NULL) || (node == NULL))
02755     return(NULL);
02756 
02757     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
02758     attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
02759     else
02760     attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
02761         XSLT_NAMESPACE);
02762     if (attr == NULL)   
02763     return(def);
02764 
02765     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
02766     /*
02767     * Mark the XSLT attr.
02768     */
02769     attr->psvi = (void *) xsltXSLTAttrMarker;
02770     }
02771 
02772     if ((attr->children != NULL) && 
02773     (attr->children->content != NULL))
02774     value = attr->children->content;
02775     else {
02776     xsltTransformError(NULL, cctxt->style, node,
02777         "Attribute 'exclude-result-prefixes': Invalid value.\n");
02778     cctxt->style->errors++;
02779     return(def);
02780     }        
02781 
02782     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
02783     BAD_CAST value) != 0)
02784     goto exit;
02785     if (cctxt->tmpList->number == 0)    
02786     goto exit;    
02787     /*
02788     * Merge the list with the inherited list.
02789     */
02790     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
02791     if (list == NULL)
02792     goto exit;    
02793     /*
02794     * Store the list in the stylesheet/compiler context.
02795     */
02796     if (xsltPointerListAddSize(
02797     cctxt->psData->exclResultNamespaces, list, 5) == -1)
02798     {
02799     xsltPointerListFree(list);
02800     list = NULL;
02801     goto exit;
02802     }
02803     /*
02804     * Notify of change in status wrt namespaces.
02805     */
02806     if (cctxt->inode != NULL)
02807     cctxt->inode->nsChanged = 1;
02808 
02809 exit:    
02810     if (list != NULL)
02811     return(list);
02812     else
02813     return(def);
02814 }
02815 
02816 /*
02817 * xsltParseExtElemPrefixes:
02818 *
02819 * Create and store the list of in-scope namespaces for the given
02820 * node in the stylesheet. If there are no changes in the in-scope
02821 * namespaces then the last ns-info of the ancestor axis will be returned.
02822 * Compilation-time only.
02823 *
02824 * Returns the ns-info or NULL if there are no namespaces in scope.
02825 */
02826 static xsltPointerListPtr
02827 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
02828              xsltPointerListPtr def,
02829              int instrCategory)
02830 {    
02831     xsltPointerListPtr list = NULL;
02832     xmlAttrPtr attr;
02833     xmlChar *value;
02834     int i;
02835 
02836     if ((cctxt == NULL) || (node == NULL))
02837     return(NULL);
02838 
02839     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
02840     attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
02841     else
02842     attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
02843         XSLT_NAMESPACE);
02844     if (attr == NULL)   
02845     return(def);
02846 
02847     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
02848     /*
02849     * Mark the XSLT attr.
02850     */
02851     attr->psvi = (void *) xsltXSLTAttrMarker;
02852     }
02853 
02854     if ((attr->children != NULL) && 
02855     (attr->children->content != NULL))
02856     value = attr->children->content;
02857     else {
02858     xsltTransformError(NULL, cctxt->style, node,
02859         "Attribute 'extension-element-prefixes': Invalid value.\n");
02860     cctxt->style->errors++;
02861     return(def);
02862     }
02863 
02864 
02865     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
02866     BAD_CAST value) != 0)
02867     goto exit;
02868 
02869     if (cctxt->tmpList->number == 0)
02870     goto exit;    
02871     /*
02872     * REVISIT: Register the extension namespaces.
02873     */
02874     for (i = 0; i < cctxt->tmpList->number; i++)
02875     xsltRegisterExtPrefix(cctxt->style, NULL,
02876     BAD_CAST cctxt->tmpList->items[i]);
02877     /*
02878     * Merge the list with the inherited list.
02879     */
02880     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
02881     if (list == NULL)
02882     goto exit;
02883     /*
02884     * Store the list in the stylesheet.
02885     */
02886     if (xsltPointerListAddSize(
02887     cctxt->psData->extElemNamespaces, list, 5) == -1)
02888     {
02889     xsltPointerListFree(list);
02890     list = NULL;
02891     goto exit;
02892     }
02893     /*
02894     * Notify of change in status wrt namespaces.
02895     */
02896     if (cctxt->inode != NULL)
02897     cctxt->inode->nsChanged = 1;
02898 
02899 exit:    
02900     if (list != NULL)
02901     return(list);
02902     else
02903     return(def);
02904 }
02905 
02906 /*
02907 * xsltParseAttrXSLTVersion:
02908 *
02909 * @cctxt: the compilation context
02910 * @node: the element-node
02911 * @isXsltElem: whether this is an XSLT element
02912 *
02913 * Parses the attribute xsl:version.
02914 *
02915 * Returns 1 if there was such an attribute, 0 if not and
02916 *         -1 if an internal or API error occured.
02917 */
02918 static int
02919 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,             
02920              int instrCategory)
02921 {
02922     xmlChar *value;
02923     xmlAttrPtr attr;
02924 
02925     if ((cctxt == NULL) || (node == NULL))
02926     return(-1);
02927 
02928     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
02929     attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
02930     else
02931     attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
02932 
02933     if (attr == NULL)   
02934     return(0);
02935 
02936     attr->psvi = (void *) xsltXSLTAttrMarker;
02937 
02938     if ((attr->children != NULL) && 
02939     (attr->children->content != NULL))
02940     value = attr->children->content;
02941     else {
02942     xsltTransformError(NULL, cctxt->style, node,
02943         "Attribute 'version': Invalid value.\n");
02944     cctxt->style->errors++;
02945     return(1);
02946     }
02947     
02948     if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
02949     cctxt->inode->forwardsCompat = 1;
02950     /*
02951     * TODO: To what extent do we support the
02952     *  forwards-compatible mode?
02953     */
02954     /*
02955     * Report this only once per compilation episode.
02956     */
02957     if (! cctxt->hasForwardsCompat) {
02958         cctxt->hasForwardsCompat = 1;
02959         cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
02960         xsltTransformError(NULL, cctxt->style, node,
02961         "Warning: the attribute xsl:version specifies a value "
02962         "different from '1.0'. Switching to forwards-compatible "
02963         "mode. Only features of XSLT 1.0 are supported by this "
02964         "processor.\n");
02965         cctxt->style->warnings++;
02966         cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
02967     }   
02968     } else {
02969     cctxt->inode->forwardsCompat = 0;
02970     }
02971 
02972     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
02973     /*
02974     * Set a marker on XSLT attributes.
02975     */
02976     attr->psvi = (void *) xsltXSLTAttrMarker;
02977     }
02978     return(1);
02979 }
02980 
02981 static int
02982 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
02983 {
02984     xmlNodePtr deleteNode, cur, txt, textNode = NULL;
02985     xmlDocPtr doc;
02986     xsltStylesheetPtr style;
02987     int internalize = 0, findSpaceAttr;
02988     int xsltStylesheetElemDepth;
02989     xmlAttrPtr attr;
02990     xmlChar *value;
02991     const xmlChar *name, *nsNameXSLT = NULL;
02992     int strictWhitespace, inXSLText = 0;
02993 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
02994     xsltNsMapPtr nsMapItem;
02995 #endif
02996 
02997     if ((cctxt == NULL) || (cctxt->style == NULL) ||
02998     (node == NULL) || (node->type != XML_ELEMENT_NODE))
02999         return(-1);
03000 
03001     doc = node->doc;
03002     if (doc == NULL)
03003     goto internal_err;
03004 
03005     style = cctxt->style;
03006     if ((style->dict != NULL) && (doc->dict == style->dict))
03007     internalize = 1;
03008     else
03009         style->internalized = 0;
03010 
03011     /*
03012     * Init value of xml:space. Since this might be an embedded
03013     * stylesheet, this is needed to be performed on the element
03014     * where the stylesheet is rooted at, taking xml:space of
03015     * ancestors into account.
03016     */
03017     if (! cctxt->simplified)
03018     xsltStylesheetElemDepth = cctxt->depth +1;
03019     else
03020     xsltStylesheetElemDepth = 0;
03021 
03022     if (xmlNodeGetSpacePreserve(node) != 1)
03023     cctxt->inode->preserveWhitespace = 0;
03024     else
03025     cctxt->inode->preserveWhitespace = 1; 
03026     
03027     /*
03028     * Eval if we should keep the old incorrect behaviour.
03029     */
03030     strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
03031 
03032     nsNameXSLT = xsltConstNamespaceNameXSLT;
03033 
03034     deleteNode = NULL;
03035     cur = node;
03036     while (cur != NULL) {
03037     if (deleteNode != NULL) {
03038 
03039 #ifdef WITH_XSLT_DEBUG_BLANKS
03040         xsltGenericDebug(xsltGenericDebugContext,
03041          "xsltParsePreprocessStylesheetTree: removing node\n");
03042 #endif
03043         xmlUnlinkNode(deleteNode);
03044         xmlFreeNode(deleteNode);
03045         deleteNode = NULL;
03046     }
03047     if (cur->type == XML_ELEMENT_NODE) {
03048         
03049         /*
03050         * Clear the PSVI field.
03051         */
03052         cur->psvi = NULL;
03053 
03054         xsltCompilerNodePush(cctxt, cur);
03055 
03056         inXSLText = 0;
03057         textNode = NULL;        
03058         findSpaceAttr = 1;      
03059         cctxt->inode->stripWhitespace = 0;
03060         /*
03061         * TODO: I'd love to use a string pointer comparison here :-/
03062         */
03063         if (IS_XSLT_ELEM(cur)) {
03064 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
03065         if (cur->ns->href != nsNameXSLT) {
03066             nsMapItem = xsltNewNamespaceMapItem(cctxt,
03067             doc, cur->ns, cur);
03068             if (nsMapItem == NULL)
03069             goto internal_err;
03070             cur->ns->href = nsNameXSLT;
03071         }
03072 #endif
03073 
03074         if (cur->name == NULL)
03075             goto process_attributes;
03076         /*
03077         * Mark the XSLT element for later recognition.
03078         * TODO: Using the marker is still too dangerous, since if
03079         *   the parsing mechanism leaves out an XSLT element, then
03080         *   this might hit the transformation-mechanism, which
03081         *   will break if it doesn't expect such a marker.
03082         */
03083         /* cur->psvi = (void *) xsltXSLTElemMarker; */
03084 
03085         /*
03086         * XSLT 2.0: "Any whitespace text node whose parent is
03087         * one of the following elements is removed from the "
03088         * tree, regardless of any xml:space attributes:..."
03089         * xsl:apply-imports, 
03090         * xsl:apply-templates,
03091         * xsl:attribute-set,
03092         * xsl:call-template, 
03093         * xsl:choose,
03094         * xsl:stylesheet, xsl:transform.
03095         * XSLT 2.0: xsl:analyze-string,
03096         *           xsl:character-map,
03097         *           xsl:next-match      
03098         *
03099         * TODO: I'd love to use a string pointer comparison here :-/
03100         */      
03101         name = cur->name;
03102         switch (*name) {
03103             case 't':
03104             if ((name[0] == 't') && (name[1] == 'e') &&
03105                 (name[2] == 'x') && (name[3] == 't') &&
03106                 (name[4] == 0))
03107             {
03108                 /*
03109                 * Process the xsl:text element.
03110                 * ----------------------------
03111                 * Mark it for later recognition.
03112                 */
03113                 cur->psvi = (void *) xsltXSLTTextMarker;
03114                 /*
03115                 * For stylesheets, the set of
03116                 * whitespace-preserving element names
03117                 * consists of just xsl:text.
03118                 */
03119                 findSpaceAttr = 0;
03120                 cctxt->inode->preserveWhitespace = 1;
03121                 inXSLText = 1;
03122             }               
03123             break;
03124             case 'c':
03125             if (xmlStrEqual(name, BAD_CAST "choose") ||
03126                 xmlStrEqual(name, BAD_CAST "call-template"))
03127                 cctxt->inode->stripWhitespace = 1;
03128             break;
03129             case 'a':
03130             if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
03131                 xmlStrEqual(name, BAD_CAST "apply-imports") ||
03132                 xmlStrEqual(name, BAD_CAST "attribute-set"))
03133 
03134                 cctxt->inode->stripWhitespace = 1;
03135             break;
03136             default:
03137             if (xsltStylesheetElemDepth == cctxt->depth) {
03138                 /*
03139                 * This is a xsl:stylesheet/xsl:transform.
03140                 */
03141                 cctxt->inode->stripWhitespace = 1;
03142                 break;
03143             }
03144 
03145             if ((cur->prev != NULL) &&
03146                 (cur->prev->type == XML_TEXT_NODE))
03147             {
03148                 /*
03149                 * XSLT 2.0 : "Any whitespace text node whose
03150                 *  following-sibling node is an xsl:param or
03151                 *  xsl:sort element is removed from the tree,
03152                 *  regardless of any xml:space attributes."
03153                 */
03154                 if (((*name == 'p') || (*name == 's')) &&
03155                 (xmlStrEqual(name, BAD_CAST "param") ||
03156                  xmlStrEqual(name, BAD_CAST "sort")))
03157                 {
03158                 do {
03159                     if (IS_BLANK_NODE(cur->prev)) {
03160                     txt = cur->prev;
03161                     xmlUnlinkNode(txt);
03162                     xmlFreeNode(txt);
03163                     } else {
03164                     /*
03165                     * This will result in a content
03166                     * error, when hitting the parsing
03167                     * functions.
03168                     */
03169                     break;
03170                     }
03171                 } while (cur->prev);                    
03172                 }
03173             }
03174             break;
03175         }
03176         }
03177 
03178 process_attributes:
03179         /*
03180         * Process attributes.
03181         * ------------------
03182         */
03183         if (cur->properties != NULL) {
03184         if (cur->children == NULL)
03185             findSpaceAttr = 0;
03186         attr = cur->properties;
03187         do {
03188 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
03189             if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
03190             xmlStrEqual(attr->ns->href, nsNameXSLT))
03191             {           
03192             nsMapItem = xsltNewNamespaceMapItem(cctxt,
03193                 doc, attr->ns, cur);
03194             if (nsMapItem == NULL)
03195                 goto internal_err;
03196             attr->ns->href = nsNameXSLT;
03197             }           
03198 #endif
03199             if (internalize) {
03200             /*
03201             * Internalize the attribute's value; the goal is to
03202             * speed up operations and minimize used space by
03203             * compiled stylesheets.
03204             */
03205             txt = attr->children;
03206             /*
03207             * NOTE that this assumes only one
03208             *  text-node in the attribute's content.
03209             */
03210             if ((txt != NULL) && (txt->content != NULL) &&
03211                 (!xmlDictOwns(style->dict, txt->content)))
03212             {
03213                 value = (xmlChar *) xmlDictLookup(style->dict,
03214                 txt->content, -1);
03215                 xmlNodeSetContent(txt, NULL);
03216                 txt->content = value;
03217             }
03218             }
03219             /*
03220             * Process xml:space attributes.
03221             * ----------------------------
03222             */
03223             if ((findSpaceAttr != 0) &&
03224             (attr->ns != NULL) &&
03225             (attr->name != NULL) &&
03226             (attr->name[0] == 's') &&           
03227             (attr->ns->prefix != NULL) &&
03228             (attr->ns->prefix[0] == 'x') &&
03229             (attr->ns->prefix[1] == 'm') &&
03230             (attr->ns->prefix[2] == 'l') &&
03231             (attr->ns->prefix[3] == 0))
03232             {
03233             value = xmlGetNsProp(cur, BAD_CAST "space",
03234                 XML_XML_NAMESPACE);
03235             if (value != NULL) {
03236                 if (xmlStrEqual(value, BAD_CAST "preserve")) {
03237                 cctxt->inode->preserveWhitespace = 1;               
03238                 } else if (xmlStrEqual(value, BAD_CAST "default")) {
03239                 cctxt->inode->preserveWhitespace = 0;
03240                 } else {
03241                 /* Invalid value for xml:space. */
03242                 xsltTransformError(NULL, style, cur,
03243                     "Attribute xml:space: Invalid value.\n");
03244                 cctxt->style->warnings++;
03245                 }
03246                 findSpaceAttr = 0;
03247                 xmlFree(value);
03248             }
03249             
03250             }
03251             attr = attr->next;
03252         } while (attr != NULL);
03253         }
03254         /*
03255         * We'll descend into the children of element nodes only.
03256         */
03257         if (cur->children != NULL) {
03258         cur = cur->children;
03259         continue;
03260         }
03261     } else if ((cur->type == XML_TEXT_NODE) ||
03262         (cur->type == XML_CDATA_SECTION_NODE))
03263     {
03264         /*
03265         * Merge adjacent text/CDATA-section-nodes
03266         * ---------------------------------------       
03267         * In order to avoid breaking of existing stylesheets,
03268         * if the old behaviour is wanted (strictWhitespace == 0),
03269         * then we *won't* merge adjacent text-nodes
03270         * (except in xsl:text); this will ensure that whitespace-only
03271         * text nodes are (incorrectly) not stripped in some cases.
03272         * 
03273         * Example:               : <foo>  <!-- bar -->zoo</foo>
03274         * Corrent (strict) result: <foo>  zoo</foo>
03275         * Incorrect (old) result : <foo>zoo</foo>
03276         *    
03277         * NOTE that we *will* merge adjacent text-nodes if
03278         * they are in xsl:text.
03279         * Example, the following:
03280         * <xsl:text>  <!-- bar -->zoo<xsl:text>
03281         * will result in both cases in:
03282         * <xsl:text>  zoo<xsl:text>
03283         */
03284         cur->type = XML_TEXT_NODE;
03285         if ((strictWhitespace != 0) || (inXSLText != 0)) {
03286         /*
03287         * New behaviour; merge nodes.
03288         */
03289         if (textNode == NULL)
03290             textNode = cur;
03291         else {
03292             if (cur->content != NULL)
03293             xmlNodeAddContent(textNode, cur->content);
03294             deleteNode = cur;
03295         }
03296         if ((cur->next == NULL) ||
03297             (cur->next->type == XML_ELEMENT_NODE))
03298             goto end_of_text;
03299         else
03300             goto next_sibling;
03301         } else {
03302         /*
03303         * Old behaviour.
03304         */
03305         if (textNode == NULL)
03306             textNode = cur;
03307         goto end_of_text;
03308         }              
03309     } else if ((cur->type == XML_COMMENT_NODE) ||
03310         (cur->type == XML_PI_NODE))
03311     {       
03312         /*
03313         * Remove processing instructions and comments.
03314         */
03315         deleteNode = cur;
03316         if ((cur->next == NULL) ||
03317         (cur->next->type == XML_ELEMENT_NODE))
03318         goto end_of_text;
03319         else
03320         goto next_sibling;
03321     } else {
03322         textNode = NULL;
03323         /*
03324         * Invalid node-type for this data-model.
03325         */
03326         xsltTransformError(NULL, style, cur,
03327         "Invalid type of node for the XSLT data model.\n");
03328         cctxt->style->errors++;
03329         goto next_sibling;
03330     }
03331 
03332 end_of_text:
03333     if (textNode) {
03334         value = textNode->content;
03335         /*
03336         * At this point all adjacent text/CDATA-section nodes
03337         * have been merged.
03338         *
03339         * Strip whitespace-only text-nodes.
03340         * (cctxt->inode->stripWhitespace)
03341         */
03342         if ((value == NULL) || (*value == 0) ||
03343         (((cctxt->inode->stripWhitespace) ||
03344           (! cctxt->inode->preserveWhitespace)) &&
03345          IS_BLANK(*value) &&
03346          xsltIsBlank(value)))
03347         {       
03348         if (textNode != cur) {
03349             xmlUnlinkNode(textNode);
03350             xmlFreeNode(textNode);
03351         } else
03352             deleteNode = textNode;
03353         textNode = NULL;
03354         goto next_sibling;
03355         }
03356         /*
03357         * Convert CDATA-section nodes to text-nodes.
03358         * TODO: Can this produce problems?
03359         */
03360         if (textNode->type != XML_TEXT_NODE) {
03361         textNode->type = XML_TEXT_NODE;
03362         textNode->name = xmlStringText;
03363         }
03364         if (internalize &&
03365         (textNode->content != NULL) &&
03366         (!xmlDictOwns(style->dict, textNode->content)))
03367         {
03368         /*
03369         * Internalize the string.
03370         */
03371         value = (xmlChar *) xmlDictLookup(style->dict,
03372             textNode->content, -1);
03373         xmlNodeSetContent(textNode, NULL);
03374         textNode->content = value;
03375         }
03376         textNode = NULL;
03377         /*
03378         * Note that "disable-output-escaping" of the xsl:text
03379         * element will be applied at a later level, when
03380         * XSLT elements are processed.
03381         */
03382     }
03383 
03384 next_sibling:
03385     if (cur->type == XML_ELEMENT_NODE) {
03386         xsltCompilerNodePop(cctxt, cur);
03387     }
03388     if (cur == node)
03389         break;
03390     if (cur->next != NULL) {
03391         cur = cur->next;
03392     } else {
03393         cur = cur->parent;
03394         inXSLText = 0;
03395         goto next_sibling;
03396     };
03397     }
03398     if (deleteNode != NULL) {
03399 #ifdef WITH_XSLT_DEBUG_PARSING
03400     xsltGenericDebug(xsltGenericDebugContext,
03401      "xsltParsePreprocessStylesheetTree: removing node\n");
03402 #endif
03403     xmlUnlinkNode(deleteNode);
03404     xmlFreeNode(deleteNode);
03405     }
03406     return(0);
03407 
03408 internal_err:
03409     return(-1);
03410 }
03411 
03412 #endif /* XSLT_REFACTORED */
03413 
03414 #ifdef XSLT_REFACTORED
03415 #else
03416 static void
03417 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
03418 {
03419     xmlNodePtr deleteNode, styleelem;
03420     int internalize = 0;
03421 
03422     if ((style == NULL) || (cur == NULL))
03423         return;
03424 
03425     if ((cur->doc != NULL) && (style->dict != NULL) &&
03426         (cur->doc->dict == style->dict))
03427     internalize = 1;
03428     else
03429         style->internalized = 0;
03430 
03431     if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
03432         (IS_XSLT_NAME(cur, "stylesheet"))) {
03433     styleelem = cur;
03434     } else {
03435         styleelem = NULL;
03436     }
03437 
03438     /*
03439      * This content comes from the stylesheet
03440      * For stylesheets, the set of whitespace-preserving
03441      * element names consists of just xsl:text.
03442      */
03443     deleteNode = NULL;
03444     while (cur != NULL) {
03445     if (deleteNode != NULL) {
03446 #ifdef WITH_XSLT_DEBUG_BLANKS
03447         xsltGenericDebug(xsltGenericDebugContext,
03448          "xsltPrecomputeStylesheet: removing ignorable blank node\n");
03449 #endif
03450         xmlUnlinkNode(deleteNode);
03451         xmlFreeNode(deleteNode);
03452         deleteNode = NULL;
03453     }
03454     if (cur->type == XML_ELEMENT_NODE) {
03455         int exclPrefixes;
03456         /*
03457          * Internalize attributes values.
03458          */
03459         if ((internalize) && (cur->properties != NULL)) {
03460             xmlAttrPtr attr = cur->properties;
03461         xmlNodePtr txt;
03462 
03463         while (attr != NULL) {
03464             txt = attr->children;
03465             if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
03466                 (txt->content != NULL) &&
03467             (!xmlDictOwns(style->dict, txt->content)))
03468             {
03469             xmlChar *tmp;
03470 
03471             /*
03472              * internalize the text string, goal is to speed
03473              * up operations and minimize used space by compiled
03474              * stylesheets.
03475              */
03476             tmp = (xmlChar *) xmlDictLookup(style->dict,
03477                                             txt->content, -1);
03478             if (tmp != txt->content) {
03479                 xmlNodeSetContent(txt, NULL);
03480                 txt->content = tmp;
03481             }
03482             }
03483             attr = attr->next;
03484         }
03485         }
03486         if (IS_XSLT_ELEM(cur)) {
03487         exclPrefixes = 0;
03488         xsltStylePreCompute(style, cur);
03489         if (IS_XSLT_NAME(cur, "text")) {
03490             for (;exclPrefixes > 0;exclPrefixes--)
03491             exclPrefixPop(style);
03492             goto skip_children;
03493         }
03494         } else {
03495         exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
03496         }
03497                  
03498         if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
03499         xmlNsPtr ns = cur->nsDef, prev = NULL, next;
03500         xmlNodePtr root = NULL;
03501         int i, moved;
03502 
03503         root = xmlDocGetRootElement(cur->doc);
03504         if ((root != NULL) && (root != cur)) {
03505             while (ns != NULL) {
03506             moved = 0;
03507             next = ns->next;
03508             for (i = 0;i < style->exclPrefixNr;i++) {
03509                 if ((ns->prefix != NULL) && 
03510                     (xmlStrEqual(ns->href,
03511                          style->exclPrefixTab[i]))) {
03512                 /*
03513                  * Move the namespace definition on the root
03514                  * element to avoid duplicating it without
03515                  * loosing it.
03516                  */
03517                 if (prev == NULL) {
03518                     cur->nsDef = ns->next;
03519                 } else {
03520                     prev->next = ns->next;
03521                 }
03522                 ns->next = root->nsDef;
03523                 root->nsDef = ns;
03524                 moved = 1;
03525                 break;
03526                 }
03527             }
03528             if (moved == 0)
03529                 prev = ns;
03530             ns = next;
03531             }
03532         }
03533         }
03534         /*
03535          * If we have prefixes locally, recurse and pop them up when
03536          * going back
03537          */
03538         if (exclPrefixes > 0) {
03539         xsltPrecomputeStylesheet(style, cur->children);
03540         for (;exclPrefixes > 0;exclPrefixes--)
03541             exclPrefixPop(style);
03542         goto skip_children;
03543         }
03544     } else if (cur->type == XML_TEXT_NODE) {
03545         if (IS_BLANK_NODE(cur)) {
03546         if (xmlNodeGetSpacePreserve(cur) != 1) {
03547             deleteNode = cur;
03548         }
03549         } else if ((cur->content != NULL) && (internalize) &&
03550                    (!xmlDictOwns(style->dict, cur->content))) {
03551         xmlChar *tmp;
03552 
03553         /*
03554          * internalize the text string, goal is to speed
03555          * up operations and minimize used space by compiled
03556          * stylesheets.
03557          */
03558         tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
03559         xmlNodeSetContent(cur, NULL);
03560         cur->content = tmp;
03561         }
03562     } else if ((cur->type != XML_ELEMENT_NODE) &&
03563            (cur->type != XML_CDATA_SECTION_NODE)) {
03564         deleteNode = cur;
03565         goto skip_children;
03566     }
03567 
03568     /*
03569      * Skip to next node. In case of a namespaced element children of
03570      * the stylesheet and not in the XSLT namespace and not an extension
03571      * element, ignore its content.
03572      */
03573     if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
03574         (styleelem != NULL) && (cur->parent == styleelem) &&
03575         (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
03576         (!xsltCheckExtURI(style, cur->ns->href))) {
03577         goto skip_children;
03578     } else if (cur->children != NULL) {
03579         if ((cur->children->type != XML_ENTITY_DECL) &&
03580         (cur->children->type != XML_ENTITY_REF_NODE) &&
03581         (cur->children->type != XML_ENTITY_NODE)) {
03582         cur = cur->children;
03583         continue;
03584         }
03585     }
03586 
03587 skip_children:
03588     if (cur->next != NULL) {
03589         cur = cur->next;
03590         continue;
03591     }
03592     do {
03593 
03594         cur = cur->parent;
03595         if (cur == NULL)
03596         break;
03597         if (cur == (xmlNodePtr) style->doc) {
03598         cur = NULL;
03599         break;
03600         }
03601         if (cur->next != NULL) {
03602         cur = cur->next;
03603         break;
03604         }
03605     } while (cur != NULL);
03606     }
03607     if (deleteNode != NULL) {
03608 #ifdef WITH_XSLT_DEBUG_PARSING
03609     xsltGenericDebug(xsltGenericDebugContext,
03610      "xsltPrecomputeStylesheet: removing ignorable blank node\n");
03611 #endif
03612     xmlUnlinkNode(deleteNode);
03613     xmlFreeNode(deleteNode);
03614     }
03615 }
03616 #endif /* end of else XSLT_REFACTORED */
03617 
03626 static void
03627 xsltGatherNamespaces(xsltStylesheetPtr style) {
03628     xmlNodePtr cur;
03629     const xmlChar *URI;
03630 
03631     if (style == NULL)
03632         return;
03633     /* 
03634      * TODO: basically if the stylesheet uses the same prefix for different
03635      *       patterns, well they may be in problem, hopefully they will get
03636      *       a warning first.
03637      */
03638     /*
03639     * TODO: Eliminate the use of the hash for XPath expressions.
03640     *   An expression should be evaluated in the context of the in-scope
03641     *   namespaces; eliminate the restriction of an XML document to contain
03642     *   no duplicate prefixes for different namespace names.
03643     * 
03644     */
03645     cur = xmlDocGetRootElement(style->doc);
03646     while (cur != NULL) {
03647     if (cur->type == XML_ELEMENT_NODE) {
03648         xmlNsPtr ns = cur->nsDef;
03649         while (ns != NULL) {
03650         if (ns->prefix != NULL) {
03651             if (style->nsHash == NULL) {
03652             style->nsHash = xmlHashCreate(10);
03653             if (style->nsHash == NULL) {
03654                 xsltTransformError(NULL, style, cur,
03655          "xsltGatherNamespaces: failed to create hash table\n");
03656                 style->errors++;
03657                 return;
03658             }
03659             }
03660             URI = xmlHashLookup(style->nsHash, ns->prefix);
03661             if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
03662             xsltTransformError(NULL, style, cur,
03663          "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
03664             style->warnings++;
03665             } else if (URI == NULL) {
03666             xmlHashUpdateEntry(style->nsHash, ns->prefix,
03667                 (void *) ns->href, (xmlHashDeallocator)xmlFree);
03668 
03669 #ifdef WITH_XSLT_DEBUG_PARSING
03670             xsltGenericDebug(xsltGenericDebugContext,
03671          "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
03672 #endif
03673             }
03674         }
03675         ns = ns->next;
03676         }
03677     }
03678 
03679     /*
03680      * Skip to next node
03681      */
03682     if (cur->children != NULL) {
03683         if (cur->children->type != XML_ENTITY_DECL) {
03684         cur = cur->children;
03685         continue;
03686         }
03687     }
03688     if (cur->next != NULL) {
03689         cur = cur->next;
03690         continue;
03691     }
03692     
03693     do {
03694         cur = cur->parent;
03695         if (cur == NULL)
03696         break;
03697         if (cur == (xmlNodePtr) style->doc) {
03698         cur = NULL;
03699         break;
03700         }
03701         if (cur->next != NULL) {
03702         cur = cur->next;
03703         break;
03704         }
03705     } while (cur != NULL);
03706     }
03707 }
03708 
03709 #ifdef XSLT_REFACTORED
03710 
03711 static xsltStyleType
03712 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
03713                  xmlNodePtr node)
03714 {
03715     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
03716     (node->name == NULL))
03717     return(0);
03718 
03719     if (node->name[0] == 'a') {
03720     if (IS_XSLT_NAME(node, "apply-templates"))
03721         return(XSLT_FUNC_APPLYTEMPLATES);
03722     else if (IS_XSLT_NAME(node, "attribute"))
03723         return(XSLT_FUNC_ATTRIBUTE);
03724     else if (IS_XSLT_NAME(node, "apply-imports"))
03725         return(XSLT_FUNC_APPLYIMPORTS);
03726     else if (IS_XSLT_NAME(node, "attribute-set"))
03727         return(0);
03728 
03729     } else if (node->name[0] == 'c') {
03730     if (IS_XSLT_NAME(node, "choose"))
03731         return(XSLT_FUNC_CHOOSE);
03732     else if (IS_XSLT_NAME(node, "copy"))
03733         return(XSLT_FUNC_COPY);
03734     else if (IS_XSLT_NAME(node, "copy-of"))
03735         return(XSLT_FUNC_COPYOF);
03736     else if (IS_XSLT_NAME(node, "call-template"))
03737         return(XSLT_FUNC_CALLTEMPLATE);
03738     else if (IS_XSLT_NAME(node, "comment"))
03739         return(XSLT_FUNC_COMMENT);
03740 
03741     } else if (node->name[0] == 'd') {
03742     if (IS_XSLT_NAME(node, "document"))
03743         return(XSLT_FUNC_DOCUMENT);
03744     else if (IS_XSLT_NAME(node, "decimal-format"))
03745         return(0);
03746 
03747     } else if (node->name[0] == 'e') {
03748     if (IS_XSLT_NAME(node, "element"))
03749         return(XSLT_FUNC_ELEMENT);
03750 
03751     } else if (node->name[0] == 'f') {
03752     if (IS_XSLT_NAME(node, "for-each"))
03753         return(XSLT_FUNC_FOREACH);
03754     else if (IS_XSLT_NAME(node, "fallback"))
03755         return(XSLT_FUNC_FALLBACK);
03756 
03757     } else if (*(node->name) == 'i') {
03758     if (IS_XSLT_NAME(node, "if"))
03759         return(XSLT_FUNC_IF);
03760     else if (IS_XSLT_NAME(node, "include"))
03761         return(0);
03762     else if (IS_XSLT_NAME(node, "import"))
03763         return(0);
03764 
03765     } else if (*(node->name) == 'k') {
03766     if (IS_XSLT_NAME(node, "key"))
03767         return(0);
03768 
03769     } else if (*(node->name) == 'm') {
03770     if (IS_XSLT_NAME(node, "message"))
03771         return(XSLT_FUNC_MESSAGE);
03772 
03773     } else if (*(node->name) == 'n') {
03774     if (IS_XSLT_NAME(node, "number"))
03775         return(XSLT_FUNC_NUMBER);
03776     else if (IS_XSLT_NAME(node, "namespace-alias"))
03777         return(0);
03778 
03779     } else if (*(node->name) == 'o') {
03780     if (IS_XSLT_NAME(node, "otherwise"))
03781         return(XSLT_FUNC_OTHERWISE);
03782     else if (IS_XSLT_NAME(node, "output"))
03783         return(0);
03784 
03785     } else if (*(node->name) == 'p') {
03786     if (IS_XSLT_NAME(node, "param"))
03787         return(XSLT_FUNC_PARAM);
03788     else if (IS_XSLT_NAME(node, "processing-instruction"))
03789         return(XSLT_FUNC_PI);
03790     else if (IS_XSLT_NAME(node, "preserve-space"))
03791         return(0);
03792 
03793     } else if (*(node->name) == 's') {
03794     if (IS_XSLT_NAME(node, "sort"))
03795         return(XSLT_FUNC_SORT);
03796     else if (IS_XSLT_NAME(node, "strip-space"))
03797         return(0);
03798     else if (IS_XSLT_NAME(node, "stylesheet"))
03799         return(0);
03800 
03801     } else if (node->name[0] == 't') {
03802     if (IS_XSLT_NAME(node, "text"))
03803         return(XSLT_FUNC_TEXT);
03804     else if (IS_XSLT_NAME(node, "template"))
03805         return(0);
03806     else if (IS_XSLT_NAME(node, "transform"))
03807         return(0);
03808 
03809     } else if (*(node->name) == 'v') {
03810     if (IS_XSLT_NAME(node, "value-of"))
03811         return(XSLT_FUNC_VALUEOF);
03812     else if (IS_XSLT_NAME(node, "variable"))
03813         return(XSLT_FUNC_VARIABLE);
03814 
03815     } else if (*(node->name) == 'w') {
03816     if (IS_XSLT_NAME(node, "when"))
03817         return(XSLT_FUNC_WHEN);
03818     if (IS_XSLT_NAME(node, "with-param"))
03819         return(XSLT_FUNC_WITHPARAM);
03820     }
03821     return(0);
03822 }
03823 
03835 int
03836 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
03837 {
03838     if ((cctxt == NULL) || (elem == NULL) ||
03839     (elem->type != XML_ELEMENT_NODE))
03840     return(-1);
03841 
03842     elem->psvi = NULL;
03843 
03844     if (! (IS_XSLT_ELEM_FAST(elem)))
03845     return(-1);
03846     /*
03847     * Detection of handled content of extension instructions.
03848     */
03849     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
03850     cctxt->inode->extContentHandled = 1;
03851     }
03852     
03853     xsltCompilerNodePush(cctxt, elem);
03854     /*
03855     * URGENT TODO: Find a way to speed up this annoying redundant
03856     *  textual node-name and namespace comparison.
03857     */
03858     if (cctxt->inode->prev->curChildType != 0)
03859     cctxt->inode->type = cctxt->inode->prev->curChildType;
03860     else
03861     cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);    
03862     /*
03863     * Update the in-scope namespaces if needed.
03864     */
03865     if (elem->nsDef != NULL)
03866     cctxt->inode->inScopeNs =
03867         xsltCompilerBuildInScopeNsList(cctxt, elem);
03868     /*
03869     * xsltStylePreCompute():
03870     *  This will compile the information found on the current
03871     *  element's attributes. NOTE that this won't process the
03872     *  children of the instruction.
03873     */
03874     xsltStylePreCompute(cctxt->style, elem);
03875     /*
03876     * TODO: How to react on errors in xsltStylePreCompute() ?
03877     */
03878 
03879     /*
03880     * Validate the content model of the XSLT-element.
03881     */
03882     switch (cctxt->inode->type) {   
03883     case XSLT_FUNC_APPLYIMPORTS:
03884         /* EMPTY */
03885         goto empty_content;
03886     case XSLT_FUNC_APPLYTEMPLATES:
03887         /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
03888         goto apply_templates;       
03889     case XSLT_FUNC_ATTRIBUTE:       
03890         /* <!-- Content: template --> */
03891         goto sequence_constructor;
03892     case XSLT_FUNC_CALLTEMPLATE:
03893         /* <!-- Content: xsl:with-param* --> */
03894         goto call_template;
03895     case XSLT_FUNC_CHOOSE:      
03896         /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
03897         goto choose;
03898     case XSLT_FUNC_COMMENT:
03899         /* <!-- Content: template --> */
03900         goto sequence_constructor;      
03901     case XSLT_FUNC_COPY:
03902         /* <!-- Content: template --> */
03903         goto sequence_constructor;      
03904     case XSLT_FUNC_COPYOF:
03905         /* EMPTY */
03906         goto empty_content;    
03907     case XSLT_FUNC_DOCUMENT: /* Extra one */
03908         /* ?? template ?? */
03909         goto sequence_constructor;
03910     case XSLT_FUNC_ELEMENT:
03911         /* <!-- Content: template --> */
03912         goto sequence_constructor;
03913     case XSLT_FUNC_FALLBACK:
03914         /* <!-- Content: template --> */
03915         goto sequence_constructor;
03916     case XSLT_FUNC_FOREACH:
03917         /* <!-- Content: (xsl:sort*, template) --> */
03918         goto for_each;
03919     case XSLT_FUNC_IF:
03920         /* <!-- Content: template --> */
03921         goto sequence_constructor;
03922     case XSLT_FUNC_OTHERWISE:
03923         /* <!-- Content: template --> */
03924         goto sequence_constructor;
03925     case XSLT_FUNC_MESSAGE:
03926         /* <!-- Content: template --> */
03927         goto sequence_constructor;
03928     case XSLT_FUNC_NUMBER:
03929         /* EMPTY */
03930         goto empty_content;
03931     case XSLT_FUNC_PARAM:
03932         /*
03933         * Check for redefinition.
03934         */
03935         if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
03936         xsltVarInfoPtr ivar = cctxt->ivar;
03937 
03938         do {
03939             if ((ivar->name ==
03940              ((xsltStyleItemParamPtr) elem->psvi)->name) &&
03941             (ivar->nsName ==
03942              ((xsltStyleItemParamPtr) elem->psvi)->ns))
03943             {
03944             elem->psvi = NULL;
03945             xsltTransformError(NULL, cctxt->style, elem,
03946                 "Redefinition of variable or parameter '%s'.\n",
03947                 ivar->name);
03948             cctxt->style->errors++;
03949             goto error;
03950             }
03951             ivar = ivar->prev;
03952         } while (ivar != NULL);
03953         }
03954         /*  <!-- Content: template --> */
03955         goto sequence_constructor;
03956     case XSLT_FUNC_PI:
03957         /*  <!-- Content: template --> */
03958         goto sequence_constructor;
03959     case XSLT_FUNC_SORT:
03960         /* EMPTY */
03961         goto empty_content;
03962     case XSLT_FUNC_TEXT:
03963         /* <!-- Content: #PCDATA --> */
03964         goto text;
03965     case XSLT_FUNC_VALUEOF:
03966         /* EMPTY */
03967         goto empty_content;
03968     case XSLT_FUNC_VARIABLE:
03969         /*
03970         * Check for redefinition.
03971         */
03972         if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
03973         xsltVarInfoPtr ivar = cctxt->ivar;      
03974 
03975         do {
03976             if ((ivar->name ==
03977              ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
03978             (ivar->nsName ==
03979              ((xsltStyleItemVariablePtr) elem->psvi)->ns))
03980             {
03981             elem->psvi = NULL;
03982             xsltTransformError(NULL, cctxt->style, elem,
03983                 "Redefinition of variable or parameter '%s'.\n",
03984                 ivar->name);
03985             cctxt->style->errors++;
03986             goto error;
03987             }
03988             ivar = ivar->prev;
03989         } while (ivar != NULL);
03990         }
03991         /* <!-- Content: template --> */
03992         goto sequence_constructor;
03993     case XSLT_FUNC_WHEN:
03994         /* <!-- Content: template --> */
03995         goto sequence_constructor;
03996     case XSLT_FUNC_WITHPARAM:
03997         /* <!-- Content: template --> */
03998         goto sequence_constructor;
03999     default:
04000 #ifdef WITH_XSLT_DEBUG_PARSING
04001         xsltGenericDebug(xsltGenericDebugContext,
04002         "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
04003         elem->name);        
04004 #endif
04005         xsltTransformError(NULL, cctxt->style, elem,
04006         "xsltParseXSLTNode: Internal error; "
04007         "unhandled XSLT element '%s'.\n", elem->name);
04008         cctxt->style->errors++;
04009         goto internal_err;
04010     }
04011 
04012 apply_templates:
04013     /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
04014     if (elem->children != NULL) {
04015     xmlNodePtr child = elem->children;
04016     do {
04017         if (child->type == XML_ELEMENT_NODE) {
04018         if (IS_XSLT_ELEM_FAST(child)) {
04019             if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
04020             cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
04021             xsltParseAnyXSLTElem(cctxt, child);
04022             } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
04023             cctxt->inode->curChildType = XSLT_FUNC_SORT;
04024             xsltParseAnyXSLTElem(cctxt, child);
04025             } else
04026             xsltParseContentError(cctxt->style, child);
04027         } else
04028             xsltParseContentError(cctxt->style, child);
04029         }
04030         child = child->next;
04031     } while (child != NULL);
04032     }    
04033     goto exit;
04034 
04035 call_template:
04036     /* <!-- Content: xsl:with-param* --> */
04037     if (elem->children != NULL) {
04038     xmlNodePtr child = elem->children;
04039     do {
04040         if (child->type == XML_ELEMENT_NODE) {
04041         if (IS_XSLT_ELEM_FAST(child)) {
04042             xsltStyleType type;
04043 
04044             type = xsltGetXSLTElementTypeByNode(cctxt, child);
04045             if (type == XSLT_FUNC_WITHPARAM) {
04046             cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
04047             xsltParseAnyXSLTElem(cctxt, child);
04048             } else {
04049             xsltParseContentError(cctxt->style, child);
04050             }
04051         } else
04052             xsltParseContentError(cctxt->style, child);
04053         }
04054         child = child->next;
04055     } while (child != NULL);
04056     }    
04057     goto exit;
04058 
04059 text:
04060     if (elem->children != NULL) {
04061     xmlNodePtr child = elem->children;
04062     do {
04063         if ((child->type != XML_TEXT_NODE) &&
04064         (child->type != XML_CDATA_SECTION_NODE))
04065         {
04066         xsltTransformError(NULL, cctxt->style, elem,
04067             "The XSLT 'text' element must have only character "
04068             "data as content.\n");
04069         }
04070         child = child->next;
04071     } while (child != NULL);
04072     }
04073     goto exit;
04074 
04075 empty_content:
04076     if (elem->children != NULL) {
04077     xmlNodePtr child = elem->children;
04078     /*
04079     * Relaxed behaviour: we will allow whitespace-only text-nodes.
04080     */
04081     do {
04082         if (((child->type != XML_TEXT_NODE) &&
04083          (child->type != XML_CDATA_SECTION_NODE)) ||
04084         (! IS_BLANK_NODE(child)))
04085         {
04086         xsltTransformError(NULL, cctxt->style, elem,
04087             "This XSLT element must have no content.\n");
04088         cctxt->style->errors++;
04089         break;
04090         }
04091         child = child->next;
04092     } while (child != NULL);        
04093     }
04094     goto exit;
04095 
04096 choose:
04097     /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
04098     /*
04099     * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
04100     *   The old behaviour did not check this.
04101     * NOTE: In XSLT 2.0 they are stripped beforehand
04102     *  if whitespace-only (regardless of xml:space).
04103     */
04104     if (elem->children != NULL) {
04105     xmlNodePtr child = elem->children;
04106     int nbWhen = 0, nbOtherwise = 0, err = 0;
04107     do {
04108         if (child->type == XML_ELEMENT_NODE) {
04109         if (IS_XSLT_ELEM_FAST(child)) {
04110             xsltStyleType type;
04111         
04112             type = xsltGetXSLTElementTypeByNode(cctxt, child);
04113             if (type == XSLT_FUNC_WHEN) {
04114             nbWhen++;
04115             if (nbOtherwise) {
04116                 xsltParseContentError(cctxt->style, child);
04117                 err = 1;
04118                 break;
04119             }
04120             cctxt->inode->curChildType = XSLT_FUNC_WHEN;
04121             xsltParseAnyXSLTElem(cctxt, child);
04122             } else if (type == XSLT_FUNC_OTHERWISE) {
04123             if (! nbWhen) {
04124                 xsltParseContentError(cctxt->style, child);
04125                 err = 1;
04126                 break;
04127             }           
04128             if (nbOtherwise) {
04129                 xsltTransformError(NULL, cctxt->style, elem,
04130                 "The XSLT 'choose' element must not contain "
04131                 "more than one XSLT 'otherwise' element.\n");
04132                 cctxt->style->errors++;
04133                 err = 1;
04134                 break;
04135             }
04136             nbOtherwise++;
04137             cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
04138             xsltParseAnyXSLTElem(cctxt, child);
04139             } else
04140             xsltParseContentError(cctxt->style, child);
04141         } else
04142             xsltParseContentError(cctxt->style, child);
04143         } 
04144         /*
04145         else
04146             xsltParseContentError(cctxt, child);
04147         */
04148         child = child->next;
04149     } while (child != NULL);
04150     if ((! err) && (! nbWhen)) {
04151         xsltTransformError(NULL, cctxt->style, elem,
04152         "The XSLT element 'choose' must contain at least one "
04153         "XSLT element 'when'.\n");
04154         cctxt->style->errors++;
04155     }   
04156     }    
04157     goto exit;
04158 
04159 for_each:
04160     /* <!-- Content: (xsl:sort*, template) --> */
04161     /*
04162     * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
04163     *   The old behaviour did not allow this, but it catched this
04164     *   only at transformation-time.
04165     *   In XSLT 2.0 they are stripped beforehand if whitespace-only
04166     *   (regardless of xml:space).
04167     */
04168     if (elem->children != NULL) {
04169     xmlNodePtr child = elem->children;
04170     /*
04171     * Parse xsl:sort first.
04172     */
04173     do {        
04174         if ((child->type == XML_ELEMENT_NODE) &&
04175         IS_XSLT_ELEM_FAST(child))
04176         {       
04177         if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
04178             XSLT_FUNC_SORT)
04179         {       
04180             cctxt->inode->curChildType = XSLT_FUNC_SORT;
04181             xsltParseAnyXSLTElem(cctxt, child);
04182         } else
04183             break;
04184         } else
04185         break;
04186         child = child->next;
04187     } while (child != NULL);
04188     /*
04189     * Parse the sequece constructor.
04190     */
04191     if (child != NULL)
04192         xsltParseSequenceConstructor(cctxt, child);
04193     }    
04194     goto exit;
04195 
04196 sequence_constructor:
04197     /*
04198     * Parse the sequence constructor.
04199     */
04200     if (elem->children != NULL)
04201     xsltParseSequenceConstructor(cctxt, elem->children);
04202 
04203     /*
04204     * Register information for vars/params. Only needed if there
04205     * are any following siblings.
04206     */
04207     if ((elem->next != NULL) &&
04208     ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
04209      (cctxt->inode->type == XSLT_FUNC_PARAM)))
04210     {   
04211     if ((elem->psvi != NULL) &&
04212         (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
04213     {   
04214         xsltCompilerVarInfoPush(cctxt, elem,
04215         ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
04216         ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
04217     }
04218     }
04219 
04220 error:
04221 exit:
04222     xsltCompilerNodePop(cctxt, elem);
04223     return(0);
04224 
04225 internal_err:
04226     xsltCompilerNodePop(cctxt, elem);
04227     return(-1);
04228 }
04229 
04240 static xsltStyleItemUknownPtr
04241 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
04242 {
04243     xsltStyleItemUknownPtr item;
04244 
04245     item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
04246     if (item == NULL) {
04247     xsltTransformError(NULL, cctxt->style, NULL,
04248         "Internal error in xsltForwardsCompatUnkownItemCreate(): "
04249         "Failed to allocate memory.\n");
04250     cctxt->style->errors++;
04251     return(NULL);
04252     }
04253     memset(item, 0, sizeof(xsltStyleItemUknown));
04254     item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
04255     /*
04256     * Store it in the stylesheet.
04257     */
04258     item->next = cctxt->style->preComps;
04259     cctxt->style->preComps = (xsltElemPreCompPtr) item;
04260     return(item);
04261 }
04262 
04277 static int
04278 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
04279                 xmlNodePtr node)
04280 {
04281     if ((cctxt == NULL) || (node == NULL))
04282     return(-1);
04283 
04284     /*
04285     * Detection of handled content of extension instructions.
04286     */
04287     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
04288     cctxt->inode->extContentHandled = 1;
04289     }    
04290     if (cctxt->inode->forwardsCompat == 0) {    
04291     /*
04292     * We are not in forwards-compatible mode, so raise an error.
04293     */
04294     xsltTransformError(NULL, cctxt->style, node,
04295         "Unknown XSLT element '%s'.\n", node->name);
04296     cctxt->style->errors++;
04297     return(1);
04298     }
04299     /*
04300     * Forwards-compatible mode.
04301     * ------------------------
04302     *    
04303     * Parse/compile xsl:fallback elements.
04304     *
04305     * QUESTION: Do we have to raise an error if there's no xsl:fallback?
04306     * ANSWER: No, since in the stylesheet the fallback behaviour might
04307     *  also be provided by using the XSLT function "element-available".
04308     */
04309     if (cctxt->unknownItem == NULL) {
04310     /*
04311     * Create a singleton for all unknown XSLT instructions.
04312     */
04313     cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
04314     if (cctxt->unknownItem == NULL) {
04315         node->psvi = NULL;
04316         return(-1);
04317     }
04318     }
04319     node->psvi = cctxt->unknownItem;
04320     if (node->children == NULL)
04321     return(0);
04322     else {
04323     xmlNodePtr child = node->children;
04324 
04325     xsltCompilerNodePush(cctxt, node);
04326     /*
04327     * Update the in-scope namespaces if needed.
04328     */
04329     if (node->nsDef != NULL)
04330         cctxt->inode->inScopeNs =
04331         xsltCompilerBuildInScopeNsList(cctxt, node);
04332     /*
04333     * Parse all xsl:fallback children.
04334     */
04335     do {
04336         if ((child->type == XML_ELEMENT_NODE) &&
04337         IS_XSLT_ELEM_FAST(child) &&
04338         IS_XSLT_NAME(child, "fallback"))
04339         {
04340         cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
04341         xsltParseAnyXSLTElem(cctxt, child);
04342         }
04343         child = child->next;
04344     } while (child != NULL);
04345     
04346     xsltCompilerNodePop(cctxt, node);
04347     }
04348     return(0);
04349 }
04350 
04360 void
04361 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
04362 {
04363     xsltStyleType type;
04364     xmlNodePtr deleteNode = NULL;
04365 
04366     if (cctxt == NULL) {
04367     xmlGenericError(xmlGenericErrorContext,
04368         "xsltParseSequenceConstructor: Bad arguments\n");
04369     cctxt->style->errors++;
04370     return;
04371     }
04372     /*
04373     * Detection of handled content of extension instructions.
04374     */
04375     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
04376     cctxt->inode->extContentHandled = 1;
04377     }
04378     if (cur == NULL)
04379     return;
04380     /*
04381     * This is the content reffered to as a "template".
04382     * E.g. an xsl:element has such content model:
04383     * <xsl:element
04384     *   name = { qname }
04385     *   namespace = { uri-reference }
04386     *   use-attribute-sets = qnames>
04387     * <!-- Content: template -->
04388     *
04389     * NOTE that in XSLT-2 the term "template" was abandoned due to
04390     *  confusion with xsl:template and the term "sequence constructor"
04391     *  was introduced instead.
04392     *
04393     * The following XSLT-instructions are allowed to appear:
04394     *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
04395     *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
04396     *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
04397     *  xsl:message, xsl:fallback,
04398     *  xsl:processing-instruction, xsl:comment, xsl:element
04399     *  xsl:attribute. 
04400     * Additional allowed content:
04401     * 1) extension instructions
04402     * 2) literal result elements
04403     * 3) PCDATA
04404     *
04405     * NOTE that this content model does *not* allow xsl:param.
04406     */    
04407     while (cur != NULL) {
04408     if (deleteNode != NULL) {
04409 #ifdef WITH_XSLT_DEBUG_BLANKS
04410         xsltGenericDebug(xsltGenericDebugContext,
04411          "xsltParseSequenceConstructor: removing xsl:text element\n");
04412 #endif
04413         xmlUnlinkNode(deleteNode);
04414         xmlFreeNode(deleteNode);
04415         deleteNode = NULL;
04416     }
04417     if (cur->type == XML_ELEMENT_NODE) {        
04418         
04419         if (cur->psvi == xsltXSLTTextMarker) {
04420         /*
04421         * xsl:text elements
04422         * --------------------------------------------------------
04423         */
04424         xmlNodePtr tmp;
04425 
04426         cur->psvi = NULL;
04427         /*
04428         * Mark the xsl:text element for later deletion.
04429         */
04430         deleteNode = cur;
04431         /*
04432         * Validate content.
04433         */
04434         tmp = cur->children;
04435         if (tmp) {
04436             /*
04437             * We don't expect more than one text-node in the
04438             * content, since we already merged adjacent
04439             * text/CDATA-nodes and eliminated PI/comment-nodes.
04440             */
04441             if ((tmp->type == XML_TEXT_NODE) ||
04442             (tmp->next == NULL))
04443             {
04444             /*
04445             * Leave the contained text-node in the tree.
04446             */
04447             xmlUnlinkNode(tmp);
04448             xmlAddPrevSibling(cur, tmp);
04449             } else {
04450             tmp = NULL;
04451             xsltTransformError(NULL, cctxt->style, cur,
04452                 "Element 'xsl:text': Invalid type "
04453                 "of node found in content.\n");
04454             cctxt->style->errors++;
04455             } 
04456         }
04457         if (cur->properties) {
04458             xmlAttrPtr attr;
04459             /*
04460             * TODO: We need to report errors for
04461             *  invalid attrs.
04462             */
04463             attr = cur->properties;
04464             do {
04465             if ((attr->ns == NULL) &&
04466                 (attr->name != NULL) &&
04467                 (attr->name[0] == 'd') &&
04468                 xmlStrEqual(attr->name,
04469                 BAD_CAST "disable-output-escaping"))
04470             {
04471                 /*
04472                 * Attr "disable-output-escaping".
04473                 * XSLT-2: This attribute is deprecated.
04474                 */
04475                 if ((attr->children != NULL) &&
04476                 xmlStrEqual(attr->children->content,
04477                 BAD_CAST "yes"))
04478                 {
04479                 /*
04480                 * Disable output escaping for this
04481                 * text node.
04482                 */
04483                 if (tmp)
04484                     tmp->name = xmlStringTextNoenc;
04485                 } else if ((attr->children == NULL) ||
04486                 (attr->children->content == NULL) ||
04487                 (!xmlStrEqual(attr->children->content,
04488                 BAD_CAST "no")))
04489                 {
04490                 xsltTransformError(NULL, cctxt->style,
04491                     cur,
04492                     "Attribute 'disable-output-escaping': "
04493                     "Invalid value. Expected is "
04494                     "'yes' or 'no'.\n");
04495                 cctxt->style->errors++;
04496                 }
04497                 break;
04498             }
04499             attr = attr->next;
04500             } while (attr != NULL);
04501         }
04502         } else if (IS_XSLT_ELEM_FAST(cur)) {
04503         /*
04504         * TODO: Using the XSLT-marker is still not stable yet.
04505         */
04506         /* if (cur->psvi == xsltXSLTElemMarker) { */        
04507         /*
04508         * XSLT instructions
04509         * --------------------------------------------------------
04510         */
04511         cur->psvi = NULL;
04512         type = xsltGetXSLTElementTypeByNode(cctxt, cur);
04513         switch (type) {
04514             case XSLT_FUNC_APPLYIMPORTS:
04515             case XSLT_FUNC_APPLYTEMPLATES:
04516             case XSLT_FUNC_ATTRIBUTE:
04517             case XSLT_FUNC_CALLTEMPLATE:
04518             case XSLT_FUNC_CHOOSE:
04519             case XSLT_FUNC_COMMENT:
04520             case XSLT_FUNC_COPY:
04521             case XSLT_FUNC_COPYOF:
04522             case XSLT_FUNC_DOCUMENT: /* Extra one */
04523             case XSLT_FUNC_ELEMENT:
04524             case XSLT_FUNC_FALLBACK:
04525             case XSLT_FUNC_FOREACH:
04526             case XSLT_FUNC_IF:
04527             case XSLT_FUNC_MESSAGE:
04528             case XSLT_FUNC_NUMBER:
04529             case XSLT_FUNC_PI:
04530             case XSLT_FUNC_TEXT:
04531             case XSLT_FUNC_VALUEOF:
04532             case XSLT_FUNC_VARIABLE:
04533             /*
04534             * Parse the XSLT element.
04535             */
04536             cctxt->inode->curChildType = type;
04537             xsltParseAnyXSLTElem(cctxt, cur);
04538             break;
04539             default:
04540             xsltParseUnknownXSLTElem(cctxt, cur);           
04541             cur = cur->next;
04542             continue;
04543         }
04544         } else {
04545         /*
04546         * Non-XSLT elements
04547         * -----------------
04548         */
04549         xsltCompilerNodePush(cctxt, cur);
04550         /*
04551         * Update the in-scope namespaces if needed.
04552         */
04553         if (cur->nsDef != NULL)
04554             cctxt->inode->inScopeNs =
04555             xsltCompilerBuildInScopeNsList(cctxt, cur);
04556         /*
04557         * The current element is either a literal result element
04558         * or an extension instruction.
04559         *
04560         * Process attr "xsl:extension-element-prefixes".
04561         * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
04562         * processed by the implementor of the extension function;
04563         * i.e., it won't be handled by the XSLT processor.
04564         */
04565         /* SPEC 1.0:
04566         *   "exclude-result-prefixes" is only allowed on literal
04567         *   result elements and "xsl:exclude-result-prefixes"
04568         *   on xsl:stylesheet/xsl:transform.
04569         * SPEC 2.0:
04570         *   "There are a number of standard attributes
04571         *   that may appear on any XSLT element: specifically
04572         *   version, exclude-result-prefixes,
04573         *   extension-element-prefixes, xpath-default-namespace,
04574         *   default-collation, and use-when."
04575         *
04576         * SPEC 2.0:
04577         *   For literal result elements:
04578         *   "xsl:version, xsl:exclude-result-prefixes,
04579         *    xsl:extension-element-prefixes,
04580         *    xsl:xpath-default-namespace,
04581         *    xsl:default-collation, or xsl:use-when."
04582         */
04583         if (cur->properties)
04584             cctxt->inode->extElemNs =
04585             xsltParseExtElemPrefixes(cctxt,
04586                 cur, cctxt->inode->extElemNs,
04587                 XSLT_ELEMENT_CATEGORY_LRE);
04588         /*
04589         * Eval if we have an extension instruction here.
04590         */
04591         if ((cur->ns != NULL) &&
04592             (cctxt->inode->extElemNs != NULL) &&
04593             (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
04594         {
04595             /*
04596             * Extension instructions
04597             * ----------------------------------------------------
04598             * Mark the node information.
04599             */
04600             cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
04601             cctxt->inode->extContentHandled = 0;
04602             if (cur->psvi != NULL) {
04603             cur->psvi = NULL;
04604             /*
04605             * TODO: Temporary sanity check.
04606             */
04607             xsltTransformError(NULL, cctxt->style, cur,
04608                 "Internal error in xsltParseSequenceConstructor(): "
04609                 "Occupied PSVI field.\n");
04610             cctxt->style->errors++;
04611             cur = cur->next;
04612             continue;
04613             }
04614             cur->psvi = (void *)
04615             xsltPreComputeExtModuleElement(cctxt->style, cur);
04616             
04617             if (cur->psvi == NULL) {
04618             /*
04619             * OLD COMMENT: "Unknown element, maybe registered
04620             *  at the context level. Mark it for later
04621             *  recognition."
04622             * QUESTION: What does the xsltExtMarker mean?
04623             *  ANSWER: It is used in
04624             *   xsltApplySequenceConstructor() at
04625             *   transformation-time to look out for extension
04626             *   registered in the transformation context.
04627             */
04628             cur->psvi = (void *) xsltExtMarker;
04629             }
04630             /*
04631             * BIG NOTE: Now the ugly part. In previous versions
04632             *  of Libxslt (until 1.1.16), all the content of an
04633             *  extension instruction was processed and compiled without
04634             *  the need of the extension-author to explicitely call
04635             *  such a processing;.We now need to mimic this old
04636             *  behaviour in order to avoid breaking old code
04637             *  on the extension-author's side.
04638             * The mechanism:
04639             *  1) If the author does *not* set the
04640             *    compile-time-flag @extContentHandled, then we'll
04641             *    parse the content assuming that it's a "template"
04642             *    (or "sequence constructor in XSLT 2.0 terms).
04643             *    NOTE: If the extension is registered at
04644             *    transformation-time only, then there's no way of
04645             *    knowing that content shall be valid, and we'll
04646             *    process the content the same way.
04647             *  2) If the author *does* set the flag, then we'll assume
04648             *   that the author has handled the parsing him/herself
04649             *   (e.g. called xsltParseSequenceConstructor(), etc.
04650             *   explicitely in his/her code).
04651             */
04652             if ((cur->children != NULL) &&
04653             (cctxt->inode->extContentHandled == 0))
04654             {
04655             /*
04656             * Default parsing of the content using the
04657             * sequence-constructor model.
04658             */
04659             xsltParseSequenceConstructor(cctxt, cur->children);
04660             }
04661         } else {
04662             /*
04663             * Literal result element
04664             * ----------------------------------------------------
04665             * Allowed XSLT attributes:
04666             *  xsl:extension-element-prefixes CDATA #IMPLIED
04667             *  xsl:exclude-result-prefixes CDATA #IMPLIED
04668             *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
04669             *  xsl:version NMTOKEN #IMPLIED
04670             */
04671             cur->psvi = NULL;
04672             cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
04673             if (cur->properties != NULL) {
04674             xmlAttrPtr attr = cur->properties;
04675             /*
04676             * Attribute "xsl:exclude-result-prefixes".
04677             */
04678             cctxt->inode->exclResultNs =
04679                 xsltParseExclResultPrefixes(cctxt, cur,
04680                 cctxt->inode->exclResultNs,
04681                 XSLT_ELEMENT_CATEGORY_LRE);
04682             /*
04683             * Attribute "xsl:version".
04684             */
04685             xsltParseAttrXSLTVersion(cctxt, cur,
04686                 XSLT_ELEMENT_CATEGORY_LRE);
04687             /*
04688             * Report invalid XSLT attributes.           
04689             * For XSLT 1.0 only xsl:use-attribute-sets is allowed
04690             * next to xsl:version, xsl:exclude-result-prefixes and
04691             * xsl:extension-element-prefixes.
04692             *
04693             * Mark all XSLT attributes, in order to skip such
04694             * attributes when instantiating the LRE.
04695             */
04696             do {
04697                 if ((attr->psvi != xsltXSLTAttrMarker) &&
04698                 IS_XSLT_ATTR_FAST(attr))
04699                 {                   
04700                 if (! xmlStrEqual(attr->name,
04701                     BAD_CAST "use-attribute-sets"))
04702                 {               
04703                     xsltTransformError(NULL, cctxt->style,
04704                     cur,
04705                     "Unknown XSLT attribute '%s'.\n",
04706                     attr->name);
04707                     cctxt->style->errors++;
04708                 } else {
04709                     /*
04710                     * XSLT attr marker.
04711                     */
04712                     attr->psvi = (void *) xsltXSLTAttrMarker;
04713                 }
04714                 }
04715                 attr = attr->next;
04716             } while (attr != NULL);
04717             }
04718             /*
04719             * Create/reuse info for the literal result element.
04720             */
04721             if (cctxt->inode->nsChanged)
04722             xsltLREInfoCreate(cctxt, cur, 1);
04723             cur->psvi = cctxt->inode->litResElemInfo;
04724             /*
04725             * Apply ns-aliasing on the element and on its attributes.
04726             */
04727             if (cctxt->hasNsAliases)
04728             xsltLREBuildEffectiveNs(cctxt, cur);
04729             /*
04730             * Compile attribute value templates (AVT).
04731             */
04732             if (cur->properties) {
04733             xmlAttrPtr attr = cur->properties;
04734             
04735             while (attr != NULL) {
04736                 xsltCompileAttr(cctxt->style, attr);
04737                 attr = attr->next;
04738             }
04739             }
04740             /*
04741             * Parse the content, which is defined to be a "template"
04742             * (or "sequence constructor" in XSLT 2.0 terms).
04743             */
04744             if (cur->children != NULL) {
04745             xsltParseSequenceConstructor(cctxt, cur->children);
04746             }
04747         }
04748         /*
04749         * Leave the non-XSLT element.
04750         */
04751         xsltCompilerNodePop(cctxt, cur);
04752         }
04753     }
04754     cur = cur->next;
04755     }
04756     if (deleteNode != NULL) {
04757 #ifdef WITH_XSLT_DEBUG_BLANKS
04758     xsltGenericDebug(xsltGenericDebugContext,
04759         "xsltParseSequenceConstructor: removing xsl:text element\n");
04760 #endif
04761     xmlUnlinkNode(deleteNode);
04762     xmlFreeNode(deleteNode);
04763     deleteNode = NULL;
04764     }
04765 }
04766 
04781 void
04782 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
04783     if ((style == NULL) || (templ == NULL))
04784     return;
04785 
04786     /*
04787     * Detection of handled content of extension instructions.
04788     */
04789     if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
04790     XSLT_CCTXT(style)->inode->extContentHandled = 1;
04791     }
04792 
04793     if (templ->children != NULL) {  
04794     xmlNodePtr child = templ->children;
04795     /*
04796     * Process xsl:param elements, which can only occur as the
04797     * immediate children of xsl:template (well, and of any
04798     * user-defined extension instruction if needed).
04799     */  
04800     do {
04801         if ((child->type == XML_ELEMENT_NODE) &&
04802         IS_XSLT_ELEM_FAST(child) &&
04803         IS_XSLT_NAME(child, "param"))
04804         {
04805         XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
04806         xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
04807         } else
04808         break;
04809         child = child->next;
04810     } while (child != NULL);
04811     /*
04812     * Parse the content and register the pattern.
04813     */
04814     xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
04815     }
04816 }
04817 
04818 #else /* XSLT_REFACTORED */
04819 
04829 void
04830 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
04831     xmlNodePtr cur, delete;
04832     /*
04833      * This content comes from the stylesheet
04834      * For stylesheets, the set of whitespace-preserving
04835      * element names consists of just xsl:text.
04836      */
04837     cur = templ->children;
04838     delete = NULL;
04839     while (cur != NULL) {
04840     if (delete != NULL) {
04841 #ifdef WITH_XSLT_DEBUG_BLANKS
04842         xsltGenericDebug(xsltGenericDebugContext,
04843          "xsltParseTemplateContent: removing text\n");
04844 #endif
04845         xmlUnlinkNode(delete);
04846         xmlFreeNode(delete);
04847         delete = NULL;
04848     }
04849     if (IS_XSLT_ELEM(cur)) {
04850         if (IS_XSLT_NAME(cur, "text")) {
04851         /*
04852         * TODO: Processing of xsl:text should be moved to
04853         *   xsltPrecomputeStylesheet(), since otherwise this
04854         *   will be performed for every multiply included
04855         *   stylesheet; i.e. this here is not skipped with
04856         *   the use of the style->nopreproc flag.
04857         */
04858         if (cur->children != NULL) {
04859             xmlChar *prop;
04860             xmlNodePtr text = cur->children, next;
04861             int noesc = 0;
04862             
04863             prop = xmlGetNsProp(cur,
04864             (const xmlChar *)"disable-output-escaping",
04865             NULL);
04866             if (prop != NULL) {
04867 #ifdef WITH_XSLT_DEBUG_PARSING
04868             xsltGenericDebug(xsltGenericDebugContext,
04869                  "Disable escaping: %s\n", text->content);
04870 #endif
04871             if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
04872                 noesc = 1;
04873             } else if (!xmlStrEqual(prop,
04874                         (const xmlChar *)"no")){
04875                 xsltTransformError(NULL, style, cur,
04876          "xsl:text: disable-output-escaping allows only yes or no\n");
04877                 style->warnings++;
04878 
04879             }
04880             xmlFree(prop);
04881             }
04882 
04883             while (text != NULL) {
04884             if (text->type == XML_COMMENT_NODE) {
04885                 text = text->next;
04886                 continue;
04887             }
04888             if ((text->type != XML_TEXT_NODE) &&
04889                  (text->type != XML_CDATA_SECTION_NODE)) {
04890                 xsltTransformError(NULL, style, cur,
04891          "xsltParseTemplateContent: xslt:text content problem\n");
04892                 style->errors++;
04893                 break;
04894             }
04895             if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
04896                 text->name = xmlStringTextNoenc;
04897             text = text->next;
04898             }
04899 
04900             /*
04901              * replace xsl:text by the list of childs
04902              */
04903             if (text == NULL) {
04904             text = cur->children;
04905             while (text != NULL) {
04906                 if ((style->internalized) &&
04907                     (text->content != NULL) &&
04908                     (!xmlDictOwns(style->dict, text->content))) {
04909 
04910                 /*
04911                  * internalize the text string
04912                  */
04913                 if (text->doc->dict != NULL) {
04914                     const xmlChar *tmp;
04915                     
04916                     tmp = xmlDictLookup(text->doc->dict,
04917                                         text->content, -1);
04918                     if (tmp != text->content) {
04919                         xmlNodeSetContent(text, NULL);
04920                     text->content = (xmlChar *) tmp;
04921                     }
04922                 }
04923                 }
04924 
04925                 next = text->next;
04926                 xmlUnlinkNode(text);
04927                 xmlAddPrevSibling(cur, text);
04928                 text = next;
04929             }
04930             }
04931         }
04932         delete = cur;
04933         goto skip_children;
04934         }
04935     }
04936     else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
04937         (xsltCheckExtPrefix(style, cur->ns->prefix)))
04938     {
04939         /*
04940          * okay this is an extension element compile it too
04941          */
04942         xsltStylePreCompute(style, cur);
04943     }
04944     else if (cur->type == XML_ELEMENT_NODE)
04945     {
04946         /*
04947          * This is an element which will be output as part of the
04948          * template exectution, precompile AVT if found.
04949          */
04950         if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
04951         cur->ns = xmlSearchNsByHref(cur->doc, cur,
04952             style->defaultAlias);
04953         }
04954         if (cur->properties != NULL) {
04955             xmlAttrPtr attr = cur->properties;
04956 
04957         while (attr != NULL) {
04958             xsltCompileAttr(style, attr);
04959             attr = attr->next;
04960         }
04961         }
04962     }
04963     /*
04964      * Skip to next node
04965      */
04966     if (cur->children != NULL) {
04967         if (cur->children->type != XML_ENTITY_DECL) {
04968         cur = cur->children;
04969         continue;
04970         }
04971     }
04972 skip_children:
04973     if (cur->next != NULL) {
04974         cur = cur->next;
04975         continue;
04976     }
04977     
04978     do {
04979         cur = cur->parent;
04980         if (cur == NULL)
04981         break;
04982         if (cur == templ) {
04983         cur = NULL;
04984         break;
04985         }
04986         if (cur->next != NULL) {
04987         cur = cur->next;
04988         break;
04989         }
04990     } while (cur != NULL);
04991     }
04992     if (delete != NULL) {
04993 #ifdef WITH_XSLT_DEBUG_PARSING
04994     xsltGenericDebug(xsltGenericDebugContext,
04995      "xsltParseTemplateContent: removing text\n");
04996 #endif
04997     xmlUnlinkNode(delete);
04998     xmlFreeNode(delete);
04999     delete = NULL;
05000     }
05001 
05002     /*
05003      * Skip the first params
05004      */
05005     cur = templ->children;
05006     while (cur != NULL) {
05007     if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
05008         break;
05009     cur = cur->next;
05010     }
05011 
05012     /*
05013      * Browse the remainder of the template
05014      */
05015     while (cur != NULL) {
05016     if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
05017         xmlNodePtr param = cur;
05018 
05019         xsltTransformError(NULL, style, cur,
05020         "xsltParseTemplateContent: ignoring misplaced param element\n");
05021         if (style != NULL) style->warnings++;
05022             cur = cur->next;
05023         xmlUnlinkNode(param);
05024         xmlFreeNode(param);
05025     } else
05026         break;
05027     }
05028 }
05029 
05030 #endif /* else XSLT_REFACTORED */
05031 
05043 static void
05044 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
05045     xmlChar *prop = NULL;
05046     xmlChar *use = NULL;
05047     xmlChar *match = NULL;
05048     xmlChar *name = NULL;
05049     xmlChar *nameURI = NULL;
05050 
05051     if ((style == NULL) || (key == NULL))
05052     return;
05053 
05054     /*
05055      * Get arguments
05056      */
05057     prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
05058     if (prop != NULL) {
05059         const xmlChar *URI;
05060 
05061     /*
05062     * TODO: Don't use xsltGetQNameURI().
05063     */
05064     URI = xsltGetQNameURI(key, &prop);
05065     if (prop == NULL) {
05066         if (style != NULL) style->errors++;
05067         goto error;
05068     } else {
05069         name = prop;
05070         if (URI != NULL)
05071         nameURI = xmlStrdup(URI);
05072     }
05073 #ifdef WITH_XSLT_DEBUG_PARSING
05074     xsltGenericDebug(xsltGenericDebugContext,
05075          "xsltParseStylesheetKey: name %s\n", name);
05076 #endif
05077     } else {
05078     xsltTransformError(NULL, style, key,
05079         "xsl:key : error missing name\n");
05080     if (style != NULL) style->errors++;
05081     goto error;
05082     }
05083 
05084     match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
05085     if (match == NULL) {
05086     xsltTransformError(NULL, style, key,
05087         "xsl:key : error missing match\n");
05088     if (style != NULL) style->errors++;
05089     goto error;
05090     }
05091 
05092     use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
05093     if (use == NULL) {
05094     xsltTransformError(NULL, style, key,
05095         "xsl:key : error missing use\n");
05096     if (style != NULL) style->errors++;
05097     goto error;
05098     }
05099 
05100     /*
05101      * register the keys
05102      */
05103     xsltAddKey(style, name, nameURI, match, use, key);
05104 
05105 
05106 error:
05107     if (use != NULL)
05108     xmlFree(use);
05109     if (match != NULL)
05110     xmlFree(match);
05111     if (name != NULL)
05112     xmlFree(name);
05113     if (nameURI != NULL)
05114     xmlFree(nameURI);
05115 
05116     if (key->children != NULL) {
05117     xsltParseContentError(style, key->children);
05118     }
05119 }
05120 
05121 #ifdef XSLT_REFACTORED
05122 
05135 static void
05136 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
05137     xsltTemplatePtr templ;
05138     xmlChar *prop;    
05139     double  priority;    
05140 
05141     if ((cctxt == NULL) || (templNode == NULL))
05142     return;
05143 
05144     /*
05145      * Create and link the structure
05146      */
05147     templ = xsltNewTemplate();
05148     if (templ == NULL)
05149     return;
05150 
05151     xsltCompilerNodePush(cctxt, templNode);
05152     if (templNode->nsDef != NULL)
05153     cctxt->inode->inScopeNs =
05154         xsltCompilerBuildInScopeNsList(cctxt, templNode);
05155 
05156     templ->next = cctxt->style->templates;
05157     cctxt->style->templates = templ;
05158     templ->style = cctxt->style;  
05159 
05160     /*
05161     * Attribute "mode".
05162     */
05163     prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
05164     if (prop != NULL) { 
05165         const xmlChar *modeURI;
05166 
05167     /*
05168     * TODO: We need a standardized function for extraction
05169     *  of namespace names and local names from QNames.
05170     *  Don't use xsltGetQNameURI() as it cannot channeö
05171     *  reports through the context.
05172     */
05173     modeURI = xsltGetQNameURI(templNode, &prop);
05174     if (prop == NULL) {
05175         cctxt->style->errors++;
05176         goto error;
05177     }
05178     templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
05179     xmlFree(prop);
05180     prop = NULL;
05181     if (xmlValidateNCName(templ->mode, 0)) {
05182         xsltTransformError(NULL, cctxt->style, templNode,
05183         "xsl:template: Attribute 'mode': The local part '%s' "
05184         "of the value is not a valid NCName.\n", templ->name);
05185         cctxt->style->errors++;
05186         goto error;
05187     }
05188     if (modeURI != NULL)
05189         templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
05190 #ifdef WITH_XSLT_DEBUG_PARSING
05191     xsltGenericDebug(xsltGenericDebugContext,
05192          "xsltParseXSLTTemplate: mode %s\n", templ->mode);
05193 #endif
05194     }
05195     /*
05196     * Attribute "match".
05197     */
05198     prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
05199     if (prop != NULL) {
05200     templ->match  = prop;
05201     prop = NULL;
05202     }
05203     /*
05204     * Attribute "priority".
05205     */
05206     prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
05207     if (prop != NULL) {
05208     priority = xmlXPathStringEvalNumber(prop);
05209     templ->priority = (float) priority;
05210     xmlFree(prop);
05211     prop = NULL;
05212     }
05213     /*
05214     * Attribute "name".
05215     */
05216     prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
05217     if (prop != NULL) {
05218         const xmlChar *nameURI;
05219     xsltTemplatePtr curTempl;
05220     
05221     /*
05222     * TODO: Don't use xsltGetQNameURI().
05223     */
05224     nameURI = xsltGetQNameURI(templNode, &prop);
05225     if (prop == NULL) {
05226         cctxt->style->errors++;
05227         goto error;
05228     }
05229     templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
05230     xmlFree(prop);
05231     prop = NULL;
05232     if (xmlValidateNCName(templ->name, 0)) {
05233         xsltTransformError(NULL, cctxt->style, templNode,
05234         "xsl:template: Attribute 'name': The local part '%s' of "
05235         "the value is not a valid NCName.\n", templ->name);
05236         cctxt->style->errors++;
05237         goto error;
05238     }   
05239     if (nameURI != NULL)
05240         templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
05241     curTempl = templ->next;
05242     while (curTempl != NULL) {
05243         if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
05244         xmlStrEqual(curTempl->nameURI, nameURI) ) ||
05245         (nameURI == NULL && curTempl->nameURI == NULL &&
05246         xmlStrEqual(curTempl->name, templ->name)))
05247         {
05248         xsltTransformError(NULL, cctxt->style, templNode,
05249             "xsl:template: error duplicate name '%s'\n", templ->name);
05250         cctxt->style->errors++;
05251         goto error;
05252         }
05253         curTempl = curTempl->next;
05254     }
05255     }
05256     if (templNode->children != NULL) {
05257     xsltParseTemplateContent(cctxt->style, templNode);  
05258     /*
05259     * MAYBE TODO: Custom behaviour: In order to stay compatible with
05260     * Xalan and MSXML(.NET), we could allow whitespace
05261     * to appear before an xml:param element; this whitespace
05262     * will additionally become part of the "template".
05263     * NOTE that this is totally deviates from the spec, but
05264     * is the de facto behaviour of Xalan and MSXML(.NET).
05265     * Personally I wouldn't allow this, since if we have:
05266     * <xsl:template ...xml:space="preserve">
05267     *   <xsl:param name="foo"/>
05268     *   <xsl:param name="bar"/>
05269     *   <xsl:param name="zoo"/>
05270     * ... the whitespace between every xsl:param would be
05271     * added to the result tree.
05272     */      
05273     }    
05274     
05275     templ->elem = templNode;
05276     templ->content = templNode->children;
05277     xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
05278 
05279 error:
05280     xsltCompilerNodePop(cctxt, templNode);
05281     return;
05282 }
05283 
05284 #else /* XSLT_REFACTORED */
05285 
05294 static void
05295 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
05296     xsltTemplatePtr ret;
05297     xmlChar *prop;
05298     xmlChar *mode = NULL;
05299     xmlChar *modeURI = NULL;
05300     double  priority;
05301 
05302     if (template == NULL)
05303     return;
05304 
05305     /*
05306      * Create and link the structure
05307      */
05308     ret = xsltNewTemplate();
05309     if (ret == NULL)
05310     return;
05311     ret->next = style->templates;
05312     style->templates = ret;
05313     ret->style = style;
05314    
05315     /*
05316      * Get inherited namespaces
05317      */
05318     /*
05319     * TODO: Apply the optimized in-scope-namespace mechanism
05320     *   as for the other XSLT instructions.
05321     */
05322     xsltGetInheritedNsList(style, ret, template);
05323 
05324     /*
05325      * Get arguments
05326      */
05327     prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
05328     if (prop != NULL) {
05329         const xmlChar *URI;
05330 
05331     /*
05332     * TODO: Don't use xsltGetQNameURI().
05333     */
05334     URI = xsltGetQNameURI(template, &prop);
05335     if (prop == NULL) {
05336         if (style != NULL) style->errors++;
05337         goto error;
05338     } else {
05339         mode = prop;
05340         if (URI != NULL)
05341         modeURI = xmlStrdup(URI);
05342     }
05343     ret->mode = xmlDictLookup(style->dict, mode, -1);
05344     ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
05345 #ifdef WITH_XSLT_DEBUG_PARSING
05346     xsltGenericDebug(xsltGenericDebugContext,
05347          "xsltParseStylesheetTemplate: mode %s\n", mode);
05348 #endif
05349         if (mode != NULL) xmlFree(mode);
05350     if (modeURI != NULL) xmlFree(modeURI);
05351     }
05352     prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
05353     if (prop != NULL) {
05354     if (ret->match != NULL) xmlFree(ret->match);
05355     ret->match  = prop;
05356     }
05357 
05358     prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
05359     if (prop != NULL) {
05360     priority = xmlXPathStringEvalNumber(prop);
05361     ret->priority = (float) priority;
05362     xmlFree(prop);
05363     }
05364 
05365     prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
05366     if (prop != NULL) {
05367         const xmlChar *URI;
05368     xsltTemplatePtr cur;
05369     
05370     /*
05371     * TODO: Don't use xsltGetQNameURI().
05372     */
05373     URI = xsltGetQNameURI(template, &prop);
05374     if (prop == NULL) {
05375         if (style != NULL) style->errors++;
05376         goto error;
05377     } else {
05378         if (xmlValidateNCName(prop,0)) {
05379             xsltTransformError(NULL, style, template,
05380                 "xsl:template : error invalid name '%s'\n", prop);
05381         if (style != NULL) style->errors++;
05382         goto error;
05383         }
05384         ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
05385         xmlFree(prop);
05386         prop = NULL;
05387         if (URI != NULL)
05388         ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
05389         else
05390         ret->nameURI = NULL;
05391         cur = ret->next;
05392         while (cur != NULL) {
05393             if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
05394                 xmlStrEqual(cur->nameURI, URI) ) ||
05395             (URI == NULL && cur->nameURI == NULL &&
05396                 xmlStrEqual(cur->name, ret->name))) {
05397             xsltTransformError(NULL, style, template,
05398                 "xsl:template: error duplicate name '%s'\n", ret->name);
05399             style->errors++;
05400             goto error;
05401         }
05402         cur = cur->next;
05403         }
05404     }
05405     }
05406 
05407     /*
05408      * parse the content and register the pattern
05409      */
05410     xsltParseTemplateContent(style, template);
05411     ret->elem = template;
05412     ret->content = template->children;
05413     xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
05414 
05415 error:
05416     return;
05417 }
05418 
05419 #endif /* else XSLT_REFACTORED */
05420 
05421 #ifdef XSLT_REFACTORED
05422 
05430 static xsltStyleItemIncludePtr
05431 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
05432     xsltStyleItemIncludePtr item;
05433 
05434     if ((cctxt == NULL) || (node == NULL))
05435     return(NULL);
05436 
05437     node->psvi = NULL;
05438     item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
05439     if (item == NULL) {
05440     xsltTransformError(NULL, cctxt->style, node,
05441         "xsltIncludeComp : malloc failed\n");
05442     cctxt->style->errors++;
05443     return(NULL);
05444     }
05445     memset(item, 0, sizeof(xsltStyleItemInclude));
05446 
05447     node->psvi = item;
05448     item->inst = node;
05449     item->type = XSLT_FUNC_INCLUDE;
05450 
05451     item->next = cctxt->style->preComps;
05452     cctxt->style->preComps = (xsltElemPreCompPtr) item;
05453 
05454     return(item);
05455 }
05456 
05460 static int
05461 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
05462                   xmlNodePtr cur,
05463                   const xmlChar *name,
05464                   const xmlChar *namespaceURI,
05465                   int breakOnOtherElem,               
05466                   xmlNodePtr *resultNode)
05467 {
05468     if (name == NULL)
05469     return(-1);
05470 
05471     *resultNode = NULL;
05472     while (cur != NULL) {
05473     if (cur->type == XML_ELEMENT_NODE) {
05474         if ((cur->ns != NULL) && (cur->name != NULL)) {
05475         if ((*(cur->name) == *name) &&
05476             xmlStrEqual(cur->name, name) &&
05477             xmlStrEqual(cur->ns->href, namespaceURI))           
05478         {
05479             *resultNode = cur;
05480             return(1);
05481         }
05482         }
05483         if (breakOnOtherElem)
05484         break;
05485     }
05486     cur = cur->next;
05487     }
05488     *resultNode = cur;
05489     return(0);
05490 }
05491 
05492 static int
05493 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
05494               xmlNodePtr node,
05495               xsltStyleType type)
05496 {
05497     int ret = 0;
05498 
05499     /*
05500     * TODO: The reason why this function exists:
05501     *  due to historical reasons some of the
05502     *  top-level declarations are processed by functions
05503     *  in other files. Since we need still to set
05504     *  up the node-info and generate information like
05505     *  in-scope namespaces, this is a wrapper around
05506     *  those old parsing functions.
05507     */
05508     xsltCompilerNodePush(cctxt, node);
05509     if (node->nsDef != NULL)
05510     cctxt->inode->inScopeNs =
05511         xsltCompilerBuildInScopeNsList(cctxt, node);
05512     cctxt->inode->type = type;
05513 
05514     switch (type) {
05515     case XSLT_FUNC_INCLUDE:
05516         {
05517         int oldIsInclude;
05518 
05519         if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
05520             goto exit;      
05521         /*
05522         * Mark this stylesheet tree as being currently included.
05523         */
05524         oldIsInclude = cctxt->isInclude;
05525         cctxt->isInclude = 1;
05526                         
05527         if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
05528             cctxt->style->errors++;
05529         }
05530         cctxt->isInclude = oldIsInclude;
05531         }
05532         break;
05533     case XSLT_FUNC_PARAM:
05534         xsltStylePreCompute(cctxt->style, node);
05535         xsltParseGlobalParam(cctxt->style, node);
05536         break;
05537     case XSLT_FUNC_VARIABLE:
05538         xsltStylePreCompute(cctxt->style, node);
05539         xsltParseGlobalVariable(cctxt->style, node);
05540         break;
05541     case XSLT_FUNC_ATTRSET:
05542         xsltParseStylesheetAttributeSet(cctxt->style, node);
05543         break;
05544     default:
05545         xsltTransformError(NULL, cctxt->style, node,
05546         "Internal error: (xsltParseTopLevelXSLTElem) "
05547         "Cannot handle this top-level declaration.\n");
05548         cctxt->style->errors++;
05549         ret = -1;
05550     }
05551 
05552 exit:
05553     xsltCompilerNodePop(cctxt, node);
05554 
05555     return(ret);
05556 }
05557 
05558 #if 0
05559 static int
05560 xsltParseRemoveWhitespace(xmlNodePtr node)
05561 {
05562     if ((node == NULL) || (node->children == NULL))
05563     return(0);
05564     else {
05565     xmlNodePtr delNode = NULL, child = node->children;
05566 
05567     do {
05568         if (delNode) {
05569         xmlUnlinkNode(delNode);
05570         xmlFreeNode(delNode);
05571         delNode = NULL;
05572         }
05573         if (((child->type == XML_TEXT_NODE) ||
05574          (child->type == XML_CDATA_SECTION_NODE)) &&
05575         (IS_BLANK_NODE(child)))
05576         delNode = child;        
05577         child = child->next;
05578     } while (child != NULL);
05579     if (delNode) {
05580         xmlUnlinkNode(delNode);
05581         xmlFreeNode(delNode);
05582         delNode = NULL;
05583     }
05584     }
05585     return(0);
05586 }
05587 #endif
05588 
05589 static int
05590 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
05591 {
05592 #ifdef WITH_XSLT_DEBUG_PARSING
05593     int templates = 0;
05594 #endif
05595     xmlNodePtr cur, start = NULL;
05596     xsltStylesheetPtr style;
05597 
05598     if ((cctxt == NULL) || (node == NULL) ||
05599     (node->type != XML_ELEMENT_NODE))
05600     return(-1);    
05601 
05602     style = cctxt->style;    
05603     /*
05604     * At this stage all import declarations of all stylesheet modules
05605     * with the same stylesheet level have been processed.
05606     * Now we can safely parse the rest of the declarations.
05607     */
05608     if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
05609     {
05610     xsltDocumentPtr include;
05611     /*
05612     * URGENT TODO: Make this work with simplified stylesheets!
05613     *   I.e., when we won't find an xsl:stylesheet element.
05614     */
05615     /*
05616     * This is as include declaration.
05617     */
05618     include = ((xsltStyleItemIncludePtr) node->psvi)->include;
05619     if (include == NULL) {
05620         /* TODO: raise error? */
05621         return(-1);
05622     }
05623     /*
05624     * TODO: Actually an xsl:include should locate an embedded
05625     *  stylesheet as well; so the document-element won't always
05626     *  be the element where the actual stylesheet is rooted at.
05627     *  But such embedded stylesheets are not supported by Libxslt yet.
05628     */
05629     node = xmlDocGetRootElement(include->doc);
05630     if (node == NULL) {
05631         return(-1);
05632     }
05633     }    
05634     
05635     if (node->children == NULL)
05636     return(0);
05637     /*
05638     * Push the xsl:stylesheet/xsl:transform element.
05639     */  
05640     xsltCompilerNodePush(cctxt, node);
05641     cctxt->inode->isRoot = 1;
05642     cctxt->inode->nsChanged = 0;
05643     /*
05644     * Start with the naked dummy info for literal result elements.
05645     */
05646     cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
05647 
05648     /*
05649     * In every case, we need to have
05650     * the in-scope namespaces of the element, where the
05651     * stylesheet is rooted at, regardless if it's an XSLT
05652     * instruction or a literal result instruction (or if
05653     * this is an embedded stylesheet).
05654     */      
05655     cctxt->inode->inScopeNs =
05656     xsltCompilerBuildInScopeNsList(cctxt, node);
05657 
05658     /*
05659     * Process attributes of xsl:stylesheet/xsl:transform.
05660     * --------------------------------------------------
05661     * Allowed are:
05662     *  id = id
05663     *  extension-element-prefixes = tokens
05664     *  exclude-result-prefixes = tokens
05665     *  version = number (mandatory)    
05666     */
05667     if (xsltParseAttrXSLTVersion(cctxt, node,
05668     XSLT_ELEMENT_CATEGORY_XSLT) == 0)
05669     {    
05670     /*
05671     * Attribute "version".
05672     * XSLT 1.0: "An xsl:stylesheet element *must* have a version
05673     *  attribute, indicating the version of XSLT that the
05674     *  stylesheet requires".
05675     * The root element of a simplified stylesheet must also have
05676     * this attribute.
05677     */
05678 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
05679     if (isXsltElem)
05680         xsltTransformError(NULL, cctxt->style, node,
05681         "The attribute 'version' is missing.\n");
05682     cctxt->style->errors++; 
05683 #else
05684     /* OLD behaviour. */
05685     xsltTransformError(NULL, cctxt->style, node,
05686         "xsl:version is missing: document may not be a stylesheet\n");
05687     cctxt->style->warnings++;
05688 #endif
05689     }    
05690     /*
05691     * The namespaces declared by the attributes
05692     *  "extension-element-prefixes" and
05693     *  "exclude-result-prefixes" are local to *this*
05694     *  stylesheet tree; i.e., they are *not* visible to
05695     *  other stylesheet-modules, whether imported or included.
05696     * 
05697     * Attribute "extension-element-prefixes".
05698     */
05699     cctxt->inode->extElemNs =
05700     xsltParseExtElemPrefixes(cctxt, node, NULL,
05701         XSLT_ELEMENT_CATEGORY_XSLT);
05702     /*
05703     * Attribute "exclude-result-prefixes".
05704     */
05705     cctxt->inode->exclResultNs =
05706     xsltParseExclResultPrefixes(cctxt, node, NULL,
05707         XSLT_ELEMENT_CATEGORY_XSLT);
05708     /*
05709     * Create/reuse info for the literal result element.
05710     */
05711     if (cctxt->inode->nsChanged)
05712     xsltLREInfoCreate(cctxt, node, 0);
05713     /*
05714     * Processed top-level elements:
05715     * ----------------------------
05716     *  xsl:variable, xsl:param (QName, in-scope ns,
05717     *    expression (vars allowed))
05718     *  xsl:attribute-set (QName, in-scope ns)
05719     *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
05720     *    in-scope ns)
05721     *    I *think* global scope, merge with includes
05722     *  xsl:output (QName, in-scope ns)
05723     *  xsl:key (QName, in-scope ns, pattern,
05724     *    expression (vars *not* allowed))
05725     *  xsl:decimal-format (QName, needs in-scope ns)
05726     *  xsl:namespace-alias (in-scope ns)
05727     *    global scope, merge with includes
05728     *  xsl:template (last, QName, pattern)
05729     *
05730     * (whitespace-only text-nodes have *not* been removed
05731     *  yet; this will be done in xsltParseSequenceConstructor)
05732     *
05733     * Report misplaced child-nodes first.
05734     */
05735     cur = node->children;
05736     while (cur != NULL) {
05737     if (cur->type == XML_TEXT_NODE) {
05738         xsltTransformError(NULL, style, cur,
05739         "Misplaced text node (content: '%s').\n",
05740         (cur->content != NULL) ? cur->content : BAD_CAST "");
05741         style->errors++;
05742     } else if (cur->type != XML_ELEMENT_NODE) {
05743         xsltTransformError(NULL, style, cur, "Misplaced node.\n");
05744         style->errors++;
05745     }
05746     cur = cur->next;
05747     }
05748     /*
05749     * Skip xsl:import elements; they have been processed
05750     * already.
05751     */
05752     cur = node->children;
05753     while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
05754         BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
05755     cur = cur->next;
05756     if (cur == NULL)
05757     goto exit;
05758 
05759     start = cur;
05760     /*
05761     * Process all top-level xsl:param elements.
05762     */
05763     while ((cur != NULL) &&
05764     xsltParseFindTopLevelElem(cctxt, cur,
05765     BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
05766     {
05767     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); 
05768     cur = cur->next;
05769     }  
05770     /*
05771     * Process all top-level xsl:variable elements.
05772     */
05773     cur = start;
05774     while ((cur != NULL) &&
05775     xsltParseFindTopLevelElem(cctxt, cur,
05776     BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
05777     {
05778     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
05779     cur = cur->next;
05780     }   
05781     /*
05782     * Process all the rest of top-level elements.
05783     */
05784     cur = start;
05785     while (cur != NULL) {   
05786     /*
05787     * Process element nodes.
05788     */
05789     if (cur->type == XML_ELEMENT_NODE) {        
05790         if (cur->ns == NULL) {
05791         xsltTransformError(NULL, style, cur,
05792             "Unexpected top-level element in no namespace.\n");
05793         style->errors++;
05794         cur = cur->next;
05795         continue;
05796         }
05797         /*
05798         * Process all XSLT elements.
05799         */
05800         if (IS_XSLT_ELEM_FAST(cur)) {
05801         /*
05802         * xsl:import is only allowed at the beginning.
05803         */
05804         if (IS_XSLT_NAME(cur, "import")) {
05805             xsltTransformError(NULL, style, cur,
05806             "Misplaced xsl:import element.\n");
05807             style->errors++;
05808             cur = cur->next;
05809             continue;
05810         }
05811         /* 
05812         * TODO: Change the return type of the parsing functions
05813         *  to int.
05814         */
05815         if (IS_XSLT_NAME(cur, "template")) {
05816 #ifdef WITH_XSLT_DEBUG_PARSING
05817             templates++;
05818 #endif
05819             /*
05820             * TODO: Is the position of xsl:template in the
05821             *  tree significant? If not it would be easier to
05822             *  parse them at a later stage.
05823             */
05824             xsltParseXSLTTemplate(cctxt, cur);
05825         } else if (IS_XSLT_NAME(cur, "variable")) {
05826             /* NOP; done already */
05827         } else if (IS_XSLT_NAME(cur, "param")) {
05828             /* NOP; done already */
05829         } else if (IS_XSLT_NAME(cur, "include")) {          
05830             if (cur->psvi != NULL)          
05831             xsltParseXSLTStylesheetElemCore(cctxt, cur);
05832             else {
05833             xsltTransformError(NULL, style, cur,
05834                 "Internal error: "
05835                 "(xsltParseXSLTStylesheetElemCore) "
05836                 "The xsl:include element was not compiled.\n");
05837             style->errors++;
05838             }
05839         } else if (IS_XSLT_NAME(cur, "strip-space")) {
05840             /* No node info needed. */
05841             xsltParseStylesheetStripSpace(style, cur);
05842         } else if (IS_XSLT_NAME(cur, "preserve-space")) {
05843             /* No node info needed. */
05844             xsltParseStylesheetPreserveSpace(style, cur);
05845         } else if (IS_XSLT_NAME(cur, "output")) {
05846             /* No node-info needed. */
05847             xsltParseStylesheetOutput(style, cur);
05848         } else if (IS_XSLT_NAME(cur, "key")) {
05849             /* TODO: node-info needed for expressions ? */
05850             xsltParseStylesheetKey(style, cur);
05851         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
05852             /* No node-info needed. */           
05853             xsltParseStylesheetDecimalFormat(style, cur);
05854         } else if (IS_XSLT_NAME(cur, "attribute-set")) {            
05855             xsltParseTopLevelXSLTElem(cctxt, cur,
05856             XSLT_FUNC_ATTRSET);     
05857         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
05858             /* NOP; done already */         
05859         } else {
05860             if (cctxt->inode->forwardsCompat) {
05861             /*
05862             * Forwards-compatible mode:
05863             *
05864             * XSLT-1: "if it is a top-level element and
05865             *  XSLT 1.0 does not allow such elements as top-level
05866             *  elements, then the element must be ignored along
05867             *  with its content;"
05868             */
05869             /*
05870             * TODO: I don't think we should generate a warning.
05871             */
05872             xsltTransformError(NULL, style, cur,
05873                 "Forwards-compatible mode: Ignoring unknown XSLT "
05874                 "element '%s'.\n", cur->name);
05875             style->warnings++;
05876             } else {
05877             xsltTransformError(NULL, style, cur,
05878                 "Unknown XSLT element '%s'.\n", cur->name);
05879             style->errors++;
05880             }
05881         }
05882         } else {
05883         xsltTopLevelFunction function;
05884 
05885         /*
05886         * Process non-XSLT elements, which are in a
05887         *  non-NULL namespace.
05888         */
05889         /*
05890         * QUESTION: What does xsltExtModuleTopLevelLookup()
05891         *  do exactly?
05892         */
05893         function = xsltExtModuleTopLevelLookup(cur->name,
05894             cur->ns->href);
05895         if (function != NULL)
05896             function(style, cur);
05897 #ifdef WITH_XSLT_DEBUG_PARSING
05898         xsltGenericDebug(xsltGenericDebugContext,
05899             "xsltParseXSLTStylesheetElemCore : User-defined "
05900             "data element '%s'.\n", cur->name);
05901 #endif
05902         }
05903     }
05904     cur = cur->next;
05905     }
05906 
05907 exit:
05908 
05909 #ifdef WITH_XSLT_DEBUG_PARSING
05910     xsltGenericDebug(xsltGenericDebugContext,
05911     "### END of parsing top-level elements of doc '%s'.\n",
05912     node->doc->URL);
05913     xsltGenericDebug(xsltGenericDebugContext,
05914     "### Templates: %d\n", templates);
05915 #ifdef XSLT_REFACTORED
05916     xsltGenericDebug(xsltGenericDebugContext,
05917     "### Max inodes: %d\n", cctxt->maxNodeInfos);
05918     xsltGenericDebug(xsltGenericDebugContext,
05919     "### Max LREs  : %d\n", cctxt->maxLREs);
05920 #endif /* XSLT_REFACTORED */
05921 #endif /* WITH_XSLT_DEBUG_PARSING */
05922 
05923     xsltCompilerNodePop(cctxt, node);
05924     return(0);
05925 }
05926 
05949 static int
05950 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
05951 {
05952     xmlNodePtr cur, start;
05953 
05954     if ((cctxt == NULL) || (node == NULL))
05955     return(-1);
05956     
05957     if (node->children == NULL)
05958     goto exit;
05959 
05960     /*
05961     * Process top-level elements:
05962     *  xsl:import (must be first)
05963     *  xsl:include (this is just a pre-processing)
05964     */
05965     cur = node->children;
05966     /*
05967     * Process xsl:import elements.
05968     * XSLT 1.0: "The xsl:import element children must precede all
05969     *  other element children of an xsl:stylesheet element,
05970     *  including any xsl:include element children."
05971     */    
05972     while ((cur != NULL) &&
05973     xsltParseFindTopLevelElem(cctxt, cur,
05974         BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
05975     {
05976     if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
05977         cctxt->style->errors++;
05978     }
05979     cur = cur->next;
05980     }
05981     if (cur == NULL)
05982     goto exit;
05983     start = cur;
05984     /*
05985     * Pre-process all xsl:include elements.
05986     */
05987     cur = start;
05988     while ((cur != NULL) &&
05989     xsltParseFindTopLevelElem(cctxt, cur,
05990         BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
05991     {
05992     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
05993     cur = cur->next;
05994     }
05995     /*
05996     * Pre-process all xsl:namespace-alias elements.
05997     * URGENT TODO: This won't work correctly: the order of included
05998     *  aliases and aliases defined here is significant.
05999     */
06000     cur = start;
06001     while ((cur != NULL) &&
06002     xsltParseFindTopLevelElem(cctxt, cur,
06003         BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
06004     {
06005     xsltNamespaceAlias(cctxt->style, cur);
06006     cur = cur->next;
06007     }
06008 
06009     if (cctxt->isInclude) {
06010     /*
06011     * If this stylesheet is intended for inclusion, then
06012     * we will process only imports and includes. 
06013     */
06014     goto exit;
06015     } 
06016     /*
06017     * Now parse the rest of the top-level elements.
06018     */
06019     xsltParseXSLTStylesheetElemCore(cctxt, node);   
06020 exit:
06021 
06022     return(0);
06023 }
06024 
06025 #else /* XSLT_REFACTORED */
06026 
06034 static void
06035 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
06036     xmlNodePtr cur;
06037     xmlChar *prop;
06038 #ifdef WITH_XSLT_DEBUG_PARSING
06039     int templates = 0;
06040 #endif
06041 
06042     if (top == NULL)
06043     return;
06044 
06045     prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
06046     if (prop == NULL) {
06047     xsltTransformError(NULL, style, top,
06048         "xsl:version is missing: document may not be a stylesheet\n");
06049     if (style != NULL) style->warnings++;
06050     } else {
06051     if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
06052             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
06053         xsltTransformError(NULL, style, top,
06054         "xsl:version: only 1.0 features are supported\n");
06055          /* TODO set up compatibility when not XSLT 1.0 */
06056         if (style != NULL) style->warnings++;
06057     }
06058     xmlFree(prop);
06059     }
06060 
06061     /*
06062      * process xsl:import elements
06063      */
06064     cur = top->children;
06065     while (cur != NULL) {
06066         if (IS_BLANK_NODE(cur)) {
06067             cur = cur->next;
06068             continue;
06069         }
06070         if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
06071             if (xsltParseStylesheetImport(style, cur) != 0)
06072                 if (style != NULL) style->errors++;
06073         } else
06074             break;
06075         cur = cur->next;
06076     }
06077 
06078     /*
06079      * process other top-level elements
06080      */
06081     while (cur != NULL) {
06082     if (IS_BLANK_NODE(cur)) {
06083         cur = cur->next;
06084         continue;
06085     }
06086     if (cur->type == XML_TEXT_NODE) {
06087         if (cur->content != NULL) {
06088         xsltTransformError(NULL, style, cur,
06089             "misplaced text node: '%s'\n", cur->content);
06090         }
06091         if (style != NULL) style->errors++;
06092             cur = cur->next;
06093         continue;
06094     }
06095     if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
06096         xsltGenericError(xsltGenericErrorContext,
06097              "Found a top-level element %s with null namespace URI\n",
06098              cur->name);
06099         if (style != NULL) style->errors++;
06100         cur = cur->next;
06101         continue;
06102     }
06103     if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
06104         xsltTopLevelFunction function;
06105 
06106         function = xsltExtModuleTopLevelLookup(cur->name,
06107                            cur->ns->href);
06108         if (function != NULL)
06109         function(style, cur);
06110 
06111 #ifdef WITH_XSLT_DEBUG_PARSING
06112         xsltGenericDebug(xsltGenericDebugContext,
06113             "xsltParseStylesheetTop : found foreign element %s\n",
06114             cur->name);
06115 #endif
06116             cur = cur->next;
06117         continue;
06118     }
06119     if (IS_XSLT_NAME(cur, "import")) {
06120         xsltTransformError(NULL, style, cur,
06121             "xsltParseStylesheetTop: ignoring misplaced import element\n");
06122         if (style != NULL) style->errors++;
06123     } else if (IS_XSLT_NAME(cur, "include")) {
06124         if (xsltParseStylesheetInclude(style, cur) != 0)
06125         if (style != NULL) style->errors++;
06126     } else if (IS_XSLT_NAME(cur, "strip-space")) {
06127         xsltParseStylesheetStripSpace(style, cur);
06128     } else if (IS_XSLT_NAME(cur, "preserve-space")) {
06129         xsltParseStylesheetPreserveSpace(style, cur);
06130     } else if (IS_XSLT_NAME(cur, "output")) {
06131         xsltParseStylesheetOutput(style, cur);
06132     } else if (IS_XSLT_NAME(cur, "key")) {
06133         xsltParseStylesheetKey(style, cur);
06134     } else if (IS_XSLT_NAME(cur, "decimal-format")) {
06135         xsltParseStylesheetDecimalFormat(style, cur);
06136     } else if (IS_XSLT_NAME(cur, "attribute-set")) {
06137         xsltParseStylesheetAttributeSet(style, cur);
06138     } else if (IS_XSLT_NAME(cur, "variable")) {
06139         xsltParseGlobalVariable(style, cur);
06140     } else if (IS_XSLT_NAME(cur, "param")) {
06141         xsltParseGlobalParam(style, cur);
06142     } else if (IS_XSLT_NAME(cur, "template")) {
06143 #ifdef WITH_XSLT_DEBUG_PARSING
06144         templates++;
06145 #endif
06146         xsltParseStylesheetTemplate(style, cur);
06147     } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
06148         xsltNamespaceAlias(style, cur);
06149     } else {
06150         /*
06151         * BUG TODO: The version of the *doc* is irrelevant for
06152         *  the forwards-compatible mode.
06153         */
06154             if ((style != NULL) && (style->doc->version != NULL) &&
06155             (!strncmp((const char *) style->doc->version, "1.0", 3))) {
06156             xsltTransformError(NULL, style, cur,
06157             "xsltParseStylesheetTop: unknown %s element\n",
06158             cur->name);
06159             if (style != NULL) style->errors++;
06160         }
06161         else {
06162                 /* do Forwards-Compatible Processing */
06163             xsltTransformError(NULL, style, cur,
06164             "xsltParseStylesheetTop: ignoring unknown %s element\n",
06165             cur->name);
06166             if (style != NULL) style->warnings++;
06167             }
06168     }
06169     cur = cur->next;
06170     }
06171 #ifdef WITH_XSLT_DEBUG_PARSING
06172     xsltGenericDebug(xsltGenericDebugContext,
06173             "parsed %d templates\n", templates);
06174 #endif
06175 }
06176 
06177 #endif /* else of XSLT_REFACTORED */
06178 
06179 #ifdef XSLT_REFACTORED
06180 
06190 static int
06191 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
06192                   xmlDocPtr doc,
06193                   xmlNodePtr node)
06194 {
06195     xsltTemplatePtr templ;
06196     
06197     if ((cctxt == NULL) || (node == NULL))
06198     return(-1);
06199 
06200     if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
06201     {
06202     /*
06203     * TODO: Adjust report, since this might be an
06204     * embedded stylesheet.
06205     */
06206     xsltTransformError(NULL, cctxt->style, node,
06207         "The attribute 'xsl:version' is missing; cannot identify "
06208         "this document as an XSLT stylesheet document.\n");
06209     cctxt->style->errors++;
06210     return(1);
06211     }
06212     
06213 #ifdef WITH_XSLT_DEBUG_PARSING
06214     xsltGenericDebug(xsltGenericDebugContext,
06215     "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
06216 #endif        
06217     
06218     /*
06219     * Create and link the template
06220     */
06221     templ = xsltNewTemplate();
06222     if (templ == NULL) {
06223     return(-1);
06224     }
06225     templ->next = cctxt->style->templates;
06226     cctxt->style->templates = templ;
06227     templ->match = xmlStrdup(BAD_CAST "/");
06228 
06229     /*
06230     * Note that we push the document-node in this special case.
06231     */
06232     xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
06233     /*
06234     * In every case, we need to have
06235     * the in-scope namespaces of the element, where the
06236     * stylesheet is rooted at, regardless if it's an XSLT
06237     * instruction or a literal result instruction (or if
06238     * this is an embedded stylesheet).
06239     */
06240     cctxt->inode->inScopeNs =
06241     xsltCompilerBuildInScopeNsList(cctxt, node);
06242     /*
06243     * Parse the content and register the match-pattern.
06244     */
06245     xsltParseSequenceConstructor(cctxt, node);
06246     xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
06247 
06248     templ->elem = (xmlNodePtr) doc;
06249     templ->content = node;
06250     xsltAddTemplate(cctxt->style, templ, NULL, NULL);
06251     cctxt->style->literal_result = 1;
06252     return(0);
06253 }
06254 
06255 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
06256 
06265 int
06266 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
06267 {
06268     if (doc == NULL)
06269     return(-1);
06270     /*
06271     * Revert the changes we have applied to the namespace-URIs of
06272     * ns-decls.
06273     */    
06274     while (ns != NULL) {
06275     if ((ns->doc == doc) && (ns->ns != NULL)) {
06276         ns->ns->href = ns->origNsName;
06277         ns->origNsName = NULL;
06278         ns->ns = NULL;      
06279     }
06280     ns = ns->next;
06281     }
06282     return(0);
06283 }
06284 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
06285 
06299 xsltStylesheetPtr
06300 xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
06301 {
06302     xsltCompilerCtxtPtr cctxt;
06303     xmlNodePtr cur;
06304     int oldIsSimplifiedStylesheet;
06305 
06306     xsltInitGlobals();
06307 
06308     if ((style == NULL) || (doc == NULL))
06309     return(NULL);
06310 
06311     cctxt = XSLT_CCTXT(style);
06312 
06313     cur = xmlDocGetRootElement(doc);
06314     if (cur == NULL) {
06315     xsltTransformError(NULL, style, (xmlNodePtr) doc,
06316         "xsltParseStylesheetProcess : empty stylesheet\n");
06317     return(NULL);
06318     }
06319     oldIsSimplifiedStylesheet = cctxt->simplified;
06320 
06321     if ((IS_XSLT_ELEM(cur)) && 
06322     ((IS_XSLT_NAME(cur, "stylesheet")) ||
06323      (IS_XSLT_NAME(cur, "transform")))) {   
06324 #ifdef WITH_XSLT_DEBUG_PARSING
06325     xsltGenericDebug(xsltGenericDebugContext,
06326         "xsltParseStylesheetProcess : found stylesheet\n");
06327 #endif
06328     cctxt->simplified = 0;
06329     style->literal_result = 0;
06330     } else {
06331     cctxt->simplified = 1;
06332     style->literal_result = 1;
06333     }
06334     /*
06335     * Pre-process the stylesheet if not already done before.
06336     *  This will remove PIs and comments, merge adjacent
06337     *  text nodes, internalize strings, etc.
06338     */
06339     if (! style->nopreproc)
06340     xsltParsePreprocessStylesheetTree(cctxt, cur);
06341     /*
06342     * Parse and compile the stylesheet.
06343     */
06344     if (style->literal_result == 0) {
06345     if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
06346         return(NULL);
06347     } else {
06348     if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
06349         return(NULL);
06350     }    
06351 
06352     cctxt->simplified = oldIsSimplifiedStylesheet;
06353 
06354     return(style);
06355 }
06356 
06357 #else /* XSLT_REFACTORED */
06358 
06372 xsltStylesheetPtr
06373 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
06374     xmlNodePtr cur;
06375 
06376     xsltInitGlobals();
06377 
06378     if (doc == NULL)
06379     return(NULL);
06380     if (ret == NULL)
06381     return(ret);
06382     
06383     /*
06384      * First steps, remove blank nodes,
06385      * locate the xsl:stylesheet element and the
06386      * namespace declaration.
06387      */
06388     cur = xmlDocGetRootElement(doc);
06389     if (cur == NULL) {
06390     xsltTransformError(NULL, ret, (xmlNodePtr) doc,
06391         "xsltParseStylesheetProcess : empty stylesheet\n");
06392     return(NULL);
06393     }
06394 
06395     if ((IS_XSLT_ELEM(cur)) && 
06396     ((IS_XSLT_NAME(cur, "stylesheet")) ||
06397      (IS_XSLT_NAME(cur, "transform")))) {   
06398 #ifdef WITH_XSLT_DEBUG_PARSING
06399     xsltGenericDebug(xsltGenericDebugContext,
06400         "xsltParseStylesheetProcess : found stylesheet\n");
06401 #endif
06402     ret->literal_result = 0;
06403     xsltParseStylesheetExcludePrefix(ret, cur, 1);
06404     xsltParseStylesheetExtPrefix(ret, cur, 1);
06405     } else {
06406     xsltParseStylesheetExcludePrefix(ret, cur, 0);
06407     xsltParseStylesheetExtPrefix(ret, cur, 0);
06408     ret->literal_result = 1;
06409     }
06410     if (!ret->nopreproc) {
06411     xsltPrecomputeStylesheet(ret, cur);
06412     }
06413     if (ret->literal_result == 0) {
06414     xsltParseStylesheetTop(ret, cur);
06415     } else {
06416     xmlChar *prop;
06417     xsltTemplatePtr template;
06418 
06419     /*
06420      * the document itself might be the template, check xsl:version
06421      */
06422     prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
06423     if (prop == NULL) {
06424         xsltTransformError(NULL, ret, cur,
06425         "xsltParseStylesheetProcess : document is not a stylesheet\n");
06426         return(NULL);
06427     }
06428 
06429 #ifdef WITH_XSLT_DEBUG_PARSING
06430         xsltGenericDebug(xsltGenericDebugContext,
06431         "xsltParseStylesheetProcess : document is stylesheet\n");
06432 #endif
06433     
06434     if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
06435         xsltTransformError(NULL, ret, cur,
06436         "xsl:version: only 1.0 features are supported\n");
06437          /* TODO set up compatibility when not XSLT 1.0 */
06438         ret->warnings++;
06439     }
06440     xmlFree(prop);
06441 
06442     /*
06443      * Create and link the template
06444      */
06445     template = xsltNewTemplate();
06446     if (template == NULL) {
06447         return(NULL);
06448     }
06449     template->next = ret->templates;
06450     ret->templates = template;
06451     template->match = xmlStrdup((const xmlChar *)"/");
06452 
06453     /*
06454      * parse the content and register the pattern
06455      */
06456     xsltParseTemplateContent(ret, (xmlNodePtr) doc);
06457     template->elem = (xmlNodePtr) doc;
06458     template->content = doc->children;
06459     xsltAddTemplate(ret, template, NULL, NULL);
06460     ret->literal_result = 1;    
06461     }
06462 
06463     return(ret);
06464 }
06465 
06466 #endif /* else of XSLT_REFACTORED */
06467 
06479 xsltStylesheetPtr
06480 xsltParseStylesheetImportedDoc(xmlDocPtr doc,
06481                    xsltStylesheetPtr parentStyle) {
06482     xsltStylesheetPtr retStyle;
06483 
06484     if (doc == NULL)
06485     return(NULL);
06486 
06487     retStyle = xsltNewStylesheet();
06488     if (retStyle == NULL)
06489     return(NULL);
06490     /*
06491     * Set the importing stylesheet module; also used to detect recursion.
06492     */
06493     retStyle->parent = parentStyle;
06494     /*
06495     * Adjust the string dict.
06496     */
06497     if (doc->dict != NULL) {
06498         xmlDictFree(retStyle->dict);
06499     retStyle->dict = doc->dict;
06500 #ifdef WITH_XSLT_DEBUG
06501         xsltGenericDebug(xsltGenericDebugContext,
06502         "reusing dictionary from %s for stylesheet\n",
06503         doc->URL);
06504 #endif
06505     xmlDictReference(retStyle->dict);
06506     }       
06507     
06508     /*
06509     * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
06510     *  the stylesheet to containt distinct namespace prefixes.
06511     */
06512     xsltGatherNamespaces(retStyle);
06513 
06514 #ifdef XSLT_REFACTORED
06515     {
06516     xsltCompilerCtxtPtr cctxt;
06517     xsltStylesheetPtr oldCurSheet;
06518         
06519     if (parentStyle == NULL) {
06520         xsltPrincipalStylesheetDataPtr principalData;
06521         /*
06522         * Principal stylesheet
06523         * --------------------
06524         */
06525         retStyle->principal = retStyle;
06526         /*
06527         * Create extra data for the principal stylesheet.
06528         */
06529         principalData = xsltNewPrincipalStylesheetData();
06530         if (principalData == NULL) {
06531         xsltFreeStylesheet(retStyle);
06532         return(NULL);
06533         }
06534         retStyle->principalData = principalData;
06535         /*
06536         * Create the compilation context
06537         * ------------------------------
06538         * (only once; for the principal stylesheet).
06539         * This is currently the only function where the
06540         * compilation context is created.
06541         */
06542         cctxt = xsltCompilationCtxtCreate(retStyle);
06543         if (cctxt == NULL) {
06544         xsltFreeStylesheet(retStyle);
06545         return(NULL);
06546         }               
06547         retStyle->compCtxt = (void *) cctxt;
06548         cctxt->style = retStyle;
06549         cctxt->dict = retStyle->dict;
06550         cctxt->psData = principalData;
06551         /*
06552         * Push initial dummy node info.
06553         */
06554         cctxt->depth = -1;
06555         xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
06556     } else {
06557         /*
06558         * Imported stylesheet.
06559         */
06560         retStyle->principal = parentStyle->principal;
06561         cctxt = parentStyle->compCtxt;
06562         retStyle->compCtxt = cctxt;
06563     }
06564     /*
06565     * Save the old and set the current stylesheet structure in the
06566     * compilation context.
06567     */
06568     oldCurSheet = cctxt->style;
06569     cctxt->style = retStyle;
06570     
06571     retStyle->doc = doc;
06572     xsltParseStylesheetProcess(retStyle, doc);
06573     
06574     cctxt->style = oldCurSheet;
06575     if (parentStyle == NULL) {
06576         /*
06577         * Pop the initial dummy node info.
06578         */
06579         xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
06580     } else {
06581         /*
06582         * Clear the compilation context of imported
06583         * stylesheets.
06584         * TODO: really?
06585         */
06586         /* retStyle->compCtxt = NULL; */
06587     }
06588     /*
06589     * Free the stylesheet if there were errors.
06590     */
06591     if (retStyle != NULL) {
06592         if (retStyle->errors != 0) {
06593 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
06594         /*
06595         * Restore all changes made to namespace URIs of ns-decls.
06596         */
06597         if (cctxt->psData->nsMap)       
06598             xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
06599 #endif
06600         /*
06601         * Detach the doc from the stylesheet; otherwise the doc
06602         * will be freed in xsltFreeStylesheet().
06603         */
06604         retStyle->doc = NULL;
06605         /*
06606         * Cleanup the doc if its the main stylesheet.
06607         */
06608         if (parentStyle == NULL) {
06609             xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
06610             if (retStyle->compCtxt != NULL) {           
06611             xsltCompilationCtxtFree(retStyle->compCtxt);
06612             retStyle->compCtxt = NULL;
06613             }
06614         }
06615 
06616         xsltFreeStylesheet(retStyle);
06617         retStyle = NULL;
06618         }
06619     }
06620     }
06621         
06622 #else /* XSLT_REFACTORED */
06623     /*
06624     * Old behaviour.
06625     */
06626     retStyle->doc = doc;
06627     if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
06628         retStyle->doc = NULL;
06629         xsltFreeStylesheet(retStyle);
06630         retStyle = NULL;
06631     }
06632     if (retStyle != NULL) {
06633     if (retStyle->errors != 0) {
06634         retStyle->doc = NULL;
06635         if (parentStyle == NULL)
06636         xsltCleanupStylesheetTree(doc,
06637             xmlDocGetRootElement(doc));
06638         xsltFreeStylesheet(retStyle);
06639         retStyle = NULL;
06640     }
06641     }
06642 #endif /* else of XSLT_REFACTORED */
06643         
06644     return(retStyle);
06645 }
06646 
06660 xsltStylesheetPtr
06661 xsltParseStylesheetDoc(xmlDocPtr doc) {
06662     xsltStylesheetPtr ret;
06663 
06664     xsltInitGlobals();
06665 
06666     ret = xsltParseStylesheetImportedDoc(doc, NULL);
06667     if (ret == NULL)
06668     return(NULL);
06669 
06670     xsltResolveStylesheetAttributeSet(ret);
06671 #ifdef XSLT_REFACTORED
06672     /*
06673     * Free the compilation context.
06674     * TODO: Check if it's better to move this cleanup to
06675     *   xsltParseStylesheetImportedDoc().
06676     */
06677     if (ret->compCtxt != NULL) {
06678     xsltCompilationCtxtFree(XSLT_CCTXT(ret));
06679     ret->compCtxt = NULL;
06680     }
06681 #endif
06682     return(ret);
06683 }
06684 
06694 xsltStylesheetPtr
06695 xsltParseStylesheetFile(const xmlChar* filename) {
06696     xsltSecurityPrefsPtr sec;
06697     xsltStylesheetPtr ret;
06698     xmlDocPtr doc;
06699     
06700     xsltInitGlobals();
06701 
06702     if (filename == NULL)
06703     return(NULL);
06704 
06705 #ifdef WITH_XSLT_DEBUG_PARSING
06706     xsltGenericDebug(xsltGenericDebugContext,
06707         "xsltParseStylesheetFile : parse %s\n", filename);
06708 #endif
06709 
06710     /*
06711      * Security framework check
06712      */
06713     sec = xsltGetDefaultSecurityPrefs();
06714     if (sec != NULL) {
06715     int res;
06716 
06717     res = xsltCheckRead(sec, NULL, filename);
06718     if (res == 0) {
06719         xsltTransformError(NULL, NULL, NULL,
06720          "xsltParseStylesheetFile: read rights for %s denied\n",
06721                  filename);
06722         return(NULL);
06723     }
06724     }
06725 
06726     doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
06727                                NULL, XSLT_LOAD_START);
06728     if (doc == NULL) {
06729     xsltTransformError(NULL, NULL, NULL,
06730         "xsltParseStylesheetFile : cannot parse %s\n", filename);
06731     return(NULL);
06732     }
06733     ret = xsltParseStylesheetDoc(doc);
06734     if (ret == NULL) {
06735     xmlFreeDoc(doc);
06736     return(NULL);
06737     }
06738 
06739     return(ret);
06740 }
06741 
06742 /************************************************************************
06743  *                                  *
06744  *          Handling of Stylesheet PI           *
06745  *                                  *
06746  ************************************************************************/
06747 
06748 #define CUR (*cur)
06749 #define SKIP(val) cur += (val)
06750 #define NXT(val) cur[(val)]
06751 #define SKIP_BLANKS                     \
06752     while (IS_BLANK(CUR)) NEXT
06753 #define NEXT ((*cur) ?  cur++ : cur)
06754 
06765 static xmlChar *
06766 xsltParseStylesheetPI(const xmlChar *value) {
06767     const xmlChar *cur;
06768     const xmlChar *start;
06769     xmlChar *val;
06770     xmlChar tmp;
06771     xmlChar *href = NULL;
06772     int isXml = 0;
06773 
06774     if (value == NULL)
06775     return(NULL);
06776 
06777     cur = value;
06778     while (CUR != 0) {
06779     SKIP_BLANKS;
06780     if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
06781         (NXT(3) == 'e')) {
06782         SKIP(4);
06783         SKIP_BLANKS;
06784         if (CUR != '=')
06785         continue;
06786         NEXT;
06787         if ((CUR != '\'') && (CUR != '"'))
06788         continue;
06789         tmp = CUR;
06790         NEXT;
06791         start = cur;
06792         while ((CUR != 0) && (CUR != tmp))
06793         NEXT;
06794         if (CUR != tmp)
06795         continue;
06796         val = xmlStrndup(start, cur - start);
06797         NEXT;
06798         if (val == NULL) 
06799         return(NULL);
06800         if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
06801         (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
06802                 xmlFree(val);
06803         break;
06804         }
06805         isXml = 1;
06806         xmlFree(val);
06807     } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
06808         (NXT(3) == 'f')) {
06809         SKIP(4);
06810         SKIP_BLANKS;
06811         if (CUR != '=')
06812         continue;
06813         NEXT;
06814         if ((CUR != '\'') && (CUR != '"'))
06815         continue;
06816         tmp = CUR;
06817         NEXT;
06818         start = cur;
06819         while ((CUR != 0) && (CUR != tmp))
06820         NEXT;
06821         if (CUR != tmp)
06822         continue;
06823         if (href == NULL)
06824         href = xmlStrndup(start, cur - start);
06825         NEXT;
06826     } else {
06827         while ((CUR != 0) && (!IS_BLANK(CUR)))
06828         NEXT;
06829     }
06830             
06831     }
06832 
06833     if (!isXml) {
06834     if (href != NULL)
06835         xmlFree(href);
06836     href = NULL;
06837     }
06838     return(href);
06839 }
06840 
06855 xsltStylesheetPtr
06856 xsltLoadStylesheetPI(xmlDocPtr doc) {
06857     xmlNodePtr child;
06858     xsltStylesheetPtr ret = NULL;
06859     xmlChar *href = NULL;
06860     xmlURIPtr URI;
06861 
06862     xsltInitGlobals();
06863 
06864     if (doc == NULL)
06865     return(NULL);
06866 
06867     /*
06868      * Find the text/xml stylesheet PI id any before the root
06869      */
06870     child = doc->children;
06871     while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
06872     if ((child->type == XML_PI_NODE) &&
06873         (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
06874         href = xsltParseStylesheetPI(child->content);
06875         if (href != NULL)
06876         break;
06877     }
06878     child = child->next;
06879     }
06880 
06881     /*
06882      * If found check the href to select processing
06883      */
06884     if (href != NULL) {
06885 #ifdef WITH_XSLT_DEBUG_PARSING
06886     xsltGenericDebug(xsltGenericDebugContext,
06887         "xsltLoadStylesheetPI : found PI href=%s\n", href);
06888 #endif
06889     URI = xmlParseURI((const char *) href);
06890     if (URI == NULL) {
06891         xsltTransformError(NULL, NULL, child,
06892             "xml-stylesheet : href %s is not valid\n", href);
06893         xmlFree(href);
06894         return(NULL);
06895     }
06896     if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
06897             (URI->opaque == NULL) && (URI->authority == NULL) &&
06898             (URI->server == NULL) && (URI->user == NULL) &&
06899             (URI->path == NULL) && (URI->query == NULL)) {
06900         xmlAttrPtr ID;
06901 
06902 #ifdef WITH_XSLT_DEBUG_PARSING
06903         xsltGenericDebug(xsltGenericDebugContext,
06904             "xsltLoadStylesheetPI : Reference to ID %s\n", href);
06905 #endif
06906         if (URI->fragment[0] == '#')
06907         ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
06908         else
06909         ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
06910         if (ID == NULL) {
06911         xsltTransformError(NULL, NULL, child,
06912             "xml-stylesheet : no ID %s found\n", URI->fragment);
06913         } else {
06914         xmlDocPtr fake;
06915         xmlNodePtr subtree, newtree;
06916         xmlNsPtr ns;
06917 
06918 #ifdef WITH_XSLT_DEBUG
06919         xsltGenericDebug(xsltGenericDebugContext,
06920             "creating new document from %s for embedded stylesheet\n",
06921             doc->URL);
06922 #endif
06923         /*
06924          * move the subtree in a new document passed to
06925          * the stylesheet analyzer
06926          */
06927         subtree = ID->parent;
06928         fake = xmlNewDoc(NULL);
06929         if (fake != NULL) {
06930             /*
06931             * Should the dictionary still be shared even though
06932             * the nodes are being copied rather than moved?
06933             */
06934             fake->dict = doc->dict;
06935             xmlDictReference(doc->dict);
06936 #ifdef WITH_XSLT_DEBUG
06937             xsltGenericDebug(xsltGenericDebugContext,
06938             "reusing dictionary from %s for embedded stylesheet\n",
06939             doc->URL);
06940 #endif
06941 
06942             newtree = xmlDocCopyNode(subtree, fake, 1);
06943 
06944             fake->URL = xmlNodeGetBase(doc, subtree->parent);
06945 #ifdef WITH_XSLT_DEBUG
06946             xsltGenericDebug(xsltGenericDebugContext,
06947             "set base URI for embedded stylesheet as %s\n",
06948             fake->URL);
06949 #endif
06950 
06951             /*
06952             * Add all namespaces in scope of embedded stylesheet to
06953             * root element of newly created stylesheet document
06954             */
06955             while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
06956             for (ns = subtree->ns; ns; ns = ns->next) {
06957                 xmlNewNs(newtree,  ns->href, ns->prefix);
06958             }
06959             }
06960 
06961             xmlAddChild((xmlNodePtr)fake, newtree);
06962             ret = xsltParseStylesheetDoc(fake);
06963             if (ret == NULL)
06964             xmlFreeDoc(fake);
06965         }
06966         }
06967     } else {
06968         xmlChar *URL, *base;
06969 
06970         /*
06971          * Reference to an external stylesheet
06972          */
06973 
06974         base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
06975         URL = xmlBuildURI(href, base);
06976         if (URL != NULL) {
06977 #ifdef WITH_XSLT_DEBUG_PARSING
06978         xsltGenericDebug(xsltGenericDebugContext,
06979             "xsltLoadStylesheetPI : fetching %s\n", URL);
06980 #endif
06981         ret = xsltParseStylesheetFile(URL);
06982         xmlFree(URL);
06983         } else {
06984 #ifdef WITH_XSLT_DEBUG_PARSING
06985         xsltGenericDebug(xsltGenericDebugContext,
06986             "xsltLoadStylesheetPI : fetching %s\n", href);
06987 #endif
06988         ret = xsltParseStylesheetFile(href);
06989         }
06990         if (base != NULL)
06991         xmlFree(base);
06992     }
06993     xmlFreeURI(URI);
06994     xmlFree(href);
06995     }
06996     return(ret);
06997 }

Generated on Fri May 25 2012 04:17:49 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.