Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvariables.c
Go to the documentation of this file.
00001 /* 00002 * variables.c: Implementation of the variable storage and lookup 00003 * 00004 * Reference: 00005 * http://www.w3.org/TR/1999/REC-xslt-19991116 00006 * 00007 * See Copyright for the status of this software. 00008 * 00009 * daniel@veillard.com 00010 */ 00011 00012 #define IN_LIBXSLT 00013 #include "libxslt.h" 00014 00015 #include <string.h> 00016 00017 #include <libxml/xmlmemory.h> 00018 #include <libxml/tree.h> 00019 #include <libxml/valid.h> 00020 #include <libxml/hash.h> 00021 #include <libxml/xmlerror.h> 00022 #include <libxml/xpath.h> 00023 #include <libxml/xpathInternals.h> 00024 #include <libxml/parserInternals.h> 00025 #include <libxml/dict.h> 00026 #include "xslt.h" 00027 #include "xsltInternals.h" 00028 #include "xsltutils.h" 00029 #include "variables.h" 00030 #include "transform.h" 00031 #include "imports.h" 00032 #include "preproc.h" 00033 #include "keys.h" 00034 00035 #ifdef WITH_XSLT_DEBUG 00036 #define WITH_XSLT_DEBUG_VARIABLE 00037 #endif 00038 00039 #ifdef XSLT_REFACTORED 00040 const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; 00041 #endif 00042 00043 const xmlChar *xsltComputingGlobalVarMarker = 00044 (const xmlChar *) " var/param being computed"; 00045 00046 #define XSLT_VAR_GLOBAL 1<<0 00047 #define XSLT_VAR_IN_SELECT 1<<1 00048 #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) 00049 00050 /************************************************************************ 00051 * * 00052 * Result Value Tree (Result Tree Fragment) interfaces * 00053 * * 00054 ************************************************************************/ 00064 xmlDocPtr 00065 xsltCreateRVT(xsltTransformContextPtr ctxt) 00066 { 00067 xmlDocPtr container; 00068 00069 /* 00070 * Question: Why is this function public? 00071 * Answer: It is called by the EXSLT module. 00072 */ 00073 if (ctxt == NULL) 00074 return(NULL); 00075 00076 /* 00077 * Reuse a RTF from the cache if available. 00078 */ 00079 if (ctxt->cache->RVT) { 00080 container = ctxt->cache->RVT; 00081 ctxt->cache->RVT = (xmlDocPtr) container->next; 00082 /* clear the internal pointers */ 00083 container->next = NULL; 00084 container->prev = NULL; 00085 if (ctxt->cache->nbRVT > 0) 00086 ctxt->cache->nbRVT--; 00087 #ifdef XSLT_DEBUG_PROFILE_CACHE 00088 ctxt->cache->dbgReusedRVTs++; 00089 #endif 00090 return(container); 00091 } 00092 00093 container = xmlNewDoc(NULL); 00094 if (container == NULL) 00095 return(NULL); 00096 container->dict = ctxt->dict; 00097 xmlDictReference(container->dict); 00098 XSLT_MARK_RES_TREE_FRAG(container); 00099 container->doc = container; 00100 container->parent = NULL; 00101 return(container); 00102 } 00103 00119 int 00120 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 00121 { 00122 if ((ctxt == NULL) || (RVT == NULL)) 00123 return(-1); 00124 00125 /* 00126 * We'll restrict the lifetime of user-created fragments 00127 * insinde an xsl:variable and xsl:param to the lifetime of the 00128 * var/param itself. 00129 */ 00130 if (ctxt->contextVariable != NULL) { 00131 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; 00132 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; 00133 return(0); 00134 } 00135 00136 RVT->next = (xmlNodePtr) ctxt->tmpRVT; 00137 if (ctxt->tmpRVT != NULL) 00138 ctxt->tmpRVT->prev = (xmlNodePtr) RVT; 00139 ctxt->tmpRVT = RVT; 00140 return(0); 00141 } 00142 00155 int 00156 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, 00157 xmlDocPtr RVT) 00158 { 00159 if ((ctxt == NULL) || (RVT == NULL)) 00160 return(-1); 00161 00162 /* 00163 * When evaluating "select" expressions of xsl:variable 00164 * and xsl:param, we need to bind newly created tree fragments 00165 * to the variable itself; otherwise the tragment will be 00166 * freed before we leave the scope of a var. 00167 */ 00168 if ((ctxt->contextVariable != NULL) && 00169 (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) 00170 { 00171 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; 00172 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; 00173 return(0); 00174 } 00175 /* 00176 * Store the fragment in the scope of the current instruction. 00177 * If not reference by a returning instruction (like EXSLT's function), 00178 * then this fragment will be freed, when the instruction exits. 00179 */ 00180 RVT->next = (xmlNodePtr) ctxt->localRVT; 00181 if (ctxt->localRVT != NULL) 00182 ctxt->localRVT->prev = (xmlNodePtr) RVT; 00183 ctxt->localRVT = RVT; 00184 /* 00185 * We need to keep track of the first registered fragment 00186 * for extension instructions which return fragments 00187 * (e.g. EXSLT'S function), in order to let 00188 * xsltExtensionInstructionResultFinalize() clear the 00189 * preserving flag on the fragments. 00190 */ 00191 if (ctxt->localRVTBase == NULL) 00192 ctxt->localRVTBase = RVT; 00193 return(0); 00194 } 00195 00208 int 00209 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt) 00210 { 00211 xmlDocPtr cur; 00212 00213 if (ctxt == NULL) 00214 return(-1); 00215 if (ctxt->localRVTBase == NULL) 00216 return(0); 00217 /* 00218 * Enable remaining local tree fragments to be freed 00219 * by the fragment garbage collector. 00220 */ 00221 cur = ctxt->localRVTBase; 00222 do { 00223 cur->psvi = NULL; 00224 cur = (xmlDocPtr) cur->next; 00225 } while (cur != NULL); 00226 return(0); 00227 } 00228 00242 int 00243 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt, 00244 xmlXPathObjectPtr obj) 00245 { 00246 int i; 00247 xmlNodePtr cur; 00248 xmlDocPtr doc; 00249 00250 if ((ctxt == NULL) || (obj == NULL)) 00251 return(-1); 00252 00253 /* 00254 * OPTIMIZE TODO: If no local variables/params and no local tree 00255 * fragments were created, then we don't need to analyse the XPath 00256 * objects for tree fragments. 00257 */ 00258 00259 if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE)) 00260 return(0); 00261 if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) 00262 return(0); 00263 00264 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 00265 cur = obj->nodesetval->nodeTab[i]; 00266 if (cur->type == XML_NAMESPACE_DECL) { 00267 /* 00268 * The XPath module sets the owner element of a ns-node on 00269 * the ns->next field. 00270 */ 00271 if ((((xmlNsPtr) cur)->next != NULL) && 00272 (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE)) 00273 { 00274 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; 00275 doc = cur->doc; 00276 } else { 00277 xsltTransformError(ctxt, NULL, ctxt->inst, 00278 "Internal error in " 00279 "xsltExtensionInstructionResultRegister(): " 00280 "Cannot retrieve the doc of a namespace node.\n"); 00281 goto error; 00282 } 00283 } else { 00284 doc = cur->doc; 00285 } 00286 if (doc == NULL) { 00287 xsltTransformError(ctxt, NULL, ctxt->inst, 00288 "Internal error in " 00289 "xsltExtensionInstructionResultRegister(): " 00290 "Cannot retrieve the doc of a node.\n"); 00291 goto error; 00292 } 00293 if (doc->name && (doc->name[0] == ' ')) { 00294 /* 00295 * This is a result tree fragment. 00296 * We'll use the @psvi field for reference counting. 00297 * TODO: How do we know if this is a value of a 00298 * global variable or a doc acquired via the 00299 * document() function? 00300 */ 00301 doc->psvi = (void *) ((long) 1); 00302 } 00303 } 00304 00305 return(0); 00306 error: 00307 return(-1); 00308 } 00309 00318 void 00319 xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 00320 { 00321 if (RVT == NULL) 00322 return; 00323 00324 if (ctxt && (ctxt->cache->nbRVT < 40)) { 00325 /* 00326 * Store the Result Tree Fragment. 00327 * Free the document info. 00328 */ 00329 if (RVT->_private != NULL) { 00330 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); 00331 xmlFree(RVT->_private); 00332 RVT->_private = NULL; 00333 } 00334 /* 00335 * Clear the document tree. 00336 * REVISIT TODO: Do we expect ID/IDREF tables to be existent? 00337 */ 00338 if (RVT->children != NULL) { 00339 xmlFreeNodeList(RVT->children); 00340 RVT->children = NULL; 00341 RVT->last = NULL; 00342 } 00343 if (RVT->ids != NULL) { 00344 xmlFreeIDTable((xmlIDTablePtr) RVT->ids); 00345 RVT->ids = NULL; 00346 } 00347 if (RVT->refs != NULL) { 00348 xmlFreeRefTable((xmlRefTablePtr) RVT->refs); 00349 RVT->refs = NULL; 00350 } 00351 00352 /* 00353 * Reset the reference counter. 00354 */ 00355 RVT->psvi = 0; 00356 00357 RVT->next = (xmlNodePtr) ctxt->cache->RVT; 00358 ctxt->cache->RVT = RVT; 00359 00360 ctxt->cache->nbRVT++; 00361 00362 #ifdef XSLT_DEBUG_PROFILE_CACHE 00363 ctxt->cache->dbgCachedRVTs++; 00364 #endif 00365 return; 00366 } 00367 /* 00368 * Free it. 00369 */ 00370 if (RVT->_private != NULL) { 00371 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); 00372 xmlFree(RVT->_private); 00373 } 00374 xmlFreeDoc(RVT); 00375 } 00376 00389 int 00390 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) 00391 { 00392 if ((ctxt == NULL) || (RVT == NULL)) return(-1); 00393 00394 RVT->next = (xmlNodePtr) ctxt->persistRVT; 00395 if (ctxt->persistRVT != NULL) 00396 ctxt->persistRVT->prev = (xmlNodePtr) RVT; 00397 ctxt->persistRVT = RVT; 00398 return(0); 00399 } 00400 00409 void 00410 xsltFreeRVTs(xsltTransformContextPtr ctxt) 00411 { 00412 xmlDocPtr cur, next; 00413 00414 if (ctxt == NULL) 00415 return; 00416 /* 00417 * Local fragments. 00418 */ 00419 cur = ctxt->localRVT; 00420 while (cur != NULL) { 00421 next = (xmlDocPtr) cur->next; 00422 if (cur->_private != NULL) { 00423 xsltFreeDocumentKeys(cur->_private); 00424 xmlFree(cur->_private); 00425 } 00426 xmlFreeDoc(cur); 00427 cur = next; 00428 } 00429 ctxt->localRVT = NULL; 00430 /* 00431 * User-created per-template fragments. 00432 */ 00433 cur = ctxt->tmpRVT; 00434 while (cur != NULL) { 00435 next = (xmlDocPtr) cur->next; 00436 if (cur->_private != NULL) { 00437 xsltFreeDocumentKeys(cur->_private); 00438 xmlFree(cur->_private); 00439 } 00440 xmlFreeDoc(cur); 00441 cur = next; 00442 } 00443 ctxt->tmpRVT = NULL; 00444 /* 00445 * Global fragments. 00446 */ 00447 cur = ctxt->persistRVT; 00448 while (cur != NULL) { 00449 next = (xmlDocPtr) cur->next; 00450 if (cur->_private != NULL) { 00451 xsltFreeDocumentKeys(cur->_private); 00452 xmlFree(cur->_private); 00453 } 00454 xmlFreeDoc(cur); 00455 cur = next; 00456 } 00457 ctxt->persistRVT = NULL; 00458 } 00459 00460 /************************************************************************ 00461 * * 00462 * Module interfaces * 00463 * * 00464 ************************************************************************/ 00465 00473 static xsltStackElemPtr 00474 xsltNewStackElem(xsltTransformContextPtr ctxt) 00475 { 00476 xsltStackElemPtr ret; 00477 /* 00478 * Reuse a stack item from the cache if available. 00479 */ 00480 if (ctxt && ctxt->cache->stackItems) { 00481 ret = ctxt->cache->stackItems; 00482 ctxt->cache->stackItems = ret->next; 00483 ret->next = NULL; 00484 ctxt->cache->nbStackItems--; 00485 #ifdef XSLT_DEBUG_PROFILE_CACHE 00486 ctxt->cache->dbgReusedVars++; 00487 #endif 00488 return(ret); 00489 } 00490 ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); 00491 if (ret == NULL) { 00492 xsltTransformError(NULL, NULL, NULL, 00493 "xsltNewStackElem : malloc failed\n"); 00494 return(NULL); 00495 } 00496 memset(ret, 0, sizeof(xsltStackElem)); 00497 ret->context = ctxt; 00498 return(ret); 00499 } 00500 00509 static xsltStackElemPtr 00510 xsltCopyStackElem(xsltStackElemPtr elem) { 00511 xsltStackElemPtr cur; 00512 00513 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); 00514 if (cur == NULL) { 00515 xsltTransformError(NULL, NULL, NULL, 00516 "xsltCopyStackElem : malloc failed\n"); 00517 return(NULL); 00518 } 00519 memset(cur, 0, sizeof(xsltStackElem)); 00520 cur->context = elem->context; 00521 cur->name = elem->name; 00522 cur->nameURI = elem->nameURI; 00523 cur->select = elem->select; 00524 cur->tree = elem->tree; 00525 cur->comp = elem->comp; 00526 return(cur); 00527 } 00528 00535 static void 00536 xsltFreeStackElem(xsltStackElemPtr elem) { 00537 if (elem == NULL) 00538 return; 00539 if (elem->value != NULL) 00540 xmlXPathFreeObject(elem->value); 00541 /* 00542 * Release the list of temporary Result Tree Fragments. 00543 */ 00544 if (elem->fragment) { 00545 xmlDocPtr cur; 00546 00547 while (elem->fragment != NULL) { 00548 cur = elem->fragment; 00549 elem->fragment = (xmlDocPtr) cur->next; 00550 00551 if (elem->context && 00552 (cur->psvi == (void *) ((long) 1))) 00553 { 00554 /* 00555 * This fragment is a result of an extension instruction 00556 * (e.g. XSLT's function) and needs to be preserved until 00557 * the instruction exits. 00558 * Example: The fragment of the variable must not be freed 00559 * since it is returned by the EXSLT function: 00560 * <f:function name="foo"> 00561 * <xsl:variable name="bar"> 00562 * <bar/> 00563 * </xsl:variable> 00564 * <f:result select="$bar"/> 00565 * </f:function> 00566 * 00567 */ 00568 xsltRegisterLocalRVT(elem->context, cur); 00569 } else { 00570 xsltReleaseRVT((xsltTransformContextPtr) elem->context, 00571 cur); 00572 } 00573 } 00574 } 00575 /* 00576 * Cache or free the variable structure. 00577 */ 00578 if (elem->context && (elem->context->cache->nbStackItems < 50)) { 00579 /* 00580 * Store the item in the cache. 00581 */ 00582 xsltTransformContextPtr ctxt = elem->context; 00583 memset(elem, 0, sizeof(xsltStackElem)); 00584 elem->context = ctxt; 00585 elem->next = ctxt->cache->stackItems; 00586 ctxt->cache->stackItems = elem; 00587 ctxt->cache->nbStackItems++; 00588 #ifdef XSLT_DEBUG_PROFILE_CACHE 00589 ctxt->cache->dbgCachedVars++; 00590 #endif 00591 return; 00592 } 00593 xmlFree(elem); 00594 } 00595 00602 void 00603 xsltFreeStackElemList(xsltStackElemPtr elem) { 00604 xsltStackElemPtr next; 00605 00606 while (elem != NULL) { 00607 next = elem->next; 00608 xsltFreeStackElem(elem); 00609 elem = next; 00610 } 00611 } 00612 00621 #if 0 /* TODO: Those seem to have been used for debugging. */ 00622 static int stack_addr = 0; 00623 static int stack_cmp = 0; 00624 #endif 00625 00626 static xsltStackElemPtr 00627 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 00628 const xmlChar *nameURI) { 00629 int i; 00630 xsltStackElemPtr cur; 00631 00632 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0)) 00633 return(NULL); 00634 00635 /* 00636 * Do the lookup from the top of the stack, but 00637 * don't use params being computed in a call-param 00638 * First lookup expects the variable name and URI to 00639 * come from the disctionnary and hence pointer comparison. 00640 */ 00641 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { 00642 cur = ctxt->varsTab[i-1]; 00643 while (cur != NULL) { 00644 if ((cur->name == name) && (cur->nameURI == nameURI)) { 00645 #if 0 00646 stack_addr++; 00647 #endif 00648 return(cur); 00649 } 00650 cur = cur->next; 00651 } 00652 } 00653 00654 /* 00655 * Redo the lookup with interned string compares 00656 * to avoid string compares. 00657 */ 00658 name = xmlDictLookup(ctxt->dict, name, -1); 00659 if (nameURI != NULL) 00660 nameURI = xmlDictLookup(ctxt->dict, nameURI, -1); 00661 00662 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { 00663 cur = ctxt->varsTab[i-1]; 00664 while (cur != NULL) { 00665 if ((cur->name == name) && (cur->nameURI == nameURI)) { 00666 #if 0 00667 stack_cmp++; 00668 #endif 00669 return(cur); 00670 } 00671 cur = cur->next; 00672 } 00673 } 00674 00675 return(NULL); 00676 } 00677 00692 static int 00693 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name, 00694 const xmlChar *nameURI) { 00695 xsltStackElemPtr cur; 00696 00697 if ((ctxt == NULL) || (name == NULL)) 00698 return(-1); 00699 00700 cur = xsltStackLookup(ctxt, name, nameURI); 00701 if (cur == NULL) 00702 return(0); 00703 if (cur->comp != NULL) { 00704 if (cur->comp->type == XSLT_FUNC_WITHPARAM) 00705 return(3); 00706 else if (cur->comp->type == XSLT_FUNC_PARAM) 00707 return(2); 00708 } 00709 00710 return(1); 00711 } 00712 00725 static int 00726 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) 00727 { 00728 if ((ctxt == NULL) || (elem == NULL)) 00729 return(-1); 00730 00731 do { 00732 if (ctxt->varsMax == 0) { 00733 ctxt->varsMax = 10; 00734 ctxt->varsTab = 00735 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * 00736 sizeof(ctxt->varsTab[0])); 00737 if (ctxt->varsTab == NULL) { 00738 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 00739 return (-1); 00740 } 00741 } 00742 if (ctxt->varsNr >= ctxt->varsMax) { 00743 ctxt->varsMax *= 2; 00744 ctxt->varsTab = 00745 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, 00746 ctxt->varsMax * 00747 sizeof(ctxt->varsTab[0])); 00748 if (ctxt->varsTab == NULL) { 00749 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 00750 return (-1); 00751 } 00752 } 00753 ctxt->varsTab[ctxt->varsNr++] = elem; 00754 ctxt->vars = elem; 00755 00756 elem = elem->next; 00757 } while (elem != NULL); 00758 00759 return(0); 00760 } 00761 00771 int 00772 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) 00773 { 00774 return(xsltAddStackElem(ctxt, elems)); 00775 } 00776 00777 /************************************************************************ 00778 * * 00779 * Module interfaces * 00780 * * 00781 ************************************************************************/ 00782 00793 static xmlXPathObjectPtr 00794 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, 00795 xsltStylePreCompPtr castedComp) 00796 { 00797 #ifdef XSLT_REFACTORED 00798 xsltStyleItemVariablePtr comp = 00799 (xsltStyleItemVariablePtr) castedComp; 00800 #else 00801 xsltStylePreCompPtr comp = castedComp; 00802 #endif 00803 xmlXPathObjectPtr result = NULL; 00804 xmlNodePtr oldInst; 00805 00806 if ((ctxt == NULL) || (variable == NULL)) 00807 return(NULL); 00808 00809 /* 00810 * A variable or parameter are evaluated on demand; thus the 00811 * context (of XSLT and XPath) need to be temporarily adjusted and 00812 * restored on exit. 00813 */ 00814 oldInst = ctxt->inst; 00815 00816 #ifdef WITH_XSLT_DEBUG_VARIABLE 00817 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 00818 "Evaluating variable '%s'\n", variable->name)); 00819 #endif 00820 if (variable->select != NULL) { 00821 xmlXPathCompExprPtr xpExpr = NULL; 00822 xmlDocPtr oldXPDoc; 00823 xmlNodePtr oldXPContextNode; 00824 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 00825 xmlNsPtr *oldXPNamespaces; 00826 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 00827 xsltStackElemPtr oldVar = ctxt->contextVariable; 00828 00829 if ((comp != NULL) && (comp->comp != NULL)) { 00830 xpExpr = comp->comp; 00831 } else { 00832 xpExpr = xmlXPathCompile(variable->select); 00833 } 00834 if (xpExpr == NULL) 00835 return(NULL); 00836 /* 00837 * Save context states. 00838 */ 00839 oldXPDoc = xpctxt->doc; 00840 oldXPContextNode = xpctxt->node; 00841 oldXPProximityPosition = xpctxt->proximityPosition; 00842 oldXPContextSize = xpctxt->contextSize; 00843 oldXPNamespaces = xpctxt->namespaces; 00844 oldXPNsNr = xpctxt->nsNr; 00845 00846 xpctxt->node = ctxt->node; 00847 /* 00848 * OPTIMIZE TODO: Lame try to set the context doc. 00849 * Get rid of this somehow in xpath.c. 00850 */ 00851 if ((ctxt->node->type != XML_NAMESPACE_DECL) && 00852 ctxt->node->doc) 00853 xpctxt->doc = ctxt->node->doc; 00854 /* 00855 * BUG TODO: The proximity position and the context size will 00856 * potentially be wrong. 00857 * Example: 00858 * <xsl:template select="foo"> 00859 * <xsl:variable name="pos" select="position()"/> 00860 * <xsl:for-each select="bar"> 00861 * <xsl:value-of select="$pos"/> 00862 * </xsl:for-each> 00863 * </xsl:template> 00864 * Here the proximity position and context size are changed 00865 * to the context of <xsl:for-each select="bar">, but 00866 * the variable needs to be evaluated in the context of 00867 * <xsl:template select="foo">. 00868 */ 00869 if (comp != NULL) { 00870 00871 #ifdef XSLT_REFACTORED 00872 if (comp->inScopeNs != NULL) { 00873 xpctxt->namespaces = comp->inScopeNs->list; 00874 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 00875 } else { 00876 xpctxt->namespaces = NULL; 00877 xpctxt->nsNr = 0; 00878 } 00879 #else 00880 xpctxt->namespaces = comp->nsList; 00881 xpctxt->nsNr = comp->nsNr; 00882 #endif 00883 } else { 00884 xpctxt->namespaces = NULL; 00885 xpctxt->nsNr = 0; 00886 } 00887 00888 /* 00889 * We need to mark that we are "selecting" a var's value; 00890 * if any tree fragments are created inside the expression, 00891 * then those need to be stored inside the variable; otherwise 00892 * we'll eventually free still referenced fragments, before 00893 * we leave the scope of the variable. 00894 */ 00895 ctxt->contextVariable = variable; 00896 variable->flags |= XSLT_VAR_IN_SELECT; 00897 00898 result = xmlXPathCompiledEval(xpExpr, xpctxt); 00899 00900 variable->flags ^= XSLT_VAR_IN_SELECT; 00901 /* 00902 * Restore Context states. 00903 */ 00904 ctxt->contextVariable = oldVar; 00905 00906 xpctxt->doc = oldXPDoc; 00907 xpctxt->node = oldXPContextNode; 00908 xpctxt->contextSize = oldXPContextSize; 00909 xpctxt->proximityPosition = oldXPProximityPosition; 00910 xpctxt->namespaces = oldXPNamespaces; 00911 xpctxt->nsNr = oldXPNsNr; 00912 00913 if ((comp == NULL) || (comp->comp == NULL)) 00914 xmlXPathFreeCompExpr(xpExpr); 00915 if (result == NULL) { 00916 xsltTransformError(ctxt, NULL, 00917 (comp != NULL) ? comp->inst : NULL, 00918 "Failed to evaluate the expression of variable '%s'.\n", 00919 variable->name); 00920 ctxt->state = XSLT_STATE_STOPPED; 00921 00922 #ifdef WITH_XSLT_DEBUG_VARIABLE 00923 #ifdef LIBXML_DEBUG_ENABLED 00924 } else { 00925 if ((xsltGenericDebugContext == stdout) || 00926 (xsltGenericDebugContext == stderr)) 00927 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 00928 result, 0); 00929 #endif 00930 #endif 00931 } 00932 } else { 00933 if (variable->tree == NULL) { 00934 result = xmlXPathNewCString(""); 00935 } else { 00936 if (variable->tree) { 00937 xmlDocPtr container; 00938 xmlNodePtr oldInsert; 00939 xmlDocPtr oldOutput; 00940 xsltStackElemPtr oldVar = ctxt->contextVariable; 00941 00942 /* 00943 * Generate a result tree fragment. 00944 */ 00945 container = xsltCreateRVT(ctxt); 00946 if (container == NULL) 00947 goto error; 00948 /* 00949 * NOTE: Local Result Tree Fragments of params/variables 00950 * are not registered globally anymore; the life-time 00951 * is not directly dependant of the param/variable itself. 00952 * 00953 * OLD: xsltRegisterTmpRVT(ctxt, container); 00954 */ 00955 /* 00956 * Attach the Result Tree Fragment to the variable; 00957 * when the variable is freed, it will also free 00958 * the Result Tree Fragment. 00959 */ 00960 variable->fragment = container; 00961 00962 oldOutput = ctxt->output; 00963 oldInsert = ctxt->insert; 00964 00965 ctxt->output = container; 00966 ctxt->insert = (xmlNodePtr) container; 00967 ctxt->contextVariable = variable; 00968 /* 00969 * Process the sequence constructor (variable->tree). 00970 * The resulting tree will be held by @container. 00971 */ 00972 xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree, 00973 NULL, NULL); 00974 00975 ctxt->contextVariable = oldVar; 00976 ctxt->insert = oldInsert; 00977 ctxt->output = oldOutput; 00978 00979 result = xmlXPathNewValueTree((xmlNodePtr) container); 00980 } 00981 if (result == NULL) { 00982 result = xmlXPathNewCString(""); 00983 } else { 00984 /* 00985 * Freeing is not handled there anymore. 00986 * QUESTION TODO: What does the above comment mean? 00987 */ 00988 result->boolval = 0; 00989 } 00990 #ifdef WITH_XSLT_DEBUG_VARIABLE 00991 #ifdef LIBXML_DEBUG_ENABLED 00992 00993 if ((xsltGenericDebugContext == stdout) || 00994 (xsltGenericDebugContext == stderr)) 00995 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 00996 result, 0); 00997 #endif 00998 #endif 00999 } 01000 } 01001 01002 error: 01003 ctxt->inst = oldInst; 01004 return(result); 01005 } 01006 01017 static xmlXPathObjectPtr 01018 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) 01019 { 01020 xmlXPathObjectPtr result = NULL; 01021 xmlNodePtr oldInst; 01022 const xmlChar* oldVarName; 01023 01024 #ifdef XSLT_REFACTORED 01025 xsltStyleBasicItemVariablePtr comp; 01026 #else 01027 xsltStylePreCompPtr comp; 01028 #endif 01029 01030 if ((ctxt == NULL) || (elem == NULL)) 01031 return(NULL); 01032 if (elem->computed) 01033 return(elem->value); 01034 01035 01036 #ifdef WITH_XSLT_DEBUG_VARIABLE 01037 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01038 "Evaluating global variable %s\n", elem->name)); 01039 #endif 01040 01041 #ifdef WITH_DEBUGGER 01042 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && 01043 elem->comp && elem->comp->inst) 01044 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt); 01045 #endif 01046 01047 oldInst = ctxt->inst; 01048 comp = elem->comp; 01049 oldVarName = elem->name; 01050 elem->name = xsltComputingGlobalVarMarker; 01051 /* 01052 * OPTIMIZE TODO: We should consider instantiating global vars/params 01053 * on-demand. The vars/params don't need to be evaluated if never 01054 * called; and in the case of global params, if values for such params 01055 * are provided by the user. 01056 */ 01057 if (elem->select != NULL) { 01058 xmlXPathCompExprPtr xpExpr = NULL; 01059 xmlDocPtr oldXPDoc; 01060 xmlNodePtr oldXPContextNode; 01061 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 01062 xmlNsPtr *oldXPNamespaces; 01063 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 01064 01065 if ((comp != NULL) && (comp->comp != NULL)) { 01066 xpExpr = comp->comp; 01067 } else { 01068 xpExpr = xmlXPathCompile(elem->select); 01069 } 01070 if (xpExpr == NULL) 01071 goto error; 01072 01073 01074 if (comp != NULL) 01075 ctxt->inst = comp->inst; 01076 else 01077 ctxt->inst = NULL; 01078 /* 01079 * SPEC XSLT 1.0: 01080 * "At top-level, the expression or template specifying the 01081 * variable value is evaluated with the same context as that used 01082 * to process the root node of the source document: the current 01083 * node is the root node of the source document and the current 01084 * node list is a list containing just the root node of the source 01085 * document." 01086 */ 01087 /* 01088 * Save context states. 01089 */ 01090 oldXPDoc = xpctxt->doc; 01091 oldXPContextNode = xpctxt->node; 01092 oldXPProximityPosition = xpctxt->proximityPosition; 01093 oldXPContextSize = xpctxt->contextSize; 01094 oldXPNamespaces = xpctxt->namespaces; 01095 oldXPNsNr = xpctxt->nsNr; 01096 01097 xpctxt->node = ctxt->initialContextNode; 01098 xpctxt->doc = ctxt->initialContextDoc; 01099 xpctxt->contextSize = 1; 01100 xpctxt->proximityPosition = 1; 01101 01102 if (comp != NULL) { 01103 01104 #ifdef XSLT_REFACTORED 01105 if (comp->inScopeNs != NULL) { 01106 xpctxt->namespaces = comp->inScopeNs->list; 01107 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 01108 } else { 01109 xpctxt->namespaces = NULL; 01110 xpctxt->nsNr = 0; 01111 } 01112 #else 01113 xpctxt->namespaces = comp->nsList; 01114 xpctxt->nsNr = comp->nsNr; 01115 #endif 01116 } else { 01117 xpctxt->namespaces = NULL; 01118 xpctxt->nsNr = 0; 01119 } 01120 01121 result = xmlXPathCompiledEval(xpExpr, xpctxt); 01122 01123 /* 01124 * Restore Context states. 01125 */ 01126 xpctxt->doc = oldXPDoc; 01127 xpctxt->node = oldXPContextNode; 01128 xpctxt->contextSize = oldXPContextSize; 01129 xpctxt->proximityPosition = oldXPProximityPosition; 01130 xpctxt->namespaces = oldXPNamespaces; 01131 xpctxt->nsNr = oldXPNsNr; 01132 01133 if ((comp == NULL) || (comp->comp == NULL)) 01134 xmlXPathFreeCompExpr(xpExpr); 01135 if (result == NULL) { 01136 if (comp == NULL) 01137 xsltTransformError(ctxt, NULL, NULL, 01138 "Evaluating global variable %s failed\n", elem->name); 01139 else 01140 xsltTransformError(ctxt, NULL, comp->inst, 01141 "Evaluating global variable %s failed\n", elem->name); 01142 ctxt->state = XSLT_STATE_STOPPED; 01143 #ifdef WITH_XSLT_DEBUG_VARIABLE 01144 #ifdef LIBXML_DEBUG_ENABLED 01145 } else { 01146 if ((xsltGenericDebugContext == stdout) || 01147 (xsltGenericDebugContext == stderr)) 01148 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 01149 result, 0); 01150 #endif 01151 #endif 01152 } 01153 } else { 01154 if (elem->tree == NULL) { 01155 result = xmlXPathNewCString(""); 01156 } else { 01157 xmlDocPtr container; 01158 xmlNodePtr oldInsert; 01159 xmlDocPtr oldOutput, oldXPDoc; 01160 /* 01161 * Generate a result tree fragment. 01162 */ 01163 container = xsltCreateRVT(ctxt); 01164 if (container == NULL) 01165 goto error; 01166 /* 01167 * Let the lifetime of the tree fragment be handled by 01168 * the Libxslt's garbage collector. 01169 */ 01170 xsltRegisterPersistRVT(ctxt, container); 01171 01172 oldOutput = ctxt->output; 01173 oldInsert = ctxt->insert; 01174 01175 oldXPDoc = ctxt->xpathCtxt->doc; 01176 01177 ctxt->output = container; 01178 ctxt->insert = (xmlNodePtr) container; 01179 01180 ctxt->xpathCtxt->doc = ctxt->initialContextDoc; 01181 /* 01182 * Process the sequence constructor. 01183 */ 01184 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL); 01185 01186 ctxt->xpathCtxt->doc = oldXPDoc; 01187 01188 ctxt->insert = oldInsert; 01189 ctxt->output = oldOutput; 01190 01191 result = xmlXPathNewValueTree((xmlNodePtr) container); 01192 if (result == NULL) { 01193 result = xmlXPathNewCString(""); 01194 } else { 01195 result->boolval = 0; /* Freeing is not handled there anymore */ 01196 } 01197 #ifdef WITH_XSLT_DEBUG_VARIABLE 01198 #ifdef LIBXML_DEBUG_ENABLED 01199 if ((xsltGenericDebugContext == stdout) || 01200 (xsltGenericDebugContext == stderr)) 01201 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 01202 result, 0); 01203 #endif 01204 #endif 01205 } 01206 } 01207 01208 error: 01209 elem->name = oldVarName; 01210 ctxt->inst = oldInst; 01211 if (result != NULL) { 01212 elem->value = result; 01213 elem->computed = 1; 01214 } 01215 return(result); 01216 } 01217 01227 int 01228 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) { 01229 xsltStackElemPtr elem; 01230 xsltStylesheetPtr style; 01231 01232 if ((ctxt == NULL) || (ctxt->document == NULL)) 01233 return(-1); 01234 01235 #ifdef WITH_XSLT_DEBUG_VARIABLE 01236 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01237 "Registering global variables\n")); 01238 #endif 01239 /* 01240 * Walk the list from the stylesheets and populate the hash table 01241 */ 01242 style = ctxt->style; 01243 while (style != NULL) { 01244 elem = style->variables; 01245 01246 #ifdef WITH_XSLT_DEBUG_VARIABLE 01247 if ((style->doc != NULL) && (style->doc->URL != NULL)) { 01248 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01249 "Registering global variables from %s\n", 01250 style->doc->URL)); 01251 } 01252 #endif 01253 01254 while (elem != NULL) { 01255 xsltStackElemPtr def; 01256 01257 /* 01258 * Global variables are stored in the variables pool. 01259 */ 01260 def = (xsltStackElemPtr) 01261 xmlHashLookup2(ctxt->globalVars, 01262 elem->name, elem->nameURI); 01263 if (def == NULL) { 01264 01265 def = xsltCopyStackElem(elem); 01266 xmlHashAddEntry2(ctxt->globalVars, 01267 elem->name, elem->nameURI, def); 01268 } else if ((elem->comp != NULL) && 01269 (elem->comp->type == XSLT_FUNC_VARIABLE)) { 01270 /* 01271 * Redefinition of variables from a different stylesheet 01272 * should not generate a message. 01273 */ 01274 if ((elem->comp->inst != NULL) && 01275 (def->comp != NULL) && (def->comp->inst != NULL) && 01276 (elem->comp->inst->doc == def->comp->inst->doc)) 01277 { 01278 xsltTransformError(ctxt, style, elem->comp->inst, 01279 "Global variable %s already defined\n", elem->name); 01280 if (style != NULL) style->errors++; 01281 } 01282 } 01283 elem = elem->next; 01284 } 01285 01286 style = xsltNextImport(style); 01287 } 01288 01289 /* 01290 * This part does the actual evaluation 01291 */ 01292 xmlHashScan(ctxt->globalVars, 01293 (xmlHashScanner) xsltEvalGlobalVariable, ctxt); 01294 01295 return(0); 01296 } 01297 01313 static int 01314 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, 01315 const xmlChar *ns_uri, const xmlChar *sel, 01316 xmlNodePtr tree, xsltStylePreCompPtr comp, 01317 const xmlChar *value) { 01318 xsltStackElemPtr elem, tmp; 01319 if (style == NULL) 01320 return(-1); 01321 if (name == NULL) 01322 return(-1); 01323 if (comp == NULL) 01324 return(-1); 01325 01326 #ifdef WITH_XSLT_DEBUG_VARIABLE 01327 if (comp->type == XSLT_FUNC_PARAM) 01328 xsltGenericDebug(xsltGenericDebugContext, 01329 "Defining global param %s\n", name); 01330 else 01331 xsltGenericDebug(xsltGenericDebugContext, 01332 "Defining global variable %s\n", name); 01333 #endif 01334 01335 elem = xsltNewStackElem(NULL); 01336 if (elem == NULL) 01337 return(-1); 01338 elem->comp = comp; 01339 elem->name = xmlDictLookup(style->dict, name, -1); 01340 elem->select = xmlDictLookup(style->dict, sel, -1); 01341 if (ns_uri) 01342 elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1); 01343 elem->tree = tree; 01344 tmp = style->variables; 01345 if (tmp == NULL) { 01346 elem->next = NULL; 01347 style->variables = elem; 01348 } else { 01349 while (tmp != NULL) { 01350 if ((elem->comp->type == XSLT_FUNC_VARIABLE) && 01351 (tmp->comp->type == XSLT_FUNC_VARIABLE) && 01352 (xmlStrEqual(elem->name, tmp->name)) && 01353 ((elem->nameURI == tmp->nameURI) || 01354 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) 01355 { 01356 xsltTransformError(NULL, style, comp->inst, 01357 "redefinition of global variable %s\n", elem->name); 01358 style->errors++; 01359 } 01360 if (tmp->next == NULL) 01361 break; 01362 tmp = tmp->next; 01363 } 01364 elem->next = NULL; 01365 tmp->next = elem; 01366 } 01367 if (value != NULL) { 01368 elem->computed = 1; 01369 elem->value = xmlXPathNewString(value); 01370 } 01371 return(0); 01372 } 01373 01405 static 01406 int 01407 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, 01408 const xmlChar * name, 01409 const xmlChar * value, 01410 int eval) { 01411 01412 xsltStylesheetPtr style; 01413 const xmlChar *prefix; 01414 const xmlChar *href; 01415 xmlXPathCompExprPtr xpExpr; 01416 xmlXPathObjectPtr result; 01417 01418 xsltStackElemPtr elem; 01419 int res; 01420 void *res_ptr; 01421 01422 if (ctxt == NULL) 01423 return(-1); 01424 if (name == NULL) 01425 return(0); 01426 if (value == NULL) 01427 return(0); 01428 01429 style = ctxt->style; 01430 01431 #ifdef WITH_XSLT_DEBUG_VARIABLE 01432 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01433 "Evaluating user parameter %s=%s\n", name, value)); 01434 #endif 01435 01436 /* 01437 * Name lookup 01438 */ 01439 01440 name = xsltSplitQName(ctxt->dict, name, &prefix); 01441 href = NULL; 01442 if (prefix != NULL) { 01443 xmlNsPtr ns; 01444 01445 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), 01446 prefix); 01447 if (ns == NULL) { 01448 xsltTransformError(ctxt, style, NULL, 01449 "user param : no namespace bound to prefix %s\n", prefix); 01450 href = NULL; 01451 } else { 01452 href = ns->href; 01453 } 01454 } 01455 01456 if (name == NULL) 01457 return (-1); 01458 01459 res_ptr = xmlHashLookup2(ctxt->globalVars, name, href); 01460 if (res_ptr != 0) { 01461 xsltTransformError(ctxt, style, NULL, 01462 "Global parameter %s already defined\n", name); 01463 } 01464 if (ctxt->globalVars == NULL) 01465 ctxt->globalVars = xmlHashCreate(20); 01466 01467 /* 01468 * do not overwrite variables with parameters from the command line 01469 */ 01470 while (style != NULL) { 01471 elem = ctxt->style->variables; 01472 while (elem != NULL) { 01473 if ((elem->comp != NULL) && 01474 (elem->comp->type == XSLT_FUNC_VARIABLE) && 01475 (xmlStrEqual(elem->name, name)) && 01476 (xmlStrEqual(elem->nameURI, href))) { 01477 return(0); 01478 } 01479 elem = elem->next; 01480 } 01481 style = xsltNextImport(style); 01482 } 01483 style = ctxt->style; 01484 elem = NULL; 01485 01486 /* 01487 * Do the evaluation if @eval is non-zero. 01488 */ 01489 01490 result = NULL; 01491 if (eval != 0) { 01492 xpExpr = xmlXPathCompile(value); 01493 if (xpExpr != NULL) { 01494 xmlDocPtr oldXPDoc; 01495 xmlNodePtr oldXPContextNode; 01496 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 01497 xmlNsPtr *oldXPNamespaces; 01498 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 01499 01500 /* 01501 * Save context states. 01502 */ 01503 oldXPDoc = xpctxt->doc; 01504 oldXPContextNode = xpctxt->node; 01505 oldXPProximityPosition = xpctxt->proximityPosition; 01506 oldXPContextSize = xpctxt->contextSize; 01507 oldXPNamespaces = xpctxt->namespaces; 01508 oldXPNsNr = xpctxt->nsNr; 01509 01510 /* 01511 * SPEC XSLT 1.0: 01512 * "At top-level, the expression or template specifying the 01513 * variable value is evaluated with the same context as that used 01514 * to process the root node of the source document: the current 01515 * node is the root node of the source document and the current 01516 * node list is a list containing just the root node of the source 01517 * document." 01518 */ 01519 xpctxt->doc = ctxt->initialContextDoc; 01520 xpctxt->node = ctxt->initialContextNode; 01521 xpctxt->contextSize = 1; 01522 xpctxt->proximityPosition = 1; 01523 /* 01524 * There is really no in scope namespace for parameters on the 01525 * command line. 01526 */ 01527 xpctxt->namespaces = NULL; 01528 xpctxt->nsNr = 0; 01529 01530 result = xmlXPathCompiledEval(xpExpr, xpctxt); 01531 01532 /* 01533 * Restore Context states. 01534 */ 01535 xpctxt->doc = oldXPDoc; 01536 xpctxt->node = oldXPContextNode; 01537 xpctxt->contextSize = oldXPContextSize; 01538 xpctxt->proximityPosition = oldXPProximityPosition; 01539 xpctxt->namespaces = oldXPNamespaces; 01540 xpctxt->nsNr = oldXPNsNr; 01541 01542 xmlXPathFreeCompExpr(xpExpr); 01543 } 01544 if (result == NULL) { 01545 xsltTransformError(ctxt, style, NULL, 01546 "Evaluating user parameter %s failed\n", name); 01547 ctxt->state = XSLT_STATE_STOPPED; 01548 return(-1); 01549 } 01550 } 01551 01552 /* 01553 * If @eval is 0 then @value is to be taken literally and result is NULL 01554 * 01555 * If @eval is not 0, then @value is an XPath expression and has been 01556 * successfully evaluated and result contains the resulting value and 01557 * is not NULL. 01558 * 01559 * Now create an xsltStackElemPtr for insertion into the context's 01560 * global variable/parameter hash table. 01561 */ 01562 01563 #ifdef WITH_XSLT_DEBUG_VARIABLE 01564 #ifdef LIBXML_DEBUG_ENABLED 01565 if ((xsltGenericDebugContext == stdout) || 01566 (xsltGenericDebugContext == stderr)) 01567 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, 01568 result, 0); 01569 #endif 01570 #endif 01571 01572 elem = xsltNewStackElem(NULL); 01573 if (elem != NULL) { 01574 elem->name = name; 01575 elem->select = xmlDictLookup(ctxt->dict, value, -1); 01576 if (href != NULL) 01577 elem->nameURI = xmlDictLookup(ctxt->dict, href, -1); 01578 elem->tree = NULL; 01579 elem->computed = 1; 01580 if (eval == 0) { 01581 elem->value = xmlXPathNewString(value); 01582 } 01583 else { 01584 elem->value = result; 01585 } 01586 } 01587 01588 /* 01589 * Global parameters are stored in the XPath context variables pool. 01590 */ 01591 01592 res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem); 01593 if (res != 0) { 01594 xsltFreeStackElem(elem); 01595 xsltTransformError(ctxt, style, NULL, 01596 "Global parameter %s already defined\n", name); 01597 } 01598 return(0); 01599 } 01600 01616 int 01617 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) { 01618 int indx = 0; 01619 const xmlChar *name; 01620 const xmlChar *value; 01621 01622 if (params == NULL) 01623 return(0); 01624 while (params[indx] != NULL) { 01625 name = (const xmlChar *) params[indx++]; 01626 value = (const xmlChar *) params[indx++]; 01627 if (xsltEvalOneUserParam(ctxt, name, value) != 0) 01628 return(-1); 01629 } 01630 return 0; 01631 } 01632 01646 int 01647 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) { 01648 int indx = 0; 01649 const xmlChar *name; 01650 const xmlChar *value; 01651 01652 if (params == NULL) 01653 return(0); 01654 while (params[indx] != NULL) { 01655 name = (const xmlChar *) params[indx++]; 01656 value = (const xmlChar *) params[indx++]; 01657 if (xsltQuoteOneUserParam(ctxt, name, value) != 0) 01658 return(-1); 01659 } 01660 return 0; 01661 } 01662 01681 int 01682 xsltEvalOneUserParam(xsltTransformContextPtr ctxt, 01683 const xmlChar * name, 01684 const xmlChar * value) { 01685 return xsltProcessUserParamInternal(ctxt, name, value, 01686 1 /* xpath eval ? */); 01687 } 01688 01702 int 01703 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt, 01704 const xmlChar * name, 01705 const xmlChar * value) { 01706 return xsltProcessUserParamInternal(ctxt, name, value, 01707 0 /* xpath eval ? */); 01708 } 01709 01720 static xsltStackElemPtr 01721 xsltBuildVariable(xsltTransformContextPtr ctxt, 01722 xsltStylePreCompPtr castedComp, 01723 xmlNodePtr tree) 01724 { 01725 #ifdef XSLT_REFACTORED 01726 xsltStyleBasicItemVariablePtr comp = 01727 (xsltStyleBasicItemVariablePtr) castedComp; 01728 #else 01729 xsltStylePreCompPtr comp = castedComp; 01730 #endif 01731 xsltStackElemPtr elem; 01732 01733 #ifdef WITH_XSLT_DEBUG_VARIABLE 01734 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01735 "Building variable %s", comp->name)); 01736 if (comp->select != NULL) 01737 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01738 " select %s", comp->select)); 01739 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n")); 01740 #endif 01741 01742 elem = xsltNewStackElem(ctxt); 01743 if (elem == NULL) 01744 return(NULL); 01745 elem->comp = (xsltStylePreCompPtr) comp; 01746 elem->name = comp->name; 01747 elem->select = comp->select; 01748 elem->nameURI = comp->ns; 01749 elem->tree = tree; 01750 elem->value = xsltEvalVariable(ctxt, elem, 01751 (xsltStylePreCompPtr) comp); 01752 if (elem->value != NULL) 01753 elem->computed = 1; 01754 return(elem); 01755 } 01756 01768 static int 01769 xsltRegisterVariable(xsltTransformContextPtr ctxt, 01770 xsltStylePreCompPtr castedComp, 01771 xmlNodePtr tree, int isParam) 01772 { 01773 #ifdef XSLT_REFACTORED 01774 xsltStyleBasicItemVariablePtr comp = 01775 (xsltStyleBasicItemVariablePtr) castedComp; 01776 #else 01777 xsltStylePreCompPtr comp = castedComp; 01778 int present; 01779 #endif 01780 xsltStackElemPtr variable; 01781 01782 #ifdef XSLT_REFACTORED 01783 /* 01784 * REFACTORED NOTE: Redefinitions of vars/params are checked 01785 * at compilation time in the refactored code. 01786 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate(). 01787 */ 01788 #else 01789 present = xsltCheckStackElem(ctxt, comp->name, comp->ns); 01790 if (isParam == 0) { 01791 if ((present != 0) && (present != 3)) { 01792 /* TODO: report QName. */ 01793 xsltTransformError(ctxt, NULL, comp->inst, 01794 "XSLT-variable: Redefinition of variable '%s'.\n", comp->name); 01795 return(0); 01796 } 01797 } else if (present != 0) { 01798 if ((present == 1) || (present == 2)) { 01799 /* TODO: report QName. */ 01800 xsltTransformError(ctxt, NULL, comp->inst, 01801 "XSLT-param: Redefinition of parameter '%s'.\n", comp->name); 01802 return(0); 01803 } 01804 #ifdef WITH_XSLT_DEBUG_VARIABLE 01805 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01806 "param %s defined by caller\n", comp->name)); 01807 #endif 01808 return(0); 01809 } 01810 #endif /* else of XSLT_REFACTORED */ 01811 01812 variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); 01813 xsltAddStackElem(ctxt, variable); 01814 return(0); 01815 } 01816 01828 static xmlXPathObjectPtr 01829 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 01830 const xmlChar *ns_uri) { 01831 xsltStackElemPtr elem; 01832 xmlXPathObjectPtr ret = NULL; 01833 01834 /* 01835 * Lookup the global variables in XPath global variable hash table 01836 */ 01837 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL)) 01838 return(NULL); 01839 elem = (xsltStackElemPtr) 01840 xmlHashLookup2(ctxt->globalVars, name, ns_uri); 01841 if (elem == NULL) { 01842 #ifdef WITH_XSLT_DEBUG_VARIABLE 01843 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01844 "global variable not found %s\n", name)); 01845 #endif 01846 return(NULL); 01847 } 01848 /* 01849 * URGENT TODO: Move the detection of recursive definitions 01850 * to compile-time. 01851 */ 01852 if (elem->computed == 0) { 01853 if (elem->name == xsltComputingGlobalVarMarker) { 01854 xsltTransformError(ctxt, NULL, elem->comp->inst, 01855 "Recursive definition of %s\n", name); 01856 return(NULL); 01857 } 01858 ret = xsltEvalGlobalVariable(elem, ctxt); 01859 } else 01860 ret = elem->value; 01861 return(xmlXPathObjectCopy(ret)); 01862 } 01863 01875 xmlXPathObjectPtr 01876 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, 01877 const xmlChar *ns_uri) { 01878 xsltStackElemPtr elem; 01879 01880 if (ctxt == NULL) 01881 return(NULL); 01882 01883 elem = xsltStackLookup(ctxt, name, ns_uri); 01884 if (elem == NULL) { 01885 return(xsltGlobalVariableLookup(ctxt, name, ns_uri)); 01886 } 01887 if (elem->computed == 0) { 01888 #ifdef WITH_XSLT_DEBUG_VARIABLE 01889 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01890 "uncomputed variable %s\n", name)); 01891 #endif 01892 elem->value = xsltEvalVariable(ctxt, elem, NULL); 01893 elem->computed = 1; 01894 } 01895 if (elem->value != NULL) 01896 return(xmlXPathObjectCopy(elem->value)); 01897 #ifdef WITH_XSLT_DEBUG_VARIABLE 01898 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01899 "variable not found %s\n", name)); 01900 #endif 01901 return(NULL); 01902 } 01903 01917 xsltStackElemPtr 01918 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst) 01919 { 01920 #ifdef XSLT_REFACTORED 01921 xsltStyleBasicItemVariablePtr comp; 01922 #else 01923 xsltStylePreCompPtr comp; 01924 #endif 01925 xmlNodePtr tree = NULL; /* The first child node of the instruction or 01926 the instruction itself. */ 01927 xsltStackElemPtr param = NULL; 01928 01929 if ((ctxt == NULL) || (inst == NULL)) 01930 return(NULL); 01931 01932 #ifdef XSLT_REFACTORED 01933 comp = (xsltStyleBasicItemVariablePtr) inst->psvi; 01934 #else 01935 comp = (xsltStylePreCompPtr) inst->psvi; 01936 #endif 01937 01938 if (comp == NULL) { 01939 xsltTransformError(ctxt, NULL, inst, 01940 "Internal error in xsltParseStylesheetCallerParam(): " 01941 "The XSLT 'with-param' instruction was not compiled.\n"); 01942 return(NULL); 01943 } 01944 if (comp->name == NULL) { 01945 xsltTransformError(ctxt, NULL, inst, 01946 "Internal error in xsltParseStylesheetCallerParam(): " 01947 "XSLT 'with-param': The attribute 'name' was not compiled.\n"); 01948 return(NULL); 01949 } 01950 01951 #ifdef WITH_XSLT_DEBUG_VARIABLE 01952 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01953 "Handling xsl:with-param %s\n", comp->name)); 01954 #endif 01955 01956 if (comp->select == NULL) { 01957 tree = inst->children; 01958 } else { 01959 #ifdef WITH_XSLT_DEBUG_VARIABLE 01960 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 01961 " select %s\n", comp->select)); 01962 #endif 01963 tree = inst; 01964 } 01965 01966 param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); 01967 01968 return(param); 01969 } 01970 01979 void 01980 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) 01981 { 01982 #ifdef XSLT_REFACTORED 01983 xsltStyleItemVariablePtr comp; 01984 #else 01985 xsltStylePreCompPtr comp; 01986 #endif 01987 01988 if ((cur == NULL) || (style == NULL)) 01989 return; 01990 01991 #ifdef XSLT_REFACTORED 01992 /* 01993 * Note that xsltStylePreCompute() will be called from 01994 * xslt.c only. 01995 */ 01996 comp = (xsltStyleItemVariablePtr) cur->psvi; 01997 #else 01998 xsltStylePreCompute(style, cur); 01999 comp = (xsltStylePreCompPtr) cur->psvi; 02000 #endif 02001 if (comp == NULL) { 02002 xsltTransformError(NULL, style, cur, 02003 "xsl:variable : compilation failed\n"); 02004 return; 02005 } 02006 02007 if (comp->name == NULL) { 02008 xsltTransformError(NULL, style, cur, 02009 "xsl:variable : missing name attribute\n"); 02010 return; 02011 } 02012 02013 /* 02014 * Parse the content (a sequence constructor) of xsl:variable. 02015 */ 02016 if (cur->children != NULL) { 02017 #ifdef XSLT_REFACTORED 02018 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); 02019 #else 02020 xsltParseTemplateContent(style, cur); 02021 #endif 02022 } 02023 #ifdef WITH_XSLT_DEBUG_VARIABLE 02024 xsltGenericDebug(xsltGenericDebugContext, 02025 "Registering global variable %s\n", comp->name); 02026 #endif 02027 02028 xsltRegisterGlobalVariable(style, comp->name, comp->ns, 02029 comp->select, cur->children, (xsltStylePreCompPtr) comp, 02030 NULL); 02031 } 02032 02042 void 02043 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { 02044 #ifdef XSLT_REFACTORED 02045 xsltStyleItemParamPtr comp; 02046 #else 02047 xsltStylePreCompPtr comp; 02048 #endif 02049 02050 if ((cur == NULL) || (style == NULL)) 02051 return; 02052 02053 #ifdef XSLT_REFACTORED 02054 /* 02055 * Note that xsltStylePreCompute() will be called from 02056 * xslt.c only. 02057 */ 02058 comp = (xsltStyleItemParamPtr) cur->psvi; 02059 #else 02060 xsltStylePreCompute(style, cur); 02061 comp = (xsltStylePreCompPtr) cur->psvi; 02062 #endif 02063 if (comp == NULL) { 02064 xsltTransformError(NULL, style, cur, 02065 "xsl:param : compilation failed\n"); 02066 return; 02067 } 02068 02069 if (comp->name == NULL) { 02070 xsltTransformError(NULL, style, cur, 02071 "xsl:param : missing name attribute\n"); 02072 return; 02073 } 02074 02075 /* 02076 * Parse the content (a sequence constructor) of xsl:param. 02077 */ 02078 if (cur->children != NULL) { 02079 #ifdef XSLT_REFACTORED 02080 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); 02081 #else 02082 xsltParseTemplateContent(style, cur); 02083 #endif 02084 } 02085 02086 #ifdef WITH_XSLT_DEBUG_VARIABLE 02087 xsltGenericDebug(xsltGenericDebugContext, 02088 "Registering global param %s\n", comp->name); 02089 #endif 02090 02091 xsltRegisterGlobalVariable(style, comp->name, comp->ns, 02092 comp->select, cur->children, (xsltStylePreCompPtr) comp, 02093 NULL); 02094 } 02095 02104 void 02105 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst) 02106 { 02107 #ifdef XSLT_REFACTORED 02108 xsltStyleItemVariablePtr comp; 02109 #else 02110 xsltStylePreCompPtr comp; 02111 #endif 02112 02113 if ((inst == NULL) || (ctxt == NULL)) 02114 return; 02115 02116 comp = inst->psvi; 02117 if (comp == NULL) { 02118 xsltTransformError(ctxt, NULL, inst, 02119 "Internal error in xsltParseStylesheetVariable(): " 02120 "The XSLT 'variable' instruction was not compiled.\n"); 02121 return; 02122 } 02123 if (comp->name == NULL) { 02124 xsltTransformError(ctxt, NULL, inst, 02125 "Internal error in xsltParseStylesheetVariable(): " 02126 "The attribute 'name' was not compiled.\n"); 02127 return; 02128 } 02129 02130 #ifdef WITH_XSLT_DEBUG_VARIABLE 02131 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02132 "Registering variable '%s'\n", comp->name)); 02133 #endif 02134 02135 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0); 02136 } 02137 02146 void 02147 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) 02148 { 02149 #ifdef XSLT_REFACTORED 02150 xsltStyleItemParamPtr comp; 02151 #else 02152 xsltStylePreCompPtr comp; 02153 #endif 02154 02155 if ((cur == NULL) || (ctxt == NULL)) 02156 return; 02157 02158 comp = cur->psvi; 02159 if ((comp == NULL) || (comp->name == NULL)) { 02160 xsltTransformError(ctxt, NULL, cur, 02161 "Internal error in xsltParseStylesheetParam(): " 02162 "The XSLT 'param' declaration was not compiled correctly.\n"); 02163 return; 02164 } 02165 02166 #ifdef WITH_XSLT_DEBUG_VARIABLE 02167 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02168 "Registering param %s\n", comp->name)); 02169 #endif 02170 02171 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1); 02172 } 02173 02182 void 02183 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) { 02184 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem); 02185 } 02186 02198 xmlXPathObjectPtr 02199 xsltXPathVariableLookup(void *ctxt, const xmlChar *name, 02200 const xmlChar *ns_uri) { 02201 xsltTransformContextPtr tctxt; 02202 xmlXPathObjectPtr valueObj = NULL; 02203 02204 if ((ctxt == NULL) || (name == NULL)) 02205 return(NULL); 02206 02207 #ifdef WITH_XSLT_DEBUG_VARIABLE 02208 XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02209 "Lookup variable '%s'\n", name)); 02210 #endif 02211 02212 tctxt = (xsltTransformContextPtr) ctxt; 02213 /* 02214 * Local variables/params --------------------------------------------- 02215 * 02216 * Do the lookup from the top of the stack, but 02217 * don't use params being computed in a call-param 02218 * First lookup expects the variable name and URI to 02219 * come from the disctionnary and hence pointer comparison. 02220 */ 02221 if (tctxt->varsNr != 0) { 02222 int i; 02223 xsltStackElemPtr variable = NULL, cur; 02224 02225 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { 02226 cur = tctxt->varsTab[i-1]; 02227 if ((cur->name == name) && (cur->nameURI == ns_uri)) { 02228 #if 0 02229 stack_addr++; 02230 #endif 02231 variable = cur; 02232 goto local_variable_found; 02233 } 02234 cur = cur->next; 02235 } 02236 /* 02237 * Redo the lookup with interned strings to avoid string comparison. 02238 * 02239 * OPTIMIZE TODO: The problem here is, that if we request a 02240 * global variable, then this will be also executed. 02241 */ 02242 { 02243 const xmlChar *tmpName = name, *tmpNsName = ns_uri; 02244 02245 name = xmlDictLookup(tctxt->dict, name, -1); 02246 if (ns_uri) 02247 ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1); 02248 if ((tmpName != name) || (tmpNsName != ns_uri)) { 02249 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { 02250 cur = tctxt->varsTab[i-1]; 02251 if ((cur->name == name) && (cur->nameURI == ns_uri)) { 02252 #if 0 02253 stack_cmp++; 02254 #endif 02255 variable = cur; 02256 goto local_variable_found; 02257 } 02258 } 02259 } 02260 } 02261 02262 local_variable_found: 02263 02264 if (variable) { 02265 if (variable->computed == 0) { 02266 02267 #ifdef WITH_XSLT_DEBUG_VARIABLE 02268 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02269 "uncomputed variable '%s'\n", name)); 02270 #endif 02271 variable->value = xsltEvalVariable(tctxt, variable, NULL); 02272 variable->computed = 1; 02273 } 02274 if (variable->value != NULL) { 02275 valueObj = xmlXPathObjectCopy(variable->value); 02276 } 02277 return(valueObj); 02278 } 02279 } 02280 /* 02281 * Global variables/params -------------------------------------------- 02282 */ 02283 if (tctxt->globalVars) { 02284 valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri); 02285 } 02286 02287 if (valueObj == NULL) { 02288 02289 #ifdef WITH_XSLT_DEBUG_VARIABLE 02290 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02291 "variable not found '%s'\n", name)); 02292 #endif 02293 02294 if (ns_uri) { 02295 xsltTransformError(tctxt, NULL, tctxt->inst, 02296 "Variable '{%s}%s' has not been declared.\n", ns_uri, name); 02297 } else { 02298 xsltTransformError(tctxt, NULL, tctxt->inst, 02299 "Variable '%s' has not been declared.\n", name); 02300 } 02301 } else { 02302 02303 #ifdef WITH_XSLT_DEBUG_VARIABLE 02304 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, 02305 "found variable '%s'\n", name)); 02306 #endif 02307 } 02308 02309 return(valueObj); 02310 } 02311 02312 Generated on Sat May 26 2012 04:18:29 for ReactOS by
1.7.6.1
|