pattern.c 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569
  1. /*
  2. * pattern.c: Implemetation of the template match compilation 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. /*
  12. * TODO: handle pathological cases like *[*[@a="b"]]
  13. * TODO: detect [number] at compilation, optimize accordingly
  14. */
  15. #define IN_LIBXSLT
  16. #include "libxslt.h"
  17. #include <string.h>
  18. #include <libxml/xmlmemory.h>
  19. #include <libxml/tree.h>
  20. #include <libxml/valid.h>
  21. #include <libxml/hash.h>
  22. #include <libxml/xmlerror.h>
  23. #include <libxml/parserInternals.h>
  24. #include <libxml/xpath.h>
  25. #include "xslt.h"
  26. #include "xsltInternals.h"
  27. #include "xsltutils.h"
  28. #include "imports.h"
  29. #include "templates.h"
  30. #include "keys.h"
  31. #include "pattern.h"
  32. #include "documents.h"
  33. #ifdef WITH_XSLT_DEBUG
  34. #define WITH_XSLT_DEBUG_PATTERN
  35. #endif
  36. /*
  37. * Types are private:
  38. */
  39. typedef enum {
  40. XSLT_OP_END=0,
  41. XSLT_OP_ROOT,
  42. XSLT_OP_ELEM,
  43. XSLT_OP_ATTR,
  44. XSLT_OP_PARENT,
  45. XSLT_OP_ANCESTOR,
  46. XSLT_OP_ID,
  47. XSLT_OP_KEY,
  48. XSLT_OP_NS,
  49. XSLT_OP_ALL,
  50. XSLT_OP_PI,
  51. XSLT_OP_COMMENT,
  52. XSLT_OP_TEXT,
  53. XSLT_OP_NODE,
  54. XSLT_OP_PREDICATE
  55. } xsltOp;
  56. typedef enum {
  57. AXIS_CHILD=1,
  58. AXIS_ATTRIBUTE
  59. } xsltAxis;
  60. typedef struct _xsltStepState xsltStepState;
  61. typedef xsltStepState *xsltStepStatePtr;
  62. struct _xsltStepState {
  63. int step;
  64. xmlNodePtr node;
  65. };
  66. typedef struct _xsltStepStates xsltStepStates;
  67. typedef xsltStepStates *xsltStepStatesPtr;
  68. struct _xsltStepStates {
  69. int nbstates;
  70. int maxstates;
  71. xsltStepStatePtr states;
  72. };
  73. typedef struct _xsltStepOp xsltStepOp;
  74. typedef xsltStepOp *xsltStepOpPtr;
  75. struct _xsltStepOp {
  76. xsltOp op;
  77. xmlChar *value;
  78. xmlChar *value2;
  79. xmlChar *value3;
  80. xmlXPathCompExprPtr comp;
  81. /*
  82. * Optimisations for count
  83. */
  84. int previousExtra;
  85. int indexExtra;
  86. int lenExtra;
  87. };
  88. struct _xsltCompMatch {
  89. struct _xsltCompMatch *next; /* siblings in the name hash */
  90. float priority; /* the priority */
  91. const xmlChar *pattern; /* the pattern */
  92. const xmlChar *mode; /* the mode */
  93. const xmlChar *modeURI; /* the mode URI */
  94. xsltTemplatePtr template; /* the associated template */
  95. xmlNodePtr node; /* the containing element */
  96. int direct;
  97. /* TODO fix the statically allocated size steps[] */
  98. int nbStep;
  99. int maxStep;
  100. xmlNsPtr *nsList; /* the namespaces in scope */
  101. int nsNr; /* the number of namespaces in scope */
  102. xsltStepOpPtr steps; /* ops for computation */
  103. };
  104. typedef struct _xsltParserContext xsltParserContext;
  105. typedef xsltParserContext *xsltParserContextPtr;
  106. struct _xsltParserContext {
  107. xsltStylesheetPtr style; /* the stylesheet */
  108. xsltTransformContextPtr ctxt; /* the transformation or NULL */
  109. const xmlChar *cur; /* the current char being parsed */
  110. const xmlChar *base; /* the full expression */
  111. xmlDocPtr doc; /* the source document */
  112. xmlNodePtr elem; /* the source element */
  113. int error; /* error code */
  114. xsltCompMatchPtr comp; /* the result */
  115. };
  116. /************************************************************************
  117. * *
  118. * Type functions *
  119. * *
  120. ************************************************************************/
  121. /**
  122. * xsltNewCompMatch:
  123. *
  124. * Create a new XSLT CompMatch
  125. *
  126. * Returns the newly allocated xsltCompMatchPtr or NULL in case of error
  127. */
  128. static xsltCompMatchPtr
  129. xsltNewCompMatch(void) {
  130. xsltCompMatchPtr cur;
  131. cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
  132. if (cur == NULL) {
  133. xsltTransformError(NULL, NULL, NULL,
  134. "xsltNewCompMatch : out of memory error\n");
  135. return(NULL);
  136. }
  137. memset(cur, 0, sizeof(xsltCompMatch));
  138. cur->maxStep = 10;
  139. cur->nbStep = 0;
  140. cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) *
  141. cur->maxStep);
  142. if (cur->steps == NULL) {
  143. xsltTransformError(NULL, NULL, NULL,
  144. "xsltNewCompMatch : out of memory error\n");
  145. xmlFree(cur);
  146. return(NULL);
  147. }
  148. cur->nsNr = 0;
  149. cur->nsList = NULL;
  150. cur->direct = 0;
  151. return(cur);
  152. }
  153. /**
  154. * xsltFreeCompMatch:
  155. * @comp: an XSLT comp
  156. *
  157. * Free up the memory allocated by @comp
  158. */
  159. static void
  160. xsltFreeCompMatch(xsltCompMatchPtr comp) {
  161. xsltStepOpPtr op;
  162. int i;
  163. if (comp == NULL)
  164. return;
  165. if (comp->pattern != NULL)
  166. xmlFree((xmlChar *)comp->pattern);
  167. if (comp->nsList != NULL)
  168. xmlFree(comp->nsList);
  169. for (i = 0;i < comp->nbStep;i++) {
  170. op = &comp->steps[i];
  171. if (op->value != NULL)
  172. xmlFree(op->value);
  173. if (op->value2 != NULL)
  174. xmlFree(op->value2);
  175. if (op->value3 != NULL)
  176. xmlFree(op->value3);
  177. if (op->comp != NULL)
  178. xmlXPathFreeCompExpr(op->comp);
  179. }
  180. xmlFree(comp->steps);
  181. memset(comp, -1, sizeof(xsltCompMatch));
  182. xmlFree(comp);
  183. }
  184. /**
  185. * xsltFreeCompMatchList:
  186. * @comp: an XSLT comp list
  187. *
  188. * Free up the memory allocated by all the elements of @comp
  189. */
  190. void
  191. xsltFreeCompMatchList(xsltCompMatchPtr comp) {
  192. xsltCompMatchPtr cur;
  193. while (comp != NULL) {
  194. cur = comp;
  195. comp = comp->next;
  196. xsltFreeCompMatch(cur);
  197. }
  198. }
  199. static void
  200. xsltFreeCompMatchListEntry(void *payload,
  201. const xmlChar *name ATTRIBUTE_UNUSED) {
  202. xsltFreeCompMatchList((xsltCompMatchPtr) payload);
  203. }
  204. /**
  205. * xsltNormalizeCompSteps:
  206. * @payload: pointer to template hash table entry
  207. * @data: pointer to the stylesheet
  208. * @name: template match name
  209. *
  210. * This is a hashtable scanner function to normalize the compiled
  211. * steps of an imported stylesheet.
  212. */
  213. void xsltNormalizeCompSteps(void *payload,
  214. void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
  215. xsltCompMatchPtr comp = payload;
  216. xsltStylesheetPtr style = data;
  217. int ix;
  218. for (ix = 0; ix < comp->nbStep; ix++) {
  219. comp->steps[ix].previousExtra += style->extrasNr;
  220. comp->steps[ix].indexExtra += style->extrasNr;
  221. comp->steps[ix].lenExtra += style->extrasNr;
  222. }
  223. }
  224. /**
  225. * xsltNewParserContext:
  226. * @style: the stylesheet
  227. * @ctxt: the transformation context, if done at run-time
  228. *
  229. * Create a new XSLT ParserContext
  230. *
  231. * Returns the newly allocated xsltParserContextPtr or NULL in case of error
  232. */
  233. static xsltParserContextPtr
  234. xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) {
  235. xsltParserContextPtr cur;
  236. cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));
  237. if (cur == NULL) {
  238. xsltTransformError(NULL, NULL, NULL,
  239. "xsltNewParserContext : malloc failed\n");
  240. return(NULL);
  241. }
  242. memset(cur, 0, sizeof(xsltParserContext));
  243. cur->style = style;
  244. cur->ctxt = ctxt;
  245. return(cur);
  246. }
  247. /**
  248. * xsltFreeParserContext:
  249. * @ctxt: an XSLT parser context
  250. *
  251. * Free up the memory allocated by @ctxt
  252. */
  253. static void
  254. xsltFreeParserContext(xsltParserContextPtr ctxt) {
  255. if (ctxt == NULL)
  256. return;
  257. memset(ctxt, -1, sizeof(xsltParserContext));
  258. xmlFree(ctxt);
  259. }
  260. /**
  261. * xsltCompMatchAdd:
  262. * @comp: the compiled match expression
  263. * @op: an op
  264. * @value: the first value
  265. * @value2: the second value
  266. * @novar: flag to set XML_XPATH_NOVAR
  267. *
  268. * Add an step to an XSLT Compiled Match
  269. *
  270. * Returns -1 in case of failure, 0 otherwise.
  271. */
  272. static int
  273. xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
  274. xsltOp op, xmlChar * value, xmlChar * value2, int novar)
  275. {
  276. if (comp->nbStep >= comp->maxStep) {
  277. xsltStepOpPtr tmp;
  278. tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
  279. sizeof(xsltStepOp));
  280. if (tmp == NULL) {
  281. xsltGenericError(xsltGenericErrorContext,
  282. "xsltCompMatchAdd: memory re-allocation failure.\n");
  283. if (ctxt->style != NULL)
  284. ctxt->style->errors++;
  285. if (value)
  286. xmlFree(value);
  287. if (value2)
  288. xmlFree(value2);
  289. return (-1);
  290. }
  291. comp->maxStep *= 2;
  292. comp->steps = tmp;
  293. }
  294. comp->steps[comp->nbStep].op = op;
  295. comp->steps[comp->nbStep].value = value;
  296. comp->steps[comp->nbStep].value2 = value2;
  297. comp->steps[comp->nbStep].value3 = NULL;
  298. comp->steps[comp->nbStep].comp = NULL;
  299. if (ctxt->ctxt != NULL) {
  300. comp->steps[comp->nbStep].previousExtra =
  301. xsltAllocateExtraCtxt(ctxt->ctxt);
  302. comp->steps[comp->nbStep].indexExtra =
  303. xsltAllocateExtraCtxt(ctxt->ctxt);
  304. comp->steps[comp->nbStep].lenExtra =
  305. xsltAllocateExtraCtxt(ctxt->ctxt);
  306. } else {
  307. comp->steps[comp->nbStep].previousExtra =
  308. xsltAllocateExtra(ctxt->style);
  309. comp->steps[comp->nbStep].indexExtra =
  310. xsltAllocateExtra(ctxt->style);
  311. comp->steps[comp->nbStep].lenExtra =
  312. xsltAllocateExtra(ctxt->style);
  313. }
  314. if (op == XSLT_OP_PREDICATE) {
  315. int flags = 0;
  316. #ifdef XML_XPATH_NOVAR
  317. if (novar != 0)
  318. flags = XML_XPATH_NOVAR;
  319. #endif
  320. comp->steps[comp->nbStep].comp = xsltXPathCompileFlags(ctxt->style,
  321. value, flags);
  322. if (comp->steps[comp->nbStep].comp == NULL) {
  323. xsltTransformError(NULL, ctxt->style, ctxt->elem,
  324. "Failed to compile predicate\n");
  325. if (ctxt->style != NULL)
  326. ctxt->style->errors++;
  327. }
  328. }
  329. comp->nbStep++;
  330. return (0);
  331. }
  332. /**
  333. * xsltSwapTopCompMatch:
  334. * @comp: the compiled match expression
  335. *
  336. * reverse the two top steps.
  337. */
  338. static void
  339. xsltSwapTopCompMatch(xsltCompMatchPtr comp) {
  340. int i;
  341. int j = comp->nbStep - 1;
  342. if (j > 0) {
  343. register xmlChar *tmp;
  344. register xsltOp op;
  345. register xmlXPathCompExprPtr expr;
  346. register int t;
  347. i = j - 1;
  348. tmp = comp->steps[i].value;
  349. comp->steps[i].value = comp->steps[j].value;
  350. comp->steps[j].value = tmp;
  351. tmp = comp->steps[i].value2;
  352. comp->steps[i].value2 = comp->steps[j].value2;
  353. comp->steps[j].value2 = tmp;
  354. tmp = comp->steps[i].value3;
  355. comp->steps[i].value3 = comp->steps[j].value3;
  356. comp->steps[j].value3 = tmp;
  357. op = comp->steps[i].op;
  358. comp->steps[i].op = comp->steps[j].op;
  359. comp->steps[j].op = op;
  360. expr = comp->steps[i].comp;
  361. comp->steps[i].comp = comp->steps[j].comp;
  362. comp->steps[j].comp = expr;
  363. t = comp->steps[i].previousExtra;
  364. comp->steps[i].previousExtra = comp->steps[j].previousExtra;
  365. comp->steps[j].previousExtra = t;
  366. t = comp->steps[i].indexExtra;
  367. comp->steps[i].indexExtra = comp->steps[j].indexExtra;
  368. comp->steps[j].indexExtra = t;
  369. t = comp->steps[i].lenExtra;
  370. comp->steps[i].lenExtra = comp->steps[j].lenExtra;
  371. comp->steps[j].lenExtra = t;
  372. }
  373. }
  374. /**
  375. * xsltReverseCompMatch:
  376. * @ctxt: the parser context
  377. * @comp: the compiled match expression
  378. *
  379. * reverse all the stack of expressions
  380. */
  381. static void
  382. xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
  383. int i = 0;
  384. int j = comp->nbStep - 1;
  385. while (j > i) {
  386. register xmlChar *tmp;
  387. register xsltOp op;
  388. register xmlXPathCompExprPtr expr;
  389. register int t;
  390. tmp = comp->steps[i].value;
  391. comp->steps[i].value = comp->steps[j].value;
  392. comp->steps[j].value = tmp;
  393. tmp = comp->steps[i].value2;
  394. comp->steps[i].value2 = comp->steps[j].value2;
  395. comp->steps[j].value2 = tmp;
  396. tmp = comp->steps[i].value3;
  397. comp->steps[i].value3 = comp->steps[j].value3;
  398. comp->steps[j].value3 = tmp;
  399. op = comp->steps[i].op;
  400. comp->steps[i].op = comp->steps[j].op;
  401. comp->steps[j].op = op;
  402. expr = comp->steps[i].comp;
  403. comp->steps[i].comp = comp->steps[j].comp;
  404. comp->steps[j].comp = expr;
  405. t = comp->steps[i].previousExtra;
  406. comp->steps[i].previousExtra = comp->steps[j].previousExtra;
  407. comp->steps[j].previousExtra = t;
  408. t = comp->steps[i].indexExtra;
  409. comp->steps[i].indexExtra = comp->steps[j].indexExtra;
  410. comp->steps[j].indexExtra = t;
  411. t = comp->steps[i].lenExtra;
  412. comp->steps[i].lenExtra = comp->steps[j].lenExtra;
  413. comp->steps[j].lenExtra = t;
  414. j--;
  415. i++;
  416. }
  417. xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
  418. /*
  419. * Detect consecutive XSLT_OP_PREDICATE indicating a direct matching
  420. * should be done.
  421. */
  422. for (i = 0;i < comp->nbStep - 1;i++) {
  423. if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
  424. (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
  425. comp->direct = 1;
  426. if (comp->pattern[0] != '/') {
  427. xmlChar *query;
  428. query = xmlStrdup((const xmlChar *)"//");
  429. query = xmlStrcat(query, comp->pattern);
  430. xmlFree((xmlChar *) comp->pattern);
  431. comp->pattern = query;
  432. }
  433. break;
  434. }
  435. }
  436. }
  437. /************************************************************************
  438. * *
  439. * The interpreter for the precompiled patterns *
  440. * *
  441. ************************************************************************/
  442. static int
  443. xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states,
  444. int step, xmlNodePtr node) {
  445. if ((states->states == NULL) || (states->maxstates <= 0)) {
  446. states->maxstates = 4;
  447. states->nbstates = 0;
  448. states->states = xmlMalloc(4 * sizeof(xsltStepState));
  449. }
  450. else if (states->maxstates <= states->nbstates) {
  451. xsltStepState *tmp;
  452. tmp = (xsltStepStatePtr) xmlRealloc(states->states,
  453. 2 * states->maxstates * sizeof(xsltStepState));
  454. if (tmp == NULL) {
  455. xsltGenericError(xsltGenericErrorContext,
  456. "xsltPatPushState: memory re-allocation failure.\n");
  457. ctxt->state = XSLT_STATE_STOPPED;
  458. return(-1);
  459. }
  460. states->states = tmp;
  461. states->maxstates *= 2;
  462. }
  463. states->states[states->nbstates].step = step;
  464. states->states[states->nbstates++].node = node;
  465. #if 0
  466. fprintf(stderr, "Push: %d, %s\n", step, node->name);
  467. #endif
  468. return(0);
  469. }
  470. static void
  471. xmlXPathFreeObjectWrapper(void *obj) {
  472. xmlXPathFreeObject((xmlXPathObjectPtr) obj);
  473. }
  474. /**
  475. * xsltTestCompMatchDirect:
  476. * @ctxt: a XSLT process context
  477. * @comp: the precompiled pattern
  478. * @node: a node
  479. * @nsList: the namespaces in scope
  480. * @nsNr: the number of namespaces in scope
  481. *
  482. * Test whether the node matches the pattern, do a direct evalutation
  483. * and not a step by step evaluation.
  484. *
  485. * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  486. */
  487. static int
  488. xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
  489. xmlNodePtr node, xmlNsPtr *nsList, int nsNr) {
  490. xsltStepOpPtr sel = NULL;
  491. xmlDocPtr prevdoc;
  492. xmlDocPtr doc;
  493. xmlXPathObjectPtr list;
  494. int ix, j;
  495. int nocache = 0;
  496. int isRVT;
  497. doc = node->doc;
  498. if (XSLT_IS_RES_TREE_FRAG(doc))
  499. isRVT = 1;
  500. else
  501. isRVT = 0;
  502. sel = &comp->steps[0]; /* store extra in first step arbitrarily */
  503. prevdoc = (xmlDocPtr)
  504. XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
  505. ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
  506. list = (xmlXPathObjectPtr)
  507. XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
  508. if ((list == NULL) || (prevdoc != doc)) {
  509. xmlXPathObjectPtr newlist;
  510. xmlNodePtr parent = node->parent;
  511. xmlDocPtr olddoc;
  512. xmlNodePtr oldnode;
  513. int oldNsNr, oldContextSize, oldProximityPosition;
  514. xmlNsPtr *oldNamespaces;
  515. oldnode = ctxt->xpathCtxt->node;
  516. olddoc = ctxt->xpathCtxt->doc;
  517. oldNsNr = ctxt->xpathCtxt->nsNr;
  518. oldNamespaces = ctxt->xpathCtxt->namespaces;
  519. oldContextSize = ctxt->xpathCtxt->contextSize;
  520. oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
  521. ctxt->xpathCtxt->node = node;
  522. ctxt->xpathCtxt->doc = doc;
  523. ctxt->xpathCtxt->namespaces = nsList;
  524. ctxt->xpathCtxt->nsNr = nsNr;
  525. newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
  526. ctxt->xpathCtxt->node = oldnode;
  527. ctxt->xpathCtxt->doc = olddoc;
  528. ctxt->xpathCtxt->namespaces = oldNamespaces;
  529. ctxt->xpathCtxt->nsNr = oldNsNr;
  530. ctxt->xpathCtxt->contextSize = oldContextSize;
  531. ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
  532. if (newlist == NULL)
  533. return(-1);
  534. if (newlist->type != XPATH_NODESET) {
  535. xmlXPathFreeObject(newlist);
  536. return(-1);
  537. }
  538. ix = 0;
  539. if ((parent == NULL) || (node->doc == NULL) || isRVT)
  540. nocache = 1;
  541. if (nocache == 0) {
  542. if (list != NULL)
  543. xmlXPathFreeObject(list);
  544. list = newlist;
  545. XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
  546. (void *) list;
  547. XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
  548. (void *) doc;
  549. XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
  550. 0;
  551. XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
  552. xmlXPathFreeObjectWrapper;
  553. } else
  554. list = newlist;
  555. }
  556. if ((list->nodesetval == NULL) ||
  557. (list->nodesetval->nodeNr <= 0)) {
  558. if (nocache == 1)
  559. xmlXPathFreeObject(list);
  560. return(0);
  561. }
  562. /* TODO: store the index and use it for the scan */
  563. if (ix == 0) {
  564. for (j = 0;j < list->nodesetval->nodeNr;j++) {
  565. if (list->nodesetval->nodeTab[j] == node) {
  566. if (nocache == 1)
  567. xmlXPathFreeObject(list);
  568. return(1);
  569. }
  570. }
  571. } else {
  572. }
  573. if (nocache == 1)
  574. xmlXPathFreeObject(list);
  575. return(0);
  576. }
  577. /**
  578. * xsltTestStepMatch:
  579. * @ctxt: a XSLT process context
  580. * @node: a node
  581. * @step: the step
  582. *
  583. * Test whether the node matches the step.
  584. *
  585. * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  586. */
  587. static int
  588. xsltTestStepMatch(xsltTransformContextPtr ctxt, xmlNodePtr node,
  589. xsltStepOpPtr step) {
  590. switch (step->op) {
  591. case XSLT_OP_ROOT:
  592. if ((node->type == XML_DOCUMENT_NODE) ||
  593. #ifdef LIBXML_DOCB_ENABLED
  594. (node->type == XML_DOCB_DOCUMENT_NODE) ||
  595. #endif
  596. (node->type == XML_HTML_DOCUMENT_NODE))
  597. return(1);
  598. if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
  599. return(1);
  600. return(0);
  601. case XSLT_OP_ELEM:
  602. if (node->type != XML_ELEMENT_NODE)
  603. return(0);
  604. if (step->value == NULL)
  605. return(1);
  606. if (step->value[0] != node->name[0])
  607. return(0);
  608. if (!xmlStrEqual(step->value, node->name))
  609. return(0);
  610. /* Namespace test */
  611. if (node->ns == NULL) {
  612. if (step->value2 != NULL)
  613. return(0);
  614. } else if (node->ns->href != NULL) {
  615. if (step->value2 == NULL)
  616. return(0);
  617. if (!xmlStrEqual(step->value2, node->ns->href))
  618. return(0);
  619. }
  620. return(1);
  621. case XSLT_OP_ATTR:
  622. if (node->type != XML_ATTRIBUTE_NODE)
  623. return(0);
  624. if (step->value != NULL) {
  625. if (step->value[0] != node->name[0])
  626. return(0);
  627. if (!xmlStrEqual(step->value, node->name))
  628. return(0);
  629. }
  630. /* Namespace test */
  631. if (node->ns == NULL) {
  632. if (step->value2 != NULL)
  633. return(0);
  634. } else if (step->value2 != NULL) {
  635. if (!xmlStrEqual(step->value2, node->ns->href))
  636. return(0);
  637. }
  638. return(1);
  639. case XSLT_OP_ID: {
  640. /* TODO Handle IDs decently, must be done differently */
  641. xmlAttrPtr id;
  642. if (node->type != XML_ELEMENT_NODE)
  643. return(0);
  644. id = xmlGetID(node->doc, step->value);
  645. if ((id == NULL) || (id->parent != node))
  646. return(0);
  647. break;
  648. }
  649. case XSLT_OP_KEY: {
  650. xmlNodeSetPtr list;
  651. int indx;
  652. list = xsltGetKey(ctxt, step->value,
  653. step->value3, step->value2);
  654. if (list == NULL)
  655. return(0);
  656. for (indx = 0;indx < list->nodeNr;indx++)
  657. if (list->nodeTab[indx] == node)
  658. break;
  659. if (indx >= list->nodeNr)
  660. return(0);
  661. break;
  662. }
  663. case XSLT_OP_NS:
  664. if (node->type != XML_ELEMENT_NODE)
  665. return(0);
  666. if (node->ns == NULL) {
  667. if (step->value != NULL)
  668. return(0);
  669. } else if (node->ns->href != NULL) {
  670. if (step->value == NULL)
  671. return(0);
  672. if (!xmlStrEqual(step->value, node->ns->href))
  673. return(0);
  674. }
  675. break;
  676. case XSLT_OP_ALL:
  677. if (node->type != XML_ELEMENT_NODE)
  678. return(0);
  679. break;
  680. case XSLT_OP_PI:
  681. if (node->type != XML_PI_NODE)
  682. return(0);
  683. if (step->value != NULL) {
  684. if (!xmlStrEqual(step->value, node->name))
  685. return(0);
  686. }
  687. break;
  688. case XSLT_OP_COMMENT:
  689. if (node->type != XML_COMMENT_NODE)
  690. return(0);
  691. break;
  692. case XSLT_OP_TEXT:
  693. if ((node->type != XML_TEXT_NODE) &&
  694. (node->type != XML_CDATA_SECTION_NODE))
  695. return(0);
  696. break;
  697. case XSLT_OP_NODE:
  698. switch (node->type) {
  699. case XML_ELEMENT_NODE:
  700. case XML_CDATA_SECTION_NODE:
  701. case XML_PI_NODE:
  702. case XML_COMMENT_NODE:
  703. case XML_TEXT_NODE:
  704. break;
  705. default:
  706. return(0);
  707. }
  708. break;
  709. default:
  710. xsltTransformError(ctxt, NULL, node,
  711. "xsltTestStepMatch: unexpected step op %d\n",
  712. step->op);
  713. return(-1);
  714. }
  715. return(1);
  716. }
  717. /**
  718. * xsltTestPredicateMatch:
  719. * @ctxt: a XSLT process context
  720. * @comp: the precompiled pattern
  721. * @node: a node
  722. * @step: the predicate step
  723. * @sel: the previous step
  724. *
  725. * Test whether the node matches the predicate
  726. *
  727. * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  728. */
  729. static int
  730. xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
  731. xmlNodePtr node, xsltStepOpPtr step,
  732. xsltStepOpPtr sel) {
  733. xmlNodePtr oldNode;
  734. xmlDocPtr doc;
  735. int oldCS, oldCP;
  736. int pos = 0, len = 0;
  737. int isRVT;
  738. int match;
  739. if (step->value == NULL)
  740. return(0);
  741. if (step->comp == NULL)
  742. return(0);
  743. if (sel == NULL)
  744. return(0);
  745. doc = node->doc;
  746. if (XSLT_IS_RES_TREE_FRAG(doc))
  747. isRVT = 1;
  748. else
  749. isRVT = 0;
  750. /*
  751. * Recompute contextSize and proximityPosition.
  752. *
  753. * This could be improved in the following ways:
  754. *
  755. * - Skip recomputation if predicates don't use position() or last()
  756. * - Keep data for multiple parents. This would require a hash table
  757. * or an unused member in xmlNode.
  758. * - Store node test results in a bitmap to avoid computing them twice.
  759. */
  760. oldCS = ctxt->xpathCtxt->contextSize;
  761. oldCP = ctxt->xpathCtxt->proximityPosition;
  762. {
  763. xmlNodePtr previous;
  764. int nocache = 0;
  765. previous = (xmlNodePtr)
  766. XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
  767. if ((previous != NULL) &&
  768. (previous->parent == node->parent)) {
  769. /*
  770. * just walk back to adjust the index
  771. */
  772. int indx = 0;
  773. xmlNodePtr sibling = node;
  774. while (sibling != NULL) {
  775. if (sibling == previous)
  776. break;
  777. if (xsltTestStepMatch(ctxt, sibling, sel))
  778. indx++;
  779. sibling = sibling->prev;
  780. }
  781. if (sibling == NULL) {
  782. /* hum going backward in document order ... */
  783. indx = 0;
  784. sibling = node;
  785. while (sibling != NULL) {
  786. if (sibling == previous)
  787. break;
  788. if (xsltTestStepMatch(ctxt, sibling, sel))
  789. indx--;
  790. sibling = sibling->next;
  791. }
  792. }
  793. if (sibling != NULL) {
  794. pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx;
  795. /*
  796. * If the node is in a Value Tree we need to
  797. * save len, but cannot cache the node!
  798. * (bugs 153137 and 158840)
  799. */
  800. if (node->doc != NULL) {
  801. len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
  802. if (!isRVT) {
  803. XSLT_RUNTIME_EXTRA(ctxt,
  804. sel->previousExtra, ptr) = node;
  805. XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
  806. }
  807. }
  808. } else
  809. pos = 0;
  810. } else {
  811. /*
  812. * recompute the index
  813. */
  814. xmlNodePtr parent = node->parent;
  815. xmlNodePtr siblings = NULL;
  816. if (parent) siblings = parent->children;
  817. while (siblings != NULL) {
  818. if (siblings == node) {
  819. len++;
  820. pos = len;
  821. } else if (xsltTestStepMatch(ctxt, siblings, sel)) {
  822. len++;
  823. }
  824. siblings = siblings->next;
  825. }
  826. if ((parent == NULL) || (node->doc == NULL))
  827. nocache = 1;
  828. else {
  829. while (parent->parent != NULL)
  830. parent = parent->parent;
  831. if (((parent->type != XML_DOCUMENT_NODE) &&
  832. (parent->type != XML_HTML_DOCUMENT_NODE)) ||
  833. (parent != (xmlNodePtr) node->doc))
  834. nocache = 1;
  835. }
  836. }
  837. if (pos != 0) {
  838. ctxt->xpathCtxt->contextSize = len;
  839. ctxt->xpathCtxt->proximityPosition = pos;
  840. /*
  841. * If the node is in a Value Tree we cannot
  842. * cache it !
  843. */
  844. if ((!isRVT) && (node->doc != NULL) &&
  845. (nocache == 0)) {
  846. XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
  847. XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
  848. XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
  849. }
  850. }
  851. }
  852. oldNode = ctxt->node;
  853. ctxt->node = node;
  854. match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr);
  855. if (pos != 0) {
  856. ctxt->xpathCtxt->contextSize = oldCS;
  857. ctxt->xpathCtxt->proximityPosition = oldCP;
  858. }
  859. ctxt->node = oldNode;
  860. return match;
  861. }
  862. /**
  863. * xsltTestCompMatch:
  864. * @ctxt: a XSLT process context
  865. * @comp: the precompiled pattern
  866. * @node: a node
  867. * @mode: the mode name or NULL
  868. * @modeURI: the mode URI or NULL
  869. *
  870. * Test whether the node matches the pattern
  871. *
  872. * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  873. */
  874. static int
  875. xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
  876. xmlNodePtr matchNode, const xmlChar *mode,
  877. const xmlChar *modeURI) {
  878. int i;
  879. int found = 0;
  880. xmlNodePtr node = matchNode;
  881. xmlNodePtr oldInst;
  882. xsltStepOpPtr step, sel = NULL;
  883. xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
  884. if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
  885. xsltTransformError(ctxt, NULL, node,
  886. "xsltTestCompMatch: null arg\n");
  887. return(-1);
  888. }
  889. if (mode != NULL) {
  890. if (comp->mode == NULL)
  891. return(0);
  892. /*
  893. * both mode strings must be interned on the stylesheet dictionary
  894. */
  895. if (comp->mode != mode)
  896. return(0);
  897. } else {
  898. if (comp->mode != NULL)
  899. return(0);
  900. }
  901. if (modeURI != NULL) {
  902. if (comp->modeURI == NULL)
  903. return(0);
  904. /*
  905. * both modeURI strings must be interned on the stylesheet dictionary
  906. */
  907. if (comp->modeURI != modeURI)
  908. return(0);
  909. } else {
  910. if (comp->modeURI != NULL)
  911. return(0);
  912. }
  913. /* Some XPath functions rely on inst being set correctly. */
  914. oldInst = ctxt->inst;
  915. ctxt->inst = comp->node;
  916. i = 0;
  917. restart:
  918. for (;i < comp->nbStep;i++) {
  919. step = &comp->steps[i];
  920. if (step->op != XSLT_OP_PREDICATE)
  921. sel = step;
  922. switch (step->op) {
  923. case XSLT_OP_END:
  924. goto found;
  925. case XSLT_OP_PARENT:
  926. if ((node->type == XML_DOCUMENT_NODE) ||
  927. (node->type == XML_HTML_DOCUMENT_NODE) ||
  928. #ifdef LIBXML_DOCB_ENABLED
  929. (node->type == XML_DOCB_DOCUMENT_NODE) ||
  930. #endif
  931. (node->type == XML_NAMESPACE_DECL))
  932. goto rollback;
  933. node = node->parent;
  934. if (node == NULL)
  935. goto rollback;
  936. if (step->value == NULL)
  937. continue;
  938. if (step->value[0] != node->name[0])
  939. goto rollback;
  940. if (!xmlStrEqual(step->value, node->name))
  941. goto rollback;
  942. /* Namespace test */
  943. if (node->ns == NULL) {
  944. if (step->value2 != NULL)
  945. goto rollback;
  946. } else if (node->ns->href != NULL) {
  947. if (step->value2 == NULL)
  948. goto rollback;
  949. if (!xmlStrEqual(step->value2, node->ns->href))
  950. goto rollback;
  951. }
  952. continue;
  953. case XSLT_OP_ANCESTOR:
  954. /* TODO: implement coalescing of ANCESTOR/NODE ops */
  955. if (step->value == NULL) {
  956. step = &comp->steps[i+1];
  957. if (step->op == XSLT_OP_ROOT)
  958. goto found;
  959. /* added NS, ID and KEY as a result of bug 168208 */
  960. if ((step->op != XSLT_OP_ELEM) &&
  961. (step->op != XSLT_OP_ALL) &&
  962. (step->op != XSLT_OP_NS) &&
  963. (step->op != XSLT_OP_ID) &&
  964. (step->op != XSLT_OP_KEY))
  965. goto rollback;
  966. }
  967. if (node == NULL)
  968. goto rollback;
  969. if ((node->type == XML_DOCUMENT_NODE) ||
  970. (node->type == XML_HTML_DOCUMENT_NODE) ||
  971. #ifdef LIBXML_DOCB_ENABLED
  972. (node->type == XML_DOCB_DOCUMENT_NODE) ||
  973. #endif
  974. (node->type == XML_NAMESPACE_DECL))
  975. goto rollback;
  976. node = node->parent;
  977. if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
  978. xsltPatPushState(ctxt, &states, i, node);
  979. continue;
  980. }
  981. i++;
  982. sel = step;
  983. if (step->value == NULL) {
  984. xsltPatPushState(ctxt, &states, i - 1, node);
  985. continue;
  986. }
  987. while (node != NULL) {
  988. if ((node->type == XML_ELEMENT_NODE) &&
  989. (step->value[0] == node->name[0]) &&
  990. (xmlStrEqual(step->value, node->name))) {
  991. /* Namespace test */
  992. if (node->ns == NULL) {
  993. if (step->value2 == NULL)
  994. break;
  995. } else if (node->ns->href != NULL) {
  996. if ((step->value2 != NULL) &&
  997. (xmlStrEqual(step->value2, node->ns->href)))
  998. break;
  999. }
  1000. }
  1001. node = node->parent;
  1002. }
  1003. if (node == NULL)
  1004. goto rollback;
  1005. xsltPatPushState(ctxt, &states, i - 1, node);
  1006. continue;
  1007. case XSLT_OP_PREDICATE: {
  1008. /*
  1009. * When there is cascading XSLT_OP_PREDICATE or a predicate
  1010. * after an op which hasn't been optimized yet, then use a
  1011. * direct computation approach. It's not done directly
  1012. * at the beginning of the routine to filter out as much
  1013. * as possible this costly computation.
  1014. */
  1015. if (comp->direct) {
  1016. found = xsltTestCompMatchDirect(ctxt, comp, matchNode,
  1017. comp->nsList, comp->nsNr);
  1018. goto exit;
  1019. }
  1020. if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
  1021. goto rollback;
  1022. break;
  1023. }
  1024. default:
  1025. if (xsltTestStepMatch(ctxt, node, step) != 1)
  1026. goto rollback;
  1027. break;
  1028. }
  1029. }
  1030. found:
  1031. found = 1;
  1032. exit:
  1033. ctxt->inst = oldInst;
  1034. if (states.states != NULL) {
  1035. /* Free the rollback states */
  1036. xmlFree(states.states);
  1037. }
  1038. return found;
  1039. rollback:
  1040. /* got an error try to rollback */
  1041. if (states.states == NULL || states.nbstates <= 0) {
  1042. found = 0;
  1043. goto exit;
  1044. }
  1045. states.nbstates--;
  1046. i = states.states[states.nbstates].step;
  1047. node = states.states[states.nbstates].node;
  1048. #if 0
  1049. fprintf(stderr, "Pop: %d, %s\n", i, node->name);
  1050. #endif
  1051. goto restart;
  1052. }
  1053. /**
  1054. * xsltTestCompMatchList:
  1055. * @ctxt: a XSLT process context
  1056. * @node: a node
  1057. * @comp: the precompiled pattern list
  1058. *
  1059. * Test whether the node matches one of the patterns in the list
  1060. *
  1061. * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
  1062. */
  1063. int
  1064. xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,
  1065. xsltCompMatchPtr comp) {
  1066. int ret;
  1067. if ((ctxt == NULL) || (node == NULL))
  1068. return(-1);
  1069. while (comp != NULL) {
  1070. ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);
  1071. if (ret == 1)
  1072. return(1);
  1073. comp = comp->next;
  1074. }
  1075. return(0);
  1076. }
  1077. /**
  1078. * xsltCompMatchClearCache:
  1079. * @ctxt: a XSLT process context
  1080. * @comp: the precompiled pattern list
  1081. *
  1082. * Clear pattern match cache.
  1083. */
  1084. void
  1085. xsltCompMatchClearCache(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp) {
  1086. xsltStepOpPtr sel;
  1087. xmlXPathObjectPtr list;
  1088. if ((ctxt == NULL) || (comp == NULL))
  1089. return;
  1090. sel = &comp->steps[0];
  1091. list = (xmlXPathObjectPtr) XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
  1092. if (list != NULL) {
  1093. xmlXPathFreeObject(list);
  1094. XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) = NULL;
  1095. XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = NULL;
  1096. XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 0;
  1097. XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) = NULL;
  1098. }
  1099. }
  1100. /************************************************************************
  1101. * *
  1102. * Dedicated parser for templates *
  1103. * *
  1104. ************************************************************************/
  1105. #define CUR (*ctxt->cur)
  1106. #define SKIP(val) ctxt->cur += (val)
  1107. #define NXT(val) ctxt->cur[(val)]
  1108. #define CUR_PTR ctxt->cur
  1109. #define SKIP_BLANKS \
  1110. while (IS_BLANK_CH(CUR)) NEXT
  1111. #define CURRENT (*ctxt->cur)
  1112. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  1113. #define PUSH(op, val, val2, novar) \
  1114. if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
  1115. #define SWAP() \
  1116. xsltSwapTopCompMatch(ctxt->comp);
  1117. #define XSLT_ERROR(X) \
  1118. { xsltError(ctxt, __FILE__, __LINE__, X); \
  1119. ctxt->error = (X); return; }
  1120. #define XSLT_ERROR0(X) \
  1121. { xsltError(ctxt, __FILE__, __LINE__, X); \
  1122. ctxt->error = (X); return(0); }
  1123. /**
  1124. * xsltScanLiteral:
  1125. * @ctxt: the XPath Parser context
  1126. *
  1127. * Parse an XPath Litteral:
  1128. *
  1129. * [29] Literal ::= '"' [^"]* '"'
  1130. * | "'" [^']* "'"
  1131. *
  1132. * Returns the Literal parsed or NULL
  1133. */
  1134. static xmlChar *
  1135. xsltScanLiteral(xsltParserContextPtr ctxt) {
  1136. const xmlChar *q, *cur;
  1137. xmlChar *ret = NULL;
  1138. int val, len;
  1139. SKIP_BLANKS;
  1140. if (CUR == '"') {
  1141. NEXT;
  1142. cur = q = CUR_PTR;
  1143. val = xmlStringCurrentChar(NULL, cur, &len);
  1144. while ((IS_CHAR(val)) && (val != '"')) {
  1145. cur += len;
  1146. val = xmlStringCurrentChar(NULL, cur, &len);
  1147. }
  1148. if (!IS_CHAR(val)) {
  1149. ctxt->error = 1;
  1150. return(NULL);
  1151. } else {
  1152. ret = xmlStrndup(q, cur - q);
  1153. }
  1154. cur += len;
  1155. CUR_PTR = cur;
  1156. } else if (CUR == '\'') {
  1157. NEXT;
  1158. cur = q = CUR_PTR;
  1159. val = xmlStringCurrentChar(NULL, cur, &len);
  1160. while ((IS_CHAR(val)) && (val != '\'')) {
  1161. cur += len;
  1162. val = xmlStringCurrentChar(NULL, cur, &len);
  1163. }
  1164. if (!IS_CHAR(val)) {
  1165. ctxt->error = 1;
  1166. return(NULL);
  1167. } else {
  1168. ret = xmlStrndup(q, cur - q);
  1169. }
  1170. cur += len;
  1171. CUR_PTR = cur;
  1172. } else {
  1173. /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
  1174. ctxt->error = 1;
  1175. return(NULL);
  1176. }
  1177. return(ret);
  1178. }
  1179. /**
  1180. * xsltScanNCName:
  1181. * @ctxt: the XPath Parser context
  1182. *
  1183. * Parses a non qualified name
  1184. *
  1185. * Returns the Name parsed or NULL
  1186. */
  1187. static xmlChar *
  1188. xsltScanNCName(xsltParserContextPtr ctxt) {
  1189. const xmlChar *q, *cur;
  1190. xmlChar *ret = NULL;
  1191. int val, len;
  1192. SKIP_BLANKS;
  1193. cur = q = CUR_PTR;
  1194. val = xmlStringCurrentChar(NULL, cur, &len);
  1195. if (!IS_LETTER(val) && (val != '_'))
  1196. return(NULL);
  1197. while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
  1198. (val == '.') || (val == '-') ||
  1199. (val == '_') ||
  1200. (IS_COMBINING(val)) ||
  1201. (IS_EXTENDER(val))) {
  1202. cur += len;
  1203. val = xmlStringCurrentChar(NULL, cur, &len);
  1204. }
  1205. ret = xmlStrndup(q, cur - q);
  1206. CUR_PTR = cur;
  1207. return(ret);
  1208. }
  1209. /*
  1210. * xsltCompileIdKeyPattern:
  1211. * @ctxt: the compilation context
  1212. * @name: a preparsed name
  1213. * @aid: whether id/key are allowed there
  1214. * @novar: flag to prohibit xslt var
  1215. *
  1216. * Compile the XSLT LocationIdKeyPattern
  1217. * [3] IdKeyPattern ::= 'id' '(' Literal ')'
  1218. * | 'key' '(' Literal ',' Literal ')'
  1219. *
  1220. * also handle NodeType and PI from:
  1221. *
  1222. * [7] NodeTest ::= NameTest
  1223. * | NodeType '(' ')'
  1224. * | 'processing-instruction' '(' Literal ')'
  1225. */
  1226. static void
  1227. xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
  1228. int aid, int novar, xsltAxis axis) {
  1229. xmlChar *lit = NULL;
  1230. xmlChar *lit2 = NULL;
  1231. if (CUR != '(') {
  1232. xsltTransformError(NULL, NULL, NULL,
  1233. "xsltCompileIdKeyPattern : ( expected\n");
  1234. ctxt->error = 1;
  1235. return;
  1236. }
  1237. if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
  1238. if (axis != 0) {
  1239. xsltTransformError(NULL, NULL, NULL,
  1240. "xsltCompileIdKeyPattern : NodeTest expected\n");
  1241. ctxt->error = 1;
  1242. return;
  1243. }
  1244. NEXT;
  1245. SKIP_BLANKS;
  1246. lit = xsltScanLiteral(ctxt);
  1247. if (ctxt->error) {
  1248. xsltTransformError(NULL, NULL, NULL,
  1249. "xsltCompileIdKeyPattern : Literal expected\n");
  1250. xmlFree(lit);
  1251. return;
  1252. }
  1253. SKIP_BLANKS;
  1254. if (CUR != ')') {
  1255. xsltTransformError(NULL, NULL, NULL,
  1256. "xsltCompileIdKeyPattern : ) expected\n");
  1257. xmlFree(lit);
  1258. ctxt->error = 1;
  1259. return;
  1260. }
  1261. NEXT;
  1262. PUSH(XSLT_OP_ID, lit, NULL, novar);
  1263. lit = NULL;
  1264. } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
  1265. if (axis != 0) {
  1266. xsltTransformError(NULL, NULL, NULL,
  1267. "xsltCompileIdKeyPattern : NodeTest expected\n");
  1268. ctxt->error = 1;
  1269. return;
  1270. }
  1271. NEXT;
  1272. SKIP_BLANKS;
  1273. lit = xsltScanLiteral(ctxt);
  1274. if (ctxt->error) {
  1275. xsltTransformError(NULL, NULL, NULL,
  1276. "xsltCompileIdKeyPattern : Literal expected\n");
  1277. xmlFree(lit);
  1278. return;
  1279. }
  1280. SKIP_BLANKS;
  1281. if (CUR != ',') {
  1282. xsltTransformError(NULL, NULL, NULL,
  1283. "xsltCompileIdKeyPattern : , expected\n");
  1284. xmlFree(lit);
  1285. ctxt->error = 1;
  1286. return;
  1287. }
  1288. NEXT;
  1289. SKIP_BLANKS;
  1290. lit2 = xsltScanLiteral(ctxt);
  1291. if (ctxt->error) {
  1292. xsltTransformError(NULL, NULL, NULL,
  1293. "xsltCompileIdKeyPattern : Literal expected\n");
  1294. xmlFree(lit);
  1295. return;
  1296. }
  1297. SKIP_BLANKS;
  1298. if (CUR != ')') {
  1299. xsltTransformError(NULL, NULL, NULL,
  1300. "xsltCompileIdKeyPattern : ) expected\n");
  1301. xmlFree(lit);
  1302. xmlFree(lit2);
  1303. ctxt->error = 1;
  1304. return;
  1305. }
  1306. NEXT;
  1307. /* URGENT TODO: support namespace in keys */
  1308. PUSH(XSLT_OP_KEY, lit, lit2, novar);
  1309. lit = NULL;
  1310. lit2 = NULL;
  1311. } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
  1312. NEXT;
  1313. SKIP_BLANKS;
  1314. if (CUR != ')') {
  1315. lit = xsltScanLiteral(ctxt);
  1316. if (ctxt->error) {
  1317. xsltTransformError(NULL, NULL, NULL,
  1318. "xsltCompileIdKeyPattern : Literal expected\n");
  1319. xmlFree(lit);
  1320. return;
  1321. }
  1322. SKIP_BLANKS;
  1323. if (CUR != ')') {
  1324. xsltTransformError(NULL, NULL, NULL,
  1325. "xsltCompileIdKeyPattern : ) expected\n");
  1326. ctxt->error = 1;
  1327. xmlFree(lit);
  1328. return;
  1329. }
  1330. }
  1331. NEXT;
  1332. PUSH(XSLT_OP_PI, lit, NULL, novar);
  1333. lit = NULL;
  1334. } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
  1335. NEXT;
  1336. SKIP_BLANKS;
  1337. if (CUR != ')') {
  1338. xsltTransformError(NULL, NULL, NULL,
  1339. "xsltCompileIdKeyPattern : ) expected\n");
  1340. ctxt->error = 1;
  1341. return;
  1342. }
  1343. NEXT;
  1344. PUSH(XSLT_OP_TEXT, NULL, NULL, novar);
  1345. } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
  1346. NEXT;
  1347. SKIP_BLANKS;
  1348. if (CUR != ')') {
  1349. xsltTransformError(NULL, NULL, NULL,
  1350. "xsltCompileIdKeyPattern : ) expected\n");
  1351. ctxt->error = 1;
  1352. return;
  1353. }
  1354. NEXT;
  1355. PUSH(XSLT_OP_COMMENT, NULL, NULL, novar);
  1356. } else if (xmlStrEqual(name, (const xmlChar *)"node")) {
  1357. NEXT;
  1358. SKIP_BLANKS;
  1359. if (CUR != ')') {
  1360. xsltTransformError(NULL, NULL, NULL,
  1361. "xsltCompileIdKeyPattern : ) expected\n");
  1362. ctxt->error = 1;
  1363. return;
  1364. }
  1365. NEXT;
  1366. if (axis == AXIS_ATTRIBUTE) {
  1367. PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
  1368. }
  1369. else {
  1370. PUSH(XSLT_OP_NODE, NULL, NULL, novar);
  1371. }
  1372. } else if (aid) {
  1373. xsltTransformError(NULL, NULL, NULL,
  1374. "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
  1375. ctxt->error = 1;
  1376. return;
  1377. } else {
  1378. xsltTransformError(NULL, NULL, NULL,
  1379. "xsltCompileIdKeyPattern : node type\n");
  1380. ctxt->error = 1;
  1381. return;
  1382. }
  1383. error:
  1384. return;
  1385. }
  1386. /**
  1387. * xsltCompileStepPattern:
  1388. * @ctxt: the compilation context
  1389. * @token: a posible precompiled name
  1390. * @novar: flag to prohibit xslt variables from pattern
  1391. *
  1392. * Compile the XSLT StepPattern and generates a precompiled
  1393. * form suitable for fast matching.
  1394. *
  1395. * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
  1396. * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
  1397. * | ('child' | 'attribute') '::'
  1398. * from XPath
  1399. * [7] NodeTest ::= NameTest
  1400. * | NodeType '(' ')'
  1401. * | 'processing-instruction' '(' Literal ')'
  1402. * [8] Predicate ::= '[' PredicateExpr ']'
  1403. * [9] PredicateExpr ::= Expr
  1404. * [13] AbbreviatedAxisSpecifier ::= '@'?
  1405. * [37] NameTest ::= '*' | NCName ':' '*' | QName
  1406. */
  1407. static void
  1408. xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
  1409. xmlChar *name = NULL;
  1410. const xmlChar *URI = NULL;
  1411. xmlChar *URL = NULL;
  1412. int level;
  1413. xsltAxis axis = 0;
  1414. SKIP_BLANKS;
  1415. if ((token == NULL) && (CUR == '@')) {
  1416. NEXT;
  1417. axis = AXIS_ATTRIBUTE;
  1418. }
  1419. parse_node_test:
  1420. if (token == NULL)
  1421. token = xsltScanNCName(ctxt);
  1422. if (token == NULL) {
  1423. if (CUR == '*') {
  1424. NEXT;
  1425. if (axis == AXIS_ATTRIBUTE) {
  1426. PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
  1427. }
  1428. else {
  1429. PUSH(XSLT_OP_ALL, NULL, NULL, novar);
  1430. }
  1431. goto parse_predicate;
  1432. } else {
  1433. xsltTransformError(NULL, NULL, NULL,
  1434. "xsltCompileStepPattern : Name expected\n");
  1435. ctxt->error = 1;
  1436. goto error;
  1437. }
  1438. }
  1439. SKIP_BLANKS;
  1440. if (CUR == '(') {
  1441. xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis);
  1442. xmlFree(token);
  1443. token = NULL;
  1444. if (ctxt->error)
  1445. goto error;
  1446. } else if (CUR == ':') {
  1447. NEXT;
  1448. if (CUR != ':') {
  1449. xmlChar *prefix = token;
  1450. xmlNsPtr ns;
  1451. /*
  1452. * This is a namespace match
  1453. */
  1454. token = xsltScanNCName(ctxt);
  1455. ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
  1456. if (ns == NULL) {
  1457. xsltTransformError(NULL, NULL, NULL,
  1458. "xsltCompileStepPattern : no namespace bound to prefix %s\n",
  1459. prefix);
  1460. xmlFree(prefix);
  1461. prefix=NULL;
  1462. ctxt->error = 1;
  1463. goto error;
  1464. } else {
  1465. URL = xmlStrdup(ns->href);
  1466. }
  1467. xmlFree(prefix);
  1468. prefix=NULL;
  1469. if (token == NULL) {
  1470. if (CUR == '*') {
  1471. NEXT;
  1472. if (axis == AXIS_ATTRIBUTE) {
  1473. PUSH(XSLT_OP_ATTR, NULL, URL, novar);
  1474. URL = NULL;
  1475. }
  1476. else {
  1477. PUSH(XSLT_OP_NS, URL, NULL, novar);
  1478. URL = NULL;
  1479. }
  1480. } else {
  1481. xsltTransformError(NULL, NULL, NULL,
  1482. "xsltCompileStepPattern : Name expected\n");
  1483. ctxt->error = 1;
  1484. xmlFree(URL);
  1485. goto error;
  1486. }
  1487. } else {
  1488. if (axis == AXIS_ATTRIBUTE) {
  1489. PUSH(XSLT_OP_ATTR, token, URL, novar);
  1490. token = NULL;
  1491. URL = NULL;
  1492. }
  1493. else {
  1494. PUSH(XSLT_OP_ELEM, token, URL, novar);
  1495. token = NULL;
  1496. URL = NULL;
  1497. }
  1498. }
  1499. } else {
  1500. if (axis != 0) {
  1501. xsltTransformError(NULL, NULL, NULL,
  1502. "xsltCompileStepPattern : NodeTest expected\n");
  1503. ctxt->error = 1;
  1504. goto error;
  1505. }
  1506. NEXT;
  1507. if (xmlStrEqual(token, (const xmlChar *) "child")) {
  1508. axis = AXIS_CHILD;
  1509. } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
  1510. axis = AXIS_ATTRIBUTE;
  1511. } else {
  1512. xsltTransformError(NULL, NULL, NULL,
  1513. "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
  1514. ctxt->error = 1;
  1515. goto error;
  1516. }
  1517. xmlFree(token);
  1518. token = NULL;
  1519. SKIP_BLANKS;
  1520. token = xsltScanNCName(ctxt);
  1521. goto parse_node_test;
  1522. }
  1523. } else {
  1524. URI = xsltGetQNameURI(ctxt->elem, &token);
  1525. if (token == NULL) {
  1526. ctxt->error = 1;
  1527. goto error;
  1528. }
  1529. if (URI != NULL)
  1530. URL = xmlStrdup(URI);
  1531. if (axis == AXIS_ATTRIBUTE) {
  1532. PUSH(XSLT_OP_ATTR, token, URL, novar);
  1533. token = NULL;
  1534. URL = NULL;
  1535. }
  1536. else {
  1537. PUSH(XSLT_OP_ELEM, token, URL, novar);
  1538. token = NULL;
  1539. URL = NULL;
  1540. }
  1541. }
  1542. parse_predicate:
  1543. SKIP_BLANKS;
  1544. level = 0;
  1545. while (CUR == '[') {
  1546. const xmlChar *q;
  1547. xmlChar *ret = NULL;
  1548. level++;
  1549. NEXT;
  1550. q = CUR_PTR;
  1551. while (CUR != 0) {
  1552. /* Skip over nested predicates */
  1553. if (CUR == '[')
  1554. level++;
  1555. else if (CUR == ']') {
  1556. level--;
  1557. if (level == 0)
  1558. break;
  1559. } else if (CUR == '"') {
  1560. NEXT;
  1561. while ((CUR != 0) && (CUR != '"'))
  1562. NEXT;
  1563. } else if (CUR == '\'') {
  1564. NEXT;
  1565. while ((CUR != 0) && (CUR != '\''))
  1566. NEXT;
  1567. }
  1568. NEXT;
  1569. }
  1570. if (CUR == 0) {
  1571. xsltTransformError(NULL, NULL, NULL,
  1572. "xsltCompileStepPattern : ']' expected\n");
  1573. ctxt->error = 1;
  1574. return;
  1575. }
  1576. ret = xmlStrndup(q, CUR_PTR - q);
  1577. PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);
  1578. ret = NULL;
  1579. /* push the predicate lower than local test */
  1580. SWAP();
  1581. NEXT;
  1582. SKIP_BLANKS;
  1583. }
  1584. return;
  1585. error:
  1586. if (token != NULL)
  1587. xmlFree(token);
  1588. if (name != NULL)
  1589. xmlFree(name);
  1590. }
  1591. /**
  1592. * xsltCompileRelativePathPattern:
  1593. * @comp: the compilation context
  1594. * @token: a posible precompiled name
  1595. * @novar: flag to prohibit xslt variables
  1596. *
  1597. * Compile the XSLT RelativePathPattern and generates a precompiled
  1598. * form suitable for fast matching.
  1599. *
  1600. * [4] RelativePathPattern ::= StepPattern
  1601. * | RelativePathPattern '/' StepPattern
  1602. * | RelativePathPattern '//' StepPattern
  1603. */
  1604. static void
  1605. xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
  1606. xsltCompileStepPattern(ctxt, token, novar);
  1607. if (ctxt->error)
  1608. goto error;
  1609. SKIP_BLANKS;
  1610. while ((CUR != 0) && (CUR != '|')) {
  1611. if ((CUR == '/') && (NXT(1) == '/')) {
  1612. PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
  1613. NEXT;
  1614. NEXT;
  1615. SKIP_BLANKS;
  1616. xsltCompileStepPattern(ctxt, NULL, novar);
  1617. } else if (CUR == '/') {
  1618. PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
  1619. NEXT;
  1620. SKIP_BLANKS;
  1621. xsltCompileStepPattern(ctxt, NULL, novar);
  1622. } else {
  1623. ctxt->error = 1;
  1624. }
  1625. if (ctxt->error)
  1626. goto error;
  1627. SKIP_BLANKS;
  1628. }
  1629. error:
  1630. return;
  1631. }
  1632. /**
  1633. * xsltCompileLocationPathPattern:
  1634. * @ctxt: the compilation context
  1635. * @novar: flag to prohibit xslt variables
  1636. *
  1637. * Compile the XSLT LocationPathPattern and generates a precompiled
  1638. * form suitable for fast matching.
  1639. *
  1640. * [2] LocationPathPattern ::= '/' RelativePathPattern?
  1641. * | IdKeyPattern (('/' | '//') RelativePathPattern)?
  1642. * | '//'? RelativePathPattern
  1643. */
  1644. static void
  1645. xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {
  1646. SKIP_BLANKS;
  1647. if ((CUR == '/') && (NXT(1) == '/')) {
  1648. /*
  1649. * since we reverse the query
  1650. * a leading // can be safely ignored
  1651. */
  1652. NEXT;
  1653. NEXT;
  1654. ctxt->comp->priority = 0.5; /* '//' means not 0 priority */
  1655. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1656. } else if (CUR == '/') {
  1657. /*
  1658. * We need to find root as the parent
  1659. */
  1660. NEXT;
  1661. SKIP_BLANKS;
  1662. PUSH(XSLT_OP_ROOT, NULL, NULL, novar);
  1663. if ((CUR != 0) && (CUR != '|')) {
  1664. PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
  1665. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1666. }
  1667. } else if (CUR == '*') {
  1668. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1669. } else if (CUR == '@') {
  1670. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1671. } else {
  1672. xmlChar *name;
  1673. name = xsltScanNCName(ctxt);
  1674. if (name == NULL) {
  1675. xsltTransformError(NULL, NULL, NULL,
  1676. "xsltCompileLocationPathPattern : Name expected\n");
  1677. ctxt->error = 1;
  1678. return;
  1679. }
  1680. SKIP_BLANKS;
  1681. if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
  1682. xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0);
  1683. xmlFree(name);
  1684. name = NULL;
  1685. if (ctxt->error)
  1686. return;
  1687. if ((CUR == '/') && (NXT(1) == '/')) {
  1688. PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
  1689. NEXT;
  1690. NEXT;
  1691. SKIP_BLANKS;
  1692. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1693. } else if (CUR == '/') {
  1694. PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
  1695. NEXT;
  1696. SKIP_BLANKS;
  1697. xsltCompileRelativePathPattern(ctxt, NULL, novar);
  1698. }
  1699. return;
  1700. }
  1701. xsltCompileRelativePathPattern(ctxt, name, novar);
  1702. }
  1703. error:
  1704. return;
  1705. }
  1706. /**
  1707. * xsltCompilePatternInternal:
  1708. * @pattern: an XSLT pattern
  1709. * @doc: the containing document
  1710. * @node: the containing element
  1711. * @style: the stylesheet
  1712. * @runtime: the transformation context, if done at run-time
  1713. * @novar: flag to prohibit xslt variables
  1714. *
  1715. * Compile the XSLT pattern and generates a list of precompiled form suitable
  1716. * for fast matching.
  1717. *
  1718. * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
  1719. *
  1720. * Returns the generated pattern list or NULL in case of failure
  1721. */
  1722. static xsltCompMatchPtr
  1723. xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
  1724. xmlNodePtr node, xsltStylesheetPtr style,
  1725. xsltTransformContextPtr runtime, int novar) {
  1726. xsltParserContextPtr ctxt = NULL;
  1727. xsltCompMatchPtr element, first = NULL, previous = NULL;
  1728. int current, start, end, level, j;
  1729. if (pattern == NULL) {
  1730. xsltTransformError(NULL, NULL, node,
  1731. "xsltCompilePattern : NULL pattern\n");
  1732. return(NULL);
  1733. }
  1734. ctxt = xsltNewParserContext(style, runtime);
  1735. if (ctxt == NULL)
  1736. return(NULL);
  1737. ctxt->doc = doc;
  1738. ctxt->elem = node;
  1739. current = end = 0;
  1740. while (pattern[current] != 0) {
  1741. start = current;
  1742. while (IS_BLANK_CH(pattern[current]))
  1743. current++;
  1744. end = current;
  1745. level = 0;
  1746. while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {
  1747. if (pattern[end] == '[')
  1748. level++;
  1749. else if (pattern[end] == ']')
  1750. level--;
  1751. else if (pattern[end] == '\'') {
  1752. end++;
  1753. while ((pattern[end] != 0) && (pattern[end] != '\''))
  1754. end++;
  1755. } else if (pattern[end] == '"') {
  1756. end++;
  1757. while ((pattern[end] != 0) && (pattern[end] != '"'))
  1758. end++;
  1759. }
  1760. if (pattern[end] == 0)
  1761. break;
  1762. end++;
  1763. }
  1764. if (current == end) {
  1765. xsltTransformError(NULL, NULL, node,
  1766. "xsltCompilePattern : NULL pattern\n");
  1767. goto error;
  1768. }
  1769. element = xsltNewCompMatch();
  1770. if (element == NULL) {
  1771. goto error;
  1772. }
  1773. if (first == NULL)
  1774. first = element;
  1775. else if (previous != NULL)
  1776. previous->next = element;
  1777. previous = element;
  1778. ctxt->comp = element;
  1779. ctxt->base = xmlStrndup(&pattern[start], end - start);
  1780. if (ctxt->base == NULL)
  1781. goto error;
  1782. ctxt->cur = &(ctxt->base)[current - start];
  1783. element->pattern = ctxt->base;
  1784. element->node = node;
  1785. element->nsList = xmlGetNsList(doc, node);
  1786. j = 0;
  1787. if (element->nsList != NULL) {
  1788. while (element->nsList[j] != NULL)
  1789. j++;
  1790. }
  1791. element->nsNr = j;
  1792. #ifdef WITH_XSLT_DEBUG_PATTERN
  1793. xsltGenericDebug(xsltGenericDebugContext,
  1794. "xsltCompilePattern : parsing '%s'\n",
  1795. element->pattern);
  1796. #endif
  1797. /*
  1798. Preset default priority to be zero.
  1799. This may be changed by xsltCompileLocationPathPattern.
  1800. */
  1801. element->priority = 0;
  1802. xsltCompileLocationPathPattern(ctxt, novar);
  1803. if (ctxt->error) {
  1804. xsltTransformError(NULL, style, node,
  1805. "xsltCompilePattern : failed to compile '%s'\n",
  1806. element->pattern);
  1807. if (style != NULL) style->errors++;
  1808. goto error;
  1809. }
  1810. /*
  1811. * Reverse for faster interpretation.
  1812. */
  1813. xsltReverseCompMatch(ctxt, element);
  1814. /*
  1815. * Set-up the priority
  1816. */
  1817. if (element->priority == 0) { /* if not yet determined */
  1818. if (((element->steps[0].op == XSLT_OP_ELEM) ||
  1819. (element->steps[0].op == XSLT_OP_ATTR) ||
  1820. (element->steps[0].op == XSLT_OP_PI)) &&
  1821. (element->steps[0].value != NULL) &&
  1822. (element->steps[1].op == XSLT_OP_END)) {
  1823. ; /* previously preset */
  1824. } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
  1825. (element->steps[0].value2 != NULL) &&
  1826. (element->steps[1].op == XSLT_OP_END)) {
  1827. element->priority = -0.25;
  1828. } else if ((element->steps[0].op == XSLT_OP_NS) &&
  1829. (element->steps[0].value != NULL) &&
  1830. (element->steps[1].op == XSLT_OP_END)) {
  1831. element->priority = -0.25;
  1832. } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
  1833. (element->steps[0].value == NULL) &&
  1834. (element->steps[0].value2 == NULL) &&
  1835. (element->steps[1].op == XSLT_OP_END)) {
  1836. element->priority = -0.5;
  1837. } else if (((element->steps[0].op == XSLT_OP_PI) ||
  1838. (element->steps[0].op == XSLT_OP_TEXT) ||
  1839. (element->steps[0].op == XSLT_OP_ALL) ||
  1840. (element->steps[0].op == XSLT_OP_NODE) ||
  1841. (element->steps[0].op == XSLT_OP_COMMENT)) &&
  1842. (element->steps[1].op == XSLT_OP_END)) {
  1843. element->priority = -0.5;
  1844. } else {
  1845. element->priority = 0.5;
  1846. }
  1847. }
  1848. #ifdef WITH_XSLT_DEBUG_PATTERN
  1849. xsltGenericDebug(xsltGenericDebugContext,
  1850. "xsltCompilePattern : parsed %s, default priority %f\n",
  1851. element->pattern, element->priority);
  1852. #endif
  1853. if (pattern[end] == '|')
  1854. end++;
  1855. current = end;
  1856. }
  1857. if (end == 0) {
  1858. xsltTransformError(NULL, style, node,
  1859. "xsltCompilePattern : NULL pattern\n");
  1860. if (style != NULL) style->errors++;
  1861. goto error;
  1862. }
  1863. xsltFreeParserContext(ctxt);
  1864. return(first);
  1865. error:
  1866. if (ctxt != NULL)
  1867. xsltFreeParserContext(ctxt);
  1868. if (first != NULL)
  1869. xsltFreeCompMatchList(first);
  1870. return(NULL);
  1871. }
  1872. /**
  1873. * xsltCompilePattern:
  1874. * @pattern: an XSLT pattern
  1875. * @doc: the containing document
  1876. * @node: the containing element
  1877. * @style: the stylesheet
  1878. * @runtime: the transformation context, if done at run-time
  1879. *
  1880. * Compile the XSLT pattern and generates a list of precompiled form suitable
  1881. * for fast matching.
  1882. *
  1883. * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
  1884. *
  1885. * Returns the generated pattern list or NULL in case of failure
  1886. */
  1887. xsltCompMatchPtr
  1888. xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc,
  1889. xmlNodePtr node, xsltStylesheetPtr style,
  1890. xsltTransformContextPtr runtime) {
  1891. return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));
  1892. }
  1893. /************************************************************************
  1894. * *
  1895. * Module interfaces *
  1896. * *
  1897. ************************************************************************/
  1898. /**
  1899. * xsltAddTemplate:
  1900. * @style: an XSLT stylesheet
  1901. * @cur: an XSLT template
  1902. * @mode: the mode name or NULL
  1903. * @modeURI: the mode URI or NULL
  1904. *
  1905. * Register the XSLT pattern associated to @cur
  1906. *
  1907. * Returns -1 in case of error, 0 otherwise
  1908. */
  1909. int
  1910. xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
  1911. const xmlChar *mode, const xmlChar *modeURI) {
  1912. xsltCompMatchPtr pat, list, next;
  1913. /*
  1914. * 'top' will point to style->xxxMatch ptr - declaring as 'void'
  1915. * avoids gcc 'type-punned pointer' warning.
  1916. */
  1917. xsltCompMatchPtr *top = NULL;
  1918. const xmlChar *name = NULL;
  1919. float priority; /* the priority */
  1920. if ((style == NULL) || (cur == NULL))
  1921. return(-1);
  1922. if (cur->next != NULL)
  1923. cur->position = cur->next->position + 1;
  1924. /* Register named template */
  1925. if (cur->name != NULL) {
  1926. if (style->namedTemplates == NULL) {
  1927. style->namedTemplates = xmlHashCreate(10);
  1928. if (style->namedTemplates == NULL)
  1929. return(-1);
  1930. }
  1931. else {
  1932. void *dup = xmlHashLookup2(style->namedTemplates, cur->name,
  1933. cur->nameURI);
  1934. if (dup != NULL) {
  1935. xsltTransformError(NULL, style, cur->elem,
  1936. "xsl:template: error duplicate name '%s'\n",
  1937. cur->name);
  1938. style->errors++;
  1939. return(-1);
  1940. }
  1941. }
  1942. xmlHashAddEntry2(style->namedTemplates, cur->name, cur->nameURI, cur);
  1943. }
  1944. if (cur->match == NULL) {
  1945. if (cur->name == NULL) {
  1946. xsltTransformError(NULL, style, cur->elem,
  1947. "xsl:template: need to specify match or name attribute\n");
  1948. style->errors++;
  1949. return(-1);
  1950. }
  1951. return(0);
  1952. }
  1953. priority = cur->priority;
  1954. pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
  1955. style, NULL, 1);
  1956. if (pat == NULL)
  1957. return(-1);
  1958. while (pat) {
  1959. next = pat->next;
  1960. pat->next = NULL;
  1961. name = NULL;
  1962. pat->template = cur;
  1963. if (mode != NULL)
  1964. pat->mode = xmlDictLookup(style->dict, mode, -1);
  1965. if (modeURI != NULL)
  1966. pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
  1967. if (priority != XSLT_PAT_NO_PRIORITY)
  1968. pat->priority = priority;
  1969. /*
  1970. * insert it in the hash table list corresponding to its lookup name
  1971. */
  1972. switch (pat->steps[0].op) {
  1973. case XSLT_OP_ATTR:
  1974. if (pat->steps[0].value != NULL)
  1975. name = pat->steps[0].value;
  1976. else
  1977. top = &(style->attrMatch);
  1978. break;
  1979. case XSLT_OP_PARENT:
  1980. case XSLT_OP_ANCESTOR:
  1981. top = &(style->elemMatch);
  1982. break;
  1983. case XSLT_OP_ROOT:
  1984. top = &(style->rootMatch);
  1985. break;
  1986. case XSLT_OP_KEY:
  1987. top = &(style->keyMatch);
  1988. break;
  1989. case XSLT_OP_ID:
  1990. /* TODO optimize ID !!! */
  1991. case XSLT_OP_NS:
  1992. case XSLT_OP_ALL:
  1993. top = &(style->elemMatch);
  1994. break;
  1995. case XSLT_OP_END:
  1996. case XSLT_OP_PREDICATE:
  1997. xsltTransformError(NULL, style, NULL,
  1998. "xsltAddTemplate: invalid compiled pattern\n");
  1999. xsltFreeCompMatch(pat);
  2000. return(-1);
  2001. /*
  2002. * TODO: some flags at the top level about type based patterns
  2003. * would be faster than inclusion in the hash table.
  2004. */
  2005. case XSLT_OP_PI:
  2006. if (pat->steps[0].value != NULL)
  2007. name = pat->steps[0].value;
  2008. else
  2009. top = &(style->piMatch);
  2010. break;
  2011. case XSLT_OP_COMMENT:
  2012. top = &(style->commentMatch);
  2013. break;
  2014. case XSLT_OP_TEXT:
  2015. top = &(style->textMatch);
  2016. break;
  2017. case XSLT_OP_ELEM:
  2018. case XSLT_OP_NODE:
  2019. if (pat->steps[0].value != NULL)
  2020. name = pat->steps[0].value;
  2021. else
  2022. top = &(style->elemMatch);
  2023. break;
  2024. }
  2025. if (name != NULL) {
  2026. if (style->templatesHash == NULL) {
  2027. style->templatesHash = xmlHashCreate(1024);
  2028. if (style->templatesHash == NULL) {
  2029. xsltFreeCompMatch(pat);
  2030. return(-1);
  2031. }
  2032. xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
  2033. } else {
  2034. list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
  2035. name, mode, modeURI);
  2036. if (list == NULL) {
  2037. xmlHashAddEntry3(style->templatesHash, name,
  2038. mode, modeURI, pat);
  2039. } else {
  2040. /*
  2041. * Note '<=' since one must choose among the matching
  2042. * template rules that are left, the one that occurs
  2043. * last in the stylesheet
  2044. */
  2045. if (list->priority <= pat->priority) {
  2046. pat->next = list;
  2047. xmlHashUpdateEntry3(style->templatesHash, name,
  2048. mode, modeURI, pat, NULL);
  2049. } else {
  2050. while (list->next != NULL) {
  2051. if (list->next->priority <= pat->priority)
  2052. break;
  2053. list = list->next;
  2054. }
  2055. pat->next = list->next;
  2056. list->next = pat;
  2057. }
  2058. }
  2059. }
  2060. } else if (top != NULL) {
  2061. list = *top;
  2062. if (list == NULL) {
  2063. *top = pat;
  2064. pat->next = NULL;
  2065. } else if (list->priority <= pat->priority) {
  2066. pat->next = list;
  2067. *top = pat;
  2068. } else {
  2069. while (list->next != NULL) {
  2070. if (list->next->priority <= pat->priority)
  2071. break;
  2072. list = list->next;
  2073. }
  2074. pat->next = list->next;
  2075. list->next = pat;
  2076. }
  2077. } else {
  2078. xsltTransformError(NULL, style, NULL,
  2079. "xsltAddTemplate: invalid compiled pattern\n");
  2080. xsltFreeCompMatch(pat);
  2081. return(-1);
  2082. }
  2083. #ifdef WITH_XSLT_DEBUG_PATTERN
  2084. if (mode)
  2085. xsltGenericDebug(xsltGenericDebugContext,
  2086. "added pattern : '%s' mode '%s' priority %f\n",
  2087. pat->pattern, pat->mode, pat->priority);
  2088. else
  2089. xsltGenericDebug(xsltGenericDebugContext,
  2090. "added pattern : '%s' priority %f\n",
  2091. pat->pattern, pat->priority);
  2092. #endif
  2093. pat = next;
  2094. }
  2095. return(0);
  2096. }
  2097. static int
  2098. xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)
  2099. {
  2100. if ((ctxt == NULL) || (contextNode == NULL)) {
  2101. xsltTransformError(ctxt, NULL, ctxt->inst,
  2102. "Internal error in xsltComputeAllKeys(): "
  2103. "Bad arguments.\n");
  2104. return(-1);
  2105. }
  2106. if (ctxt->document == NULL) {
  2107. /*
  2108. * The document info will only be NULL if we have a RTF.
  2109. */
  2110. if (contextNode->doc->_private != NULL)
  2111. goto doc_info_mismatch;
  2112. /*
  2113. * On-demand creation of the document info (needed for keys).
  2114. */
  2115. ctxt->document = xsltNewDocument(ctxt, contextNode->doc);
  2116. if (ctxt->document == NULL)
  2117. return(-1);
  2118. }
  2119. return xsltInitAllDocKeys(ctxt);
  2120. doc_info_mismatch:
  2121. xsltTransformError(ctxt, NULL, ctxt->inst,
  2122. "Internal error in xsltComputeAllKeys(): "
  2123. "The context's document info doesn't match the "
  2124. "document info of the current result tree.\n");
  2125. ctxt->state = XSLT_STATE_STOPPED;
  2126. return(-1);
  2127. }
  2128. /**
  2129. * xsltGetTemplate:
  2130. * @ctxt: a XSLT process context
  2131. * @node: the node being processed
  2132. * @style: the current style
  2133. *
  2134. * Finds the template applying to this node, if @style is non-NULL
  2135. * it means one needs to look for the next imported template in scope.
  2136. *
  2137. * Returns the xsltTemplatePtr or NULL if not found
  2138. */
  2139. xsltTemplatePtr
  2140. xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
  2141. xsltStylesheetPtr style)
  2142. {
  2143. xsltStylesheetPtr curstyle;
  2144. xsltTemplatePtr ret = NULL;
  2145. const xmlChar *name = NULL;
  2146. xsltCompMatchPtr list = NULL;
  2147. float priority;
  2148. int keyed = 0;
  2149. if ((ctxt == NULL) || (node == NULL))
  2150. return(NULL);
  2151. if (style == NULL) {
  2152. curstyle = ctxt->style;
  2153. } else {
  2154. curstyle = xsltNextImport(style);
  2155. }
  2156. while ((curstyle != NULL) && (curstyle != style)) {
  2157. priority = XSLT_PAT_NO_PRIORITY;
  2158. /* TODO : handle IDs/keys here ! */
  2159. if (curstyle->templatesHash != NULL) {
  2160. /*
  2161. * Use the top name as selector
  2162. */
  2163. switch (node->type) {
  2164. case XML_ELEMENT_NODE:
  2165. if (node->name[0] == ' ')
  2166. break;
  2167. /* Intentional fall-through */
  2168. case XML_ATTRIBUTE_NODE:
  2169. case XML_PI_NODE:
  2170. name = node->name;
  2171. break;
  2172. case XML_DOCUMENT_NODE:
  2173. case XML_HTML_DOCUMENT_NODE:
  2174. case XML_TEXT_NODE:
  2175. case XML_CDATA_SECTION_NODE:
  2176. case XML_COMMENT_NODE:
  2177. case XML_ENTITY_REF_NODE:
  2178. case XML_ENTITY_NODE:
  2179. case XML_DOCUMENT_TYPE_NODE:
  2180. case XML_DOCUMENT_FRAG_NODE:
  2181. case XML_NOTATION_NODE:
  2182. case XML_DTD_NODE:
  2183. case XML_ELEMENT_DECL:
  2184. case XML_ATTRIBUTE_DECL:
  2185. case XML_ENTITY_DECL:
  2186. case XML_NAMESPACE_DECL:
  2187. case XML_XINCLUDE_START:
  2188. case XML_XINCLUDE_END:
  2189. break;
  2190. default:
  2191. return(NULL);
  2192. }
  2193. }
  2194. if (name != NULL) {
  2195. /*
  2196. * find the list of applicable expressions based on the name
  2197. */
  2198. list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
  2199. name, ctxt->mode, ctxt->modeURI);
  2200. } else
  2201. list = NULL;
  2202. while (list != NULL) {
  2203. if (xsltTestCompMatch(ctxt, list, node,
  2204. ctxt->mode, ctxt->modeURI) == 1) {
  2205. ret = list->template;
  2206. priority = list->priority;
  2207. break;
  2208. }
  2209. list = list->next;
  2210. }
  2211. list = NULL;
  2212. /*
  2213. * find alternate generic matches
  2214. */
  2215. switch (node->type) {
  2216. case XML_ELEMENT_NODE:
  2217. if (node->name[0] == ' ')
  2218. list = curstyle->rootMatch;
  2219. else
  2220. list = curstyle->elemMatch;
  2221. if (node->psvi != NULL) keyed = 1;
  2222. break;
  2223. case XML_ATTRIBUTE_NODE: {
  2224. xmlAttrPtr attr;
  2225. list = curstyle->attrMatch;
  2226. attr = (xmlAttrPtr) node;
  2227. if (attr->psvi != NULL) keyed = 1;
  2228. break;
  2229. }
  2230. case XML_PI_NODE:
  2231. list = curstyle->piMatch;
  2232. if (node->psvi != NULL) keyed = 1;
  2233. break;
  2234. case XML_DOCUMENT_NODE:
  2235. case XML_HTML_DOCUMENT_NODE: {
  2236. xmlDocPtr doc;
  2237. list = curstyle->rootMatch;
  2238. doc = (xmlDocPtr) node;
  2239. if (doc->psvi != NULL) keyed = 1;
  2240. break;
  2241. }
  2242. case XML_TEXT_NODE:
  2243. case XML_CDATA_SECTION_NODE:
  2244. list = curstyle->textMatch;
  2245. if (node->psvi != NULL) keyed = 1;
  2246. break;
  2247. case XML_COMMENT_NODE:
  2248. list = curstyle->commentMatch;
  2249. if (node->psvi != NULL) keyed = 1;
  2250. break;
  2251. case XML_ENTITY_REF_NODE:
  2252. case XML_ENTITY_NODE:
  2253. case XML_DOCUMENT_TYPE_NODE:
  2254. case XML_DOCUMENT_FRAG_NODE:
  2255. case XML_NOTATION_NODE:
  2256. case XML_DTD_NODE:
  2257. case XML_ELEMENT_DECL:
  2258. case XML_ATTRIBUTE_DECL:
  2259. case XML_ENTITY_DECL:
  2260. case XML_NAMESPACE_DECL:
  2261. case XML_XINCLUDE_START:
  2262. case XML_XINCLUDE_END:
  2263. break;
  2264. default:
  2265. break;
  2266. }
  2267. while ((list != NULL) &&
  2268. ((ret == NULL) ||
  2269. (list->priority > priority) ||
  2270. ((list->priority == priority) &&
  2271. (list->template->position > ret->position)))) {
  2272. if (xsltTestCompMatch(ctxt, list, node,
  2273. ctxt->mode, ctxt->modeURI) == 1) {
  2274. ret = list->template;
  2275. priority = list->priority;
  2276. break;
  2277. }
  2278. list = list->next;
  2279. }
  2280. /*
  2281. * Some of the tests for elements can also apply to documents
  2282. */
  2283. if ((node->type == XML_DOCUMENT_NODE) ||
  2284. (node->type == XML_HTML_DOCUMENT_NODE) ||
  2285. (node->type == XML_TEXT_NODE)) {
  2286. list = curstyle->elemMatch;
  2287. while ((list != NULL) &&
  2288. ((ret == NULL) ||
  2289. (list->priority > priority) ||
  2290. ((list->priority == priority) &&
  2291. (list->template->position > ret->position)))) {
  2292. if (xsltTestCompMatch(ctxt, list, node,
  2293. ctxt->mode, ctxt->modeURI) == 1) {
  2294. ret = list->template;
  2295. priority = list->priority;
  2296. break;
  2297. }
  2298. list = list->next;
  2299. }
  2300. } else if ((node->type == XML_PI_NODE) ||
  2301. (node->type == XML_COMMENT_NODE)) {
  2302. list = curstyle->elemMatch;
  2303. while ((list != NULL) &&
  2304. ((ret == NULL) ||
  2305. (list->priority > priority) ||
  2306. ((list->priority == priority) &&
  2307. (list->template->position > ret->position)))) {
  2308. if (xsltTestCompMatch(ctxt, list, node,
  2309. ctxt->mode, ctxt->modeURI) == 1) {
  2310. ret = list->template;
  2311. priority = list->priority;
  2312. break;
  2313. }
  2314. list = list->next;
  2315. }
  2316. }
  2317. keyed_match:
  2318. if (keyed) {
  2319. list = curstyle->keyMatch;
  2320. while ((list != NULL) &&
  2321. ((ret == NULL) ||
  2322. (list->priority > priority) ||
  2323. ((list->priority == priority) &&
  2324. (list->template->position > ret->position)))) {
  2325. if (xsltTestCompMatch(ctxt, list, node,
  2326. ctxt->mode, ctxt->modeURI) == 1) {
  2327. ret = list->template;
  2328. priority = list->priority;
  2329. break;
  2330. }
  2331. list = list->next;
  2332. }
  2333. }
  2334. else if (ctxt->hasTemplKeyPatterns &&
  2335. ((ctxt->document == NULL) ||
  2336. (ctxt->document->nbKeysComputed < ctxt->nbKeys)))
  2337. {
  2338. /*
  2339. * Compute all remaining keys for this document.
  2340. *
  2341. * REVISIT TODO: I think this could be further optimized.
  2342. */
  2343. if (xsltComputeAllKeys(ctxt, node) == -1)
  2344. goto error;
  2345. switch (node->type) {
  2346. case XML_ELEMENT_NODE:
  2347. if (node->psvi != NULL) keyed = 1;
  2348. break;
  2349. case XML_ATTRIBUTE_NODE:
  2350. if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
  2351. break;
  2352. case XML_TEXT_NODE:
  2353. case XML_CDATA_SECTION_NODE:
  2354. case XML_COMMENT_NODE:
  2355. case XML_PI_NODE:
  2356. if (node->psvi != NULL) keyed = 1;
  2357. break;
  2358. case XML_DOCUMENT_NODE:
  2359. case XML_HTML_DOCUMENT_NODE:
  2360. if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
  2361. break;
  2362. default:
  2363. break;
  2364. }
  2365. if (keyed)
  2366. goto keyed_match;
  2367. }
  2368. if (ret != NULL)
  2369. return(ret);
  2370. /*
  2371. * Cycle on next curstylesheet import.
  2372. */
  2373. curstyle = xsltNextImport(curstyle);
  2374. }
  2375. error:
  2376. return(NULL);
  2377. }
  2378. /**
  2379. * xsltCleanupTemplates:
  2380. * @style: an XSLT stylesheet
  2381. *
  2382. * Cleanup the state of the templates used by the stylesheet and
  2383. * the ones it imports.
  2384. */
  2385. void
  2386. xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) {
  2387. }
  2388. /**
  2389. * xsltFreeTemplateHashes:
  2390. * @style: an XSLT stylesheet
  2391. *
  2392. * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism
  2393. */
  2394. void
  2395. xsltFreeTemplateHashes(xsltStylesheetPtr style) {
  2396. if (style->templatesHash != NULL)
  2397. xmlHashFree(style->templatesHash, xsltFreeCompMatchListEntry);
  2398. if (style->rootMatch != NULL)
  2399. xsltFreeCompMatchList(style->rootMatch);
  2400. if (style->keyMatch != NULL)
  2401. xsltFreeCompMatchList(style->keyMatch);
  2402. if (style->elemMatch != NULL)
  2403. xsltFreeCompMatchList(style->elemMatch);
  2404. if (style->attrMatch != NULL)
  2405. xsltFreeCompMatchList(style->attrMatch);
  2406. if (style->parentMatch != NULL)
  2407. xsltFreeCompMatchList(style->parentMatch);
  2408. if (style->textMatch != NULL)
  2409. xsltFreeCompMatchList(style->textMatch);
  2410. if (style->piMatch != NULL)
  2411. xsltFreeCompMatchList(style->piMatch);
  2412. if (style->commentMatch != NULL)
  2413. xsltFreeCompMatchList(style->commentMatch);
  2414. if (style->namedTemplates != NULL)
  2415. xmlHashFree(style->namedTemplates, NULL);
  2416. }