12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375 |
- /*
- * variables.c: Implementation of the variable storage and lookup
- *
- * Reference:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
- #define IN_LIBXSLT
- #include "libxslt.h"
- #include <string.h>
- #include <libxml/xmlmemory.h>
- #include <libxml/tree.h>
- #include <libxml/valid.h>
- #include <libxml/hash.h>
- #include <libxml/xmlerror.h>
- #include <libxml/xpath.h>
- #include <libxml/xpathInternals.h>
- #include <libxml/parserInternals.h>
- #include <libxml/dict.h>
- #include "xslt.h"
- #include "xsltInternals.h"
- #include "xsltutils.h"
- #include "variables.h"
- #include "transform.h"
- #include "imports.h"
- #include "preproc.h"
- #include "keys.h"
- #ifdef WITH_XSLT_DEBUG
- #define WITH_XSLT_DEBUG_VARIABLE
- #endif
- #ifdef XSLT_REFACTORED
- const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
- #endif
- static const xmlChar *xsltComputingGlobalVarMarker =
- (const xmlChar *) " var/param being computed";
- #define XSLT_VAR_GLOBAL (1<<0)
- #define XSLT_VAR_IN_SELECT (1<<1)
- #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
- /************************************************************************
- * *
- * Result Value Tree (Result Tree Fragment) interfaces *
- * *
- ************************************************************************/
- /**
- * xsltCreateRVT:
- * @ctxt: an XSLT transformation context
- *
- * Creates a Result Value Tree
- * (the XSLT 1.0 term for this is "Result Tree Fragment")
- *
- * Returns the result value tree or NULL in case of API or internal errors.
- */
- xmlDocPtr
- xsltCreateRVT(xsltTransformContextPtr ctxt)
- {
- xmlDocPtr container;
- /*
- * Question: Why is this function public?
- * Answer: It is called by the EXSLT module.
- */
- if (ctxt == NULL)
- return(NULL);
- /*
- * Reuse a RTF from the cache if available.
- */
- if (ctxt->cache->RVT) {
- container = ctxt->cache->RVT;
- ctxt->cache->RVT = (xmlDocPtr) container->next;
- /* clear the internal pointers */
- container->next = NULL;
- container->prev = NULL;
- if (ctxt->cache->nbRVT > 0)
- ctxt->cache->nbRVT--;
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- ctxt->cache->dbgReusedRVTs++;
- #endif
- return(container);
- }
- container = xmlNewDoc(NULL);
- if (container == NULL)
- return(NULL);
- container->dict = ctxt->dict;
- xmlDictReference(container->dict);
- XSLT_MARK_RES_TREE_FRAG(container);
- container->doc = container;
- container->parent = NULL;
- return(container);
- }
- /**
- * xsltRegisterTmpRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment)
- *
- * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
- * in the garbage collector.
- * The fragment will be freed at the exit of the currently
- * instantiated xsl:template.
- * Obsolete; this function might produce massive memory overhead,
- * since the fragment is only freed when the current xsl:template
- * exits. Use xsltRegisterLocalRVT() instead.
- *
- * Returns 0 in case of success and -1 in case of API or internal errors.
- */
- int
- xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
- {
- if ((ctxt == NULL) || (RVT == NULL))
- return(-1);
- RVT->prev = NULL;
- RVT->psvi = XSLT_RVT_LOCAL;
- /*
- * We'll restrict the lifetime of user-created fragments
- * insinde an xsl:variable and xsl:param to the lifetime of the
- * var/param itself.
- */
- if (ctxt->contextVariable != NULL) {
- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
- return(0);
- }
- RVT->next = (xmlNodePtr) ctxt->tmpRVT;
- if (ctxt->tmpRVT != NULL)
- ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
- ctxt->tmpRVT = RVT;
- return(0);
- }
- /**
- * xsltRegisterLocalRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
- *
- * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
- * in the RVT garbage collector.
- * The fragment will be freed when the instruction which created the
- * fragment exits.
- *
- * Returns 0 in case of success and -1 in case of API or internal errors.
- */
- int
- xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
- xmlDocPtr RVT)
- {
- if ((ctxt == NULL) || (RVT == NULL))
- return(-1);
- RVT->prev = NULL;
- RVT->psvi = XSLT_RVT_LOCAL;
- /*
- * When evaluating "select" expressions of xsl:variable
- * and xsl:param, we need to bind newly created tree fragments
- * to the variable itself; otherwise the fragment will be
- * freed before we leave the scope of a var.
- */
- if ((ctxt->contextVariable != NULL) &&
- (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
- {
- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
- return(0);
- }
- /*
- * Store the fragment in the scope of the current instruction.
- * If not reference by a returning instruction (like EXSLT's function),
- * then this fragment will be freed, when the instruction exits.
- */
- RVT->next = (xmlNodePtr) ctxt->localRVT;
- if (ctxt->localRVT != NULL)
- ctxt->localRVT->prev = (xmlNodePtr) RVT;
- ctxt->localRVT = RVT;
- return(0);
- }
- /**
- * xsltExtensionInstructionResultFinalize:
- * @ctxt: an XSLT transformation context
- *
- * Finalizes the data (e.g. result tree fragments) created
- * within a value-returning process (e.g. EXSLT's function).
- * Tree fragments marked as being returned by a function are
- * set to normal state, which means that the fragment garbage
- * collector will free them after the function-calling process exits.
- *
- * Returns 0 in case of success and -1 in case of API or internal errors.
- *
- * This function is unsupported in newer releases of libxslt.
- */
- int
- xsltExtensionInstructionResultFinalize(
- xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED)
- {
- xmlGenericError(xmlGenericErrorContext,
- "xsltExtensionInstructionResultFinalize is unsupported "
- "in this release of libxslt.\n");
- return(-1);
- }
- /**
- * xsltExtensionInstructionResultRegister:
- * @ctxt: an XSLT transformation context
- * @obj: an XPath object to be inspected for result tree fragments
- *
- * Marks the result of a value-returning extension instruction
- * in order to avoid it being garbage collected before the
- * extension instruction exits.
- * Note that one still has to additionally register any newly created
- * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
- *
- * Returns 0 in case of success and -1 in case of error.
- *
- * It isn't necessary to call this function in newer releases of
- * libxslt.
- */
- int
- xsltExtensionInstructionResultRegister(
- xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
- xmlXPathObjectPtr obj ATTRIBUTE_UNUSED)
- {
- return(0);
- }
- /**
- * xsltFlagRVTs:
- * @ctxt: an XSLT transformation context
- * @obj: an XPath object to be inspected for result tree fragments
- * @val: the flag value
- *
- * Updates ownership information of RVTs in @obj according to @val.
- *
- * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
- * RVTs won't be destroyed after leaving the returning scope.
- * @val = XSLT_RVT_LOCAL for the result of an extension function to reset
- * the state of its RVTs after it was returned to a new scope.
- * @val = XSLT_RVT_GLOBAL for parts of global variables.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
- int
- xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) {
- int i;
- xmlNodePtr cur;
- xmlDocPtr doc;
- if ((ctxt == NULL) || (obj == NULL))
- return(-1);
- /*
- * OPTIMIZE TODO: If no local variables/params and no local tree
- * fragments were created, then we don't need to analyse the XPath
- * objects for tree fragments.
- */
- if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
- return(0);
- if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
- return(0);
- for (i = 0; i < obj->nodesetval->nodeNr; i++) {
- cur = obj->nodesetval->nodeTab[i];
- if (cur->type == XML_NAMESPACE_DECL) {
- /*
- * The XPath module sets the owner element of a ns-node on
- * the ns->next field.
- */
- if ((((xmlNsPtr) cur)->next != NULL) &&
- (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
- {
- cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
- doc = cur->doc;
- } else {
- xsltTransformError(ctxt, NULL, ctxt->inst,
- "Internal error in xsltFlagRVTs(): "
- "Cannot retrieve the doc of a namespace node.\n");
- return(-1);
- }
- } else {
- doc = cur->doc;
- }
- if (doc == NULL) {
- xsltTransformError(ctxt, NULL, ctxt->inst,
- "Internal error in xsltFlagRVTs(): "
- "Cannot retrieve the doc of a node.\n");
- return(-1);
- }
- if (doc->name && (doc->name[0] == ' ') &&
- doc->psvi != XSLT_RVT_GLOBAL) {
- /*
- * This is a result tree fragment.
- * We store ownership information in the @psvi field.
- * TODO: How do we know if this is a doc acquired via the
- * document() function?
- */
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Flagging RVT %p: %p -> %p\n", doc, doc->psvi, val));
- #endif
- if (val == XSLT_RVT_LOCAL) {
- if (doc->psvi == XSLT_RVT_FUNC_RESULT)
- doc->psvi = XSLT_RVT_LOCAL;
- } else if (val == XSLT_RVT_GLOBAL) {
- if (doc->psvi != XSLT_RVT_LOCAL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltFlagRVTs: Invalid transition %p => GLOBAL\n",
- doc->psvi);
- doc->psvi = XSLT_RVT_GLOBAL;
- return(-1);
- }
- /* Will be registered as persistant in xsltReleaseLocalRVTs. */
- doc->psvi = XSLT_RVT_GLOBAL;
- } else if (val == XSLT_RVT_FUNC_RESULT) {
- doc->psvi = val;
- }
- }
- }
- return(0);
- }
- /**
- * xsltReleaseRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment)
- *
- * Either frees the RVT (which is an xmlDoc) or stores
- * it in the context's cache for later reuse.
- */
- void
- xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
- {
- if (RVT == NULL)
- return;
- if (ctxt && (ctxt->cache->nbRVT < 40)) {
- /*
- * Store the Result Tree Fragment.
- * Free the document info.
- */
- if (RVT->_private != NULL) {
- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
- xmlFree(RVT->_private);
- RVT->_private = NULL;
- }
- /*
- * Clear the document tree.
- * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
- */
- if (RVT->children != NULL) {
- xmlFreeNodeList(RVT->children);
- RVT->children = NULL;
- RVT->last = NULL;
- }
- if (RVT->ids != NULL) {
- xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
- RVT->ids = NULL;
- }
- if (RVT->refs != NULL) {
- xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
- RVT->refs = NULL;
- }
- /*
- * Reset the ownership information.
- */
- RVT->psvi = NULL;
- RVT->next = (xmlNodePtr) ctxt->cache->RVT;
- ctxt->cache->RVT = RVT;
- ctxt->cache->nbRVT++;
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- ctxt->cache->dbgCachedRVTs++;
- #endif
- return;
- }
- /*
- * Free it.
- */
- if (RVT->_private != NULL) {
- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
- xmlFree(RVT->_private);
- }
- xmlFreeDoc(RVT);
- }
- /**
- * xsltRegisterPersistRVT:
- * @ctxt: an XSLT transformation context
- * @RVT: a result value tree (Result Tree Fragment)
- *
- * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
- * in the fragment garbage collector.
- * The fragment will be freed when the transformation context is
- * freed.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
- int
- xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
- {
- if ((ctxt == NULL) || (RVT == NULL)) return(-1);
- RVT->psvi = XSLT_RVT_GLOBAL;
- RVT->prev = NULL;
- RVT->next = (xmlNodePtr) ctxt->persistRVT;
- if (ctxt->persistRVT != NULL)
- ctxt->persistRVT->prev = (xmlNodePtr) RVT;
- ctxt->persistRVT = RVT;
- return(0);
- }
- /**
- * xsltFreeRVTs:
- * @ctxt: an XSLT transformation context
- *
- * Frees all registered result value trees (Result Tree Fragments)
- * of the transformation. Internal function; should not be called
- * by user-code.
- */
- void
- xsltFreeRVTs(xsltTransformContextPtr ctxt)
- {
- xmlDocPtr cur, next;
- if (ctxt == NULL)
- return;
- /*
- * Local fragments.
- */
- cur = ctxt->localRVT;
- while (cur != NULL) {
- next = (xmlDocPtr) cur->next;
- if (cur->_private != NULL) {
- xsltFreeDocumentKeys(cur->_private);
- xmlFree(cur->_private);
- }
- xmlFreeDoc(cur);
- cur = next;
- }
- ctxt->localRVT = NULL;
- /*
- * User-created per-template fragments.
- */
- cur = ctxt->tmpRVT;
- while (cur != NULL) {
- next = (xmlDocPtr) cur->next;
- if (cur->_private != NULL) {
- xsltFreeDocumentKeys(cur->_private);
- xmlFree(cur->_private);
- }
- xmlFreeDoc(cur);
- cur = next;
- }
- ctxt->tmpRVT = NULL;
- /*
- * Global fragments.
- */
- cur = ctxt->persistRVT;
- while (cur != NULL) {
- next = (xmlDocPtr) cur->next;
- if (cur->_private != NULL) {
- xsltFreeDocumentKeys(cur->_private);
- xmlFree(cur->_private);
- }
- xmlFreeDoc(cur);
- cur = next;
- }
- ctxt->persistRVT = NULL;
- }
- /************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
- /**
- * xsltNewStackElem:
- *
- * Create a new XSLT ParserContext
- *
- * Returns the newly allocated xsltParserStackElem or NULL in case of error
- */
- static xsltStackElemPtr
- xsltNewStackElem(xsltTransformContextPtr ctxt)
- {
- xsltStackElemPtr ret;
- /*
- * Reuse a stack item from the cache if available.
- */
- if (ctxt && ctxt->cache->stackItems) {
- ret = ctxt->cache->stackItems;
- ctxt->cache->stackItems = ret->next;
- ret->next = NULL;
- ctxt->cache->nbStackItems--;
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- ctxt->cache->dbgReusedVars++;
- #endif
- return(ret);
- }
- ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
- if (ret == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltNewStackElem : malloc failed\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltStackElem));
- ret->context = ctxt;
- return(ret);
- }
- /**
- * xsltCopyStackElem:
- * @elem: an XSLT stack element
- *
- * Makes a copy of the stack element
- *
- * Returns the copy of NULL
- */
- static xsltStackElemPtr
- xsltCopyStackElem(xsltStackElemPtr elem) {
- xsltStackElemPtr cur;
- cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
- if (cur == NULL) {
- xsltTransformError(NULL, NULL, NULL,
- "xsltCopyStackElem : malloc failed\n");
- return(NULL);
- }
- memset(cur, 0, sizeof(xsltStackElem));
- cur->context = elem->context;
- cur->name = elem->name;
- cur->nameURI = elem->nameURI;
- cur->select = elem->select;
- cur->tree = elem->tree;
- cur->comp = elem->comp;
- return(cur);
- }
- /**
- * xsltFreeStackElem:
- * @elem: an XSLT stack element
- *
- * Free up the memory allocated by @elem
- */
- static void
- xsltFreeStackElem(xsltStackElemPtr elem) {
- if (elem == NULL)
- return;
- if (elem->value != NULL)
- xmlXPathFreeObject(elem->value);
- /*
- * Release the list of temporary Result Tree Fragments.
- */
- if (elem->context) {
- xmlDocPtr cur;
- while (elem->fragment != NULL) {
- cur = elem->fragment;
- elem->fragment = (xmlDocPtr) cur->next;
- if (cur->psvi == XSLT_RVT_LOCAL) {
- xsltReleaseRVT(elem->context, cur);
- } else if (cur->psvi == XSLT_RVT_FUNC_RESULT) {
- xsltRegisterLocalRVT(elem->context, cur);
- cur->psvi = XSLT_RVT_FUNC_RESULT;
- } else {
- xmlGenericError(xmlGenericErrorContext,
- "xsltFreeStackElem: Unexpected RVT flag %p\n",
- cur->psvi);
- }
- }
- }
- /*
- * Cache or free the variable structure.
- */
- if (elem->context && (elem->context->cache->nbStackItems < 50)) {
- /*
- * Store the item in the cache.
- */
- xsltTransformContextPtr ctxt = elem->context;
- memset(elem, 0, sizeof(xsltStackElem));
- elem->context = ctxt;
- elem->next = ctxt->cache->stackItems;
- ctxt->cache->stackItems = elem;
- ctxt->cache->nbStackItems++;
- #ifdef XSLT_DEBUG_PROFILE_CACHE
- ctxt->cache->dbgCachedVars++;
- #endif
- return;
- }
- xmlFree(elem);
- }
- static void
- xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
- xsltFreeStackElem((xsltStackElemPtr) payload);
- }
- /**
- * xsltFreeStackElemList:
- * @elem: an XSLT stack element
- *
- * Free up the memory allocated by @elem
- */
- void
- xsltFreeStackElemList(xsltStackElemPtr elem) {
- xsltStackElemPtr next;
- while (elem != NULL) {
- next = elem->next;
- xsltFreeStackElem(elem);
- elem = next;
- }
- }
- /**
- * xsltStackLookup:
- * @ctxt: an XSLT transformation context
- * @name: the local part of the name
- * @nameURI: the URI part of the name
- *
- * Locate an element in the stack based on its name.
- */
- #if 0 /* TODO: Those seem to have been used for debugging. */
- static int stack_addr = 0;
- static int stack_cmp = 0;
- #endif
- static xsltStackElemPtr
- xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *nameURI) {
- int i;
- xsltStackElemPtr cur;
- if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
- return(NULL);
- /*
- * Do the lookup from the top of the stack, but
- * don't use params being computed in a call-param
- * First lookup expects the variable name and URI to
- * come from the disctionnary and hence pointer comparison.
- */
- for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
- cur = ctxt->varsTab[i-1];
- while (cur != NULL) {
- if ((cur->name == name) && (cur->nameURI == nameURI)) {
- #if 0
- stack_addr++;
- #endif
- return(cur);
- }
- cur = cur->next;
- }
- }
- /*
- * Redo the lookup with interned string compares
- * to avoid string compares.
- */
- name = xmlDictLookup(ctxt->dict, name, -1);
- if (nameURI != NULL)
- nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
- for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
- cur = ctxt->varsTab[i-1];
- while (cur != NULL) {
- if ((cur->name == name) && (cur->nameURI == nameURI)) {
- #if 0
- stack_cmp++;
- #endif
- return(cur);
- }
- cur = cur->next;
- }
- }
- return(NULL);
- }
- #ifdef XSLT_REFACTORED
- #else
- /**
- * xsltCheckStackElem:
- * @ctxt: xn XSLT transformation context
- * @name: the variable name
- * @nameURI: the variable namespace URI
- *
- * Checks whether a variable or param is already defined.
- *
- * URGENT TODO: Checks for redefinition of vars/params should be
- * done only at compilation time.
- *
- * Returns 1 if variable is present, 2 if param is present, 3 if this
- * is an inherited param, 0 if not found, -1 in case of failure.
- */
- static int
- xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *nameURI) {
- xsltStackElemPtr cur;
- if ((ctxt == NULL) || (name == NULL))
- return(-1);
- cur = xsltStackLookup(ctxt, name, nameURI);
- if (cur == NULL)
- return(0);
- if (cur->comp != NULL) {
- if (cur->comp->type == XSLT_FUNC_WITHPARAM)
- return(3);
- else if (cur->comp->type == XSLT_FUNC_PARAM)
- return(2);
- }
- return(1);
- }
- #endif /* XSLT_REFACTORED */
- /**
- * xsltAddStackElem:
- * @ctxt: xn XSLT transformation context
- * @elem: a stack element
- *
- * Push an element (or list) onto the stack.
- * In case of a list, each member will be pushed into
- * a seperate slot; i.e. there's always 1 stack entry for
- * 1 stack element.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
- static int
- xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
- {
- if ((ctxt == NULL) || (elem == NULL))
- return(-1);
- do {
- if (ctxt->varsMax == 0) {
- ctxt->varsMax = 10;
- ctxt->varsTab =
- (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
- sizeof(ctxt->varsTab[0]));
- if (ctxt->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
- return (-1);
- }
- }
- if (ctxt->varsNr >= ctxt->varsMax) {
- ctxt->varsMax *= 2;
- ctxt->varsTab =
- (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
- ctxt->varsMax *
- sizeof(ctxt->varsTab[0]));
- if (ctxt->varsTab == NULL) {
- xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
- return (-1);
- }
- }
- ctxt->varsTab[ctxt->varsNr++] = elem;
- ctxt->vars = elem;
- elem = elem->next;
- } while (elem != NULL);
- return(0);
- }
- /**
- * xsltAddStackElemList:
- * @ctxt: xn XSLT transformation context
- * @elems: a stack element list
- *
- * Push an element list onto the stack.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
- int
- xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
- {
- return(xsltAddStackElem(ctxt, elems));
- }
- /************************************************************************
- * *
- * Module interfaces *
- * *
- ************************************************************************/
- /**
- * xsltEvalVariable:
- * @ctxt: the XSLT transformation context
- * @variable: the variable or parameter item
- * @comp: the compiled XSLT instruction
- *
- * Evaluate a variable value.
- *
- * Returns the XPath Object value or NULL in case of error
- */
- static xmlXPathObjectPtr
- xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
- xsltStylePreCompPtr castedComp)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp =
- (xsltStyleItemVariablePtr) castedComp;
- #else
- xsltStylePreCompPtr comp = castedComp;
- #endif
- xmlXPathObjectPtr result = NULL;
- xmlNodePtr oldInst;
- if ((ctxt == NULL) || (variable == NULL))
- return(NULL);
- /*
- * A variable or parameter are evaluated on demand; thus the
- * context (of XSLT and XPath) need to be temporarily adjusted and
- * restored on exit.
- */
- oldInst = ctxt->inst;
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating variable '%s'\n", variable->name));
- #endif
- if (variable->select != NULL) {
- xmlXPathCompExprPtr xpExpr = NULL;
- xmlDocPtr oldXPDoc;
- xmlNodePtr oldXPContextNode;
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
- xmlNsPtr *oldXPNamespaces;
- xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
- xsltStackElemPtr oldVar = ctxt->contextVariable;
- if ((comp != NULL) && (comp->comp != NULL)) {
- xpExpr = comp->comp;
- } else {
- xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, variable->select);
- }
- if (xpExpr == NULL)
- return(NULL);
- /*
- * Save context states.
- */
- oldXPDoc = xpctxt->doc;
- oldXPContextNode = xpctxt->node;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- oldXPNamespaces = xpctxt->namespaces;
- oldXPNsNr = xpctxt->nsNr;
- xpctxt->node = ctxt->node;
- /*
- * OPTIMIZE TODO: Lame try to set the context doc.
- * Get rid of this somehow in xpath.c.
- */
- if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
- ctxt->node->doc)
- xpctxt->doc = ctxt->node->doc;
- /*
- * BUG TODO: The proximity position and the context size will
- * potentially be wrong.
- * Example:
- * <xsl:template select="foo">
- * <xsl:variable name="pos" select="position()"/>
- * <xsl:for-each select="bar">
- * <xsl:value-of select="$pos"/>
- * </xsl:for-each>
- * </xsl:template>
- * Here the proximity position and context size are changed
- * to the context of <xsl:for-each select="bar">, but
- * the variable needs to be evaluated in the context of
- * <xsl:template select="foo">.
- */
- if (comp != NULL) {
- #ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- xpctxt->namespaces = comp->inScopeNs->list;
- xpctxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- #else
- xpctxt->namespaces = comp->nsList;
- xpctxt->nsNr = comp->nsNr;
- #endif
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- /*
- * We need to mark that we are "selecting" a var's value;
- * if any tree fragments are created inside the expression,
- * then those need to be stored inside the variable; otherwise
- * we'll eventually free still referenced fragments, before
- * we leave the scope of the variable.
- */
- ctxt->contextVariable = variable;
- variable->flags |= XSLT_VAR_IN_SELECT;
- result = xmlXPathCompiledEval(xpExpr, xpctxt);
- variable->flags ^= XSLT_VAR_IN_SELECT;
- /*
- * Restore Context states.
- */
- ctxt->contextVariable = oldVar;
- xpctxt->doc = oldXPDoc;
- xpctxt->node = oldXPContextNode;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->proximityPosition = oldXPProximityPosition;
- xpctxt->namespaces = oldXPNamespaces;
- xpctxt->nsNr = oldXPNsNr;
- if ((comp == NULL) || (comp->comp == NULL))
- xmlXPathFreeCompExpr(xpExpr);
- if (result == NULL) {
- xsltTransformError(ctxt, NULL,
- (comp != NULL) ? comp->inst : NULL,
- "Failed to evaluate the expression of variable '%s'.\n",
- variable->name);
- ctxt->state = XSLT_STATE_STOPPED;
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- #ifdef LIBXML_DEBUG_ENABLED
- } else {
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
- #endif
- #endif
- }
- } else {
- if (variable->tree == NULL) {
- result = xmlXPathNewCString("");
- } else {
- if (variable->tree) {
- xmlDocPtr container;
- xmlNodePtr oldInsert;
- xmlDocPtr oldOutput;
- xsltStackElemPtr oldVar = ctxt->contextVariable;
- /*
- * Generate a result tree fragment.
- */
- container = xsltCreateRVT(ctxt);
- if (container == NULL)
- goto error;
- /*
- * NOTE: Local Result Tree Fragments of params/variables
- * are not registered globally anymore; the life-time
- * is not directly dependant of the param/variable itself.
- *
- * OLD: xsltRegisterTmpRVT(ctxt, container);
- */
- /*
- * Attach the Result Tree Fragment to the variable;
- * when the variable is freed, it will also free
- * the Result Tree Fragment.
- */
- variable->fragment = container;
- container->psvi = XSLT_RVT_LOCAL;
- oldOutput = ctxt->output;
- oldInsert = ctxt->insert;
- ctxt->output = container;
- ctxt->insert = (xmlNodePtr) container;
- ctxt->contextVariable = variable;
- /*
- * Process the sequence constructor (variable->tree).
- * The resulting tree will be held by @container.
- */
- xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
- NULL, NULL);
- ctxt->contextVariable = oldVar;
- ctxt->insert = oldInsert;
- ctxt->output = oldOutput;
- result = xmlXPathNewValueTree((xmlNodePtr) container);
- }
- if (result == NULL) {
- result = xmlXPathNewCString("");
- } else {
- /*
- * Freeing is not handled there anymore.
- * QUESTION TODO: What does the above comment mean?
- */
- result->boolval = 0;
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- #ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
- #endif
- #endif
- }
- }
- error:
- ctxt->inst = oldInst;
- return(result);
- }
- /**
- * xsltEvalGlobalVariable:
- * @elem: the variable or parameter
- * @ctxt: the XSLT transformation context
- *
- * Evaluates a the value of a global xsl:variable or
- * xsl:param declaration.
- *
- * Returns the XPath Object value or NULL in case of error
- */
- static xmlXPathObjectPtr
- xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
- {
- xmlXPathObjectPtr result = NULL;
- xmlNodePtr oldInst;
- const xmlChar* oldVarName;
- #ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- if ((ctxt == NULL) || (elem == NULL))
- return(NULL);
- if (elem->computed)
- return(elem->value);
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating global variable %s\n", elem->name));
- #endif
- #ifdef WITH_DEBUGGER
- if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
- elem->comp && elem->comp->inst)
- xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
- #endif
- oldInst = ctxt->inst;
- #ifdef XSLT_REFACTORED
- comp = (xsltStyleBasicItemVariablePtr) elem->comp;
- #else
- comp = elem->comp;
- #endif
- oldVarName = elem->name;
- elem->name = xsltComputingGlobalVarMarker;
- /*
- * OPTIMIZE TODO: We should consider instantiating global vars/params
- * on-demand. The vars/params don't need to be evaluated if never
- * called; and in the case of global params, if values for such params
- * are provided by the user.
- */
- if (elem->select != NULL) {
- xmlXPathCompExprPtr xpExpr = NULL;
- xmlDocPtr oldXPDoc;
- xmlNodePtr oldXPContextNode;
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
- xmlNsPtr *oldXPNamespaces;
- xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
- if ((comp != NULL) && (comp->comp != NULL)) {
- xpExpr = comp->comp;
- } else {
- xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, elem->select);
- }
- if (xpExpr == NULL)
- goto error;
- if (comp != NULL)
- ctxt->inst = comp->inst;
- else
- ctxt->inst = NULL;
- /*
- * SPEC XSLT 1.0:
- * "At top-level, the expression or template specifying the
- * variable value is evaluated with the same context as that used
- * to process the root node of the source document: the current
- * node is the root node of the source document and the current
- * node list is a list containing just the root node of the source
- * document."
- */
- /*
- * Save context states.
- */
- oldXPDoc = xpctxt->doc;
- oldXPContextNode = xpctxt->node;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- oldXPNamespaces = xpctxt->namespaces;
- oldXPNsNr = xpctxt->nsNr;
- xpctxt->node = ctxt->initialContextNode;
- xpctxt->doc = ctxt->initialContextDoc;
- xpctxt->contextSize = 1;
- xpctxt->proximityPosition = 1;
- if (comp != NULL) {
- #ifdef XSLT_REFACTORED
- if (comp->inScopeNs != NULL) {
- xpctxt->namespaces = comp->inScopeNs->list;
- xpctxt->nsNr = comp->inScopeNs->xpathNumber;
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- #else
- xpctxt->namespaces = comp->nsList;
- xpctxt->nsNr = comp->nsNr;
- #endif
- } else {
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- }
- result = xmlXPathCompiledEval(xpExpr, xpctxt);
- /*
- * Restore Context states.
- */
- xpctxt->doc = oldXPDoc;
- xpctxt->node = oldXPContextNode;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->proximityPosition = oldXPProximityPosition;
- xpctxt->namespaces = oldXPNamespaces;
- xpctxt->nsNr = oldXPNsNr;
- if ((comp == NULL) || (comp->comp == NULL))
- xmlXPathFreeCompExpr(xpExpr);
- if (result == NULL) {
- if (comp == NULL)
- xsltTransformError(ctxt, NULL, NULL,
- "Evaluating global variable %s failed\n", elem->name);
- else
- xsltTransformError(ctxt, NULL, comp->inst,
- "Evaluating global variable %s failed\n", elem->name);
- ctxt->state = XSLT_STATE_STOPPED;
- goto error;
- }
- /*
- * Mark all RVTs that are referenced from result as part
- * of this variable so they won't be freed too early.
- */
- xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL);
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- #ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
- #endif
- #endif
- } else {
- if (elem->tree == NULL) {
- result = xmlXPathNewCString("");
- } else {
- xmlDocPtr container;
- xmlNodePtr oldInsert;
- xmlDocPtr oldOutput, oldXPDoc;
- /*
- * Generate a result tree fragment.
- */
- container = xsltCreateRVT(ctxt);
- if (container == NULL)
- goto error;
- /*
- * Let the lifetime of the tree fragment be handled by
- * the Libxslt's garbage collector.
- */
- xsltRegisterPersistRVT(ctxt, container);
- oldOutput = ctxt->output;
- oldInsert = ctxt->insert;
- oldXPDoc = ctxt->xpathCtxt->doc;
- ctxt->output = container;
- ctxt->insert = (xmlNodePtr) container;
- ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
- /*
- * Process the sequence constructor.
- */
- xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
- ctxt->xpathCtxt->doc = oldXPDoc;
- ctxt->insert = oldInsert;
- ctxt->output = oldOutput;
- result = xmlXPathNewValueTree((xmlNodePtr) container);
- if (result == NULL) {
- result = xmlXPathNewCString("");
- } else {
- result->boolval = 0; /* Freeing is not handled there anymore */
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- #ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
- #endif
- #endif
- }
- }
- error:
- elem->name = oldVarName;
- ctxt->inst = oldInst;
- if (result != NULL) {
- elem->value = result;
- elem->computed = 1;
- }
- return(result);
- }
- static void
- xsltEvalGlobalVariableWrapper(void *payload, void *data,
- const xmlChar *name ATTRIBUTE_UNUSED) {
- xsltEvalGlobalVariable((xsltStackElemPtr) payload,
- (xsltTransformContextPtr) data);
- }
- /**
- * xsltEvalGlobalVariables:
- * @ctxt: the XSLT transformation context
- *
- * Evaluates all global variables and parameters of a stylesheet.
- * For internal use only. This is called at start of a transformation.
- *
- * Returns 0 in case of success, -1 in case of error
- */
- int
- xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
- xsltStackElemPtr elem;
- xsltStylesheetPtr style;
- if ((ctxt == NULL) || (ctxt->document == NULL))
- return(-1);
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variables\n"));
- #endif
- /*
- * Walk the list from the stylesheets and populate the hash table
- */
- style = ctxt->style;
- while (style != NULL) {
- elem = style->variables;
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- if ((style->doc != NULL) && (style->doc->URL != NULL)) {
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variables from %s\n",
- style->doc->URL));
- }
- #endif
- while (elem != NULL) {
- xsltStackElemPtr def;
- /*
- * Global variables are stored in the variables pool.
- */
- def = (xsltStackElemPtr)
- xmlHashLookup2(ctxt->globalVars,
- elem->name, elem->nameURI);
- if (def == NULL) {
- def = xsltCopyStackElem(elem);
- xmlHashAddEntry2(ctxt->globalVars,
- elem->name, elem->nameURI, def);
- } else if ((elem->comp != NULL) &&
- (elem->comp->type == XSLT_FUNC_VARIABLE)) {
- /*
- * Redefinition of variables from a different stylesheet
- * should not generate a message.
- */
- if ((elem->comp->inst != NULL) &&
- (def->comp != NULL) && (def->comp->inst != NULL) &&
- (elem->comp->inst->doc == def->comp->inst->doc))
- {
- xsltTransformError(ctxt, style, elem->comp->inst,
- "Global variable %s already defined\n", elem->name);
- if (style != NULL) style->errors++;
- }
- }
- elem = elem->next;
- }
- style = xsltNextImport(style);
- }
- /*
- * This part does the actual evaluation
- */
- xmlHashScan(ctxt->globalVars, xsltEvalGlobalVariableWrapper, ctxt);
- return(0);
- }
- /**
- * xsltRegisterGlobalVariable:
- * @style: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- * @sel: the expression which need to be evaluated to generate a value
- * @tree: the subtree if sel is NULL
- * @comp: the precompiled value
- * @value: the string value if available
- *
- * Register a new variable value. If @value is NULL it unregisters
- * the variable
- *
- * Returns 0 in case of success, -1 in case of error
- */
- static int
- xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
- const xmlChar *ns_uri, const xmlChar *sel,
- xmlNodePtr tree, xsltStylePreCompPtr comp,
- const xmlChar *value) {
- xsltStackElemPtr elem, tmp;
- if (style == NULL)
- return(-1);
- if (name == NULL)
- return(-1);
- if (comp == NULL)
- return(-1);
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- if (comp->type == XSLT_FUNC_PARAM)
- xsltGenericDebug(xsltGenericDebugContext,
- "Defining global param %s\n", name);
- else
- xsltGenericDebug(xsltGenericDebugContext,
- "Defining global variable %s\n", name);
- #endif
- elem = xsltNewStackElem(NULL);
- if (elem == NULL)
- return(-1);
- elem->comp = comp;
- elem->name = xmlDictLookup(style->dict, name, -1);
- elem->select = xmlDictLookup(style->dict, sel, -1);
- if (ns_uri)
- elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
- elem->tree = tree;
- tmp = style->variables;
- if (tmp == NULL) {
- elem->next = NULL;
- style->variables = elem;
- } else {
- while (tmp != NULL) {
- if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
- (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
- (xmlStrEqual(elem->name, tmp->name)) &&
- ((elem->nameURI == tmp->nameURI) ||
- (xmlStrEqual(elem->nameURI, tmp->nameURI))))
- {
- xsltTransformError(NULL, style, comp->inst,
- "redefinition of global variable %s\n", elem->name);
- style->errors++;
- }
- if (tmp->next == NULL)
- break;
- tmp = tmp->next;
- }
- elem->next = NULL;
- tmp->next = elem;
- }
- if (value != NULL) {
- elem->computed = 1;
- elem->value = xmlXPathNewString(value);
- }
- return(0);
- }
- /**
- * xsltProcessUserParamInternal
- *
- * @ctxt: the XSLT transformation context
- * @name: a null terminated parameter name
- * @value: a null terminated value (may be an XPath expression)
- * @eval: 0 to treat the value literally, else evaluate as XPath expression
- *
- * If @eval is 0 then @value is treated literally and is stored in the global
- * parameter/variable table without any change.
- *
- * Uf @eval is 1 then @value is treated as an XPath expression and is
- * evaluated. In this case, if you want to pass a string which will be
- * interpreted literally then it must be enclosed in single or double quotes.
- * If the string contains single quotes (double quotes) then it cannot be
- * enclosed single quotes (double quotes). If the string which you want to
- * be treated literally contains both single and double quotes (e.g. Meet
- * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
- * quoting character. You cannot use ' or " inside the string
- * because the replacement of character entities with their equivalents is
- * done at a different stage of processing. The solution is to call
- * xsltQuoteUserParams or xsltQuoteOneUserParam.
- *
- * This needs to be done on parsed stylesheets before starting to apply
- * transformations. Normally this will be called (directly or indirectly)
- * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
- * or xsltQuoteOneUserParam.
- *
- * Returns 0 in case of success, -1 in case of error
- */
- static
- int
- xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value,
- int eval) {
- xsltStylesheetPtr style;
- const xmlChar *prefix;
- const xmlChar *href;
- xmlXPathCompExprPtr xpExpr;
- xmlXPathObjectPtr result;
- xsltStackElemPtr elem;
- int res;
- void *res_ptr;
- if (ctxt == NULL)
- return(-1);
- if (name == NULL)
- return(0);
- if (value == NULL)
- return(0);
- style = ctxt->style;
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Evaluating user parameter %s=%s\n", name, value));
- #endif
- /*
- * Name lookup
- */
- href = NULL;
- if (name[0] == '{') {
- int len = 0;
- while ((name[len] != 0) && (name[len] != '}')) len++;
- if (name[len] == 0) {
- xsltTransformError(ctxt, style, NULL,
- "user param : malformed parameter name : %s\n", name);
- } else {
- href = xmlDictLookup(ctxt->dict, &name[1], len-1);
- name = xmlDictLookup(ctxt->dict, &name[len + 1], -1);
- }
- }
- else {
- name = xsltSplitQName(ctxt->dict, name, &prefix);
- if (prefix != NULL) {
- xmlNsPtr ns;
- ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
- prefix);
- if (ns == NULL) {
- xsltTransformError(ctxt, style, NULL,
- "user param : no namespace bound to prefix %s\n", prefix);
- href = NULL;
- } else {
- href = ns->href;
- }
- }
- }
- if (name == NULL)
- return (-1);
- res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
- if (res_ptr != 0) {
- xsltTransformError(ctxt, style, NULL,
- "Global parameter %s already defined\n", name);
- }
- if (ctxt->globalVars == NULL)
- ctxt->globalVars = xmlHashCreate(20);
- /*
- * do not overwrite variables with parameters from the command line
- */
- while (style != NULL) {
- elem = ctxt->style->variables;
- while (elem != NULL) {
- if ((elem->comp != NULL) &&
- (elem->comp->type == XSLT_FUNC_VARIABLE) &&
- (xmlStrEqual(elem->name, name)) &&
- (xmlStrEqual(elem->nameURI, href))) {
- return(0);
- }
- elem = elem->next;
- }
- style = xsltNextImport(style);
- }
- style = ctxt->style;
- elem = NULL;
- /*
- * Do the evaluation if @eval is non-zero.
- */
- result = NULL;
- if (eval != 0) {
- xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, value);
- if (xpExpr != NULL) {
- xmlDocPtr oldXPDoc;
- xmlNodePtr oldXPContextNode;
- int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
- xmlNsPtr *oldXPNamespaces;
- xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
- /*
- * Save context states.
- */
- oldXPDoc = xpctxt->doc;
- oldXPContextNode = xpctxt->node;
- oldXPProximityPosition = xpctxt->proximityPosition;
- oldXPContextSize = xpctxt->contextSize;
- oldXPNamespaces = xpctxt->namespaces;
- oldXPNsNr = xpctxt->nsNr;
- /*
- * SPEC XSLT 1.0:
- * "At top-level, the expression or template specifying the
- * variable value is evaluated with the same context as that used
- * to process the root node of the source document: the current
- * node is the root node of the source document and the current
- * node list is a list containing just the root node of the source
- * document."
- */
- xpctxt->doc = ctxt->initialContextDoc;
- xpctxt->node = ctxt->initialContextNode;
- xpctxt->contextSize = 1;
- xpctxt->proximityPosition = 1;
- /*
- * There is really no in scope namespace for parameters on the
- * command line.
- */
- xpctxt->namespaces = NULL;
- xpctxt->nsNr = 0;
- result = xmlXPathCompiledEval(xpExpr, xpctxt);
- /*
- * Restore Context states.
- */
- xpctxt->doc = oldXPDoc;
- xpctxt->node = oldXPContextNode;
- xpctxt->contextSize = oldXPContextSize;
- xpctxt->proximityPosition = oldXPProximityPosition;
- xpctxt->namespaces = oldXPNamespaces;
- xpctxt->nsNr = oldXPNsNr;
- xmlXPathFreeCompExpr(xpExpr);
- }
- if (result == NULL) {
- xsltTransformError(ctxt, style, NULL,
- "Evaluating user parameter %s failed\n", name);
- ctxt->state = XSLT_STATE_STOPPED;
- return(-1);
- }
- }
- /*
- * If @eval is 0 then @value is to be taken literally and result is NULL
- *
- * If @eval is not 0, then @value is an XPath expression and has been
- * successfully evaluated and result contains the resulting value and
- * is not NULL.
- *
- * Now create an xsltStackElemPtr for insertion into the context's
- * global variable/parameter hash table.
- */
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- #ifdef LIBXML_DEBUG_ENABLED
- if ((xsltGenericDebugContext == stdout) ||
- (xsltGenericDebugContext == stderr))
- xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
- result, 0);
- #endif
- #endif
- elem = xsltNewStackElem(NULL);
- if (elem != NULL) {
- elem->name = name;
- elem->select = xmlDictLookup(ctxt->dict, value, -1);
- if (href != NULL)
- elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
- elem->tree = NULL;
- elem->computed = 1;
- if (eval == 0) {
- elem->value = xmlXPathNewString(value);
- }
- else {
- elem->value = result;
- }
- }
- /*
- * Global parameters are stored in the XPath context variables pool.
- */
- res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
- if (res != 0) {
- xsltFreeStackElem(elem);
- xsltTransformError(ctxt, style, NULL,
- "Global parameter %s already defined\n", name);
- }
- return(0);
- }
- /**
- * xsltEvalUserParams:
- *
- * @ctxt: the XSLT transformation context
- * @params: a NULL terminated array of parameters name/value tuples
- *
- * Evaluate the global variables of a stylesheet. This needs to be
- * done on parsed stylesheets before starting to apply transformations.
- * Each of the parameters is evaluated as an XPath expression and stored
- * in the global variables/parameter hash table. If you want your
- * parameter used literally, use xsltQuoteUserParams.
- *
- * Returns 0 in case of success, -1 in case of error
- */
- int
- xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
- int indx = 0;
- const xmlChar *name;
- const xmlChar *value;
- if (params == NULL)
- return(0);
- while (params[indx] != NULL) {
- name = (const xmlChar *) params[indx++];
- value = (const xmlChar *) params[indx++];
- if (xsltEvalOneUserParam(ctxt, name, value) != 0)
- return(-1);
- }
- return 0;
- }
- /**
- * xsltQuoteUserParams:
- *
- * @ctxt: the XSLT transformation context
- * @params: a NULL terminated arry of parameters names/values tuples
- *
- * Similar to xsltEvalUserParams, but the values are treated literally and
- * are * *not* evaluated as XPath expressions. This should be done on parsed
- * stylesheets before starting to apply transformations.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
- int
- xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
- int indx = 0;
- const xmlChar *name;
- const xmlChar *value;
- if (params == NULL)
- return(0);
- while (params[indx] != NULL) {
- name = (const xmlChar *) params[indx++];
- value = (const xmlChar *) params[indx++];
- if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
- return(-1);
- }
- return 0;
- }
- /**
- * xsltEvalOneUserParam:
- * @ctxt: the XSLT transformation context
- * @name: a null terminated string giving the name of the parameter
- * @value: a null terminated string giving the XPath expression to be evaluated
- *
- * This is normally called from xsltEvalUserParams to process a single
- * parameter from a list of parameters. The @value is evaluated as an
- * XPath expression and the result is stored in the context's global
- * variable/parameter hash table.
- *
- * To have a parameter treated literally (not as an XPath expression)
- * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
- * details see description of xsltProcessOneUserParamInternal.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
- int
- xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value) {
- return xsltProcessUserParamInternal(ctxt, name, value,
- 1 /* xpath eval ? */);
- }
- /**
- * xsltQuoteOneUserParam:
- * @ctxt: the XSLT transformation context
- * @name: a null terminated string giving the name of the parameter
- * @value: a null terminated string giving the parameter value
- *
- * This is normally called from xsltQuoteUserParams to process a single
- * parameter from a list of parameters. The @value is stored in the
- * context's global variable/parameter hash table.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
- int
- xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
- const xmlChar * name,
- const xmlChar * value) {
- return xsltProcessUserParamInternal(ctxt, name, value,
- 0 /* xpath eval ? */);
- }
- /**
- * xsltBuildVariable:
- * @ctxt: the XSLT transformation context
- * @comp: the precompiled form
- * @tree: the tree if select is NULL
- *
- * Computes a new variable value.
- *
- * Returns the xsltStackElemPtr or NULL in case of error
- */
- static xsltStackElemPtr
- xsltBuildVariable(xsltTransformContextPtr ctxt,
- xsltStylePreCompPtr castedComp,
- xmlNodePtr tree)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp =
- (xsltStyleBasicItemVariablePtr) castedComp;
- #else
- xsltStylePreCompPtr comp = castedComp;
- #endif
- xsltStackElemPtr elem;
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Building variable %s", comp->name));
- if (comp->select != NULL)
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- " select %s", comp->select));
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
- #endif
- elem = xsltNewStackElem(ctxt);
- if (elem == NULL)
- return(NULL);
- elem->comp = (xsltStylePreCompPtr) comp;
- elem->name = comp->name;
- elem->select = comp->select;
- elem->nameURI = comp->ns;
- elem->tree = tree;
- elem->value = xsltEvalVariable(ctxt, elem,
- (xsltStylePreCompPtr) comp);
- elem->computed = 1;
- return(elem);
- }
- /**
- * xsltRegisterVariable:
- * @ctxt: the XSLT transformation context
- * @comp: the compiled XSLT-variable (or param) instruction
- * @tree: the tree if select is NULL
- * @isParam: indicates if this is a parameter
- *
- * Computes and registers a new variable.
- *
- * Returns 0 in case of success, -1 in case of error
- */
- static int
- xsltRegisterVariable(xsltTransformContextPtr ctxt,
- xsltStylePreCompPtr castedComp,
- xmlNodePtr tree, int isParam)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp =
- (xsltStyleBasicItemVariablePtr) castedComp;
- #else
- xsltStylePreCompPtr comp = castedComp;
- int present;
- #endif
- xsltStackElemPtr variable;
- #ifdef XSLT_REFACTORED
- /*
- * REFACTORED NOTE: Redefinitions of vars/params are checked
- * at compilation time in the refactored code.
- * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
- */
- #else
- present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
- if (isParam == 0) {
- if ((present != 0) && (present != 3)) {
- /* TODO: report QName. */
- xsltTransformError(ctxt, NULL, comp->inst,
- "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
- return(0);
- }
- } else if (present != 0) {
- if ((present == 1) || (present == 2)) {
- /* TODO: report QName. */
- xsltTransformError(ctxt, NULL, comp->inst,
- "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
- return(0);
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "param %s defined by caller\n", comp->name));
- #endif
- return(0);
- }
- #endif /* else of XSLT_REFACTORED */
- variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
- xsltAddStackElem(ctxt, variable);
- return(0);
- }
- /**
- * xsltGlobalVariableLookup:
- * @ctxt: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * Search in the Variable array of the context for the given
- * variable value.
- *
- * Returns the value or NULL if not found
- */
- static xmlXPathObjectPtr
- xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltStackElemPtr elem;
- xmlXPathObjectPtr ret = NULL;
- /*
- * Lookup the global variables in XPath global variable hash table
- */
- if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
- return(NULL);
- elem = (xsltStackElemPtr)
- xmlHashLookup2(ctxt->globalVars, name, ns_uri);
- if (elem == NULL) {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "global variable not found %s\n", name));
- #endif
- return(NULL);
- }
- /*
- * URGENT TODO: Move the detection of recursive definitions
- * to compile-time.
- */
- if (elem->computed == 0) {
- if (elem->name == xsltComputingGlobalVarMarker) {
- xsltTransformError(ctxt, NULL, elem->comp->inst,
- "Recursive definition of %s\n", name);
- return(NULL);
- }
- ret = xsltEvalGlobalVariable(elem, ctxt);
- } else
- ret = elem->value;
- return(xmlXPathObjectCopy(ret));
- }
- /**
- * xsltVariableLookup:
- * @ctxt: the XSLT transformation context
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * Search in the Variable array of the context for the given
- * variable value.
- *
- * Returns the value or NULL if not found
- */
- xmlXPathObjectPtr
- xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltStackElemPtr elem;
- if (ctxt == NULL)
- return(NULL);
- elem = xsltStackLookup(ctxt, name, ns_uri);
- if (elem == NULL) {
- return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
- }
- if (elem->computed == 0) {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "uncomputed variable %s\n", name));
- #endif
- elem->value = xsltEvalVariable(ctxt, elem, NULL);
- elem->computed = 1;
- }
- if (elem->value != NULL)
- return(xmlXPathObjectCopy(elem->value));
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "variable not found %s\n", name));
- #endif
- return(NULL);
- }
- /**
- * xsltParseStylesheetCallerParam:
- * @ctxt: the XSLT transformation context
- * @inst: the xsl:with-param instruction element
- *
- * Processes an xsl:with-param instruction at transformation time.
- * The value is computed, but not recorded.
- * NOTE that this is also called with an *xsl:param* element
- * from exsltFuncFunctionFunction().
- *
- * Returns the new xsltStackElemPtr or NULL
- */
- xsltStackElemPtr
- xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleBasicItemVariablePtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- xmlNodePtr tree = NULL; /* The first child node of the instruction or
- the instruction itself. */
- xsltStackElemPtr param = NULL;
- if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
- return(NULL);
- #ifdef XSLT_REFACTORED
- comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
- #else
- comp = (xsltStylePreCompPtr) inst->psvi;
- #endif
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltParseStylesheetCallerParam(): "
- "The XSLT 'with-param' instruction was not compiled.\n");
- return(NULL);
- }
- if (comp->name == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltParseStylesheetCallerParam(): "
- "XSLT 'with-param': The attribute 'name' was not compiled.\n");
- return(NULL);
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Handling xsl:with-param %s\n", comp->name));
- #endif
- if (comp->select == NULL) {
- tree = inst->children;
- } else {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- " select %s\n", comp->select));
- #endif
- tree = inst;
- }
- param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
- return(param);
- }
- /**
- * xsltParseGlobalVariable:
- * @style: the XSLT stylesheet
- * @cur: the "variable" element
- *
- * Parses a global XSLT 'variable' declaration at compilation time
- * and registers it
- */
- void
- xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- #ifdef XSLT_REFACTORED
- /*
- * Note that xsltStylePreCompute() will be called from
- * xslt.c only.
- */
- comp = (xsltStyleItemVariablePtr) cur->psvi;
- #else
- xsltStylePreCompute(style, cur);
- comp = (xsltStylePreCompPtr) cur->psvi;
- #endif
- if (comp == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:variable : compilation failed\n");
- return;
- }
- if (comp->name == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:variable : missing name attribute\n");
- return;
- }
- /*
- * Parse the content (a sequence constructor) of xsl:variable.
- */
- if (cur->children != NULL) {
- #ifdef XSLT_REFACTORED
- xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
- #else
- xsltParseTemplateContent(style, cur);
- #endif
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- xsltGenericDebug(xsltGenericDebugContext,
- "Registering global variable %s\n", comp->name);
- #endif
- xsltRegisterGlobalVariable(style, comp->name, comp->ns,
- comp->select, cur->children, (xsltStylePreCompPtr) comp,
- NULL);
- }
- /**
- * xsltParseGlobalParam:
- * @style: the XSLT stylesheet
- * @cur: the "param" element
- *
- * parse an XSLT transformation param declaration and record
- * its value.
- */
- void
- xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
- #ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- #ifdef XSLT_REFACTORED
- /*
- * Note that xsltStylePreCompute() will be called from
- * xslt.c only.
- */
- comp = (xsltStyleItemParamPtr) cur->psvi;
- #else
- xsltStylePreCompute(style, cur);
- comp = (xsltStylePreCompPtr) cur->psvi;
- #endif
- if (comp == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:param : compilation failed\n");
- return;
- }
- if (comp->name == NULL) {
- xsltTransformError(NULL, style, cur,
- "xsl:param : missing name attribute\n");
- return;
- }
- /*
- * Parse the content (a sequence constructor) of xsl:param.
- */
- if (cur->children != NULL) {
- #ifdef XSLT_REFACTORED
- xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
- #else
- xsltParseTemplateContent(style, cur);
- #endif
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- xsltGenericDebug(xsltGenericDebugContext,
- "Registering global param %s\n", comp->name);
- #endif
- xsltRegisterGlobalVariable(style, comp->name, comp->ns,
- comp->select, cur->children, (xsltStylePreCompPtr) comp,
- NULL);
- }
- /**
- * xsltParseStylesheetVariable:
- * @ctxt: the XSLT transformation context
- * @inst: the xsl:variable instruction element
- *
- * Registers a local XSLT 'variable' instruction at transformation time
- * and evaluates its value.
- */
- void
- xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemVariablePtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE))
- return;
- comp = inst->psvi;
- if (comp == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltParseStylesheetVariable(): "
- "The XSLT 'variable' instruction was not compiled.\n");
- return;
- }
- if (comp->name == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "Internal error in xsltParseStylesheetVariable(): "
- "The attribute 'name' was not compiled.\n");
- return;
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering variable '%s'\n", comp->name));
- #endif
- xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
- }
- /**
- * xsltParseStylesheetParam:
- * @ctxt: the XSLT transformation context
- * @cur: the XSLT 'param' element
- *
- * Registers a local XSLT 'param' declaration at transformation time and
- * evaluates its value.
- */
- void
- xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
- {
- #ifdef XSLT_REFACTORED
- xsltStyleItemParamPtr comp;
- #else
- xsltStylePreCompPtr comp;
- #endif
- if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE))
- return;
- comp = cur->psvi;
- if ((comp == NULL) || (comp->name == NULL)) {
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltParseStylesheetParam(): "
- "The XSLT 'param' declaration was not compiled correctly.\n");
- return;
- }
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Registering param %s\n", comp->name));
- #endif
- xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
- }
- /**
- * xsltFreeGlobalVariables:
- * @ctxt: the XSLT transformation context
- *
- * Free up the data associated to the global variables
- * its value.
- */
- void
- xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
- xmlHashFree(ctxt->globalVars, xsltFreeStackElemEntry);
- }
- /**
- * xsltXPathVariableLookup:
- * @ctxt: a void * but the the XSLT transformation context actually
- * @name: the variable name
- * @ns_uri: the variable namespace URI
- *
- * This is the entry point when a varibale is needed by the XPath
- * interpretor.
- *
- * Returns the value or NULL if not found
- */
- xmlXPathObjectPtr
- xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
- const xmlChar *ns_uri) {
- xsltTransformContextPtr tctxt;
- xmlXPathObjectPtr valueObj = NULL;
- if ((ctxt == NULL) || (name == NULL))
- return(NULL);
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "Lookup variable '%s'\n", name));
- #endif
- tctxt = (xsltTransformContextPtr) ctxt;
- /*
- * Local variables/params ---------------------------------------------
- *
- * Do the lookup from the top of the stack, but
- * don't use params being computed in a call-param
- * First lookup expects the variable name and URI to
- * come from the disctionnary and hence pointer comparison.
- */
- if (tctxt->varsNr != 0) {
- int i;
- xsltStackElemPtr variable = NULL, cur;
- for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
- cur = tctxt->varsTab[i-1];
- if ((cur->name == name) && (cur->nameURI == ns_uri)) {
- #if 0
- stack_addr++;
- #endif
- variable = cur;
- goto local_variable_found;
- }
- cur = cur->next;
- }
- /*
- * Redo the lookup with interned strings to avoid string comparison.
- *
- * OPTIMIZE TODO: The problem here is, that if we request a
- * global variable, then this will be also executed.
- */
- {
- const xmlChar *tmpName = name, *tmpNsName = ns_uri;
- name = xmlDictLookup(tctxt->dict, name, -1);
- if (ns_uri)
- ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
- if ((tmpName != name) || (tmpNsName != ns_uri)) {
- for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
- cur = tctxt->varsTab[i-1];
- if ((cur->name == name) && (cur->nameURI == ns_uri)) {
- #if 0
- stack_cmp++;
- #endif
- variable = cur;
- goto local_variable_found;
- }
- }
- }
- }
- local_variable_found:
- if (variable) {
- if (variable->computed == 0) {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "uncomputed variable '%s'\n", name));
- #endif
- variable->value = xsltEvalVariable(tctxt, variable, NULL);
- variable->computed = 1;
- }
- if (variable->value != NULL) {
- valueObj = xmlXPathObjectCopy(variable->value);
- }
- return(valueObj);
- }
- }
- /*
- * Global variables/params --------------------------------------------
- */
- if (tctxt->globalVars) {
- valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
- }
- if (valueObj == NULL) {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "variable not found '%s'\n", name));
- #endif
- if (ns_uri) {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "Variable '{%s}%s' has not been declared.\n", ns_uri, name);
- } else {
- xsltTransformError(tctxt, NULL, tctxt->inst,
- "Variable '%s' has not been declared.\n", name);
- }
- } else {
- #ifdef WITH_XSLT_DEBUG_VARIABLE
- XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
- "found variable '%s'\n", name));
- #endif
- }
- return(valueObj);
- }
|