xpath.pp 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. Implementation of the XML Path Language (XPath) for Free Pascal
  5. Copyright (c) 2000 - 2003 by
  6. Areca Systems GmbH / Sebastian Guenther, [email protected]
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit XPath;
  14. interface
  15. uses SysUtils, Classes, DOM;
  16. resourcestring
  17. { XPath variables type names }
  18. SNodeSet = 'node set';
  19. SBoolean = 'boolean';
  20. SNumber = 'number';
  21. SString = 'string';
  22. { Variable errors }
  23. SVarNoConversion = 'Conversion from %s to %s not possible';
  24. { Scanner errors }
  25. SScannerInternalError = 'Internal expression scanner error';
  26. SScannerQuotStringIsOpen = 'Ending ''"'' for string not found';
  27. SScannerAposStringIsOpen = 'Ending "''" for string not found';
  28. SScannerInvalidChar = 'Invalid character';
  29. { Parser errors }
  30. SParserExpectedLeftBracket = 'Expected ")"';
  31. SParserExpectedRightBracket = 'Expected ")"';
  32. SParserExpectedColonColor = 'Expected "::" after axis specifier';
  33. SParserExpectedBrackets = 'Expected "()" after NodeType test';
  34. SParserExpectedRightSquareBracket = 'Expected "]" after predicate';
  35. SParserInvalidPrimExpr = 'Invalid primary expression';
  36. SParserGarbageAfterExpression = 'Unrecognized input after expression';
  37. SParserInvalidNodeTest = 'Invalid node test (syntax error)';
  38. SParserExpectedVarName = 'Expected variable name after "$"';
  39. { Evaluation errors }
  40. SEvalUnknownFunction = 'Unknown function: "%s"';
  41. SEvalUnknownVariable = 'Unknown variable: "%s"';
  42. SEvalInvalidArgCount = 'Invalid number of function arguments';
  43. SEvalFunctionNotImplementedYet = 'Function "%s" has not been implemented yet'; // !!!
  44. type
  45. TXPathContext = class;
  46. TXPathEnvironment = class;
  47. TXPathVariable = class;
  48. { XPath lexical scanner }
  49. TXPathToken = ( // [28] - [38]
  50. tkInvalid,
  51. tkEndOfStream,
  52. tkIdentifier,
  53. tkString,
  54. tkNumber,
  55. tkDollar, // "$"
  56. tkLeftBracket, // "("
  57. tkRightBracket, // ")"
  58. tkAsterisk, // "*"
  59. tkPlus, // "+"
  60. tkComma, // ","
  61. tkMinus, // "-"
  62. tkDot, // "."
  63. tkDotDot, // ".."
  64. tkSlash, // "/"
  65. tkSlashSlash, // "//"
  66. tkColon, // ":"
  67. tkColonColon, // "::"
  68. tkLess, // "<"
  69. tkLessEqual, // "<="
  70. tkEqual, // "="
  71. tkNotEqual, // "!="
  72. tkGreater, // ">"
  73. tkGreaterEqual, // ">="
  74. tkAt, // "@"
  75. tkLeftSquareBracket, // "["
  76. tkRightSquareBracket, // "]"
  77. tkPipe // "|"
  78. );
  79. { XPath expression parse tree }
  80. TXPathExprNode = class
  81. public
  82. function Evaluate(AContext: TXPathContext;
  83. AEnvironment: TXPathEnvironment): TXPathVariable; virtual; abstract;
  84. end;
  85. TXPathConstantNode = class(TXPathExprNode)
  86. private
  87. FValue: TXPathVariable;
  88. public
  89. constructor Create(AValue: TXPathVariable);
  90. destructor Destroy; override;
  91. function Evaluate(AContext: TXPathContext;
  92. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  93. end;
  94. TXPathVariableNode = class(TXPathExprNode)
  95. private
  96. FName: DOMString;
  97. public
  98. constructor Create(const AName: DOMString);
  99. function Evaluate(AContext: TXPathContext;
  100. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  101. end;
  102. TXPathFunctionNode = class(TXPathExprNode)
  103. private
  104. FName: DOMString;
  105. FArgs: TList;
  106. public
  107. constructor Create(const AName: DOMString);
  108. destructor Destroy; override;
  109. function Evaluate(AContext: TXPathContext;
  110. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  111. end;
  112. TXPathNegationNode = class(TXPathExprNode)
  113. private
  114. FOperand: TXPathExprNode;
  115. public
  116. constructor Create(AOperand: TXPathExprNode);
  117. destructor Destroy; override;
  118. function Evaluate(AContext: TXPathContext;
  119. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  120. end;
  121. // Node for (binary) mathematical operation
  122. TXPathMathOp = (opAdd, opSubtract, opMultiply, opDivide, opMod);
  123. TXPathMathOpNode = class(TXPathExprNode)
  124. private
  125. FOperand1, FOperand2: TXPathExprNode;
  126. FOperator: TXPathMathOp;
  127. public
  128. constructor Create(AOperator: TXPathMathOp;
  129. AOperand1, AOperand2: TXPathExprNode);
  130. destructor Destroy; override;
  131. function Evaluate(AContext: TXPathContext;
  132. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  133. end;
  134. // Node for boolean operations
  135. TXPathBooleanOp = (opEqual, opNotEqual, opLess, opLessEqual, opGreater,
  136. opGreaterEqual, opOr, opAnd);
  137. TXPathBooleanOpNode = class(TXPathExprNode)
  138. private
  139. FOperand1, FOperand2: TXPathExprNode;
  140. FOperator: TXPathBooleanOp;
  141. public
  142. constructor Create(AOperator: TXPathBooleanOp;
  143. AOperand1, AOperand2: TXPathExprNode);
  144. destructor Destroy; override;
  145. function Evaluate(AContext: TXPathContext;
  146. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  147. end;
  148. // Node for unions (see [18])
  149. TXPathUnionNode = class(TXPathExprNode)
  150. private
  151. FOperand1, FOperand2: TXPathExprNode;
  152. public
  153. constructor Create(AOperand1, AOperand2: TXPathExprNode);
  154. destructor Destroy; override;
  155. function Evaluate(AContext: TXPathContext;
  156. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  157. end;
  158. // Filter node (for [20])
  159. TXPathFilterNode = class(TXPathExprNode)
  160. private
  161. FExpr: TXPathExprNode;
  162. FPredicates: TList;
  163. public
  164. constructor Create(AExpr: TXPathExprNode);
  165. destructor Destroy; override;
  166. function Evaluate(AContext: TXPathContext;
  167. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  168. end;
  169. // Node for location paths
  170. TAxis = (axisInvalid, axisAncestor, axisAncestorOrSelf, axisAttribute,
  171. axisChild, axisDescendant, axisDescendantOrSelf, axisFollowing,
  172. axisFollowingSibling, axisNamespace, axisParent, axisPreceding,
  173. axisPrecedingSibling, axisSelf);
  174. TNodeTestType = (ntAnyPrincipal, ntName, ntTextNode,
  175. ntCommentNode, ntPINode, ntAnyNode);
  176. TStep = class
  177. public
  178. constructor Create;
  179. destructor Destroy; override;
  180. NextStep: TStep;
  181. Axis: TAxis;
  182. NodeTestType: TNodeTestType;
  183. NodeTestString: DOMString;
  184. Predicates: TList;
  185. end;
  186. TXPathLocationPathNode = class(TXPathExprNode)
  187. private
  188. FFirstStep: TStep;
  189. FIsAbsolutePath: Boolean;
  190. public
  191. constructor Create(AIsAbsolutePath: Boolean);
  192. function Evaluate(AContext: TXPathContext;
  193. AEnvironment: TXPathEnvironment): TXPathVariable; override;
  194. end;
  195. TNodeSet = TList;
  196. { Exceptions }
  197. EXPathEvaluationError = class(Exception);
  198. procedure EvaluationError(const Msg: String);
  199. procedure EvaluationError(const Msg: String; const Args: array of const);
  200. type
  201. { XPath variables and results classes }
  202. TXPathVariable = class
  203. protected
  204. FRefCount: Integer;
  205. procedure Error(const Msg: String; const Args: array of const);
  206. public
  207. class function TypeName: String; virtual; abstract;
  208. procedure Release;
  209. function AsNodeSet: TNodeSet; virtual;
  210. function AsBoolean: Boolean; virtual;
  211. function AsNumber: Extended; virtual;
  212. function AsText: DOMString; virtual;
  213. end;
  214. TXPathNodeSetVariable = class(TXPathVariable)
  215. private
  216. FValue: TNodeSet;
  217. public
  218. constructor Create(AValue: TNodeSet);
  219. destructor Destroy; override;
  220. class function TypeName: String; override;
  221. function AsNodeSet: TNodeSet; override;
  222. function AsText: DOMString; override;
  223. property Value: TNodeSet read FValue;
  224. end;
  225. TXPathBooleanVariable = class(TXPathVariable)
  226. private
  227. FValue: Boolean;
  228. public
  229. constructor Create(AValue: Boolean);
  230. class function TypeName: String; override;
  231. function AsBoolean: Boolean; override;
  232. function AsNumber: Extended; override;
  233. function AsText: DOMString; override;
  234. property Value: Boolean read FValue;
  235. end;
  236. TXPathNumberVariable = class(TXPathVariable)
  237. private
  238. FValue: Extended;
  239. public
  240. constructor Create(AValue: Extended);
  241. class function TypeName: String; override;
  242. function AsBoolean: Boolean; override;
  243. function AsNumber: Extended; override;
  244. function AsText: DOMString; override;
  245. property Value: Extended read FValue;
  246. end;
  247. TXPathStringVariable = class(TXPathVariable)
  248. private
  249. FValue: DOMString;
  250. public
  251. constructor Create(const AValue: DOMString);
  252. class function TypeName: String; override;
  253. function AsBoolean: Boolean; override;
  254. function AsNumber: Extended; override;
  255. function AsText: DOMString; override;
  256. property Value: DOMString read FValue;
  257. end;
  258. { XPath lexical scanner }
  259. TXPathScannerState = class
  260. private
  261. FCurData: PChar;
  262. FCurToken: TXPathToken;
  263. FCurTokenString: DOMString;
  264. FDoUnget: Boolean;
  265. end;
  266. TXPathScanner = class
  267. private
  268. FExpressionString, FCurData: PChar; // !!!: Change to PWideChar in future
  269. FCurToken: TXPathToken;
  270. FCurTokenString: DOMString;
  271. FDoUnget: Boolean;
  272. procedure Error(const Msg: String);
  273. procedure Error(const Msg: String; const Args: array of const);
  274. public
  275. constructor Create(const AExpressionString: DOMString);
  276. function NextToken: TXPathToken;
  277. procedure UngetToken;
  278. function SaveState: TXPathScannerState;
  279. procedure RestoreState(AState: TXPathScannerState);
  280. property CurToken: TXPathToken read FCurToken;
  281. property CurTokenString: DOMString read FCurTokenString;
  282. end;
  283. { XPath context }
  284. TXPathContext = class
  285. public
  286. constructor Create(AContextNode: TDOMNode;
  287. AContextPosition, AContextSize: Integer);
  288. ContextNode: TDOMNode;
  289. ContextPosition: Integer;
  290. ContextSize: Integer;
  291. end;
  292. { XPath environments (not defined in XPath standard: an environment contains
  293. the variables and functions, which are part of the context in the official
  294. standard). }
  295. TXPathVarList = TList;
  296. TXPathFunction = function(Context: TXPathContext; Args: TXPathVarList):
  297. TXPathVariable of object;
  298. TXPathEnvironment = class
  299. private
  300. FFunctions: TList;
  301. FVariables: TList;
  302. function GetFunctionCount: Integer;
  303. function GetVariableCount: Integer;
  304. function GetFunction(Index: Integer): TXPathFunction;
  305. function GetFunction(const AName: String): TXPathFunction;
  306. function GetVariable(Index: Integer): TXPathVariable;
  307. function GetVariable(const AName: String): TXPathVariable;
  308. protected
  309. // XPath Core Function Library:
  310. function xpLast(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  311. function xpPosition(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  312. function xpCount(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  313. function xpId(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  314. function xpLocalName(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  315. function xpNamespaceURI(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  316. function xpName(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  317. function xpString(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  318. function xpConcat(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  319. function xpStartsWith(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  320. function xpContains(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  321. function xpSubstringBefore(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  322. function xpSubstringAfter(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  323. function xpSubstring(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  324. function xpStringLength(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  325. function xpNormalizeSpace(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  326. function xpTranslate(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  327. function xpBoolean(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  328. function xpNot(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  329. function xpTrue(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  330. function xpFalse(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  331. function xpLang(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  332. function xpNumber(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  333. function xpSum(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  334. function xpFloor(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  335. function xpCeiling(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  336. function xpRound(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  337. public
  338. constructor Create;
  339. destructor Destroy; override;
  340. function GetFunctionIndex(const AName: String): Integer;
  341. function GetVariableIndex(const AName: String): Integer;
  342. procedure AddFunction(const AName: String; AFunction: TXPathFunction);
  343. procedure AddVariable(const AName: String; AVariable: TXPathVariable);
  344. procedure RemoveFunction(Index: Integer);
  345. procedure RemoveFunction(const AName: String);
  346. procedure RemoveVariable(Index: Integer);
  347. procedure RemoveVariable(const AName: String);
  348. property FunctionCount: Integer read GetFunctionCount;
  349. property VariableCount: Integer read GetVariableCount;
  350. property Functions[Index: Integer]: TXPathFunction read GetFunction;
  351. property FunctionsByName[const AName: String]: TXPathFunction
  352. read GetFunction;
  353. property Variables[Index: Integer]: TXPathVariable read GetVariable;
  354. property VariablesByName[const AName: String]: TXPathVariable read GetVariable;
  355. end;
  356. { XPath expressions }
  357. TXPathExpression = class
  358. private
  359. FRootNode: TXPathExprNode;
  360. public
  361. { CompleteExpresion specifies wether the parser should check for gargabe
  362. after the recognised part. True => Throw exception if there is garbage }
  363. constructor Create(AScanner: TXPathScanner; CompleteExpression: Boolean);
  364. function Evaluate(AContextNode: TDOMNode): TXPathVariable;
  365. function Evaluate(AContextNode: TDOMNode;
  366. AEnvironment: TXPathEnvironment): TXPathVariable;
  367. end;
  368. function EvaluateXPathExpression(const AExpressionString: DOMString;
  369. AContextNode: TDOMNode): TXPathVariable;
  370. // ===================================================================
  371. // ===================================================================
  372. implementation
  373. { Helper functions }
  374. function NodeToText(Node: TDOMNode): DOMString;
  375. var
  376. Child: TDOMNode;
  377. begin
  378. case Node.NodeType of
  379. DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE, ELEMENT_NODE:
  380. begin
  381. SetLength(Result, 0);
  382. Child := Node.FirstChild;
  383. while Assigned(Child) do
  384. begin
  385. Result := Result + NodeToText(Child);
  386. Child := Child.NextSibling;
  387. end;
  388. end;
  389. ATTRIBUTE_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, TEXT_NODE,
  390. CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE:
  391. Result := Node.NodeValue;
  392. end;
  393. // !!!: What to do with 'namespace nodes'?
  394. end;
  395. { XPath parse tree classes }
  396. constructor TXPathConstantNode.Create(AValue: TXPathVariable);
  397. begin
  398. inherited Create;
  399. FValue := AValue;
  400. end;
  401. destructor TXPathConstantNode.Destroy;
  402. begin
  403. FValue.Free;
  404. inherited Destroy;
  405. end;
  406. function TXPathConstantNode.Evaluate(AContext: TXPathContext;
  407. AEnvironment: TXPathEnvironment): TXPathVariable;
  408. begin
  409. Result := FValue;
  410. Inc(Result.FRefCount);
  411. end;
  412. constructor TXPathVariableNode.Create(const AName: DOMString);
  413. begin
  414. inherited Create;
  415. FName := AName;
  416. end;
  417. function TXPathVariableNode.Evaluate(AContext: TXPathContext;
  418. AEnvironment: TXPathEnvironment): TXPathVariable;
  419. begin
  420. Result := AEnvironment.VariablesByName[FName];
  421. if not Assigned(Result) then
  422. EvaluationError(SEvalUnknownVariable, [FName]);
  423. end;
  424. constructor TXPathFunctionNode.Create(const AName: DOMString);
  425. begin
  426. inherited Create;
  427. FName := AName;
  428. FArgs := TList.Create;
  429. end;
  430. destructor TXPathFunctionNode.Destroy;
  431. var
  432. i: Integer;
  433. begin
  434. for i := 0 to FArgs.Count - 1 do
  435. TXPathExprNode(FArgs[i]).Free;
  436. FArgs.Free;
  437. inherited Destroy;
  438. end;
  439. function TXPathFunctionNode.Evaluate(AContext: TXPathContext;
  440. AEnvironment: TXPathEnvironment): TXPathVariable;
  441. var
  442. Fn: TXPathFunction;
  443. Args: TXPathVarList;
  444. i: Integer;
  445. begin
  446. Fn := AEnvironment.FunctionsByName[FName];
  447. if not Assigned(Fn) then
  448. EvaluationError(SEvalUnknownFunction, [FName]);
  449. Args := TXPathVarList.Create;
  450. try
  451. for i := 0 to FArgs.Count - 1 do
  452. Args.Add(TXPathExprNode(FArgs[i]).Evaluate(AContext, AEnvironment));
  453. Result := Fn(AContext, Args);
  454. finally
  455. Args.Free;
  456. end;
  457. end;
  458. constructor TXPathNegationNode.Create(AOperand: TXPathExprNode);
  459. begin
  460. inherited Create;
  461. FOperand := AOperand;
  462. end;
  463. destructor TXPathNegationNode.Destroy;
  464. begin
  465. FOperand.Free;
  466. inherited Destroy;
  467. end;
  468. function TXPathNegationNode.Evaluate(AContext: TXPathContext;
  469. AEnvironment: TXPathEnvironment): TXPathVariable;
  470. var
  471. OpResult: TXPathVariable;
  472. begin
  473. OpResult := FOperand.Evaluate(AContext, AEnvironment);
  474. try
  475. Result := TXPathNumberVariable.Create(-OpResult.AsNumber);
  476. finally
  477. OpResult.Release;
  478. end;
  479. end;
  480. constructor TXPathMathOpNode.Create(AOperator: TXPathMathOp;
  481. AOperand1, AOperand2: TXPathExprNode);
  482. begin
  483. inherited Create;
  484. FOperator := AOperator;
  485. FOperand1 := AOperand1;
  486. FOperand2 := AOperand2;
  487. end;
  488. destructor TXPathMathOpNode.Destroy;
  489. begin
  490. FOperand1.Free;
  491. FOperand2.Free;
  492. inherited Destroy;
  493. end;
  494. function TXPathMathOpNode.Evaluate(AContext: TXPathContext;
  495. AEnvironment: TXPathEnvironment): TXPathVariable;
  496. var
  497. Op1Result, Op2Result: TXPathVariable;
  498. Op1, Op2, NumberResult: Extended;
  499. begin
  500. Op1Result := FOperand1.Evaluate(AContext, AEnvironment);
  501. try
  502. Op2Result := FOperand2.Evaluate(AContext, AEnvironment);
  503. try
  504. Op1 := Op1Result.AsNumber;
  505. Op2 := Op2Result.AsNumber;
  506. case FOperator of
  507. opAdd:
  508. NumberResult := Op1 + Op2;
  509. opSubtract:
  510. NumberResult := Op1 - Op2;
  511. opMultiply:
  512. NumberResult := Op1 * Op2;
  513. opDivide:
  514. NumberResult := Op1 / Op2;
  515. opMod:
  516. NumberResult := Trunc(Op1) mod Trunc(Op2);
  517. end;
  518. finally
  519. Op2Result.Release;
  520. end;
  521. finally
  522. Op1Result.Release;
  523. end;
  524. Result := TXPathNumberVariable.Create(NumberResult);
  525. end;
  526. constructor TXPathBooleanOpNode.Create(AOperator: TXPathBooleanOp;
  527. AOperand1, AOperand2: TXPathExprNode);
  528. begin
  529. inherited Create;
  530. FOperator := AOperator;
  531. FOperand1 := AOperand1;
  532. FOperand2 := AOperand2;
  533. end;
  534. destructor TXPathBooleanOpNode.Destroy;
  535. begin
  536. FOperand1.Free;
  537. FOperand2.Free;
  538. inherited Destroy;
  539. end;
  540. function TXPathBooleanOpNode.Evaluate(AContext: TXPathContext;
  541. AEnvironment: TXPathEnvironment): TXPathVariable;
  542. var
  543. Op1, Op2: TXPathVariable;
  544. function EvalEqual: Boolean;
  545. var
  546. i, j: Integer;
  547. NodeSet1, NodeSet2: TNodeSet;
  548. s: DOMString;
  549. begin
  550. // !!!: Doesn't handle nodesets yet!
  551. if Op1.InheritsFrom(TXPathNodeSetVariable) then
  552. begin
  553. NodeSet1 := Op1.AsNodeSet;
  554. if Op2.InheritsFrom(TXPathNodeSetVariable) then
  555. begin
  556. NodeSet2 := Op2.AsNodeSet;
  557. for i := 0 to NodeSet1.Count - 1 do
  558. begin
  559. s := NodeToText(TDOMNode(NodeSet1[i]));
  560. for j := 0 to NodeSet2.Count - 1 do
  561. if s = NodeToText(TDOMNode(NodeSet2[j])) then
  562. begin
  563. Result := True;
  564. exit;
  565. end;
  566. end;
  567. end else
  568. begin
  569. s := Op2.AsText;
  570. for i := 0 to NodeSet1.Count - 1 do
  571. begin
  572. if NodeToText(TDOMNode(NodeSet1[i])) = s then
  573. begin
  574. Result := True;
  575. exit;
  576. end;
  577. end;
  578. end;
  579. Result := False;
  580. end else if Op2.InheritsFrom(TXPathNodeSetVariable) then
  581. begin
  582. s := Op1.AsText;
  583. for i := 0 to NodeSet2.Count - 1 do
  584. if s = NodeToText(TDOMNode(NodeSet2[i])) then
  585. begin
  586. Result := True;
  587. exit;
  588. end;
  589. Result := False;
  590. end else if Op1.InheritsFrom(TXPathBooleanVariable) or
  591. Op2.InheritsFrom(TXPathBooleanVariable) then
  592. Result := Op1.AsBoolean = Op2.AsBoolean
  593. else if Op1.InheritsFrom(TXPathNumberVariable) or
  594. Op2.InheritsFrom(TXPathNumberVariable) then
  595. Result := Op1.AsNumber = Op2.AsNumber
  596. else
  597. Result := Op1.AsText = Op2.AsText; // !!!: Attention with Unicode!
  598. end;
  599. var
  600. BoolResult: Boolean;
  601. begin
  602. Op1 := FOperand1.Evaluate(AContext, AEnvironment);
  603. try
  604. Op2 := FOperand2.Evaluate(AContext, AEnvironment);
  605. try
  606. case FOperator of
  607. opEqual:
  608. BoolResult := EvalEqual;
  609. opNotEqual:
  610. BoolResult := not EvalEqual;
  611. opLess:
  612. BoolResult := Op1.AsNumber < Op2.AsNumber;
  613. opLessEqual:
  614. BoolResult := Op1.AsNumber <= Op2.AsNumber;
  615. opGreater:
  616. BoolResult := Op1.AsNumber > Op2.AsNumber;
  617. opGreaterEqual:
  618. BoolResult := Op1.AsNumber >= Op2.AsNumber;
  619. opOr:
  620. BoolResult := Op1.AsBoolean or Op2.AsBoolean;
  621. opAnd:
  622. BoolResult := Op1.AsBoolean and Op2.AsBoolean;
  623. end;
  624. finally
  625. Op2.Release;
  626. end;
  627. finally
  628. Op1.Release;
  629. end;
  630. Result := TXPathBooleanVariable.Create(BoolResult);
  631. end;
  632. constructor TXPathUnionNode.Create(AOperand1, AOperand2: TXPathExprNode);
  633. begin
  634. inherited Create;
  635. FOperand1 := AOperand1;
  636. FOperand2 := AOperand2;
  637. end;
  638. destructor TXPathUnionNode.Destroy;
  639. begin
  640. FOperand1.Free;
  641. FOperand2.Free;
  642. inherited Destroy;
  643. end;
  644. function TXPathUnionNode.Evaluate(AContext: TXPathContext;
  645. AEnvironment: TXPathEnvironment): TXPathVariable;
  646. var
  647. Op1Result, Op2Result: TXPathVariable;
  648. NodeSet, NodeSet2: TNodeSet;
  649. CurNode: Pointer;
  650. i, j: Integer;
  651. DoAdd: Boolean;
  652. begin
  653. Op1Result := FOperand1.Evaluate(AContext, AEnvironment);
  654. try
  655. Op2Result := FOperand2.Evaluate(AContext, AEnvironment);
  656. try
  657. NodeSet := Op1Result.AsNodeSet;
  658. NodeSet2 := Op2Result.AsNodeSet;
  659. try
  660. for i := 0 to NodeSet2.Count - 1 do
  661. begin
  662. DoAdd := True;
  663. CurNode := NodeSet2[i];
  664. for j := 0 to NodeSet.Count - 1 do
  665. if NodeSet[j] = CurNode then
  666. begin
  667. DoAdd := False;
  668. break;
  669. end;
  670. if DoAdd then
  671. NodeSet.Add(CurNode);
  672. end;
  673. finally
  674. NodeSet2.Free;
  675. end;
  676. finally
  677. Op2Result.Release;
  678. end;
  679. finally
  680. Op1Result.Release;
  681. end;
  682. Result := TXPathNodeSetVariable.Create(NodeSet);
  683. end;
  684. constructor TXPathFilterNode.Create(AExpr: TXPathExprNode);
  685. begin
  686. inherited Create;
  687. FExpr := AExpr;
  688. FPredicates := TList.Create;
  689. end;
  690. destructor TXPathFilterNode.Destroy;
  691. var
  692. i: Integer;
  693. begin
  694. for i := 0 to FPredicates.Count - 1 do
  695. TXPathExprNode(FPredicates[i]).Free;
  696. FPredicates.Free;
  697. inherited Destroy;
  698. end;
  699. function TXPathFilterNode.Evaluate(AContext: TXPathContext;
  700. AEnvironment: TXPathEnvironment): TXPathVariable;
  701. var
  702. ExprResult, PredicateResult: TXPathVariable;
  703. NodeSet, NewNodeSet: TNodeSet;
  704. i, j: Integer;
  705. CurContextNode: TDOMNode;
  706. NewContext: TXPathContext;
  707. DoAdd: Boolean;
  708. begin
  709. ExprResult := FExpr.Evaluate(AContext, AEnvironment);
  710. NewContext := nil;
  711. NewNodeSet := nil;
  712. try
  713. NodeSet := ExprResult.AsNodeSet;
  714. NewContext := TXPathContext.Create(nil, 0, NodeSet.Count);
  715. NewNodeSet := TNodeSet.Create;
  716. try
  717. for i := 0 to NodeSet.Count - 1 do
  718. begin
  719. CurContextNode := TDOMNode(NodeSet[i]);
  720. NewContext.ContextNode := CurContextNode;
  721. Inc(NewContext.ContextPosition);
  722. DoAdd := True;
  723. for j := 0 to FPredicates.Count - 1 do
  724. begin
  725. PredicateResult := TXPathExprNode(FPredicates[j]).Evaluate(NewContext,
  726. AEnvironment);
  727. try
  728. if PredicateResult.InheritsFrom(TXPathNumberVariable) then
  729. begin
  730. if PredicateResult.AsNumber <> i + 1 then
  731. begin
  732. DoAdd := False;
  733. break;
  734. end;
  735. end else if not PredicateResult.AsBoolean then
  736. begin
  737. DoAdd := False;
  738. break;
  739. end;
  740. finally
  741. PredicateResult.Release;
  742. end;
  743. end;
  744. if DoAdd then
  745. NewNodeSet.Add(CurContextNode);
  746. end;
  747. except
  748. NewNodeSet.Free;
  749. raise;
  750. end;
  751. Result := TXPathNodeSetVariable.Create(NewNodeSet);
  752. finally
  753. NewContext.Free;
  754. ExprResult.Release;
  755. end;
  756. end;
  757. constructor TStep.Create;
  758. begin
  759. inherited Create;
  760. Predicates := TList.Create;
  761. end;
  762. destructor TStep.Destroy;
  763. var
  764. i: Integer;
  765. begin
  766. for i := 0 to Predicates.Count - 1 do
  767. TXPathExprNode(Predicates[i]).Free;
  768. Predicates.Free;
  769. inherited Free;
  770. end;
  771. constructor TXPathLocationPathNode.Create(AIsAbsolutePath: Boolean);
  772. begin
  773. inherited Create;
  774. FIsAbsolutePath := AIsAbsolutePath;
  775. end;
  776. function TXPathLocationPathNode.Evaluate(AContext: TXPathContext;
  777. AEnvironment: TXPathEnvironment): TXPathVariable;
  778. var
  779. ResultNodeSet: TNodeSet;
  780. procedure EvaluateStep(AStep: TStep; AContext: TXPathContext);
  781. var
  782. StepNodes: TList;
  783. procedure DoNodeTest(Node: TDOMNode);
  784. var
  785. i: Integer;
  786. DoAdd: Boolean;
  787. begin
  788. case AStep.NodeTestType of
  789. ntAnyPrincipal:
  790. // !!!: Probably this isn't ready for namespace support yet
  791. if (AStep.Axis <> axisAttribute) and
  792. (Node.NodeType <> ELEMENT_NODE) then
  793. exit;
  794. ntName:
  795. if Node.NodeName <> AStep.NodeTestString then
  796. exit;
  797. ntTextNode:
  798. if not Node.InheritsFrom(TDOMCharacterData) then
  799. exit;
  800. ntCommentNode:
  801. if Node.NodeType <> COMMENT_NODE then
  802. exit;
  803. ntPINode:
  804. if Node.NodeType <> PROCESSING_INSTRUCTION_NODE then
  805. exit;
  806. end;
  807. DoAdd := True;
  808. for i := 0 to StepNodes.Count - 1 do
  809. if TDOMNode(StepNodes[i]) = Node then
  810. begin
  811. DoAdd := False;
  812. break;
  813. end;
  814. if DoAdd then
  815. StepNodes.Add(Node);
  816. end;
  817. procedure AddDescendants(CurNode: TDOMNode);
  818. var
  819. Child: TDOMNode;
  820. begin
  821. Child := CurNode.FirstChild;
  822. while Assigned(Child) do
  823. begin
  824. DoNodeTest(Child);
  825. AddDescendants(Child);
  826. Child := Child.NextSibling;
  827. end;
  828. end;
  829. var
  830. Node, Node2: TDOMNode;
  831. Attr: TDOMNamedNodeMap;
  832. i, j, k: Integer;
  833. DoAdd: Boolean;
  834. NewContext: TXPathContext;
  835. NewStepNodes: TNodeSet;
  836. Predicate: TXPathExprNode;
  837. PredicateResult: TXPathVariable;
  838. begin
  839. StepNodes := TList.Create;
  840. // !!!: Protect this with an try/finally block
  841. case AStep.Axis of
  842. axisAncestor:
  843. begin
  844. Node := AContext.ContextNode.ParentNode;
  845. while Assigned(Node) do
  846. begin
  847. DoNodeTest(Node);
  848. Node := Node.ParentNode;
  849. end;
  850. end;
  851. axisAncestorOrSelf:
  852. begin
  853. Node := AContext.ContextNode;
  854. repeat
  855. DoNodeTest(Node);
  856. Node := Node.ParentNode;
  857. until not Assigned(Node);
  858. end;
  859. axisAttribute:
  860. begin
  861. Attr := AContext.ContextNode.Attributes;
  862. if Assigned(Attr) then
  863. for i := 0 to Attr.Length - 1 do
  864. DoNodeTest(Attr[i]);
  865. end;
  866. axisChild:
  867. begin
  868. Node := AContext.ContextNode.FirstChild;
  869. while Assigned(Node) do
  870. begin
  871. DoNodeTest(Node);
  872. Node := Node.NextSibling;
  873. end;
  874. end;
  875. axisDescendant:
  876. AddDescendants(AContext.ContextNode);
  877. axisDescendantOrSelf:
  878. begin
  879. DoNodeTest(AContext.ContextNode);
  880. AddDescendants(AContext.ContextNode);
  881. end;
  882. axisFollowing:
  883. begin
  884. Node := AContext.ContextNode;
  885. repeat
  886. Node2 := Node.NextSibling;
  887. while Assigned(Node2) do
  888. begin
  889. DoNodeTest(Node2);
  890. AddDescendants(Node2);
  891. Node := Node.NextSibling;
  892. end;
  893. Node := Node.ParentNode;
  894. until not Assigned(Node);
  895. end;
  896. axisFollowingSibling:
  897. begin
  898. Node := AContext.ContextNode.NextSibling;
  899. while Assigned(Node) do
  900. begin
  901. DoNodeTest(Node);
  902. Node := Node.NextSibling;
  903. end;
  904. end;
  905. {axisNamespace: !!!: Not supported yet}
  906. axisParent:
  907. if Assigned(AContext.ContextNode.ParentNode) then
  908. DoNodeTest(AContext.ContextNode);
  909. axisPreceding:
  910. begin
  911. Node := AContext.ContextNode;
  912. repeat
  913. Node2 := Node.PreviousSibling;
  914. while Assigned(Node2) do
  915. begin
  916. DoNodeTest(Node2);
  917. AddDescendants(Node2);
  918. Node := Node.PreviousSibling;
  919. end;
  920. Node := Node.ParentNode;
  921. until not Assigned(Node);
  922. end;
  923. axisPrecedingSibling:
  924. begin
  925. Node := AContext.ContextNode.PreviousSibling;
  926. while Assigned(Node) do
  927. begin
  928. DoNodeTest(Node);
  929. Node := Node.PreviousSibling;
  930. end;
  931. end;
  932. axisSelf:
  933. DoNodeTest(AContext.ContextNode);
  934. end;
  935. { Filter the nodes of this step using the predicates: The current
  936. node set (StepNodes) is filtered, all passed nodes will be added
  937. to NewStepNodes. After one filter has been applied, NewStepNodes
  938. gets copied to StepNodes, and the next filter will be processed.
  939. The final result will then be passed to the next step, or added
  940. to the result of the LocationPath if this is the last step. }
  941. for i := 0 to AStep.Predicates.Count - 1 do
  942. begin
  943. NewContext := TXPathContext.Create(nil, 0, StepNodes.Count);
  944. NewStepNodes := nil;
  945. try
  946. NewStepNodes := TNodeSet.Create;
  947. Predicate := TXPathExprNode(AStep.Predicates[i]);
  948. for j := 0 to StepNodes.Count - 1 do
  949. begin
  950. Node := TDOMNode(StepNodes[j]);
  951. NewContext.ContextNode := Node;
  952. Inc(NewContext.ContextPosition);
  953. PredicateResult := Predicate.Evaluate(NewContext, AEnvironment);
  954. try
  955. if (PredicateResult.InheritsFrom(TXPathNumberVariable) and
  956. (PredicateResult.AsNumber = j + 1)) or
  957. PredicateResult.AsBoolean then
  958. NewStepNodes.Add(Node);
  959. finally
  960. PredicateResult.Release;
  961. end;
  962. end;
  963. finally
  964. NewContext.Free;
  965. StepNodes.Free;
  966. StepNodes := NewStepNodes;
  967. end;
  968. end;
  969. if Assigned(AStep.NextStep) then
  970. begin
  971. NewContext := TXPathContext.Create(nil, 0, StepNodes.Count);
  972. try
  973. for i := 0 to StepNodes.Count - 1 do
  974. begin
  975. NewContext.ContextNode := TDOMNode(StepNodes[i]);
  976. Inc(NewContext.ContextPosition);
  977. EvaluateStep(AStep.NextStep, NewContext);
  978. end;
  979. finally
  980. NewContext.Free;
  981. end;
  982. end else
  983. begin
  984. // Only add nodes to result if it isn't duplicate
  985. for i := 0 to StepNodes.Count - 1 do
  986. begin
  987. Node := TDOMNode(StepNodes[i]);
  988. DoAdd := True;
  989. for j := 0 to ResultNodeSet.Count - 1 do
  990. if TDOMNode(ResultNodeSet[j]) = Node then
  991. begin
  992. DoAdd := False;
  993. break;
  994. end;
  995. if DoAdd then
  996. ResultNodeSet.Add(Node);
  997. end;
  998. end;
  999. StepNodes.Free;
  1000. end;
  1001. var
  1002. NewContext: TXPathContext;
  1003. begin
  1004. ResultNodeSet := TNodeSet.Create;
  1005. try
  1006. if FIsAbsolutePath then
  1007. begin
  1008. NewContext := TXPathContext.Create(AContext.ContextNode.OwnerDocument,
  1009. 1, 1);
  1010. try
  1011. EvaluateStep(FFirstStep, NewContext);
  1012. finally
  1013. NewContext.Free;
  1014. end;
  1015. end else
  1016. EvaluateStep(FFirstStep, AContext);
  1017. except
  1018. ResultNodeSet.Free;
  1019. raise;
  1020. end;
  1021. Result := TXPathNodeSetVariable.Create(ResultNodeSet);
  1022. end;
  1023. { Exceptions }
  1024. procedure EvaluationError(const Msg: String);
  1025. begin
  1026. raise EXPathEvaluationError.Create(Msg) at get_caller_addr(get_frame);
  1027. end;
  1028. procedure EvaluationError(const Msg: String; const Args: array of const);
  1029. begin
  1030. raise EXPathEvaluationError.CreateFmt(Msg, Args)
  1031. at get_caller_addr(get_frame);
  1032. end;
  1033. { TXPathVariable and derived classes}
  1034. procedure TXPathVariable.Release;
  1035. begin
  1036. if FRefCount <= 0 then
  1037. Free
  1038. else
  1039. Dec(FRefCount);
  1040. end;
  1041. function TXPathVariable.AsNodeSet: TNodeSet;
  1042. begin
  1043. Error(SVarNoConversion, [TypeName, TXPathNodeSetVariable.TypeName]);
  1044. Result := nil;
  1045. end;
  1046. function TXPathVariable.AsBoolean: Boolean;
  1047. begin
  1048. Error(SVarNoConversion, [TypeName, TXPathBooleanVariable.TypeName]);
  1049. Result := False;
  1050. end;
  1051. function TXPathVariable.AsNumber: Extended;
  1052. begin
  1053. Error(SVarNoConversion, [TypeName, TXPathNumberVariable.TypeName]);
  1054. Result := 0;
  1055. end;
  1056. function TXPathVariable.AsText: DOMString;
  1057. begin
  1058. Error(SVarNoConversion, [TypeName, TXPathStringVariable.TypeName]);
  1059. SetLength(Result, 0);
  1060. end;
  1061. procedure TXPathVariable.Error(const Msg: String; const Args: array of const);
  1062. begin
  1063. raise Exception.CreateFmt(Msg, Args) at get_caller_addr(get_frame);
  1064. end;
  1065. constructor TXPathNodeSetVariable.Create(AValue: TNodeSet);
  1066. begin
  1067. inherited Create;
  1068. FValue := AValue;
  1069. end;
  1070. destructor TXPathNodeSetVariable.Destroy;
  1071. begin
  1072. FValue.Free;
  1073. inherited Destroy;
  1074. end;
  1075. function TXPathNodeSetVariable.TypeName: String;
  1076. begin
  1077. Result := SNodeSet;
  1078. end;
  1079. function TXPathNodeSetVariable.AsNodeSet: TNodeSet;
  1080. begin
  1081. Result := FValue;
  1082. end;
  1083. function TXPathNodeSetVariable.AsText: DOMString;
  1084. begin
  1085. if FValue.Count = 0 then
  1086. SetLength(Result, 0)
  1087. else
  1088. Result := NodeToText(TDOMNode(FValue[0]));
  1089. end;
  1090. constructor TXPathBooleanVariable.Create(AValue: Boolean);
  1091. begin
  1092. inherited Create;
  1093. FValue := AValue;
  1094. end;
  1095. function TXPathBooleanVariable.TypeName: String;
  1096. begin
  1097. Result := SBoolean;
  1098. end;
  1099. function TXPathBooleanVariable.AsBoolean: Boolean;
  1100. begin
  1101. Result := FValue;
  1102. end;
  1103. function TXPathBooleanVariable.AsNumber: Extended;
  1104. begin
  1105. if FValue then
  1106. Result := 1
  1107. else
  1108. Result := 0;
  1109. end;
  1110. function TXPathBooleanVariable.AsText: DOMString;
  1111. begin
  1112. if FValue then
  1113. Result := 'true' // Do not localize!
  1114. else
  1115. Result := 'false'; // Do not localize!
  1116. end;
  1117. constructor TXPathNumberVariable.Create(AValue: Extended);
  1118. begin
  1119. inherited Create;
  1120. FValue := AValue;
  1121. end;
  1122. function TXPathNumberVariable.TypeName: String;
  1123. begin
  1124. Result := SNumber;
  1125. end;
  1126. function TXPathNumberVariable.AsBoolean: Boolean;
  1127. begin
  1128. // !!!: What about NaNs and so on?
  1129. if FValue = 0 then
  1130. Result := False
  1131. else
  1132. Result := True;
  1133. end;
  1134. function TXPathNumberVariable.AsNumber: Extended;
  1135. begin
  1136. Result := FValue;
  1137. end;
  1138. function TXPathNumberVariable.AsText: DOMString;
  1139. begin
  1140. Result := FloatToStr(FValue);
  1141. end;
  1142. constructor TXPathStringVariable.Create(const AValue: DOMString);
  1143. begin
  1144. inherited Create;
  1145. FValue := AValue;
  1146. end;
  1147. function TXPathStringVariable.TypeName: String;
  1148. begin
  1149. Result := SString;
  1150. end;
  1151. function TXPathStringVariable.AsBoolean: Boolean;
  1152. begin
  1153. Result := Length(FValue) > 0;
  1154. end;
  1155. function TXPathStringVariable.AsNumber: Extended;
  1156. begin
  1157. Result := StrToFloat(FValue);
  1158. end;
  1159. function TXPathStringVariable.AsText: DOMString;
  1160. begin
  1161. Result := FValue;
  1162. end;
  1163. { XPath lexical scanner }
  1164. constructor TXPathScanner.Create(const AExpressionString: DOMString);
  1165. begin
  1166. inherited Create;
  1167. FExpressionString := PChar(AExpressionString);
  1168. FCurData := FExpressionString;
  1169. end;
  1170. function TXPathScanner.NextToken: TXPathToken;
  1171. procedure GetNumber;
  1172. var
  1173. HasDot: Boolean;
  1174. begin
  1175. HasDot := Pos('.', FCurTokenString) > 0;
  1176. while (FCurData[1] in ['0'..'9']) or ((FCurData[1] = '.') and not HasDot) do
  1177. begin
  1178. Inc(FCurData);
  1179. FCurTokenString := FCurTokenString + FCurData[0];
  1180. if FCurData[0] = '.' then
  1181. HasDot := True;
  1182. end;
  1183. Result := tkNumber;
  1184. end;
  1185. const
  1186. IdentifierChars = ['A'..'Z', 'a'..'z', '0'..'9', '.', '-', '_'];
  1187. begin
  1188. if FDoUnget then
  1189. begin
  1190. FDoUnget := False;
  1191. Result := FCurToken;
  1192. exit;
  1193. end;
  1194. if FCurToken = tkEndOfStream then
  1195. begin
  1196. Result := tkEndOfStream;
  1197. exit;
  1198. end;
  1199. { No, we cannot use a lookup table here, as future
  1200. versions will use WideStrings -sg }
  1201. // Skip whitespace
  1202. while FCurData[0] in [#9, #10, #12, #13, ' '] do
  1203. Inc(FCurData);
  1204. FCurTokenString := FCurData[0];
  1205. case FCurData[0] of
  1206. #0:
  1207. Result := tkEndOfStream;
  1208. '!':
  1209. if FCurData[1] = '=' then
  1210. begin
  1211. Inc(FCurData);
  1212. Result := tkNotEqual;
  1213. end;
  1214. '"':
  1215. begin
  1216. SetLength(FCurTokenString, 0);
  1217. Inc(FCurData);
  1218. while FCurData[0] <> '"' do
  1219. begin
  1220. if FCurData[0] = #0 then
  1221. Error(SScannerQuotStringIsOpen);
  1222. FCurTokenString := FCurTokenString + FCurData[0];
  1223. Inc(FCurData);
  1224. end;
  1225. Result := tkString;
  1226. end;
  1227. '$':
  1228. Result := tkDollar;
  1229. '''':
  1230. begin
  1231. SetLength(FCurTokenString, 0);
  1232. Inc(FCurData);
  1233. while FCurData[0] <> '''' do
  1234. begin
  1235. if FCurData[0] = #0 then
  1236. Error(SScannerAposStringIsOpen);
  1237. FCurTokenString := FCurTokenString + FCurData[0];
  1238. Inc(FCurData);
  1239. end;
  1240. Result := tkString;
  1241. end;
  1242. '(':
  1243. Result := tkLeftBracket;
  1244. ')':
  1245. Result := tkRightBracket;
  1246. '*':
  1247. Result := tkAsterisk;
  1248. '+':
  1249. Result := tkPlus;
  1250. ',':
  1251. Result := tkComma;
  1252. '-':
  1253. Result := tkMinus;
  1254. '.':
  1255. if FCurData[1] = '.' then
  1256. begin
  1257. Inc(FCurData);
  1258. Result := tkDotDot;
  1259. end else if FCurData[1] in ['0'..'9'] then
  1260. GetNumber
  1261. else
  1262. Result := tkDot;
  1263. '/':
  1264. if FCurData[1] = '/' then
  1265. begin
  1266. Inc(FCurData);
  1267. Result := tkSlashSlash;
  1268. end else
  1269. Result := tkSlash;
  1270. '0'..'9':
  1271. GetNumber;
  1272. ':':
  1273. if FCurData[1] = ':' then
  1274. begin
  1275. Inc(FCurData);
  1276. Result := tkColonColon;
  1277. end else
  1278. Result := tkColon;
  1279. '<':
  1280. if FCurData[1] = '=' then
  1281. begin
  1282. Inc(FCurData);
  1283. Result := tkLessEqual;
  1284. end else
  1285. Result := tkLess;
  1286. '=':
  1287. Result := tkEqual;
  1288. '>':
  1289. if FCurData[1] = '=' then
  1290. begin
  1291. Inc(FCurData);
  1292. Result := tkGreaterEqual;
  1293. end else
  1294. Result := tkGreater;
  1295. '@':
  1296. Result := tkAt;
  1297. 'A'..'Z', 'a'..'z':
  1298. begin
  1299. Result := tkIdentifier;
  1300. while FCurData[1] in IdentifierChars do
  1301. begin
  1302. Inc(FCurData);
  1303. FCurTokenString := FCurTokenString + FCurData[0];
  1304. end;
  1305. end;
  1306. '[':
  1307. Result := tkLeftSquareBracket;
  1308. ']':
  1309. Result := tkRightSquareBracket;
  1310. '|':
  1311. Result := tkPipe;
  1312. else
  1313. Error(SScannerInvalidChar);
  1314. end;
  1315. // We have processed at least one character now; eat it:
  1316. if Result <> tkEndOfStream then
  1317. Inc(FCurData);
  1318. FCurToken := Result;
  1319. end;
  1320. procedure TXPathScanner.UngetToken;
  1321. begin
  1322. if FDoUnget then
  1323. Error(SScannerInternalError, ['Tried to unget token a second time']);
  1324. FDoUnget := True;
  1325. end;
  1326. function TXPathScanner.SaveState: TXPathScannerState;
  1327. begin
  1328. Result := TXPathScannerState.Create;
  1329. Result.FCurData := FCurData;
  1330. Result.FCurToken := FCurToken;
  1331. Result.FCurTokenString := FCurTokenString;
  1332. Result.FDoUnget := FDoUnget;
  1333. end;
  1334. procedure TXPathScanner.RestoreState(AState: TXPathScannerState);
  1335. begin
  1336. FCurData := AState.FCurData;
  1337. FCurToken := AState.FCurToken;
  1338. FCurTokenString := AState.FCurTokenString;
  1339. FDoUnget := AState.FDoUnget;
  1340. AState.Free;
  1341. end;
  1342. procedure TXPathScanner.Error(const Msg: String);
  1343. begin
  1344. raise Exception.Create(Msg) at get_caller_addr(get_frame);
  1345. end;
  1346. procedure TXPathScanner.Error(const Msg: String; const Args: array of const);
  1347. begin
  1348. raise Exception.CreateFmt(Msg, Args) at get_caller_addr(get_frame);
  1349. end;
  1350. { TXPathContext }
  1351. constructor TXPathContext.Create(AContextNode: TDOMNode;
  1352. AContextPosition, AContextSize: Integer);
  1353. begin
  1354. inherited Create;
  1355. ContextNode := AContextNode;
  1356. ContextPosition := AContextPosition;
  1357. ContextSize := AContextSize;
  1358. end;
  1359. { TXPathEnvironment }
  1360. type
  1361. PFunctionInfo = ^TFunctionInfo;
  1362. TFunctionInfo = record
  1363. Name: String;
  1364. Fn: TXPathFunction;
  1365. end;
  1366. PVariableInfo = ^TVariableInfo;
  1367. TVariableInfo = record
  1368. Name: String;
  1369. Variable: TXPathVariable;
  1370. end;
  1371. constructor TXPathEnvironment.Create;
  1372. begin
  1373. inherited Create;
  1374. FFunctions := TList.Create;
  1375. FVariables := TList.Create;
  1376. // Add the functions of the XPath Core Function Library
  1377. // Node set functions
  1378. AddFunction('last', @xpLast);
  1379. AddFunction('position', @xpPosition);
  1380. AddFunction('count', @xpCount);
  1381. AddFunction('id', @xpId);
  1382. AddFunction('local-name', @xpLocalName);
  1383. AddFunction('namespace-uri', @xpNamespaceURI);
  1384. AddFunction('name', @xpName);
  1385. // String functions
  1386. AddFunction('string', @xpString);
  1387. AddFunction('concat', @xpConcat);
  1388. AddFunction('starts-with', @xpStartsWith);
  1389. AddFunction('contains', @xpContains);
  1390. AddFunction('substring-before', @xpSubstringBefore);
  1391. AddFunction('substring-after', @xpSubstringAfter);
  1392. AddFunction('substring', @xpSubstring);
  1393. AddFunction('string-length', @xpStringLength);
  1394. AddFunction('normalize-space', @xpNormalizeSpace);
  1395. AddFunction('translate', @xpTranslate);
  1396. // Boolean functions
  1397. AddFunction('boolean', @xpBoolean);
  1398. AddFunction('not', @xpNot);
  1399. AddFunction('true', @xpTrue);
  1400. AddFunction('false', @xpFalse);
  1401. AddFunction('lang', @xpLang);
  1402. // Number functions
  1403. AddFunction('number', @xpNumber);
  1404. AddFunction('sum', @xpSum);
  1405. AddFunction('floor', @xpFloor);
  1406. AddFunction('ceiling', @xpCeiling);
  1407. AddFunction('round', @xpRound);
  1408. end;
  1409. destructor TXPathEnvironment.Destroy;
  1410. var
  1411. i: Integer;
  1412. FunctionInfo: PFunctionInfo;
  1413. VariableInfo: PVariableInfo;
  1414. begin
  1415. for i := 0 to FFunctions.Count - 1 do
  1416. begin
  1417. FunctionInfo := PFunctionInfo(FFunctions[i]);
  1418. FreeMem(FunctionInfo);
  1419. end;
  1420. FFunctions.Free;
  1421. for i := 0 to FVariables.Count - 1 do
  1422. begin
  1423. VariableInfo := PVariableInfo(FVariables[i]);
  1424. FreeMem(VariableInfo);
  1425. end;
  1426. FVariables.Free;
  1427. inherited Destroy;
  1428. end;
  1429. function TXPathEnvironment.GetFunctionIndex(const AName: String): Integer;
  1430. var
  1431. i: Integer;
  1432. begin
  1433. for i := 0 to FFunctions.Count - 1 do
  1434. if PFunctionInfo(FFunctions[i])^.Name = AName then
  1435. begin
  1436. Result := i;
  1437. exit;
  1438. end;
  1439. Result := -1;
  1440. end;
  1441. function TXPathEnvironment.GetVariableIndex(const AName: String): Integer;
  1442. var
  1443. i: Integer;
  1444. begin
  1445. for i := 0 to FVariables.Count - 1 do
  1446. if PVariableInfo(FFunctions[i])^.Name = AName then
  1447. begin
  1448. Result := i;
  1449. exit;
  1450. end;
  1451. Result := -1;
  1452. end;
  1453. procedure TXPathEnvironment.AddFunction(const AName: String; AFunction: TXPathFunction);
  1454. var
  1455. NewFunctionInfo: PFunctionInfo;
  1456. begin
  1457. // !!!: Prevent the addition of duplicate functions
  1458. New(NewFunctionInfo);
  1459. NewFunctionInfo^.Name := AName;
  1460. NewFunctionInfo^.Fn := AFunction;
  1461. FFunctions.Add(NewFunctionInfo);
  1462. end;
  1463. procedure TXPathEnvironment.AddVariable(const AName: String; AVariable: TXPathVariable);
  1464. var
  1465. NewVariableInfo: PVariableInfo;
  1466. begin
  1467. // !!!: Prevent the addition of duplicate variables
  1468. New(NewVariableInfo);
  1469. NewVariableInfo^.Name := AName;
  1470. NewVariableInfo^.Variable := AVariable;
  1471. FVariables.Add(NewVariableInfo);
  1472. end;
  1473. procedure TXPathEnvironment.RemoveFunction(Index: Integer);
  1474. var
  1475. FunctionInfo: PFunctionInfo;
  1476. begin
  1477. FunctionInfo := PFunctionInfo(FFunctions[Index]);
  1478. Dispose(FunctionInfo);
  1479. FFunctions.Delete(Index);
  1480. end;
  1481. procedure TXPathEnvironment.RemoveFunction(const AName: String);
  1482. var
  1483. i: Integer;
  1484. begin
  1485. for i := 0 to FFunctions.Count - 1 do
  1486. if PFunctionInfo(FFunctions[i])^.Name = AName then
  1487. begin
  1488. RemoveFunction(i);
  1489. exit;
  1490. end;
  1491. end;
  1492. procedure TXPathEnvironment.RemoveVariable(Index: Integer);
  1493. var
  1494. VariableInfo: PVariableInfo;
  1495. begin
  1496. VariableInfo := PVariableInfo(FVariables[Index]);
  1497. Dispose(VariableInfo);
  1498. FVariables.Delete(Index);
  1499. end;
  1500. procedure TXPathEnvironment.RemoveVariable(const AName: String);
  1501. var
  1502. Index: Integer;
  1503. begin
  1504. Index := GetVariableIndex(AName);
  1505. if Index >= 0 then
  1506. RemoveVariable(Index);
  1507. end;
  1508. function TXPathEnvironment.GetFunctionCount: Integer;
  1509. begin
  1510. Result := FFunctions.Count;
  1511. end;
  1512. function TXPathEnvironment.GetVariableCount: Integer;
  1513. begin
  1514. Result := FVariables.Count;
  1515. end;
  1516. function TXPathEnvironment.GetFunction(Index: Integer): TXPathFunction;
  1517. begin
  1518. Result := PFunctionInfo(FFunctions[Index])^.Fn;
  1519. end;
  1520. function TXPathEnvironment.GetFunction(const AName: String): TXPathFunction;
  1521. var
  1522. i: Integer;
  1523. begin
  1524. for i := 0 to FFunctions.Count - 1 do
  1525. if PFunctionInfo(FFunctions[i])^.Name = AName then
  1526. begin
  1527. Result := PFunctionInfo(FFunctions[i])^.Fn;
  1528. exit;
  1529. end;
  1530. Result := nil;
  1531. end;
  1532. function TXPathEnvironment.GetVariable(Index: Integer): TXPathVariable;
  1533. begin
  1534. Result := PVariableInfo(FVariables[Index])^.Variable;
  1535. end;
  1536. function TXPathEnvironment.GetVariable(const AName: String): TXPathVariable;
  1537. var
  1538. i: Integer;
  1539. begin
  1540. for i := 0 to FVariables.Count - 1 do
  1541. if PFunctionInfo(FVariables[i])^.Name = AName then
  1542. begin
  1543. Result := PVariableInfo(FVariables[i])^.Variable;
  1544. exit;
  1545. end;
  1546. Result := nil;
  1547. end;
  1548. function TXPathEnvironment.xpLast(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1549. begin
  1550. if Args.Count <> 0 then
  1551. EvaluationError(SEvalInvalidArgCount);
  1552. Result := TXPathNumberVariable.Create(Context.ContextSize);
  1553. end;
  1554. function TXPathEnvironment.xpPosition(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1555. begin
  1556. if Args.Count <> 0 then
  1557. EvaluationError(SEvalInvalidArgCount);
  1558. Result := TXPathNumberVariable.Create(Context.ContextPosition);
  1559. end;
  1560. function TXPathEnvironment.xpCount(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1561. begin
  1562. if Args.Count <> 1 then
  1563. EvaluationError(SEvalInvalidArgCount);
  1564. Result := TXPathNumberVariable.Create(TXPathVariable(Args[0]).AsNodeSet.Count);
  1565. end;
  1566. function TXPathEnvironment.xpId(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1567. begin
  1568. if Args.Count <> 1 then
  1569. EvaluationError(SEvalInvalidArgCount);
  1570. EvaluationError(SEvalFunctionNotImplementedYet, ['id']); // !!!
  1571. end;
  1572. function TXPathEnvironment.xpLocalName(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1573. begin
  1574. if Args.Count > 1 then
  1575. EvaluationError(SEvalInvalidArgCount);
  1576. EvaluationError(SEvalFunctionNotImplementedYet, ['local-name']); // !!!
  1577. end;
  1578. function TXPathEnvironment.xpNamespaceURI(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1579. begin
  1580. if Args.Count > 1 then
  1581. EvaluationError(SEvalInvalidArgCount);
  1582. EvaluationError(SEvalFunctionNotImplementedYet, ['namespace-uri']); // !!!
  1583. end;
  1584. function TXPathEnvironment.xpName(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1585. var
  1586. NodeSet: TNodeSet;
  1587. begin
  1588. if Args.Count <> 1 then
  1589. EvaluationError(SEvalInvalidArgCount);
  1590. NodeSet := TXPathVariable(Args[0]).AsNodeSet;
  1591. if NodeSet.Count = 0 then
  1592. Result := TXPathStringVariable.Create('')
  1593. else
  1594. // !!!: Probably not really correct regarding namespaces...
  1595. Result := TXPathStringVariable.Create(TDOMNode(NodeSet[0]).NodeName);
  1596. end;
  1597. function TXPathEnvironment.xpString(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1598. var
  1599. s: String;
  1600. begin
  1601. if Args.Count > 1 then
  1602. EvaluationError(SEvalInvalidArgCount);
  1603. if Args.Count = 0 then
  1604. s := NodeToText(Context.ContextNode)
  1605. else
  1606. s := TXPathVariable(Args[0]).AsText;
  1607. Result := TXPathStringVariable.Create(s);
  1608. end;
  1609. function TXPathEnvironment.xpConcat(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1610. var
  1611. i: Integer;
  1612. s: DOMString;
  1613. begin
  1614. if Args.Count < 2 then
  1615. EvaluationError(SEvalInvalidArgCount);
  1616. SetLength(s, 0);
  1617. for i := 0 to Args.Count - 1 do
  1618. s := s + TXPathVariable(Args[i]).AsText;
  1619. Result := TXPathStringVariable.Create(s);
  1620. end;
  1621. function TXPathEnvironment.xpStartsWith(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1622. begin
  1623. if Args.Count <> 2 then
  1624. EvaluationError(SEvalInvalidArgCount);
  1625. EvaluationError(SEvalFunctionNotImplementedYet, ['namespace-uri']); // !!!
  1626. end;
  1627. function TXPathEnvironment.xpContains(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1628. begin
  1629. if Args.Count <> 2 then
  1630. EvaluationError(SEvalInvalidArgCount);
  1631. EvaluationError(SEvalFunctionNotImplementedYet, ['contains']); // !!!
  1632. end;
  1633. function TXPathEnvironment.xpSubstringBefore(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1634. begin
  1635. if Args.Count <> 2 then
  1636. EvaluationError(SEvalInvalidArgCount);
  1637. EvaluationError(SEvalFunctionNotImplementedYet, ['substring-before']); // !!!
  1638. end;
  1639. function TXPathEnvironment.xpSubstringAfter(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1640. begin
  1641. if Args.Count <> 1 then
  1642. EvaluationError(SEvalInvalidArgCount);
  1643. EvaluationError(SEvalFunctionNotImplementedYet, ['substring-after']); // !!!
  1644. end;
  1645. function TXPathEnvironment.xpSubstring(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1646. begin
  1647. if (Args.Count < 2) or (Args.Count > 3) then
  1648. EvaluationError(SEvalInvalidArgCount);
  1649. EvaluationError(SEvalFunctionNotImplementedYet, ['substring']); // !!!
  1650. end;
  1651. function TXPathEnvironment.xpStringLength(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1652. var
  1653. s: DOMString;
  1654. begin
  1655. if Args.Count < 1 then
  1656. EvaluationError(SEvalInvalidArgCount);
  1657. if Args.Count = 0 then
  1658. s := NodeToText(Context.ContextNode)
  1659. else
  1660. s := TXPathVariable(Args[0]).AsText;
  1661. Result := TXPathNumberVariable.Create(Length(s));
  1662. end;
  1663. function TXPathEnvironment.xpNormalizeSpace(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1664. begin
  1665. if Args.Count < 1 then
  1666. EvaluationError(SEvalInvalidArgCount);
  1667. EvaluationError(SEvalFunctionNotImplementedYet, ['normalize-space']); // !!!
  1668. end;
  1669. function TXPathEnvironment.xpTranslate(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1670. begin
  1671. if Args.Count <> 3 then
  1672. EvaluationError(SEvalInvalidArgCount);
  1673. EvaluationError(SEvalFunctionNotImplementedYet, ['translate']); // !!!
  1674. end;
  1675. function TXPathEnvironment.xpBoolean(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1676. begin
  1677. if Args.Count <> 1 then
  1678. EvaluationError(SEvalInvalidArgCount);
  1679. Result := TXPathBooleanVariable.Create(TXPathVariable(Args[0]).AsBoolean);
  1680. end;
  1681. function TXPathEnvironment.xpNot(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1682. begin
  1683. if Args.Count <> 1 then
  1684. EvaluationError(SEvalInvalidArgCount);
  1685. Result := TXPathBooleanVariable.Create(not TXPathVariable(Args[0]).AsBoolean);
  1686. end;
  1687. function TXPathEnvironment.xpTrue(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1688. begin
  1689. if Args.Count <> 0 then
  1690. EvaluationError(SEvalInvalidArgCount);
  1691. Result := TXPathBooleanVariable.Create(True);
  1692. end;
  1693. function TXPathEnvironment.xpFalse(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1694. begin
  1695. if Args.Count <> 0 then
  1696. EvaluationError(SEvalInvalidArgCount);
  1697. Result := TXPathBooleanVariable.Create(False);
  1698. end;
  1699. function TXPathEnvironment.xpLang(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1700. begin
  1701. if Args.Count <> 1 then
  1702. EvaluationError(SEvalInvalidArgCount);
  1703. EvaluationError(SEvalFunctionNotImplementedYet, ['lang']); // !!!
  1704. end;
  1705. function TXPathEnvironment.xpNumber(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1706. begin
  1707. if Args.Count > 1 then
  1708. EvaluationError(SEvalInvalidArgCount);
  1709. EvaluationError(SEvalFunctionNotImplementedYet, ['number']); // !!!
  1710. end;
  1711. function TXPathEnvironment.xpSum(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1712. begin
  1713. if Args.Count <> 1 then
  1714. EvaluationError(SEvalInvalidArgCount);
  1715. EvaluationError(SEvalFunctionNotImplementedYet, ['sum']); // !!!
  1716. end;
  1717. function TXPathEnvironment.xpFloor(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1718. begin
  1719. if Args.Count <> 1 then
  1720. EvaluationError(SEvalInvalidArgCount);
  1721. EvaluationError(SEvalFunctionNotImplementedYet, ['floor']); // !!!
  1722. end;
  1723. function TXPathEnvironment.xpCeiling(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1724. begin
  1725. if Args.Count <> 1 then
  1726. EvaluationError(SEvalInvalidArgCount);
  1727. EvaluationError(SEvalFunctionNotImplementedYet, ['ceiling']); // !!!
  1728. end;
  1729. function TXPathEnvironment.xpRound(Context: TXPathContext; Args: TXPathVarList): TXPathVariable;
  1730. begin
  1731. if Args.Count <> 1 then
  1732. EvaluationError(SEvalInvalidArgCount);
  1733. EvaluationError(SEvalFunctionNotImplementedYet, ['round']); // !!!
  1734. end;
  1735. { TXPathExpression }
  1736. constructor TXPathExpression.Create(AScanner: TXPathScanner;
  1737. CompleteExpression: Boolean);
  1738. function ParseLocationPath: TXPathLocationPathNode; forward; // [1]
  1739. function ParsePrimaryExpr: TXPathExprNode; forward; // [15]
  1740. function ParseUnionExpr: TXPathExprNode; forward; // [18]
  1741. function ParsePathExpr: TXPathExprNode; forward; // [19]
  1742. function ParseFilterExpr: TXPathExprNode; forward; // [20]
  1743. function ParseOrExpr: TXPathExprNode; forward; // [21]
  1744. function ParseAndExpr: TXPathExprNode; forward; // [22]
  1745. function ParseEqualityExpr: TXPathExprNode; forward; // [23]
  1746. function ParseRelationalExpr: TXPathExprNode; forward; // [24]
  1747. function ParseAdditiveExpr: TXPathExprNode; forward; // [25]
  1748. function ParseMultiplicativeExpr: TXPathExprNode; forward; // [26]
  1749. function ParseUnaryExpr: TXPathExprNode; forward; // [27]
  1750. procedure Error(const Msg: String);
  1751. begin
  1752. raise Exception.Create(Msg) at get_caller_addr(get_frame);
  1753. end;
  1754. procedure Error(const Msg: String; const Args: array of const);
  1755. begin
  1756. raise Exception.CreateFmt(Msg, Args) at get_caller_addr(get_frame);
  1757. end;
  1758. function ParseLocationPath: TXPathLocationPathNode; // [1]
  1759. var
  1760. IsAbsolute, NeedColonColon: Boolean;
  1761. FirstStep, CurStep, NextStep: TStep;
  1762. begin
  1763. IsAbsolute := False;
  1764. CurStep := nil;
  1765. case AScanner.NextToken of
  1766. tkSlash: // [2] AbsoluteLocationPath, first case
  1767. begin
  1768. IsAbsolute := True;
  1769. if not (AScanner.NextToken in
  1770. [tkDot, tkDotDot, tkAsterisk, tkAt, tkIdentifier]) then
  1771. begin
  1772. AScanner.UngetToken;
  1773. exit;
  1774. end;
  1775. AScanner.UngetToken;
  1776. end;
  1777. tkSlashSlash: // [10] AbbreviatedAbsoluteLocationPath
  1778. begin
  1779. IsAbsolute := True;
  1780. CurStep := TStep.Create;
  1781. CurStep.Axis := axisDescendantOrSelf;
  1782. CurStep.NodeTestType := ntAnyNode;
  1783. end;
  1784. else
  1785. begin
  1786. AScanner.UngetToken;
  1787. IsAbsolute := False;
  1788. end;
  1789. end;
  1790. // Parse [3] RelativeLocationPath
  1791. FirstStep := CurStep;
  1792. while True do
  1793. begin
  1794. NextStep := TStep.Create;
  1795. if Assigned(CurStep) then
  1796. CurStep.NextStep := NextStep
  1797. else
  1798. FirstStep := NextStep;
  1799. CurStep := NextStep;
  1800. // Parse [4] Step
  1801. case AScanner.NextToken of
  1802. tkDot: // [12] Abbreviated step, first case
  1803. begin
  1804. CurStep.Axis := axisSelf;
  1805. CurStep.NodeTestType := ntAnyNode;
  1806. end;
  1807. tkDotDot: // [12] Abbreviated step, second case
  1808. begin
  1809. CurStep.Axis := axisParent;
  1810. CurStep.NodeTestType := ntAnyNode;
  1811. end;
  1812. else
  1813. begin
  1814. AScanner.UngetToken;
  1815. // Parse [5] AxisSpecifier
  1816. case AScanner.NextToken of
  1817. tkAt: // [13] AbbreviatedAxisSpecifier
  1818. CurStep.Axis := axisAttribute;
  1819. tkIdentifier: // [5] AxisName '::'
  1820. begin
  1821. // Check for [6] AxisName
  1822. NeedColonColon := True;
  1823. if AScanner.CurTokenString = 'ancestor' then
  1824. CurStep.Axis := axisAncestor
  1825. else if AScanner.CurTokenString = 'ancestor-or-self' then
  1826. CurStep.Axis := axisAncestorOrSelf
  1827. else if AScanner.CurTokenString = 'attribute' then
  1828. CurStep.Axis := axisAttribute
  1829. else if AScanner.CurTokenString = 'child' then
  1830. CurStep.Axis := axisChild
  1831. else if AScanner.CurTokenString = 'descendant' then
  1832. CurStep.Axis := axisDescendant
  1833. else if AScanner.CurTokenString = 'descendant-or-self' then
  1834. CurStep.Axis := axisDescendantOrSelf
  1835. else if AScanner.CurTokenString = 'following' then
  1836. CurStep.Axis := axisFollowing
  1837. else if AScanner.CurTokenString = 'following-sibling' then
  1838. CurStep.Axis := axisFollowingSibling
  1839. else if AScanner.CurTokenString = 'namespace' then
  1840. CurStep.Axis := axisNamespace
  1841. else if AScanner.CurTokenString = 'parent' then
  1842. CurStep.Axis := axisParent
  1843. else if AScanner.CurTokenString = 'preceding' then
  1844. CurStep.Axis := axisPreceding
  1845. else if AScanner.CurTokenString = 'preceding-sibling' then
  1846. CurStep.Axis := axisPrecedingSibling
  1847. else if AScanner.CurTokenString = 'self' then
  1848. CurStep.Axis := axisSelf
  1849. else
  1850. begin
  1851. NeedColonColon := False;
  1852. AScanner.UngetToken;
  1853. CurStep.Axis := axisChild;
  1854. end;
  1855. if NeedColonColon and (AScanner.NextToken <> tkColonColon) then
  1856. Error(SParserExpectedColonColor);
  1857. end;
  1858. else
  1859. begin
  1860. AScanner.UngetToken;
  1861. CurStep.Axis := axisChild;
  1862. end;
  1863. end;
  1864. // Parse [7] NodeTest
  1865. case AScanner.NextToken of
  1866. tkAsterisk: // [37] NameTest, first case
  1867. CurStep.NodeTestType := ntAnyPrincipal;
  1868. tkIdentifier:
  1869. begin
  1870. // Check for case [38] NodeType
  1871. if AScanner.CurTokenString = 'comment' then
  1872. begin
  1873. if (AScanner.NextToken <> tkLeftBracket) or
  1874. (AScanner.NextToken <> tkRightBracket) then
  1875. Error(SParserExpectedBrackets);
  1876. CurStep.NodeTestType := ntCommentNode;
  1877. end else if AScanner.CurTokenString = 'text' then
  1878. begin
  1879. if (AScanner.NextToken <> tkLeftBracket) or
  1880. (AScanner.NextToken <> tkRightBracket) then
  1881. Error(SParserExpectedBrackets);
  1882. CurStep.NodeTestType := ntTextNode;
  1883. end else if AScanner.CurTokenString = 'processing-instruction' then
  1884. begin
  1885. if (AScanner.NextToken <> tkLeftBracket) or
  1886. (AScanner.NextToken <> tkRightBracket) then
  1887. Error(SParserExpectedBrackets);
  1888. CurStep.NodeTestType := ntPINode;
  1889. end else if AScanner.CurTokenString = 'node' then
  1890. begin
  1891. if (AScanner.NextToken <> tkLeftBracket) or
  1892. (AScanner.NextToken <> tkRightBracket) then
  1893. Error(SParserExpectedBrackets);
  1894. CurStep.NodeTestType := ntAnyNode;
  1895. end else // [37] NameTest, second or third case
  1896. begin
  1897. // !!!: Doesn't support namespaces yet
  1898. // (this will have to wait until the DOM unit supports them)
  1899. CurStep.NodeTestType := ntName;
  1900. CurStep.NodeTestString := AScanner.CurTokenString;
  1901. end;
  1902. end;
  1903. else
  1904. Error(SParserInvalidNodeTest);
  1905. end;
  1906. // Parse predicates
  1907. while AScanner.NextToken = tkLeftSquareBracket do
  1908. begin
  1909. CurStep.Predicates.Add(ParseOrExpr);
  1910. if AScanner.NextToken <> tkRightSquareBracket then
  1911. Error(SParserExpectedRightSquareBracket);
  1912. end;
  1913. AScanner.UngetToken;
  1914. end;
  1915. end;
  1916. // Continue with parsing of [3] RelativeLocationPath
  1917. if AScanner.NextToken = tkSlashSlash then
  1918. begin
  1919. // Found abbreviated step ("//" for "descendant-or-self::node()")
  1920. NextStep := TStep.Create;
  1921. CurStep.NextStep := NextStep;
  1922. CurStep := NextStep;
  1923. CurStep.Axis := axisDescendantOrSelf;
  1924. CurStep.NodeTestType := ntAnyNode;
  1925. end else if AScanner.CurToken <> tkSlash then
  1926. begin
  1927. AScanner.UngetToken;
  1928. break;
  1929. end;
  1930. end;
  1931. Result := TXPathLocationPathNode.Create(IsAbsolute);
  1932. TXPathLocationPathNode(Result).FFirstStep := FirstStep;
  1933. end;
  1934. function ParsePrimaryExpr: TXPathExprNode; // [15]
  1935. var
  1936. IsFirstArg: Boolean;
  1937. begin
  1938. case AScanner.NextToken of
  1939. tkDollar: // [36] Variable reference
  1940. begin
  1941. if AScanner.NextToken <> tkIdentifier then
  1942. Error(SParserExpectedVarName);
  1943. Result := TXPathVariableNode.Create(AScanner.CurTokenString);
  1944. end;
  1945. tkLeftBracket:
  1946. begin
  1947. Result := ParseOrExpr;
  1948. if AScanner.NextToken <> tkRightBracket then
  1949. Error(SParserExpectedRightBracket);
  1950. end;
  1951. tkString: // [29] Literal
  1952. Result := TXPathConstantNode.Create(
  1953. TXPathStringVariable.Create(AScanner.CurTokenString));
  1954. tkNumber: // [30] Number
  1955. Result := TXPathConstantNode.Create(
  1956. TXPathNumberVariable.Create(StrToFloat(AScanner.CurTokenString)));
  1957. tkIdentifier: // [16] Function call
  1958. begin
  1959. Result := TXPathFunctionNode.Create(AScanner.CurTokenString);
  1960. if AScanner.NextToken <> tkLeftBracket then
  1961. Error(SParserExpectedLeftBracket);
  1962. // Parse argument list
  1963. IsFirstArg := True;
  1964. while AScanner.NextToken <> tkRightBracket do
  1965. begin
  1966. if IsFirstArg then
  1967. begin
  1968. IsFirstArg := False;
  1969. AScanner.UngetToken;
  1970. end else
  1971. if AScanner.CurToken <> tkComma then
  1972. Error(SParserExpectedRightBracket);
  1973. TXPathFunctionNode(Result).FArgs.Add(ParseOrExpr);
  1974. end;
  1975. end;
  1976. else
  1977. Error(SParserInvalidPrimExpr);
  1978. end;
  1979. end;
  1980. function ParseUnionExpr: TXPathExprNode; // [18]
  1981. begin
  1982. Result := ParsePathExpr;
  1983. while True do
  1984. if AScanner.NextToken = tkPipe then
  1985. Result := TXPathUnionNode.Create(Result, ParsePathExpr)
  1986. else
  1987. begin
  1988. AScanner.UngetToken;
  1989. break;
  1990. end;
  1991. end;
  1992. function ParsePathExpr: TXPathExprNode; // [19]
  1993. var
  1994. ScannerState: TXPathScannerState;
  1995. IsFunctionCall: Boolean;
  1996. begin
  1997. // Try to detect wether a LocationPath [1] or a FilterExpr [20] follows
  1998. IsFunctionCall := False;
  1999. if (AScanner.NextToken = tkIdentifier) and
  2000. (AScanner.CurTokenString <> 'comment') and
  2001. (AScanner.CurTokenString <> 'text') and
  2002. (AScanner.CurTokenString <> 'processing-instruction') and
  2003. (AScanner.CurTokenString <> 'node') then
  2004. begin
  2005. ScannerState := AScanner.SaveState;
  2006. if AScanner.NextToken = tkLeftBracket then
  2007. IsFunctionCall := True;
  2008. AScanner.RestoreState(ScannerState);
  2009. end;
  2010. if IsFunctionCall or (AScanner.CurToken in
  2011. [tkDollar, tkLeftBracket, tkString, tkNumber]) then
  2012. begin
  2013. // second, third or fourth case of [19]
  2014. AScanner.UngetToken;
  2015. Result := ParseFilterExpr;
  2016. // !!!: Doesn't handle "/" or "//" plus RelativeLocationPath yet!
  2017. end else
  2018. begin
  2019. AScanner.UngetToken;
  2020. Result := ParseLocationPath;
  2021. end;
  2022. end;
  2023. function ParseFilterExpr: TXPathExprNode; // [20]
  2024. var
  2025. IsFirst: Boolean;
  2026. begin
  2027. Result := ParsePrimaryExpr;
  2028. // Parse predicates
  2029. IsFirst := True;
  2030. while AScanner.NextToken = tkLeftSquareBracket do
  2031. begin
  2032. if IsFirst then
  2033. begin
  2034. Result := TXPathFilterNode.Create(Result);
  2035. IsFirst := False;
  2036. end;
  2037. TXPathFilterNode(Result).FPredicates.Add(ParseOrExpr);
  2038. if AScanner.NextToken <> tkRightSquareBracket then
  2039. Error(SParserExpectedRightSquareBracket);
  2040. end;
  2041. AScanner.UngetToken;
  2042. end;
  2043. function ParseOrExpr: TXPathExprNode; // [21]
  2044. begin
  2045. Result := ParseAndExpr;
  2046. while True do
  2047. if (AScanner.NextToken = tkIdentifier) and
  2048. (AScanner.CurTokenString = 'or') then
  2049. Result := TXPathBooleanOpNode.Create(opOr, Result, ParseAndExpr)
  2050. else
  2051. begin
  2052. AScanner.UngetToken;
  2053. break;
  2054. end;
  2055. end;
  2056. function ParseAndExpr: TXPathExprNode; // [22]
  2057. begin
  2058. Result := ParseEqualityExpr;
  2059. while True do
  2060. if (AScanner.NextToken = tkIdentifier) and
  2061. (AScanner.CurTokenString = 'and') then
  2062. Result := TXPathBooleanOpNode.Create(opAnd, Result, ParseEqualityExpr)
  2063. else
  2064. begin
  2065. AScanner.UngetToken;
  2066. break;
  2067. end;
  2068. end;
  2069. function ParseEqualityExpr: TXPathExprNode; // [23]
  2070. begin
  2071. Result := ParseRelationalExpr;
  2072. while True do
  2073. case AScanner.NextToken of
  2074. tkEqual:
  2075. Result := TXPathBooleanOpNode.Create(opEqual, Result,
  2076. ParseRelationalExpr);
  2077. tkNotEqual:
  2078. Result := TXPathBooleanOpNode.Create(opNotEqual, Result,
  2079. ParseRelationalExpr);
  2080. else
  2081. begin
  2082. AScanner.UngetToken;
  2083. break;
  2084. end;
  2085. end;
  2086. end;
  2087. function ParseRelationalExpr: TXPathExprNode; // [24]
  2088. begin
  2089. Result := ParseAdditiveExpr;
  2090. while True do
  2091. case AScanner.NextToken of
  2092. tkLess:
  2093. Result := TXPathBooleanOpNode.Create(opLess, Result,
  2094. ParseAdditiveExpr);
  2095. tkLessEqual:
  2096. Result := TXPathBooleanOpNode.Create(opLessEqual, Result,
  2097. ParseAdditiveExpr);
  2098. tkGreater:
  2099. Result := TXPathBooleanOpNode.Create(opGreater, Result,
  2100. ParseAdditiveExpr);
  2101. tkGreaterEqual:
  2102. Result := TXPathBooleanOpNode.Create(opGreaterEqual, Result,
  2103. ParseAdditiveExpr);
  2104. else
  2105. begin
  2106. AScanner.UngetToken;
  2107. break;
  2108. end;
  2109. end;
  2110. end;
  2111. function ParseAdditiveExpr: TXPathExprNode; // [25]
  2112. begin
  2113. Result := ParseMultiplicativeExpr;
  2114. while True do
  2115. case AScanner.NextToken of
  2116. tkPlus:
  2117. Result := TXPathMathOpNode.Create(opAdd, Result,
  2118. ParseMultiplicativeExpr);
  2119. tkMinus:
  2120. Result := TXPathMathOpNode.Create(opSubtract, Result,
  2121. ParseMultiplicativeExpr);
  2122. else
  2123. begin
  2124. AScanner.UngetToken;
  2125. break;
  2126. end;
  2127. end;
  2128. end;
  2129. function ParseMultiplicativeExpr: TXPathExprNode; // [26]
  2130. begin
  2131. Result := ParseUnaryExpr;
  2132. while True do
  2133. case AScanner.NextToken of
  2134. tkAsterisk:
  2135. Result := TXPathMathOpNode.Create(opMultiply, Result,
  2136. ParseUnaryExpr);
  2137. tkIdentifier:
  2138. if AScanner.CurTokenString = 'div' then
  2139. Result := TXPathMathOpNode.Create(opDivide, Result,
  2140. ParseUnaryExpr)
  2141. else if AScanner.CurTokenString = 'mod' then
  2142. Result := TXPathMathOpNode.Create(opMod, Result,
  2143. ParseUnaryExpr)
  2144. else
  2145. begin
  2146. AScanner.UngetToken;
  2147. break;
  2148. end;
  2149. else
  2150. begin
  2151. AScanner.UngetToken;
  2152. break;
  2153. end;
  2154. end;
  2155. end;
  2156. function ParseUnaryExpr: TXPathExprNode; // [27]
  2157. var
  2158. NegCount: Integer;
  2159. begin
  2160. NegCount := 0;
  2161. while AScanner.NextToken = tkMinus do
  2162. Inc(NegCount);
  2163. AScanner.UngetToken;
  2164. Result := ParseUnionExpr;
  2165. if Odd(NegCount) then
  2166. Result := TXPathNegationNode.Create(Result);
  2167. end;
  2168. begin
  2169. inherited Create;
  2170. FRootNode := ParseOrExpr;
  2171. if CompleteExpression and (AScanner.NextToken <> tkEndOfStream) then
  2172. Error(SParserGarbageAfterExpression);
  2173. end;
  2174. function TXPathExpression.Evaluate(AContextNode: TDOMNode): TXPathVariable;
  2175. var
  2176. Environment: TXPathEnvironment;
  2177. begin
  2178. Environment := TXPathEnvironment.Create;
  2179. try
  2180. Result := Evaluate(AContextNode, Environment);
  2181. finally
  2182. Environment.Free;
  2183. end;
  2184. end;
  2185. function TXPathExpression.Evaluate(AContextNode: TDOMNode;
  2186. AEnvironment: TXPathEnvironment): TXPathVariable;
  2187. var
  2188. Context: TXPathContext;
  2189. begin
  2190. if Assigned(FRootNode) then
  2191. begin
  2192. Context := TXPathContext.Create(AContextNode, 1, 1);
  2193. try
  2194. Result := FRootNode.Evaluate(Context, AEnvironment);
  2195. finally
  2196. Context.Free;
  2197. end;
  2198. end else
  2199. Result := nil;
  2200. end;
  2201. function EvaluateXPathExpression(const AExpressionString: DOMString;
  2202. AContextNode: TDOMNode): TXPathVariable;
  2203. var
  2204. Scanner: TXPathScanner;
  2205. Expression: TXPathExpression;
  2206. begin
  2207. Scanner := TXPathScanner.Create(AExpressionString);
  2208. try
  2209. Expression := TXPathExpression.Create(Scanner, True);
  2210. try
  2211. Result := Expression.Evaluate(AContextNode);
  2212. finally
  2213. Expression.Free;
  2214. end;
  2215. finally
  2216. Scanner.Free;
  2217. end;
  2218. end;
  2219. end.
  2220. {
  2221. $Log$
  2222. Revision 1.2 2003-03-17 14:32:15 peter
  2223. * Change ASText return to DOMString in implementation
  2224. Revision 1.1 2003/03/16 22:10:57 sg
  2225. * Added XPath unit
  2226. }