pattern.c 70 KB

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