Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxslt.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
1.7.6.1
|