variables.c 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375
  1. /*
  2. * variables.c: Implementation of the variable storage and lookup
  3. *
  4. * Reference:
  5. * http://www.w3.org/TR/1999/REC-xslt-19991116
  6. *
  7. * See Copyright for the status of this software.
  8. *
  9. * daniel@veillard.com
  10. */
  11. #define IN_LIBXSLT
  12. #include "libxslt.h"
  13. #include <string.h>
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/tree.h>
  16. #include <libxml/valid.h>
  17. #include <libxml/hash.h>
  18. #include <libxml/xmlerror.h>
  19. #include <libxml/xpath.h>
  20. #include <libxml/xpathInternals.h>
  21. #include <libxml/parserInternals.h>
  22. #include <libxml/dict.h>
  23. #include "xslt.h"
  24. #include "xsltInternals.h"
  25. #include "xsltutils.h"
  26. #include "variables.h"
  27. #include "transform.h"
  28. #include "imports.h"
  29. #include "preproc.h"
  30. #include "keys.h"
  31. #ifdef WITH_XSLT_DEBUG
  32. #define WITH_XSLT_DEBUG_VARIABLE
  33. #endif
  34. #ifdef XSLT_REFACTORED
  35. const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
  36. #endif
  37. static const xmlChar *xsltComputingGlobalVarMarker =
  38. (const xmlChar *) " var/param being computed";
  39. #define XSLT_VAR_GLOBAL (1<<0)
  40. #define XSLT_VAR_IN_SELECT (1<<1)
  41. #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
  42. /************************************************************************
  43. * *
  44. * Result Value Tree (Result Tree Fragment) interfaces *
  45. * *
  46. ************************************************************************/
  47. /**
  48. * xsltCreateRVT:
  49. * @ctxt: an XSLT transformation context
  50. *
  51. * Creates a Result Value Tree
  52. * (the XSLT 1.0 term for this is "Result Tree Fragment")
  53. *
  54. * Returns the result value tree or NULL in case of API or internal errors.
  55. */
  56. xmlDocPtr
  57. xsltCreateRVT(xsltTransformContextPtr ctxt)
  58. {
  59. xmlDocPtr container;
  60. /*
  61. * Question: Why is this function public?
  62. * Answer: It is called by the EXSLT module.
  63. */
  64. if (ctxt == NULL)
  65. return(NULL);
  66. /*
  67. * Reuse a RTF from the cache if available.
  68. */
  69. if (ctxt->cache->RVT) {
  70. container = ctxt->cache->RVT;
  71. ctxt->cache->RVT = (xmlDocPtr) container->next;
  72. /* clear the internal pointers */
  73. container->next = NULL;
  74. container->prev = NULL;
  75. if (ctxt->cache->nbRVT > 0)
  76. ctxt->cache->nbRVT--;
  77. #ifdef XSLT_DEBUG_PROFILE_CACHE
  78. ctxt->cache->dbgReusedRVTs++;
  79. #endif
  80. return(container);
  81. }
  82. container = xmlNewDoc(NULL);
  83. if (container == NULL)
  84. return(NULL);
  85. container->dict = ctxt->dict;
  86. xmlDictReference(container->dict);
  87. XSLT_MARK_RES_TREE_FRAG(container);
  88. container->doc = container;
  89. container->parent = NULL;
  90. return(container);
  91. }
  92. /**
  93. * xsltRegisterTmpRVT:
  94. * @ctxt: an XSLT transformation context
  95. * @RVT: a result value tree (Result Tree Fragment)
  96. *
  97. * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
  98. * in the garbage collector.
  99. * The fragment will be freed at the exit of the currently
  100. * instantiated xsl:template.
  101. * Obsolete; this function might produce massive memory overhead,
  102. * since the fragment is only freed when the current xsl:template
  103. * exits. Use xsltRegisterLocalRVT() instead.
  104. *
  105. * Returns 0 in case of success and -1 in case of API or internal errors.
  106. */
  107. int
  108. xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
  109. {
  110. if ((ctxt == NULL) || (RVT == NULL))
  111. return(-1);
  112. RVT->prev = NULL;
  113. RVT->psvi = XSLT_RVT_LOCAL;
  114. /*
  115. * We'll restrict the lifetime of user-created fragments
  116. * insinde an xsl:variable and xsl:param to the lifetime of the
  117. * var/param itself.
  118. */
  119. if (ctxt->contextVariable != NULL) {
  120. RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
  121. XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
  122. return(0);
  123. }
  124. RVT->next = (xmlNodePtr) ctxt->tmpRVT;
  125. if (ctxt->tmpRVT != NULL)
  126. ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
  127. ctxt->tmpRVT = RVT;
  128. return(0);
  129. }
  130. /**
  131. * xsltRegisterLocalRVT:
  132. * @ctxt: an XSLT transformation context
  133. * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
  134. *
  135. * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
  136. * in the RVT garbage collector.
  137. * The fragment will be freed when the instruction which created the
  138. * fragment exits.
  139. *
  140. * Returns 0 in case of success and -1 in case of API or internal errors.
  141. */
  142. int
  143. xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
  144. xmlDocPtr RVT)
  145. {
  146. if ((ctxt == NULL) || (RVT == NULL))
  147. return(-1);
  148. RVT->prev = NULL;
  149. RVT->psvi = XSLT_RVT_LOCAL;
  150. /*
  151. * When evaluating "select" expressions of xsl:variable
  152. * and xsl:param, we need to bind newly created tree fragments
  153. * to the variable itself; otherwise the fragment will be
  154. * freed before we leave the scope of a var.
  155. */
  156. if ((ctxt->contextVariable != NULL) &&
  157. (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
  158. {
  159. RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
  160. XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
  161. return(0);
  162. }
  163. /*
  164. * Store the fragment in the scope of the current instruction.
  165. * If not reference by a returning instruction (like EXSLT's function),
  166. * then this fragment will be freed, when the instruction exits.
  167. */
  168. RVT->next = (xmlNodePtr) ctxt->localRVT;
  169. if (ctxt->localRVT != NULL)
  170. ctxt->localRVT->prev = (xmlNodePtr) RVT;
  171. ctxt->localRVT = RVT;
  172. return(0);
  173. }
  174. /**
  175. * xsltExtensionInstructionResultFinalize:
  176. * @ctxt: an XSLT transformation context
  177. *
  178. * Finalizes the data (e.g. result tree fragments) created
  179. * within a value-returning process (e.g. EXSLT's function).
  180. * Tree fragments marked as being returned by a function are
  181. * set to normal state, which means that the fragment garbage
  182. * collector will free them after the function-calling process exits.
  183. *
  184. * Returns 0 in case of success and -1 in case of API or internal errors.
  185. *
  186. * This function is unsupported in newer releases of libxslt.
  187. */
  188. int
  189. xsltExtensionInstructionResultFinalize(
  190. xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED)
  191. {
  192. xmlGenericError(xmlGenericErrorContext,
  193. "xsltExtensionInstructionResultFinalize is unsupported "
  194. "in this release of libxslt.\n");
  195. return(-1);
  196. }
  197. /**
  198. * xsltExtensionInstructionResultRegister:
  199. * @ctxt: an XSLT transformation context
  200. * @obj: an XPath object to be inspected for result tree fragments
  201. *
  202. * Marks the result of a value-returning extension instruction
  203. * in order to avoid it being garbage collected before the
  204. * extension instruction exits.
  205. * Note that one still has to additionally register any newly created
  206. * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
  207. *
  208. * Returns 0 in case of success and -1 in case of error.
  209. *
  210. * It isn't necessary to call this function in newer releases of
  211. * libxslt.
  212. */
  213. int
  214. xsltExtensionInstructionResultRegister(
  215. xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
  216. xmlXPathObjectPtr obj ATTRIBUTE_UNUSED)
  217. {
  218. return(0);
  219. }
  220. /**
  221. * xsltFlagRVTs:
  222. * @ctxt: an XSLT transformation context
  223. * @obj: an XPath object to be inspected for result tree fragments
  224. * @val: the flag value
  225. *
  226. * Updates ownership information of RVTs in @obj according to @val.
  227. *
  228. * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
  229. * RVTs won't be destroyed after leaving the returning scope.
  230. * @val = XSLT_RVT_LOCAL for the result of an extension function to reset
  231. * the state of its RVTs after it was returned to a new scope.
  232. * @val = XSLT_RVT_GLOBAL for parts of global variables.
  233. *
  234. * Returns 0 in case of success and -1 in case of error.
  235. */
  236. int
  237. xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, void *val) {
  238. int i;
  239. xmlNodePtr cur;
  240. xmlDocPtr doc;
  241. if ((ctxt == NULL) || (obj == NULL))
  242. return(-1);
  243. /*
  244. * OPTIMIZE TODO: If no local variables/params and no local tree
  245. * fragments were created, then we don't need to analyse the XPath
  246. * objects for tree fragments.
  247. */
  248. if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
  249. return(0);
  250. if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
  251. return(0);
  252. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  253. cur = obj->nodesetval->nodeTab[i];
  254. if (cur->type == XML_NAMESPACE_DECL) {
  255. /*
  256. * The XPath module sets the owner element of a ns-node on
  257. * the ns->next field.
  258. */
  259. if ((((xmlNsPtr) cur)->next != NULL) &&
  260. (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
  261. {
  262. cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
  263. doc = cur->doc;
  264. } else {
  265. xsltTransformError(ctxt, NULL, ctxt->inst,
  266. "Internal error in xsltFlagRVTs(): "
  267. "Cannot retrieve the doc of a namespace node.\n");
  268. return(-1);
  269. }
  270. } else {
  271. doc = cur->doc;
  272. }
  273. if (doc == NULL) {
  274. xsltTransformError(ctxt, NULL, ctxt->inst,
  275. "Internal error in xsltFlagRVTs(): "
  276. "Cannot retrieve the doc of a node.\n");
  277. return(-1);
  278. }
  279. if (doc->name && (doc->name[0] == ' ') &&
  280. doc->psvi != XSLT_RVT_GLOBAL) {
  281. /*
  282. * This is a result tree fragment.
  283. * We store ownership information in the @psvi field.
  284. * TODO: How do we know if this is a doc acquired via the
  285. * document() function?
  286. */
  287. #ifdef WITH_XSLT_DEBUG_VARIABLE
  288. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  289. "Flagging RVT %p: %p -> %p\n", doc, doc->psvi, val));
  290. #endif
  291. if (val == XSLT_RVT_LOCAL) {
  292. if (doc->psvi == XSLT_RVT_FUNC_RESULT)
  293. doc->psvi = XSLT_RVT_LOCAL;
  294. } else if (val == XSLT_RVT_GLOBAL) {
  295. if (doc->psvi != XSLT_RVT_LOCAL) {
  296. xmlGenericError(xmlGenericErrorContext,
  297. "xsltFlagRVTs: Invalid transition %p => GLOBAL\n",
  298. doc->psvi);
  299. doc->psvi = XSLT_RVT_GLOBAL;
  300. return(-1);
  301. }
  302. /* Will be registered as persistant in xsltReleaseLocalRVTs. */
  303. doc->psvi = XSLT_RVT_GLOBAL;
  304. } else if (val == XSLT_RVT_FUNC_RESULT) {
  305. doc->psvi = val;
  306. }
  307. }
  308. }
  309. return(0);
  310. }
  311. /**
  312. * xsltReleaseRVT:
  313. * @ctxt: an XSLT transformation context
  314. * @RVT: a result value tree (Result Tree Fragment)
  315. *
  316. * Either frees the RVT (which is an xmlDoc) or stores
  317. * it in the context's cache for later reuse.
  318. */
  319. void
  320. xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
  321. {
  322. if (RVT == NULL)
  323. return;
  324. if (ctxt && (ctxt->cache->nbRVT < 40)) {
  325. /*
  326. * Store the Result Tree Fragment.
  327. * Free the document info.
  328. */
  329. if (RVT->_private != NULL) {
  330. xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
  331. xmlFree(RVT->_private);
  332. RVT->_private = NULL;
  333. }
  334. /*
  335. * Clear the document tree.
  336. * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
  337. */
  338. if (RVT->children != NULL) {
  339. xmlFreeNodeList(RVT->children);
  340. RVT->children = NULL;
  341. RVT->last = NULL;
  342. }
  343. if (RVT->ids != NULL) {
  344. xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
  345. RVT->ids = NULL;
  346. }
  347. if (RVT->refs != NULL) {
  348. xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
  349. RVT->refs = NULL;
  350. }
  351. /*
  352. * Reset the ownership information.
  353. */
  354. RVT->psvi = NULL;
  355. RVT->next = (xmlNodePtr) ctxt->cache->RVT;
  356. ctxt->cache->RVT = RVT;
  357. ctxt->cache->nbRVT++;
  358. #ifdef XSLT_DEBUG_PROFILE_CACHE
  359. ctxt->cache->dbgCachedRVTs++;
  360. #endif
  361. return;
  362. }
  363. /*
  364. * Free it.
  365. */
  366. if (RVT->_private != NULL) {
  367. xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
  368. xmlFree(RVT->_private);
  369. }
  370. xmlFreeDoc(RVT);
  371. }
  372. /**
  373. * xsltRegisterPersistRVT:
  374. * @ctxt: an XSLT transformation context
  375. * @RVT: a result value tree (Result Tree Fragment)
  376. *
  377. * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
  378. * in the fragment garbage collector.
  379. * The fragment will be freed when the transformation context is
  380. * freed.
  381. *
  382. * Returns 0 in case of success and -1 in case of error.
  383. */
  384. int
  385. xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
  386. {
  387. if ((ctxt == NULL) || (RVT == NULL)) return(-1);
  388. RVT->psvi = XSLT_RVT_GLOBAL;
  389. RVT->prev = NULL;
  390. RVT->next = (xmlNodePtr) ctxt->persistRVT;
  391. if (ctxt->persistRVT != NULL)
  392. ctxt->persistRVT->prev = (xmlNodePtr) RVT;
  393. ctxt->persistRVT = RVT;
  394. return(0);
  395. }
  396. /**
  397. * xsltFreeRVTs:
  398. * @ctxt: an XSLT transformation context
  399. *
  400. * Frees all registered result value trees (Result Tree Fragments)
  401. * of the transformation. Internal function; should not be called
  402. * by user-code.
  403. */
  404. void
  405. xsltFreeRVTs(xsltTransformContextPtr ctxt)
  406. {
  407. xmlDocPtr cur, next;
  408. if (ctxt == NULL)
  409. return;
  410. /*
  411. * Local fragments.
  412. */
  413. cur = ctxt->localRVT;
  414. while (cur != NULL) {
  415. next = (xmlDocPtr) cur->next;
  416. if (cur->_private != NULL) {
  417. xsltFreeDocumentKeys(cur->_private);
  418. xmlFree(cur->_private);
  419. }
  420. xmlFreeDoc(cur);
  421. cur = next;
  422. }
  423. ctxt->localRVT = NULL;
  424. /*
  425. * User-created per-template fragments.
  426. */
  427. cur = ctxt->tmpRVT;
  428. while (cur != NULL) {
  429. next = (xmlDocPtr) cur->next;
  430. if (cur->_private != NULL) {
  431. xsltFreeDocumentKeys(cur->_private);
  432. xmlFree(cur->_private);
  433. }
  434. xmlFreeDoc(cur);
  435. cur = next;
  436. }
  437. ctxt->tmpRVT = NULL;
  438. /*
  439. * Global fragments.
  440. */
  441. cur = ctxt->persistRVT;
  442. while (cur != NULL) {
  443. next = (xmlDocPtr) cur->next;
  444. if (cur->_private != NULL) {
  445. xsltFreeDocumentKeys(cur->_private);
  446. xmlFree(cur->_private);
  447. }
  448. xmlFreeDoc(cur);
  449. cur = next;
  450. }
  451. ctxt->persistRVT = NULL;
  452. }
  453. /************************************************************************
  454. * *
  455. * Module interfaces *
  456. * *
  457. ************************************************************************/
  458. /**
  459. * xsltNewStackElem:
  460. *
  461. * Create a new XSLT ParserContext
  462. *
  463. * Returns the newly allocated xsltParserStackElem or NULL in case of error
  464. */
  465. static xsltStackElemPtr
  466. xsltNewStackElem(xsltTransformContextPtr ctxt)
  467. {
  468. xsltStackElemPtr ret;
  469. /*
  470. * Reuse a stack item from the cache if available.
  471. */
  472. if (ctxt && ctxt->cache->stackItems) {
  473. ret = ctxt->cache->stackItems;
  474. ctxt->cache->stackItems = ret->next;
  475. ret->next = NULL;
  476. ctxt->cache->nbStackItems--;
  477. #ifdef XSLT_DEBUG_PROFILE_CACHE
  478. ctxt->cache->dbgReusedVars++;
  479. #endif
  480. return(ret);
  481. }
  482. ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
  483. if (ret == NULL) {
  484. xsltTransformError(NULL, NULL, NULL,
  485. "xsltNewStackElem : malloc failed\n");
  486. return(NULL);
  487. }
  488. memset(ret, 0, sizeof(xsltStackElem));
  489. ret->context = ctxt;
  490. return(ret);
  491. }
  492. /**
  493. * xsltCopyStackElem:
  494. * @elem: an XSLT stack element
  495. *
  496. * Makes a copy of the stack element
  497. *
  498. * Returns the copy of NULL
  499. */
  500. static xsltStackElemPtr
  501. xsltCopyStackElem(xsltStackElemPtr elem) {
  502. xsltStackElemPtr cur;
  503. cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
  504. if (cur == NULL) {
  505. xsltTransformError(NULL, NULL, NULL,
  506. "xsltCopyStackElem : malloc failed\n");
  507. return(NULL);
  508. }
  509. memset(cur, 0, sizeof(xsltStackElem));
  510. cur->context = elem->context;
  511. cur->name = elem->name;
  512. cur->nameURI = elem->nameURI;
  513. cur->select = elem->select;
  514. cur->tree = elem->tree;
  515. cur->comp = elem->comp;
  516. return(cur);
  517. }
  518. /**
  519. * xsltFreeStackElem:
  520. * @elem: an XSLT stack element
  521. *
  522. * Free up the memory allocated by @elem
  523. */
  524. static void
  525. xsltFreeStackElem(xsltStackElemPtr elem) {
  526. if (elem == NULL)
  527. return;
  528. if (elem->value != NULL)
  529. xmlXPathFreeObject(elem->value);
  530. /*
  531. * Release the list of temporary Result Tree Fragments.
  532. */
  533. if (elem->context) {
  534. xmlDocPtr cur;
  535. while (elem->fragment != NULL) {
  536. cur = elem->fragment;
  537. elem->fragment = (xmlDocPtr) cur->next;
  538. if (cur->psvi == XSLT_RVT_LOCAL) {
  539. xsltReleaseRVT(elem->context, cur);
  540. } else if (cur->psvi == XSLT_RVT_FUNC_RESULT) {
  541. xsltRegisterLocalRVT(elem->context, cur);
  542. cur->psvi = XSLT_RVT_FUNC_RESULT;
  543. } else {
  544. xmlGenericError(xmlGenericErrorContext,
  545. "xsltFreeStackElem: Unexpected RVT flag %p\n",
  546. cur->psvi);
  547. }
  548. }
  549. }
  550. /*
  551. * Cache or free the variable structure.
  552. */
  553. if (elem->context && (elem->context->cache->nbStackItems < 50)) {
  554. /*
  555. * Store the item in the cache.
  556. */
  557. xsltTransformContextPtr ctxt = elem->context;
  558. memset(elem, 0, sizeof(xsltStackElem));
  559. elem->context = ctxt;
  560. elem->next = ctxt->cache->stackItems;
  561. ctxt->cache->stackItems = elem;
  562. ctxt->cache->nbStackItems++;
  563. #ifdef XSLT_DEBUG_PROFILE_CACHE
  564. ctxt->cache->dbgCachedVars++;
  565. #endif
  566. return;
  567. }
  568. xmlFree(elem);
  569. }
  570. static void
  571. xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
  572. xsltFreeStackElem((xsltStackElemPtr) payload);
  573. }
  574. /**
  575. * xsltFreeStackElemList:
  576. * @elem: an XSLT stack element
  577. *
  578. * Free up the memory allocated by @elem
  579. */
  580. void
  581. xsltFreeStackElemList(xsltStackElemPtr elem) {
  582. xsltStackElemPtr next;
  583. while (elem != NULL) {
  584. next = elem->next;
  585. xsltFreeStackElem(elem);
  586. elem = next;
  587. }
  588. }
  589. /**
  590. * xsltStackLookup:
  591. * @ctxt: an XSLT transformation context
  592. * @name: the local part of the name
  593. * @nameURI: the URI part of the name
  594. *
  595. * Locate an element in the stack based on its name.
  596. */
  597. #if 0 /* TODO: Those seem to have been used for debugging. */
  598. static int stack_addr = 0;
  599. static int stack_cmp = 0;
  600. #endif
  601. static xsltStackElemPtr
  602. xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
  603. const xmlChar *nameURI) {
  604. int i;
  605. xsltStackElemPtr cur;
  606. if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
  607. return(NULL);
  608. /*
  609. * Do the lookup from the top of the stack, but
  610. * don't use params being computed in a call-param
  611. * First lookup expects the variable name and URI to
  612. * come from the disctionnary and hence pointer comparison.
  613. */
  614. for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
  615. cur = ctxt->varsTab[i-1];
  616. while (cur != NULL) {
  617. if ((cur->name == name) && (cur->nameURI == nameURI)) {
  618. #if 0
  619. stack_addr++;
  620. #endif
  621. return(cur);
  622. }
  623. cur = cur->next;
  624. }
  625. }
  626. /*
  627. * Redo the lookup with interned string compares
  628. * to avoid string compares.
  629. */
  630. name = xmlDictLookup(ctxt->dict, name, -1);
  631. if (nameURI != NULL)
  632. nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
  633. for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
  634. cur = ctxt->varsTab[i-1];
  635. while (cur != NULL) {
  636. if ((cur->name == name) && (cur->nameURI == nameURI)) {
  637. #if 0
  638. stack_cmp++;
  639. #endif
  640. return(cur);
  641. }
  642. cur = cur->next;
  643. }
  644. }
  645. return(NULL);
  646. }
  647. #ifdef XSLT_REFACTORED
  648. #else
  649. /**
  650. * xsltCheckStackElem:
  651. * @ctxt: xn XSLT transformation context
  652. * @name: the variable name
  653. * @nameURI: the variable namespace URI
  654. *
  655. * Checks whether a variable or param is already defined.
  656. *
  657. * URGENT TODO: Checks for redefinition of vars/params should be
  658. * done only at compilation time.
  659. *
  660. * Returns 1 if variable is present, 2 if param is present, 3 if this
  661. * is an inherited param, 0 if not found, -1 in case of failure.
  662. */
  663. static int
  664. xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
  665. const xmlChar *nameURI) {
  666. xsltStackElemPtr cur;
  667. if ((ctxt == NULL) || (name == NULL))
  668. return(-1);
  669. cur = xsltStackLookup(ctxt, name, nameURI);
  670. if (cur == NULL)
  671. return(0);
  672. if (cur->comp != NULL) {
  673. if (cur->comp->type == XSLT_FUNC_WITHPARAM)
  674. return(3);
  675. else if (cur->comp->type == XSLT_FUNC_PARAM)
  676. return(2);
  677. }
  678. return(1);
  679. }
  680. #endif /* XSLT_REFACTORED */
  681. /**
  682. * xsltAddStackElem:
  683. * @ctxt: xn XSLT transformation context
  684. * @elem: a stack element
  685. *
  686. * Push an element (or list) onto the stack.
  687. * In case of a list, each member will be pushed into
  688. * a seperate slot; i.e. there's always 1 stack entry for
  689. * 1 stack element.
  690. *
  691. * Returns 0 in case of success, -1 in case of failure.
  692. */
  693. static int
  694. xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
  695. {
  696. if ((ctxt == NULL) || (elem == NULL))
  697. return(-1);
  698. do {
  699. if (ctxt->varsMax == 0) {
  700. ctxt->varsMax = 10;
  701. ctxt->varsTab =
  702. (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
  703. sizeof(ctxt->varsTab[0]));
  704. if (ctxt->varsTab == NULL) {
  705. xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
  706. return (-1);
  707. }
  708. }
  709. if (ctxt->varsNr >= ctxt->varsMax) {
  710. ctxt->varsMax *= 2;
  711. ctxt->varsTab =
  712. (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
  713. ctxt->varsMax *
  714. sizeof(ctxt->varsTab[0]));
  715. if (ctxt->varsTab == NULL) {
  716. xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
  717. return (-1);
  718. }
  719. }
  720. ctxt->varsTab[ctxt->varsNr++] = elem;
  721. ctxt->vars = elem;
  722. elem = elem->next;
  723. } while (elem != NULL);
  724. return(0);
  725. }
  726. /**
  727. * xsltAddStackElemList:
  728. * @ctxt: xn XSLT transformation context
  729. * @elems: a stack element list
  730. *
  731. * Push an element list onto the stack.
  732. *
  733. * Returns 0 in case of success, -1 in case of failure.
  734. */
  735. int
  736. xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
  737. {
  738. return(xsltAddStackElem(ctxt, elems));
  739. }
  740. /************************************************************************
  741. * *
  742. * Module interfaces *
  743. * *
  744. ************************************************************************/
  745. /**
  746. * xsltEvalVariable:
  747. * @ctxt: the XSLT transformation context
  748. * @variable: the variable or parameter item
  749. * @comp: the compiled XSLT instruction
  750. *
  751. * Evaluate a variable value.
  752. *
  753. * Returns the XPath Object value or NULL in case of error
  754. */
  755. static xmlXPathObjectPtr
  756. xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
  757. xsltStylePreCompPtr castedComp)
  758. {
  759. #ifdef XSLT_REFACTORED
  760. xsltStyleItemVariablePtr comp =
  761. (xsltStyleItemVariablePtr) castedComp;
  762. #else
  763. xsltStylePreCompPtr comp = castedComp;
  764. #endif
  765. xmlXPathObjectPtr result = NULL;
  766. xmlNodePtr oldInst;
  767. if ((ctxt == NULL) || (variable == NULL))
  768. return(NULL);
  769. /*
  770. * A variable or parameter are evaluated on demand; thus the
  771. * context (of XSLT and XPath) need to be temporarily adjusted and
  772. * restored on exit.
  773. */
  774. oldInst = ctxt->inst;
  775. #ifdef WITH_XSLT_DEBUG_VARIABLE
  776. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  777. "Evaluating variable '%s'\n", variable->name));
  778. #endif
  779. if (variable->select != NULL) {
  780. xmlXPathCompExprPtr xpExpr = NULL;
  781. xmlDocPtr oldXPDoc;
  782. xmlNodePtr oldXPContextNode;
  783. int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
  784. xmlNsPtr *oldXPNamespaces;
  785. xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
  786. xsltStackElemPtr oldVar = ctxt->contextVariable;
  787. if ((comp != NULL) && (comp->comp != NULL)) {
  788. xpExpr = comp->comp;
  789. } else {
  790. xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, variable->select);
  791. }
  792. if (xpExpr == NULL)
  793. return(NULL);
  794. /*
  795. * Save context states.
  796. */
  797. oldXPDoc = xpctxt->doc;
  798. oldXPContextNode = xpctxt->node;
  799. oldXPProximityPosition = xpctxt->proximityPosition;
  800. oldXPContextSize = xpctxt->contextSize;
  801. oldXPNamespaces = xpctxt->namespaces;
  802. oldXPNsNr = xpctxt->nsNr;
  803. xpctxt->node = ctxt->node;
  804. /*
  805. * OPTIMIZE TODO: Lame try to set the context doc.
  806. * Get rid of this somehow in xpath.c.
  807. */
  808. if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
  809. ctxt->node->doc)
  810. xpctxt->doc = ctxt->node->doc;
  811. /*
  812. * BUG TODO: The proximity position and the context size will
  813. * potentially be wrong.
  814. * Example:
  815. * <xsl:template select="foo">
  816. * <xsl:variable name="pos" select="position()"/>
  817. * <xsl:for-each select="bar">
  818. * <xsl:value-of select="$pos"/>
  819. * </xsl:for-each>
  820. * </xsl:template>
  821. * Here the proximity position and context size are changed
  822. * to the context of <xsl:for-each select="bar">, but
  823. * the variable needs to be evaluated in the context of
  824. * <xsl:template select="foo">.
  825. */
  826. if (comp != NULL) {
  827. #ifdef XSLT_REFACTORED
  828. if (comp->inScopeNs != NULL) {
  829. xpctxt->namespaces = comp->inScopeNs->list;
  830. xpctxt->nsNr = comp->inScopeNs->xpathNumber;
  831. } else {
  832. xpctxt->namespaces = NULL;
  833. xpctxt->nsNr = 0;
  834. }
  835. #else
  836. xpctxt->namespaces = comp->nsList;
  837. xpctxt->nsNr = comp->nsNr;
  838. #endif
  839. } else {
  840. xpctxt->namespaces = NULL;
  841. xpctxt->nsNr = 0;
  842. }
  843. /*
  844. * We need to mark that we are "selecting" a var's value;
  845. * if any tree fragments are created inside the expression,
  846. * then those need to be stored inside the variable; otherwise
  847. * we'll eventually free still referenced fragments, before
  848. * we leave the scope of the variable.
  849. */
  850. ctxt->contextVariable = variable;
  851. variable->flags |= XSLT_VAR_IN_SELECT;
  852. result = xmlXPathCompiledEval(xpExpr, xpctxt);
  853. variable->flags ^= XSLT_VAR_IN_SELECT;
  854. /*
  855. * Restore Context states.
  856. */
  857. ctxt->contextVariable = oldVar;
  858. xpctxt->doc = oldXPDoc;
  859. xpctxt->node = oldXPContextNode;
  860. xpctxt->contextSize = oldXPContextSize;
  861. xpctxt->proximityPosition = oldXPProximityPosition;
  862. xpctxt->namespaces = oldXPNamespaces;
  863. xpctxt->nsNr = oldXPNsNr;
  864. if ((comp == NULL) || (comp->comp == NULL))
  865. xmlXPathFreeCompExpr(xpExpr);
  866. if (result == NULL) {
  867. xsltTransformError(ctxt, NULL,
  868. (comp != NULL) ? comp->inst : NULL,
  869. "Failed to evaluate the expression of variable '%s'.\n",
  870. variable->name);
  871. ctxt->state = XSLT_STATE_STOPPED;
  872. #ifdef WITH_XSLT_DEBUG_VARIABLE
  873. #ifdef LIBXML_DEBUG_ENABLED
  874. } else {
  875. if ((xsltGenericDebugContext == stdout) ||
  876. (xsltGenericDebugContext == stderr))
  877. xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
  878. result, 0);
  879. #endif
  880. #endif
  881. }
  882. } else {
  883. if (variable->tree == NULL) {
  884. result = xmlXPathNewCString("");
  885. } else {
  886. if (variable->tree) {
  887. xmlDocPtr container;
  888. xmlNodePtr oldInsert;
  889. xmlDocPtr oldOutput;
  890. xsltStackElemPtr oldVar = ctxt->contextVariable;
  891. /*
  892. * Generate a result tree fragment.
  893. */
  894. container = xsltCreateRVT(ctxt);
  895. if (container == NULL)
  896. goto error;
  897. /*
  898. * NOTE: Local Result Tree Fragments of params/variables
  899. * are not registered globally anymore; the life-time
  900. * is not directly dependant of the param/variable itself.
  901. *
  902. * OLD: xsltRegisterTmpRVT(ctxt, container);
  903. */
  904. /*
  905. * Attach the Result Tree Fragment to the variable;
  906. * when the variable is freed, it will also free
  907. * the Result Tree Fragment.
  908. */
  909. variable->fragment = container;
  910. container->psvi = XSLT_RVT_LOCAL;
  911. oldOutput = ctxt->output;
  912. oldInsert = ctxt->insert;
  913. ctxt->output = container;
  914. ctxt->insert = (xmlNodePtr) container;
  915. ctxt->contextVariable = variable;
  916. /*
  917. * Process the sequence constructor (variable->tree).
  918. * The resulting tree will be held by @container.
  919. */
  920. xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
  921. NULL, NULL);
  922. ctxt->contextVariable = oldVar;
  923. ctxt->insert = oldInsert;
  924. ctxt->output = oldOutput;
  925. result = xmlXPathNewValueTree((xmlNodePtr) container);
  926. }
  927. if (result == NULL) {
  928. result = xmlXPathNewCString("");
  929. } else {
  930. /*
  931. * Freeing is not handled there anymore.
  932. * QUESTION TODO: What does the above comment mean?
  933. */
  934. result->boolval = 0;
  935. }
  936. #ifdef WITH_XSLT_DEBUG_VARIABLE
  937. #ifdef LIBXML_DEBUG_ENABLED
  938. if ((xsltGenericDebugContext == stdout) ||
  939. (xsltGenericDebugContext == stderr))
  940. xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
  941. result, 0);
  942. #endif
  943. #endif
  944. }
  945. }
  946. error:
  947. ctxt->inst = oldInst;
  948. return(result);
  949. }
  950. /**
  951. * xsltEvalGlobalVariable:
  952. * @elem: the variable or parameter
  953. * @ctxt: the XSLT transformation context
  954. *
  955. * Evaluates a the value of a global xsl:variable or
  956. * xsl:param declaration.
  957. *
  958. * Returns the XPath Object value or NULL in case of error
  959. */
  960. static xmlXPathObjectPtr
  961. xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
  962. {
  963. xmlXPathObjectPtr result = NULL;
  964. xmlNodePtr oldInst;
  965. const xmlChar* oldVarName;
  966. #ifdef XSLT_REFACTORED
  967. xsltStyleBasicItemVariablePtr comp;
  968. #else
  969. xsltStylePreCompPtr comp;
  970. #endif
  971. if ((ctxt == NULL) || (elem == NULL))
  972. return(NULL);
  973. if (elem->computed)
  974. return(elem->value);
  975. #ifdef WITH_XSLT_DEBUG_VARIABLE
  976. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  977. "Evaluating global variable %s\n", elem->name));
  978. #endif
  979. #ifdef WITH_DEBUGGER
  980. if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
  981. elem->comp && elem->comp->inst)
  982. xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
  983. #endif
  984. oldInst = ctxt->inst;
  985. #ifdef XSLT_REFACTORED
  986. comp = (xsltStyleBasicItemVariablePtr) elem->comp;
  987. #else
  988. comp = elem->comp;
  989. #endif
  990. oldVarName = elem->name;
  991. elem->name = xsltComputingGlobalVarMarker;
  992. /*
  993. * OPTIMIZE TODO: We should consider instantiating global vars/params
  994. * on-demand. The vars/params don't need to be evaluated if never
  995. * called; and in the case of global params, if values for such params
  996. * are provided by the user.
  997. */
  998. if (elem->select != NULL) {
  999. xmlXPathCompExprPtr xpExpr = NULL;
  1000. xmlDocPtr oldXPDoc;
  1001. xmlNodePtr oldXPContextNode;
  1002. int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
  1003. xmlNsPtr *oldXPNamespaces;
  1004. xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
  1005. if ((comp != NULL) && (comp->comp != NULL)) {
  1006. xpExpr = comp->comp;
  1007. } else {
  1008. xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, elem->select);
  1009. }
  1010. if (xpExpr == NULL)
  1011. goto error;
  1012. if (comp != NULL)
  1013. ctxt->inst = comp->inst;
  1014. else
  1015. ctxt->inst = NULL;
  1016. /*
  1017. * SPEC XSLT 1.0:
  1018. * "At top-level, the expression or template specifying the
  1019. * variable value is evaluated with the same context as that used
  1020. * to process the root node of the source document: the current
  1021. * node is the root node of the source document and the current
  1022. * node list is a list containing just the root node of the source
  1023. * document."
  1024. */
  1025. /*
  1026. * Save context states.
  1027. */
  1028. oldXPDoc = xpctxt->doc;
  1029. oldXPContextNode = xpctxt->node;
  1030. oldXPProximityPosition = xpctxt->proximityPosition;
  1031. oldXPContextSize = xpctxt->contextSize;
  1032. oldXPNamespaces = xpctxt->namespaces;
  1033. oldXPNsNr = xpctxt->nsNr;
  1034. xpctxt->node = ctxt->initialContextNode;
  1035. xpctxt->doc = ctxt->initialContextDoc;
  1036. xpctxt->contextSize = 1;
  1037. xpctxt->proximityPosition = 1;
  1038. if (comp != NULL) {
  1039. #ifdef XSLT_REFACTORED
  1040. if (comp->inScopeNs != NULL) {
  1041. xpctxt->namespaces = comp->inScopeNs->list;
  1042. xpctxt->nsNr = comp->inScopeNs->xpathNumber;
  1043. } else {
  1044. xpctxt->namespaces = NULL;
  1045. xpctxt->nsNr = 0;
  1046. }
  1047. #else
  1048. xpctxt->namespaces = comp->nsList;
  1049. xpctxt->nsNr = comp->nsNr;
  1050. #endif
  1051. } else {
  1052. xpctxt->namespaces = NULL;
  1053. xpctxt->nsNr = 0;
  1054. }
  1055. result = xmlXPathCompiledEval(xpExpr, xpctxt);
  1056. /*
  1057. * Restore Context states.
  1058. */
  1059. xpctxt->doc = oldXPDoc;
  1060. xpctxt->node = oldXPContextNode;
  1061. xpctxt->contextSize = oldXPContextSize;
  1062. xpctxt->proximityPosition = oldXPProximityPosition;
  1063. xpctxt->namespaces = oldXPNamespaces;
  1064. xpctxt->nsNr = oldXPNsNr;
  1065. if ((comp == NULL) || (comp->comp == NULL))
  1066. xmlXPathFreeCompExpr(xpExpr);
  1067. if (result == NULL) {
  1068. if (comp == NULL)
  1069. xsltTransformError(ctxt, NULL, NULL,
  1070. "Evaluating global variable %s failed\n", elem->name);
  1071. else
  1072. xsltTransformError(ctxt, NULL, comp->inst,
  1073. "Evaluating global variable %s failed\n", elem->name);
  1074. ctxt->state = XSLT_STATE_STOPPED;
  1075. goto error;
  1076. }
  1077. /*
  1078. * Mark all RVTs that are referenced from result as part
  1079. * of this variable so they won't be freed too early.
  1080. */
  1081. xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL);
  1082. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1083. #ifdef LIBXML_DEBUG_ENABLED
  1084. if ((xsltGenericDebugContext == stdout) ||
  1085. (xsltGenericDebugContext == stderr))
  1086. xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
  1087. result, 0);
  1088. #endif
  1089. #endif
  1090. } else {
  1091. if (elem->tree == NULL) {
  1092. result = xmlXPathNewCString("");
  1093. } else {
  1094. xmlDocPtr container;
  1095. xmlNodePtr oldInsert;
  1096. xmlDocPtr oldOutput, oldXPDoc;
  1097. /*
  1098. * Generate a result tree fragment.
  1099. */
  1100. container = xsltCreateRVT(ctxt);
  1101. if (container == NULL)
  1102. goto error;
  1103. /*
  1104. * Let the lifetime of the tree fragment be handled by
  1105. * the Libxslt's garbage collector.
  1106. */
  1107. xsltRegisterPersistRVT(ctxt, container);
  1108. oldOutput = ctxt->output;
  1109. oldInsert = ctxt->insert;
  1110. oldXPDoc = ctxt->xpathCtxt->doc;
  1111. ctxt->output = container;
  1112. ctxt->insert = (xmlNodePtr) container;
  1113. ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
  1114. /*
  1115. * Process the sequence constructor.
  1116. */
  1117. xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
  1118. ctxt->xpathCtxt->doc = oldXPDoc;
  1119. ctxt->insert = oldInsert;
  1120. ctxt->output = oldOutput;
  1121. result = xmlXPathNewValueTree((xmlNodePtr) container);
  1122. if (result == NULL) {
  1123. result = xmlXPathNewCString("");
  1124. } else {
  1125. result->boolval = 0; /* Freeing is not handled there anymore */
  1126. }
  1127. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1128. #ifdef LIBXML_DEBUG_ENABLED
  1129. if ((xsltGenericDebugContext == stdout) ||
  1130. (xsltGenericDebugContext == stderr))
  1131. xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
  1132. result, 0);
  1133. #endif
  1134. #endif
  1135. }
  1136. }
  1137. error:
  1138. elem->name = oldVarName;
  1139. ctxt->inst = oldInst;
  1140. if (result != NULL) {
  1141. elem->value = result;
  1142. elem->computed = 1;
  1143. }
  1144. return(result);
  1145. }
  1146. static void
  1147. xsltEvalGlobalVariableWrapper(void *payload, void *data,
  1148. const xmlChar *name ATTRIBUTE_UNUSED) {
  1149. xsltEvalGlobalVariable((xsltStackElemPtr) payload,
  1150. (xsltTransformContextPtr) data);
  1151. }
  1152. /**
  1153. * xsltEvalGlobalVariables:
  1154. * @ctxt: the XSLT transformation context
  1155. *
  1156. * Evaluates all global variables and parameters of a stylesheet.
  1157. * For internal use only. This is called at start of a transformation.
  1158. *
  1159. * Returns 0 in case of success, -1 in case of error
  1160. */
  1161. int
  1162. xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
  1163. xsltStackElemPtr elem;
  1164. xsltStylesheetPtr style;
  1165. if ((ctxt == NULL) || (ctxt->document == NULL))
  1166. return(-1);
  1167. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1168. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1169. "Registering global variables\n"));
  1170. #endif
  1171. /*
  1172. * Walk the list from the stylesheets and populate the hash table
  1173. */
  1174. style = ctxt->style;
  1175. while (style != NULL) {
  1176. elem = style->variables;
  1177. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1178. if ((style->doc != NULL) && (style->doc->URL != NULL)) {
  1179. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1180. "Registering global variables from %s\n",
  1181. style->doc->URL));
  1182. }
  1183. #endif
  1184. while (elem != NULL) {
  1185. xsltStackElemPtr def;
  1186. /*
  1187. * Global variables are stored in the variables pool.
  1188. */
  1189. def = (xsltStackElemPtr)
  1190. xmlHashLookup2(ctxt->globalVars,
  1191. elem->name, elem->nameURI);
  1192. if (def == NULL) {
  1193. def = xsltCopyStackElem(elem);
  1194. xmlHashAddEntry2(ctxt->globalVars,
  1195. elem->name, elem->nameURI, def);
  1196. } else if ((elem->comp != NULL) &&
  1197. (elem->comp->type == XSLT_FUNC_VARIABLE)) {
  1198. /*
  1199. * Redefinition of variables from a different stylesheet
  1200. * should not generate a message.
  1201. */
  1202. if ((elem->comp->inst != NULL) &&
  1203. (def->comp != NULL) && (def->comp->inst != NULL) &&
  1204. (elem->comp->inst->doc == def->comp->inst->doc))
  1205. {
  1206. xsltTransformError(ctxt, style, elem->comp->inst,
  1207. "Global variable %s already defined\n", elem->name);
  1208. if (style != NULL) style->errors++;
  1209. }
  1210. }
  1211. elem = elem->next;
  1212. }
  1213. style = xsltNextImport(style);
  1214. }
  1215. /*
  1216. * This part does the actual evaluation
  1217. */
  1218. xmlHashScan(ctxt->globalVars, xsltEvalGlobalVariableWrapper, ctxt);
  1219. return(0);
  1220. }
  1221. /**
  1222. * xsltRegisterGlobalVariable:
  1223. * @style: the XSLT transformation context
  1224. * @name: the variable name
  1225. * @ns_uri: the variable namespace URI
  1226. * @sel: the expression which need to be evaluated to generate a value
  1227. * @tree: the subtree if sel is NULL
  1228. * @comp: the precompiled value
  1229. * @value: the string value if available
  1230. *
  1231. * Register a new variable value. If @value is NULL it unregisters
  1232. * the variable
  1233. *
  1234. * Returns 0 in case of success, -1 in case of error
  1235. */
  1236. static int
  1237. xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
  1238. const xmlChar *ns_uri, const xmlChar *sel,
  1239. xmlNodePtr tree, xsltStylePreCompPtr comp,
  1240. const xmlChar *value) {
  1241. xsltStackElemPtr elem, tmp;
  1242. if (style == NULL)
  1243. return(-1);
  1244. if (name == NULL)
  1245. return(-1);
  1246. if (comp == NULL)
  1247. return(-1);
  1248. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1249. if (comp->type == XSLT_FUNC_PARAM)
  1250. xsltGenericDebug(xsltGenericDebugContext,
  1251. "Defining global param %s\n", name);
  1252. else
  1253. xsltGenericDebug(xsltGenericDebugContext,
  1254. "Defining global variable %s\n", name);
  1255. #endif
  1256. elem = xsltNewStackElem(NULL);
  1257. if (elem == NULL)
  1258. return(-1);
  1259. elem->comp = comp;
  1260. elem->name = xmlDictLookup(style->dict, name, -1);
  1261. elem->select = xmlDictLookup(style->dict, sel, -1);
  1262. if (ns_uri)
  1263. elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
  1264. elem->tree = tree;
  1265. tmp = style->variables;
  1266. if (tmp == NULL) {
  1267. elem->next = NULL;
  1268. style->variables = elem;
  1269. } else {
  1270. while (tmp != NULL) {
  1271. if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
  1272. (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
  1273. (xmlStrEqual(elem->name, tmp->name)) &&
  1274. ((elem->nameURI == tmp->nameURI) ||
  1275. (xmlStrEqual(elem->nameURI, tmp->nameURI))))
  1276. {
  1277. xsltTransformError(NULL, style, comp->inst,
  1278. "redefinition of global variable %s\n", elem->name);
  1279. style->errors++;
  1280. }
  1281. if (tmp->next == NULL)
  1282. break;
  1283. tmp = tmp->next;
  1284. }
  1285. elem->next = NULL;
  1286. tmp->next = elem;
  1287. }
  1288. if (value != NULL) {
  1289. elem->computed = 1;
  1290. elem->value = xmlXPathNewString(value);
  1291. }
  1292. return(0);
  1293. }
  1294. /**
  1295. * xsltProcessUserParamInternal
  1296. *
  1297. * @ctxt: the XSLT transformation context
  1298. * @name: a null terminated parameter name
  1299. * @value: a null terminated value (may be an XPath expression)
  1300. * @eval: 0 to treat the value literally, else evaluate as XPath expression
  1301. *
  1302. * If @eval is 0 then @value is treated literally and is stored in the global
  1303. * parameter/variable table without any change.
  1304. *
  1305. * Uf @eval is 1 then @value is treated as an XPath expression and is
  1306. * evaluated. In this case, if you want to pass a string which will be
  1307. * interpreted literally then it must be enclosed in single or double quotes.
  1308. * If the string contains single quotes (double quotes) then it cannot be
  1309. * enclosed single quotes (double quotes). If the string which you want to
  1310. * be treated literally contains both single and double quotes (e.g. Meet
  1311. * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
  1312. * quoting character. You cannot use &apos; or &quot; inside the string
  1313. * because the replacement of character entities with their equivalents is
  1314. * done at a different stage of processing. The solution is to call
  1315. * xsltQuoteUserParams or xsltQuoteOneUserParam.
  1316. *
  1317. * This needs to be done on parsed stylesheets before starting to apply
  1318. * transformations. Normally this will be called (directly or indirectly)
  1319. * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
  1320. * or xsltQuoteOneUserParam.
  1321. *
  1322. * Returns 0 in case of success, -1 in case of error
  1323. */
  1324. static
  1325. int
  1326. xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
  1327. const xmlChar * name,
  1328. const xmlChar * value,
  1329. int eval) {
  1330. xsltStylesheetPtr style;
  1331. const xmlChar *prefix;
  1332. const xmlChar *href;
  1333. xmlXPathCompExprPtr xpExpr;
  1334. xmlXPathObjectPtr result;
  1335. xsltStackElemPtr elem;
  1336. int res;
  1337. void *res_ptr;
  1338. if (ctxt == NULL)
  1339. return(-1);
  1340. if (name == NULL)
  1341. return(0);
  1342. if (value == NULL)
  1343. return(0);
  1344. style = ctxt->style;
  1345. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1346. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1347. "Evaluating user parameter %s=%s\n", name, value));
  1348. #endif
  1349. /*
  1350. * Name lookup
  1351. */
  1352. href = NULL;
  1353. if (name[0] == '{') {
  1354. int len = 0;
  1355. while ((name[len] != 0) && (name[len] != '}')) len++;
  1356. if (name[len] == 0) {
  1357. xsltTransformError(ctxt, style, NULL,
  1358. "user param : malformed parameter name : %s\n", name);
  1359. } else {
  1360. href = xmlDictLookup(ctxt->dict, &name[1], len-1);
  1361. name = xmlDictLookup(ctxt->dict, &name[len + 1], -1);
  1362. }
  1363. }
  1364. else {
  1365. name = xsltSplitQName(ctxt->dict, name, &prefix);
  1366. if (prefix != NULL) {
  1367. xmlNsPtr ns;
  1368. ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
  1369. prefix);
  1370. if (ns == NULL) {
  1371. xsltTransformError(ctxt, style, NULL,
  1372. "user param : no namespace bound to prefix %s\n", prefix);
  1373. href = NULL;
  1374. } else {
  1375. href = ns->href;
  1376. }
  1377. }
  1378. }
  1379. if (name == NULL)
  1380. return (-1);
  1381. res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
  1382. if (res_ptr != 0) {
  1383. xsltTransformError(ctxt, style, NULL,
  1384. "Global parameter %s already defined\n", name);
  1385. }
  1386. if (ctxt->globalVars == NULL)
  1387. ctxt->globalVars = xmlHashCreate(20);
  1388. /*
  1389. * do not overwrite variables with parameters from the command line
  1390. */
  1391. while (style != NULL) {
  1392. elem = ctxt->style->variables;
  1393. while (elem != NULL) {
  1394. if ((elem->comp != NULL) &&
  1395. (elem->comp->type == XSLT_FUNC_VARIABLE) &&
  1396. (xmlStrEqual(elem->name, name)) &&
  1397. (xmlStrEqual(elem->nameURI, href))) {
  1398. return(0);
  1399. }
  1400. elem = elem->next;
  1401. }
  1402. style = xsltNextImport(style);
  1403. }
  1404. style = ctxt->style;
  1405. elem = NULL;
  1406. /*
  1407. * Do the evaluation if @eval is non-zero.
  1408. */
  1409. result = NULL;
  1410. if (eval != 0) {
  1411. xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, value);
  1412. if (xpExpr != NULL) {
  1413. xmlDocPtr oldXPDoc;
  1414. xmlNodePtr oldXPContextNode;
  1415. int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
  1416. xmlNsPtr *oldXPNamespaces;
  1417. xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
  1418. /*
  1419. * Save context states.
  1420. */
  1421. oldXPDoc = xpctxt->doc;
  1422. oldXPContextNode = xpctxt->node;
  1423. oldXPProximityPosition = xpctxt->proximityPosition;
  1424. oldXPContextSize = xpctxt->contextSize;
  1425. oldXPNamespaces = xpctxt->namespaces;
  1426. oldXPNsNr = xpctxt->nsNr;
  1427. /*
  1428. * SPEC XSLT 1.0:
  1429. * "At top-level, the expression or template specifying the
  1430. * variable value is evaluated with the same context as that used
  1431. * to process the root node of the source document: the current
  1432. * node is the root node of the source document and the current
  1433. * node list is a list containing just the root node of the source
  1434. * document."
  1435. */
  1436. xpctxt->doc = ctxt->initialContextDoc;
  1437. xpctxt->node = ctxt->initialContextNode;
  1438. xpctxt->contextSize = 1;
  1439. xpctxt->proximityPosition = 1;
  1440. /*
  1441. * There is really no in scope namespace for parameters on the
  1442. * command line.
  1443. */
  1444. xpctxt->namespaces = NULL;
  1445. xpctxt->nsNr = 0;
  1446. result = xmlXPathCompiledEval(xpExpr, xpctxt);
  1447. /*
  1448. * Restore Context states.
  1449. */
  1450. xpctxt->doc = oldXPDoc;
  1451. xpctxt->node = oldXPContextNode;
  1452. xpctxt->contextSize = oldXPContextSize;
  1453. xpctxt->proximityPosition = oldXPProximityPosition;
  1454. xpctxt->namespaces = oldXPNamespaces;
  1455. xpctxt->nsNr = oldXPNsNr;
  1456. xmlXPathFreeCompExpr(xpExpr);
  1457. }
  1458. if (result == NULL) {
  1459. xsltTransformError(ctxt, style, NULL,
  1460. "Evaluating user parameter %s failed\n", name);
  1461. ctxt->state = XSLT_STATE_STOPPED;
  1462. return(-1);
  1463. }
  1464. }
  1465. /*
  1466. * If @eval is 0 then @value is to be taken literally and result is NULL
  1467. *
  1468. * If @eval is not 0, then @value is an XPath expression and has been
  1469. * successfully evaluated and result contains the resulting value and
  1470. * is not NULL.
  1471. *
  1472. * Now create an xsltStackElemPtr for insertion into the context's
  1473. * global variable/parameter hash table.
  1474. */
  1475. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1476. #ifdef LIBXML_DEBUG_ENABLED
  1477. if ((xsltGenericDebugContext == stdout) ||
  1478. (xsltGenericDebugContext == stderr))
  1479. xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
  1480. result, 0);
  1481. #endif
  1482. #endif
  1483. elem = xsltNewStackElem(NULL);
  1484. if (elem != NULL) {
  1485. elem->name = name;
  1486. elem->select = xmlDictLookup(ctxt->dict, value, -1);
  1487. if (href != NULL)
  1488. elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
  1489. elem->tree = NULL;
  1490. elem->computed = 1;
  1491. if (eval == 0) {
  1492. elem->value = xmlXPathNewString(value);
  1493. }
  1494. else {
  1495. elem->value = result;
  1496. }
  1497. }
  1498. /*
  1499. * Global parameters are stored in the XPath context variables pool.
  1500. */
  1501. res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
  1502. if (res != 0) {
  1503. xsltFreeStackElem(elem);
  1504. xsltTransformError(ctxt, style, NULL,
  1505. "Global parameter %s already defined\n", name);
  1506. }
  1507. return(0);
  1508. }
  1509. /**
  1510. * xsltEvalUserParams:
  1511. *
  1512. * @ctxt: the XSLT transformation context
  1513. * @params: a NULL terminated array of parameters name/value tuples
  1514. *
  1515. * Evaluate the global variables of a stylesheet. This needs to be
  1516. * done on parsed stylesheets before starting to apply transformations.
  1517. * Each of the parameters is evaluated as an XPath expression and stored
  1518. * in the global variables/parameter hash table. If you want your
  1519. * parameter used literally, use xsltQuoteUserParams.
  1520. *
  1521. * Returns 0 in case of success, -1 in case of error
  1522. */
  1523. int
  1524. xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
  1525. int indx = 0;
  1526. const xmlChar *name;
  1527. const xmlChar *value;
  1528. if (params == NULL)
  1529. return(0);
  1530. while (params[indx] != NULL) {
  1531. name = (const xmlChar *) params[indx++];
  1532. value = (const xmlChar *) params[indx++];
  1533. if (xsltEvalOneUserParam(ctxt, name, value) != 0)
  1534. return(-1);
  1535. }
  1536. return 0;
  1537. }
  1538. /**
  1539. * xsltQuoteUserParams:
  1540. *
  1541. * @ctxt: the XSLT transformation context
  1542. * @params: a NULL terminated arry of parameters names/values tuples
  1543. *
  1544. * Similar to xsltEvalUserParams, but the values are treated literally and
  1545. * are * *not* evaluated as XPath expressions. This should be done on parsed
  1546. * stylesheets before starting to apply transformations.
  1547. *
  1548. * Returns 0 in case of success, -1 in case of error.
  1549. */
  1550. int
  1551. xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
  1552. int indx = 0;
  1553. const xmlChar *name;
  1554. const xmlChar *value;
  1555. if (params == NULL)
  1556. return(0);
  1557. while (params[indx] != NULL) {
  1558. name = (const xmlChar *) params[indx++];
  1559. value = (const xmlChar *) params[indx++];
  1560. if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
  1561. return(-1);
  1562. }
  1563. return 0;
  1564. }
  1565. /**
  1566. * xsltEvalOneUserParam:
  1567. * @ctxt: the XSLT transformation context
  1568. * @name: a null terminated string giving the name of the parameter
  1569. * @value: a null terminated string giving the XPath expression to be evaluated
  1570. *
  1571. * This is normally called from xsltEvalUserParams to process a single
  1572. * parameter from a list of parameters. The @value is evaluated as an
  1573. * XPath expression and the result is stored in the context's global
  1574. * variable/parameter hash table.
  1575. *
  1576. * To have a parameter treated literally (not as an XPath expression)
  1577. * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
  1578. * details see description of xsltProcessOneUserParamInternal.
  1579. *
  1580. * Returns 0 in case of success, -1 in case of error.
  1581. */
  1582. int
  1583. xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
  1584. const xmlChar * name,
  1585. const xmlChar * value) {
  1586. return xsltProcessUserParamInternal(ctxt, name, value,
  1587. 1 /* xpath eval ? */);
  1588. }
  1589. /**
  1590. * xsltQuoteOneUserParam:
  1591. * @ctxt: the XSLT transformation context
  1592. * @name: a null terminated string giving the name of the parameter
  1593. * @value: a null terminated string giving the parameter value
  1594. *
  1595. * This is normally called from xsltQuoteUserParams to process a single
  1596. * parameter from a list of parameters. The @value is stored in the
  1597. * context's global variable/parameter hash table.
  1598. *
  1599. * Returns 0 in case of success, -1 in case of error.
  1600. */
  1601. int
  1602. xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
  1603. const xmlChar * name,
  1604. const xmlChar * value) {
  1605. return xsltProcessUserParamInternal(ctxt, name, value,
  1606. 0 /* xpath eval ? */);
  1607. }
  1608. /**
  1609. * xsltBuildVariable:
  1610. * @ctxt: the XSLT transformation context
  1611. * @comp: the precompiled form
  1612. * @tree: the tree if select is NULL
  1613. *
  1614. * Computes a new variable value.
  1615. *
  1616. * Returns the xsltStackElemPtr or NULL in case of error
  1617. */
  1618. static xsltStackElemPtr
  1619. xsltBuildVariable(xsltTransformContextPtr ctxt,
  1620. xsltStylePreCompPtr castedComp,
  1621. xmlNodePtr tree)
  1622. {
  1623. #ifdef XSLT_REFACTORED
  1624. xsltStyleBasicItemVariablePtr comp =
  1625. (xsltStyleBasicItemVariablePtr) castedComp;
  1626. #else
  1627. xsltStylePreCompPtr comp = castedComp;
  1628. #endif
  1629. xsltStackElemPtr elem;
  1630. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1631. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1632. "Building variable %s", comp->name));
  1633. if (comp->select != NULL)
  1634. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1635. " select %s", comp->select));
  1636. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
  1637. #endif
  1638. elem = xsltNewStackElem(ctxt);
  1639. if (elem == NULL)
  1640. return(NULL);
  1641. elem->comp = (xsltStylePreCompPtr) comp;
  1642. elem->name = comp->name;
  1643. elem->select = comp->select;
  1644. elem->nameURI = comp->ns;
  1645. elem->tree = tree;
  1646. elem->value = xsltEvalVariable(ctxt, elem,
  1647. (xsltStylePreCompPtr) comp);
  1648. elem->computed = 1;
  1649. return(elem);
  1650. }
  1651. /**
  1652. * xsltRegisterVariable:
  1653. * @ctxt: the XSLT transformation context
  1654. * @comp: the compiled XSLT-variable (or param) instruction
  1655. * @tree: the tree if select is NULL
  1656. * @isParam: indicates if this is a parameter
  1657. *
  1658. * Computes and registers a new variable.
  1659. *
  1660. * Returns 0 in case of success, -1 in case of error
  1661. */
  1662. static int
  1663. xsltRegisterVariable(xsltTransformContextPtr ctxt,
  1664. xsltStylePreCompPtr castedComp,
  1665. xmlNodePtr tree, int isParam)
  1666. {
  1667. #ifdef XSLT_REFACTORED
  1668. xsltStyleBasicItemVariablePtr comp =
  1669. (xsltStyleBasicItemVariablePtr) castedComp;
  1670. #else
  1671. xsltStylePreCompPtr comp = castedComp;
  1672. int present;
  1673. #endif
  1674. xsltStackElemPtr variable;
  1675. #ifdef XSLT_REFACTORED
  1676. /*
  1677. * REFACTORED NOTE: Redefinitions of vars/params are checked
  1678. * at compilation time in the refactored code.
  1679. * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
  1680. */
  1681. #else
  1682. present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
  1683. if (isParam == 0) {
  1684. if ((present != 0) && (present != 3)) {
  1685. /* TODO: report QName. */
  1686. xsltTransformError(ctxt, NULL, comp->inst,
  1687. "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
  1688. return(0);
  1689. }
  1690. } else if (present != 0) {
  1691. if ((present == 1) || (present == 2)) {
  1692. /* TODO: report QName. */
  1693. xsltTransformError(ctxt, NULL, comp->inst,
  1694. "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
  1695. return(0);
  1696. }
  1697. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1698. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1699. "param %s defined by caller\n", comp->name));
  1700. #endif
  1701. return(0);
  1702. }
  1703. #endif /* else of XSLT_REFACTORED */
  1704. variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
  1705. xsltAddStackElem(ctxt, variable);
  1706. return(0);
  1707. }
  1708. /**
  1709. * xsltGlobalVariableLookup:
  1710. * @ctxt: the XSLT transformation context
  1711. * @name: the variable name
  1712. * @ns_uri: the variable namespace URI
  1713. *
  1714. * Search in the Variable array of the context for the given
  1715. * variable value.
  1716. *
  1717. * Returns the value or NULL if not found
  1718. */
  1719. static xmlXPathObjectPtr
  1720. xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
  1721. const xmlChar *ns_uri) {
  1722. xsltStackElemPtr elem;
  1723. xmlXPathObjectPtr ret = NULL;
  1724. /*
  1725. * Lookup the global variables in XPath global variable hash table
  1726. */
  1727. if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
  1728. return(NULL);
  1729. elem = (xsltStackElemPtr)
  1730. xmlHashLookup2(ctxt->globalVars, name, ns_uri);
  1731. if (elem == NULL) {
  1732. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1733. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1734. "global variable not found %s\n", name));
  1735. #endif
  1736. return(NULL);
  1737. }
  1738. /*
  1739. * URGENT TODO: Move the detection of recursive definitions
  1740. * to compile-time.
  1741. */
  1742. if (elem->computed == 0) {
  1743. if (elem->name == xsltComputingGlobalVarMarker) {
  1744. xsltTransformError(ctxt, NULL, elem->comp->inst,
  1745. "Recursive definition of %s\n", name);
  1746. return(NULL);
  1747. }
  1748. ret = xsltEvalGlobalVariable(elem, ctxt);
  1749. } else
  1750. ret = elem->value;
  1751. return(xmlXPathObjectCopy(ret));
  1752. }
  1753. /**
  1754. * xsltVariableLookup:
  1755. * @ctxt: the XSLT transformation context
  1756. * @name: the variable name
  1757. * @ns_uri: the variable namespace URI
  1758. *
  1759. * Search in the Variable array of the context for the given
  1760. * variable value.
  1761. *
  1762. * Returns the value or NULL if not found
  1763. */
  1764. xmlXPathObjectPtr
  1765. xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
  1766. const xmlChar *ns_uri) {
  1767. xsltStackElemPtr elem;
  1768. if (ctxt == NULL)
  1769. return(NULL);
  1770. elem = xsltStackLookup(ctxt, name, ns_uri);
  1771. if (elem == NULL) {
  1772. return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
  1773. }
  1774. if (elem->computed == 0) {
  1775. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1776. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1777. "uncomputed variable %s\n", name));
  1778. #endif
  1779. elem->value = xsltEvalVariable(ctxt, elem, NULL);
  1780. elem->computed = 1;
  1781. }
  1782. if (elem->value != NULL)
  1783. return(xmlXPathObjectCopy(elem->value));
  1784. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1785. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1786. "variable not found %s\n", name));
  1787. #endif
  1788. return(NULL);
  1789. }
  1790. /**
  1791. * xsltParseStylesheetCallerParam:
  1792. * @ctxt: the XSLT transformation context
  1793. * @inst: the xsl:with-param instruction element
  1794. *
  1795. * Processes an xsl:with-param instruction at transformation time.
  1796. * The value is computed, but not recorded.
  1797. * NOTE that this is also called with an *xsl:param* element
  1798. * from exsltFuncFunctionFunction().
  1799. *
  1800. * Returns the new xsltStackElemPtr or NULL
  1801. */
  1802. xsltStackElemPtr
  1803. xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
  1804. {
  1805. #ifdef XSLT_REFACTORED
  1806. xsltStyleBasicItemVariablePtr comp;
  1807. #else
  1808. xsltStylePreCompPtr comp;
  1809. #endif
  1810. xmlNodePtr tree = NULL; /* The first child node of the instruction or
  1811. the instruction itself. */
  1812. xsltStackElemPtr param = NULL;
  1813. if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
  1814. return(NULL);
  1815. #ifdef XSLT_REFACTORED
  1816. comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
  1817. #else
  1818. comp = (xsltStylePreCompPtr) inst->psvi;
  1819. #endif
  1820. if (comp == NULL) {
  1821. xsltTransformError(ctxt, NULL, inst,
  1822. "Internal error in xsltParseStylesheetCallerParam(): "
  1823. "The XSLT 'with-param' instruction was not compiled.\n");
  1824. return(NULL);
  1825. }
  1826. if (comp->name == NULL) {
  1827. xsltTransformError(ctxt, NULL, inst,
  1828. "Internal error in xsltParseStylesheetCallerParam(): "
  1829. "XSLT 'with-param': The attribute 'name' was not compiled.\n");
  1830. return(NULL);
  1831. }
  1832. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1833. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1834. "Handling xsl:with-param %s\n", comp->name));
  1835. #endif
  1836. if (comp->select == NULL) {
  1837. tree = inst->children;
  1838. } else {
  1839. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1840. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1841. " select %s\n", comp->select));
  1842. #endif
  1843. tree = inst;
  1844. }
  1845. param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
  1846. return(param);
  1847. }
  1848. /**
  1849. * xsltParseGlobalVariable:
  1850. * @style: the XSLT stylesheet
  1851. * @cur: the "variable" element
  1852. *
  1853. * Parses a global XSLT 'variable' declaration at compilation time
  1854. * and registers it
  1855. */
  1856. void
  1857. xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
  1858. {
  1859. #ifdef XSLT_REFACTORED
  1860. xsltStyleItemVariablePtr comp;
  1861. #else
  1862. xsltStylePreCompPtr comp;
  1863. #endif
  1864. if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
  1865. return;
  1866. #ifdef XSLT_REFACTORED
  1867. /*
  1868. * Note that xsltStylePreCompute() will be called from
  1869. * xslt.c only.
  1870. */
  1871. comp = (xsltStyleItemVariablePtr) cur->psvi;
  1872. #else
  1873. xsltStylePreCompute(style, cur);
  1874. comp = (xsltStylePreCompPtr) cur->psvi;
  1875. #endif
  1876. if (comp == NULL) {
  1877. xsltTransformError(NULL, style, cur,
  1878. "xsl:variable : compilation failed\n");
  1879. return;
  1880. }
  1881. if (comp->name == NULL) {
  1882. xsltTransformError(NULL, style, cur,
  1883. "xsl:variable : missing name attribute\n");
  1884. return;
  1885. }
  1886. /*
  1887. * Parse the content (a sequence constructor) of xsl:variable.
  1888. */
  1889. if (cur->children != NULL) {
  1890. #ifdef XSLT_REFACTORED
  1891. xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
  1892. #else
  1893. xsltParseTemplateContent(style, cur);
  1894. #endif
  1895. }
  1896. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1897. xsltGenericDebug(xsltGenericDebugContext,
  1898. "Registering global variable %s\n", comp->name);
  1899. #endif
  1900. xsltRegisterGlobalVariable(style, comp->name, comp->ns,
  1901. comp->select, cur->children, (xsltStylePreCompPtr) comp,
  1902. NULL);
  1903. }
  1904. /**
  1905. * xsltParseGlobalParam:
  1906. * @style: the XSLT stylesheet
  1907. * @cur: the "param" element
  1908. *
  1909. * parse an XSLT transformation param declaration and record
  1910. * its value.
  1911. */
  1912. void
  1913. xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
  1914. #ifdef XSLT_REFACTORED
  1915. xsltStyleItemParamPtr comp;
  1916. #else
  1917. xsltStylePreCompPtr comp;
  1918. #endif
  1919. if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
  1920. return;
  1921. #ifdef XSLT_REFACTORED
  1922. /*
  1923. * Note that xsltStylePreCompute() will be called from
  1924. * xslt.c only.
  1925. */
  1926. comp = (xsltStyleItemParamPtr) cur->psvi;
  1927. #else
  1928. xsltStylePreCompute(style, cur);
  1929. comp = (xsltStylePreCompPtr) cur->psvi;
  1930. #endif
  1931. if (comp == NULL) {
  1932. xsltTransformError(NULL, style, cur,
  1933. "xsl:param : compilation failed\n");
  1934. return;
  1935. }
  1936. if (comp->name == NULL) {
  1937. xsltTransformError(NULL, style, cur,
  1938. "xsl:param : missing name attribute\n");
  1939. return;
  1940. }
  1941. /*
  1942. * Parse the content (a sequence constructor) of xsl:param.
  1943. */
  1944. if (cur->children != NULL) {
  1945. #ifdef XSLT_REFACTORED
  1946. xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
  1947. #else
  1948. xsltParseTemplateContent(style, cur);
  1949. #endif
  1950. }
  1951. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1952. xsltGenericDebug(xsltGenericDebugContext,
  1953. "Registering global param %s\n", comp->name);
  1954. #endif
  1955. xsltRegisterGlobalVariable(style, comp->name, comp->ns,
  1956. comp->select, cur->children, (xsltStylePreCompPtr) comp,
  1957. NULL);
  1958. }
  1959. /**
  1960. * xsltParseStylesheetVariable:
  1961. * @ctxt: the XSLT transformation context
  1962. * @inst: the xsl:variable instruction element
  1963. *
  1964. * Registers a local XSLT 'variable' instruction at transformation time
  1965. * and evaluates its value.
  1966. */
  1967. void
  1968. xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
  1969. {
  1970. #ifdef XSLT_REFACTORED
  1971. xsltStyleItemVariablePtr comp;
  1972. #else
  1973. xsltStylePreCompPtr comp;
  1974. #endif
  1975. if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE))
  1976. return;
  1977. comp = inst->psvi;
  1978. if (comp == NULL) {
  1979. xsltTransformError(ctxt, NULL, inst,
  1980. "Internal error in xsltParseStylesheetVariable(): "
  1981. "The XSLT 'variable' instruction was not compiled.\n");
  1982. return;
  1983. }
  1984. if (comp->name == NULL) {
  1985. xsltTransformError(ctxt, NULL, inst,
  1986. "Internal error in xsltParseStylesheetVariable(): "
  1987. "The attribute 'name' was not compiled.\n");
  1988. return;
  1989. }
  1990. #ifdef WITH_XSLT_DEBUG_VARIABLE
  1991. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  1992. "Registering variable '%s'\n", comp->name));
  1993. #endif
  1994. xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
  1995. }
  1996. /**
  1997. * xsltParseStylesheetParam:
  1998. * @ctxt: the XSLT transformation context
  1999. * @cur: the XSLT 'param' element
  2000. *
  2001. * Registers a local XSLT 'param' declaration at transformation time and
  2002. * evaluates its value.
  2003. */
  2004. void
  2005. xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
  2006. {
  2007. #ifdef XSLT_REFACTORED
  2008. xsltStyleItemParamPtr comp;
  2009. #else
  2010. xsltStylePreCompPtr comp;
  2011. #endif
  2012. if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE))
  2013. return;
  2014. comp = cur->psvi;
  2015. if ((comp == NULL) || (comp->name == NULL)) {
  2016. xsltTransformError(ctxt, NULL, cur,
  2017. "Internal error in xsltParseStylesheetParam(): "
  2018. "The XSLT 'param' declaration was not compiled correctly.\n");
  2019. return;
  2020. }
  2021. #ifdef WITH_XSLT_DEBUG_VARIABLE
  2022. XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  2023. "Registering param %s\n", comp->name));
  2024. #endif
  2025. xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
  2026. }
  2027. /**
  2028. * xsltFreeGlobalVariables:
  2029. * @ctxt: the XSLT transformation context
  2030. *
  2031. * Free up the data associated to the global variables
  2032. * its value.
  2033. */
  2034. void
  2035. xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
  2036. xmlHashFree(ctxt->globalVars, xsltFreeStackElemEntry);
  2037. }
  2038. /**
  2039. * xsltXPathVariableLookup:
  2040. * @ctxt: a void * but the the XSLT transformation context actually
  2041. * @name: the variable name
  2042. * @ns_uri: the variable namespace URI
  2043. *
  2044. * This is the entry point when a varibale is needed by the XPath
  2045. * interpretor.
  2046. *
  2047. * Returns the value or NULL if not found
  2048. */
  2049. xmlXPathObjectPtr
  2050. xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
  2051. const xmlChar *ns_uri) {
  2052. xsltTransformContextPtr tctxt;
  2053. xmlXPathObjectPtr valueObj = NULL;
  2054. if ((ctxt == NULL) || (name == NULL))
  2055. return(NULL);
  2056. #ifdef WITH_XSLT_DEBUG_VARIABLE
  2057. XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  2058. "Lookup variable '%s'\n", name));
  2059. #endif
  2060. tctxt = (xsltTransformContextPtr) ctxt;
  2061. /*
  2062. * Local variables/params ---------------------------------------------
  2063. *
  2064. * Do the lookup from the top of the stack, but
  2065. * don't use params being computed in a call-param
  2066. * First lookup expects the variable name and URI to
  2067. * come from the disctionnary and hence pointer comparison.
  2068. */
  2069. if (tctxt->varsNr != 0) {
  2070. int i;
  2071. xsltStackElemPtr variable = NULL, cur;
  2072. for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
  2073. cur = tctxt->varsTab[i-1];
  2074. if ((cur->name == name) && (cur->nameURI == ns_uri)) {
  2075. #if 0
  2076. stack_addr++;
  2077. #endif
  2078. variable = cur;
  2079. goto local_variable_found;
  2080. }
  2081. cur = cur->next;
  2082. }
  2083. /*
  2084. * Redo the lookup with interned strings to avoid string comparison.
  2085. *
  2086. * OPTIMIZE TODO: The problem here is, that if we request a
  2087. * global variable, then this will be also executed.
  2088. */
  2089. {
  2090. const xmlChar *tmpName = name, *tmpNsName = ns_uri;
  2091. name = xmlDictLookup(tctxt->dict, name, -1);
  2092. if (ns_uri)
  2093. ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
  2094. if ((tmpName != name) || (tmpNsName != ns_uri)) {
  2095. for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
  2096. cur = tctxt->varsTab[i-1];
  2097. if ((cur->name == name) && (cur->nameURI == ns_uri)) {
  2098. #if 0
  2099. stack_cmp++;
  2100. #endif
  2101. variable = cur;
  2102. goto local_variable_found;
  2103. }
  2104. }
  2105. }
  2106. }
  2107. local_variable_found:
  2108. if (variable) {
  2109. if (variable->computed == 0) {
  2110. #ifdef WITH_XSLT_DEBUG_VARIABLE
  2111. XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  2112. "uncomputed variable '%s'\n", name));
  2113. #endif
  2114. variable->value = xsltEvalVariable(tctxt, variable, NULL);
  2115. variable->computed = 1;
  2116. }
  2117. if (variable->value != NULL) {
  2118. valueObj = xmlXPathObjectCopy(variable->value);
  2119. }
  2120. return(valueObj);
  2121. }
  2122. }
  2123. /*
  2124. * Global variables/params --------------------------------------------
  2125. */
  2126. if (tctxt->globalVars) {
  2127. valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
  2128. }
  2129. if (valueObj == NULL) {
  2130. #ifdef WITH_XSLT_DEBUG_VARIABLE
  2131. XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  2132. "variable not found '%s'\n", name));
  2133. #endif
  2134. if (ns_uri) {
  2135. xsltTransformError(tctxt, NULL, tctxt->inst,
  2136. "Variable '{%s}%s' has not been declared.\n", ns_uri, name);
  2137. } else {
  2138. xsltTransformError(tctxt, NULL, tctxt->inst,
  2139. "Variable '%s' has not been declared.\n", name);
  2140. }
  2141. } else {
  2142. #ifdef WITH_XSLT_DEBUG_VARIABLE
  2143. XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
  2144. "found variable '%s'\n", name));
  2145. #endif
  2146. }
  2147. return(valueObj);
  2148. }