DefaultContext.cs 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. //
  2. // System.Xml.XPath.DefaultContext & support classes
  3. //
  4. // Author:
  5. // Piers Haken ([email protected])
  6. //
  7. // (C) 2002 Piers Haken
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.Globalization;
  32. using System.Xml;
  33. using System.Xml.XPath;
  34. using System.Xml.Xsl;
  35. using System.Text;
  36. namespace System.Xml.XPath
  37. {
  38. internal class XPathFunctions
  39. {
  40. public static bool ToBoolean (object arg)
  41. {
  42. if (arg == null)
  43. throw new ArgumentNullException ();
  44. if (arg is bool)
  45. return (bool) arg;
  46. if (arg is double)
  47. {
  48. double dArg = (double) arg;
  49. return (dArg != 0.0 && !double.IsNaN (dArg));
  50. }
  51. if (arg is string)
  52. return ((string) arg).Length != 0;
  53. if (arg is XPathNodeIterator)
  54. {
  55. XPathNodeIterator iter = (XPathNodeIterator) arg;
  56. return iter.MoveNext ();
  57. }
  58. if (arg is XPathNavigator)
  59. {
  60. return ToBoolean (((XPathNavigator) arg).SelectChildren (XPathNodeType.All));
  61. }
  62. throw new ArgumentException ();
  63. }
  64. public static bool ToBoolean (bool b)
  65. {
  66. return b;
  67. }
  68. public static bool ToBoolean (double d)
  69. {
  70. return d != 0.0 && !Double.IsNaN (d);
  71. }
  72. public static bool ToBoolean (string s)
  73. {
  74. return s != null && s.Length > 0;
  75. }
  76. public static bool ToBoolean (BaseIterator iter)
  77. {
  78. return iter != null && iter.MoveNext ();
  79. }
  80. public static string ToString (object arg)
  81. {
  82. if (arg == null)
  83. throw new ArgumentNullException ();
  84. if (arg is string)
  85. return (string) arg;
  86. if (arg is bool)
  87. return ((bool) arg) ? "true" : "false";
  88. if (arg is double)
  89. return ToString ((double) arg);
  90. if (arg is XPathNodeIterator)
  91. {
  92. XPathNodeIterator iter = (XPathNodeIterator) arg;
  93. if (!iter.MoveNext ())
  94. return "";
  95. return iter.Current.Value;
  96. }
  97. if (arg is XPathNavigator)
  98. {
  99. return ((XPathNavigator) arg).Value;
  100. }
  101. throw new ArgumentException ();
  102. }
  103. public static string ToString (double d)
  104. {
  105. // See XPath 1.0 section 4.2
  106. if (d == Double.NegativeInfinity)
  107. return "-Infinity";
  108. if (d == Double.PositiveInfinity)
  109. return "Infinity";
  110. return d.ToString ("R", NumberFormatInfo.InvariantInfo);
  111. }
  112. public static double ToNumber (object arg)
  113. {
  114. if (arg == null)
  115. throw new ArgumentNullException ();
  116. if (arg is BaseIterator || arg is XPathNavigator)
  117. arg = ToString (arg); // follow on
  118. if (arg is string) {
  119. string s = arg as string;
  120. return ToNumber (s); // use explicit overload
  121. }
  122. if (arg is double)
  123. return (double) arg;
  124. if (arg is bool)
  125. return Convert.ToDouble ((bool) arg);
  126. throw new ArgumentException ();
  127. }
  128. public static double ToNumber (string arg)
  129. {
  130. if (arg == null)
  131. throw new ArgumentNullException ();
  132. string s = arg.Trim (XmlChar.WhitespaceChars);
  133. if (s.Length == 0)
  134. return double.NaN;
  135. try {
  136. return XmlConvert.ToDouble (s);
  137. } catch (System.OverflowException) {
  138. return double.NaN;
  139. } catch (System.FormatException) {
  140. return double.NaN;
  141. }
  142. }
  143. }
  144. internal abstract class XPathFunction : Expression
  145. {
  146. public XPathFunction (FunctionArguments args) {}
  147. }
  148. internal class XPathFunctionLast : XPathFunction
  149. {
  150. public XPathFunctionLast (FunctionArguments args) : base (args)
  151. {
  152. if (args != null)
  153. throw new XPathException ("last takes 0 args");
  154. }
  155. public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
  156. internal override bool Peer {
  157. get { return true; }
  158. }
  159. public override object Evaluate (BaseIterator iter)
  160. {
  161. return (double) iter.Count;
  162. }
  163. public override string ToString ()
  164. {
  165. return "last()";
  166. }
  167. internal override bool IsPositional {
  168. get { return true; }
  169. }
  170. }
  171. internal class XPathFunctionPosition : XPathFunction
  172. {
  173. public XPathFunctionPosition (FunctionArguments args) : base (args)
  174. {
  175. if (args != null)
  176. throw new XPathException ("position takes 0 args");
  177. }
  178. public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
  179. internal override bool Peer {
  180. get { return true; }
  181. }
  182. public override object Evaluate (BaseIterator iter)
  183. {
  184. return (double) iter.CurrentPosition;
  185. }
  186. public override string ToString ()
  187. {
  188. return "position()";
  189. }
  190. internal override bool IsPositional {
  191. get { return true; }
  192. }
  193. }
  194. internal class XPathFunctionCount : XPathFunction
  195. {
  196. Expression arg0;
  197. public XPathFunctionCount (FunctionArguments args) : base (args)
  198. {
  199. if (args == null || args.Tail != null)
  200. throw new XPathException ("count takes 1 arg");
  201. arg0 = args.Arg;
  202. }
  203. public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
  204. internal override bool Peer {
  205. get { return arg0.Peer; }
  206. }
  207. public override object Evaluate (BaseIterator iter)
  208. {
  209. return (double) arg0.EvaluateNodeSet (iter).Count;
  210. }
  211. public override bool EvaluateBoolean (BaseIterator iter)
  212. {
  213. if (arg0.GetReturnType (iter) == XPathResultType.NodeSet)
  214. return arg0.EvaluateBoolean (iter);
  215. return arg0.EvaluateNodeSet (iter).MoveNext ();
  216. }
  217. public override string ToString ()
  218. {
  219. return "count(" + arg0.ToString () + ")";
  220. }
  221. }
  222. internal class XPathFunctionId : XPathFunction
  223. {
  224. Expression arg0;
  225. public XPathFunctionId (FunctionArguments args) : base (args)
  226. {
  227. if (args == null || args.Tail != null)
  228. throw new XPathException ("id takes 1 arg");
  229. arg0 = args.Arg;
  230. }
  231. public Expression Id { get { return arg0; } }
  232. private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
  233. public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
  234. internal override bool Peer {
  235. get { return arg0.Peer; }
  236. }
  237. public override object Evaluate (BaseIterator iter)
  238. {
  239. String strArgs;
  240. object val = arg0.Evaluate (iter);
  241. BaseIterator valItr = val as BaseIterator;
  242. if (valItr != null)
  243. {
  244. strArgs = "";
  245. while (valItr.MoveNext ())
  246. strArgs += valItr.Current.Value + " ";
  247. }
  248. else
  249. strArgs = XPathFunctions.ToString (val);
  250. XPathNavigator n = iter.Current.Clone ();
  251. ArrayList rgNodes = new ArrayList ();
  252. string [] ids = strArgs.Split (rgchWhitespace);
  253. for (int i = 0; i < ids.Length; i++)
  254. if (n.MoveToId (ids [i]))
  255. rgNodes.Add (n.Clone ());
  256. rgNodes.Sort (XPathNavigatorComparer.Instance);
  257. return new ListIterator (iter, rgNodes);
  258. }
  259. public override string ToString ()
  260. {
  261. return "id(" + arg0.ToString () + ")";
  262. }
  263. }
  264. internal class XPathFunctionLocalName : XPathFunction
  265. {
  266. Expression arg0;
  267. public XPathFunctionLocalName (FunctionArguments args) : base (args)
  268. {
  269. if (args != null) {
  270. arg0 = args.Arg;
  271. if (args.Tail != null)
  272. throw new XPathException ("local-name takes 1 or zero args");
  273. }
  274. }
  275. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  276. internal override bool Peer {
  277. get { return arg0 != null ? arg0.Peer : true; }
  278. }
  279. public override object Evaluate (BaseIterator iter)
  280. {
  281. if (arg0 == null)
  282. return iter.Current.LocalName;
  283. BaseIterator argNs = arg0.EvaluateNodeSet (iter);
  284. if (argNs == null || !argNs.MoveNext ())
  285. return "";
  286. return argNs.Current.LocalName;
  287. }
  288. public override string ToString ()
  289. {
  290. return "local-name(" + arg0.ToString () + ")";
  291. }
  292. }
  293. internal class XPathFunctionNamespaceUri : XPathFunction
  294. {
  295. Expression arg0;
  296. public XPathFunctionNamespaceUri (FunctionArguments args) : base (args)
  297. {
  298. if (args != null) {
  299. arg0 = args.Arg;
  300. if (args.Tail != null)
  301. throw new XPathException ("namespace-uri takes 1 or zero args");
  302. }
  303. }
  304. internal override bool Peer {
  305. get { return arg0 != null ? arg0.Peer : true; }
  306. }
  307. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  308. public override object Evaluate (BaseIterator iter)
  309. {
  310. if (arg0 == null)
  311. return iter.Current.NamespaceURI;
  312. BaseIterator argNs = arg0.EvaluateNodeSet (iter);
  313. if (argNs == null || !argNs.MoveNext ())
  314. return "";
  315. return argNs.Current.NamespaceURI;
  316. }
  317. public override string ToString ()
  318. {
  319. return "namespace-uri(" + arg0.ToString () + ")";
  320. }
  321. }
  322. internal class XPathFunctionName : XPathFunction
  323. {
  324. Expression arg0;
  325. public XPathFunctionName (FunctionArguments args) : base (args)
  326. {
  327. if (args != null) {
  328. arg0 = args.Arg;
  329. if (args.Tail != null)
  330. throw new XPathException ("name takes 1 or zero args");
  331. }
  332. }
  333. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  334. internal override bool Peer {
  335. get { return arg0 != null ? arg0.Peer : true; }
  336. }
  337. public override object Evaluate (BaseIterator iter)
  338. {
  339. if (arg0 == null)
  340. return iter.Current.Name;
  341. BaseIterator argNs = arg0.EvaluateNodeSet (iter);
  342. if (argNs == null || !argNs.MoveNext ())
  343. return "";
  344. return argNs.Current.Name;
  345. }
  346. public override string ToString ()
  347. {
  348. return String.Concat ("name(",
  349. arg0 != null ? arg0.ToString () : String.Empty,
  350. ")");
  351. }
  352. }
  353. internal class XPathFunctionString : XPathFunction
  354. {
  355. Expression arg0;
  356. public XPathFunctionString (FunctionArguments args) : base (args)
  357. {
  358. if (args != null) {
  359. arg0 = args.Arg;
  360. if (args.Tail != null)
  361. throw new XPathException ("string takes 1 or zero args");
  362. }
  363. }
  364. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  365. internal override bool Peer {
  366. get { return arg0 != null ? arg0.Peer : true; }
  367. }
  368. public override object Evaluate (BaseIterator iter)
  369. {
  370. if (arg0 == null)
  371. return iter.Current.Value;
  372. return arg0.EvaluateString (iter);
  373. }
  374. public override string ToString ()
  375. {
  376. return "string(" + arg0.ToString () + ")";
  377. }
  378. }
  379. internal class XPathFunctionConcat : XPathFunction
  380. {
  381. ArrayList rgs;
  382. public XPathFunctionConcat (FunctionArguments args) : base (args)
  383. {
  384. if (args == null || args.Tail == null)
  385. throw new XPathException ("concat takes 2 or more args");
  386. args.ToArrayList (rgs = new ArrayList ());
  387. }
  388. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  389. internal override bool Peer {
  390. get {
  391. for (int i = 0; i < rgs.Count; i++)
  392. if (!((Expression) rgs [i]).Peer)
  393. return false;
  394. return true;
  395. }
  396. }
  397. public override object Evaluate (BaseIterator iter)
  398. {
  399. StringBuilder sb = new StringBuilder ();
  400. int len = rgs.Count;
  401. for (int i = 0; i < len; i++)
  402. sb.Append (((Expression)rgs[i]).EvaluateString (iter));
  403. return sb.ToString ();
  404. }
  405. public override string ToString ()
  406. {
  407. StringBuilder sb = new StringBuilder ();
  408. sb.Append ("concat(");
  409. for (int i = 0; i < rgs.Count - 1; i++) {
  410. sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [i].ToString ());
  411. sb.Append (',');
  412. }
  413. sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [rgs.Count - 1].ToString ());
  414. sb.Append (')');
  415. return sb.ToString ();
  416. }
  417. }
  418. internal class XPathFunctionStartsWith : XPathFunction
  419. {
  420. Expression arg0, arg1;
  421. public XPathFunctionStartsWith (FunctionArguments args) : base (args)
  422. {
  423. if (args == null || args.Tail == null || args.Tail.Tail != null)
  424. throw new XPathException ("starts-with takes 2 args");
  425. arg0 = args.Arg;
  426. arg1 = args.Tail.Arg;
  427. }
  428. public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
  429. internal override bool Peer {
  430. get { return arg0.Peer && arg1.Peer; }
  431. }
  432. public override object Evaluate (BaseIterator iter)
  433. {
  434. return arg0.EvaluateString (iter).StartsWith (arg1.EvaluateString (iter));
  435. }
  436. public override string ToString ()
  437. {
  438. return String.Concat ("starts-with(", arg0.ToString (), ",", arg1.ToString (), ")");
  439. }
  440. }
  441. internal class XPathFunctionContains : XPathFunction
  442. {
  443. Expression arg0, arg1;
  444. public XPathFunctionContains (FunctionArguments args) : base (args)
  445. {
  446. if (args == null || args.Tail == null || args.Tail.Tail != null)
  447. throw new XPathException ("contains takes 2 args");
  448. arg0 = args.Arg;
  449. arg1 = args.Tail.Arg;
  450. }
  451. public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
  452. internal override bool Peer {
  453. get { return arg0.Peer && arg1.Peer; }
  454. }
  455. public override object Evaluate (BaseIterator iter)
  456. {
  457. return arg0.EvaluateString (iter).IndexOf (arg1.EvaluateString (iter)) != -1;
  458. }
  459. public override string ToString ()
  460. {
  461. return String.Concat ("contains(", arg0.ToString (), ",", arg1.ToString (), ")");
  462. }
  463. }
  464. internal class XPathFunctionSubstringBefore : XPathFunction
  465. {
  466. Expression arg0, arg1;
  467. public XPathFunctionSubstringBefore (FunctionArguments args) : base (args)
  468. {
  469. if (args == null || args.Tail == null || args.Tail.Tail != null)
  470. throw new XPathException ("substring-before takes 2 args");
  471. arg0 = args.Arg;
  472. arg1 = args.Tail.Arg;
  473. }
  474. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  475. internal override bool Peer {
  476. get { return arg0.Peer && arg1.Peer; }
  477. }
  478. public override object Evaluate (BaseIterator iter)
  479. {
  480. string str1 = arg0.EvaluateString (iter);
  481. string str2 = arg1.EvaluateString (iter);
  482. int ich = str1.IndexOf (str2);
  483. if (ich <= 0)
  484. return "";
  485. return str1.Substring (0, ich);
  486. }
  487. public override string ToString ()
  488. {
  489. return String.Concat ("substring-before(", arg0.ToString (), ",", arg1.ToString (), ")");
  490. }
  491. }
  492. internal class XPathFunctionSubstringAfter : XPathFunction
  493. {
  494. Expression arg0, arg1;
  495. public XPathFunctionSubstringAfter (FunctionArguments args) : base (args)
  496. {
  497. if (args == null || args.Tail == null || args.Tail.Tail != null)
  498. throw new XPathException ("substring-after takes 2 args");
  499. arg0 = args.Arg;
  500. arg1 = args.Tail.Arg;
  501. }
  502. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  503. internal override bool Peer {
  504. get { return arg0.Peer && arg1.Peer; }
  505. }
  506. public override object Evaluate (BaseIterator iter)
  507. {
  508. string str1 = arg0.EvaluateString (iter);
  509. string str2 = arg1.EvaluateString (iter);
  510. int ich = str1.IndexOf (str2);
  511. if (ich < 0)
  512. return "";
  513. return str1.Substring (ich + str2.Length);
  514. }
  515. public override string ToString ()
  516. {
  517. return String.Concat ("substring-after(", arg0.ToString (), ",", arg1.ToString (), ")");
  518. }
  519. }
  520. internal class XPathFunctionSubstring : XPathFunction
  521. {
  522. Expression arg0, arg1, arg2;
  523. public XPathFunctionSubstring (FunctionArguments args) : base (args)
  524. {
  525. if (args == null || args.Tail == null || (args.Tail.Tail != null && args.Tail.Tail.Tail != null))
  526. throw new XPathException ("substring takes 2 or 3 args");
  527. arg0 = args.Arg;
  528. arg1 = args.Tail.Arg;
  529. if (args.Tail.Tail != null)
  530. arg2= args.Tail.Tail.Arg;
  531. }
  532. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  533. internal override bool Peer {
  534. get { return arg0.Peer && arg1.Peer && (arg2 != null ? arg2.Peer : true); }
  535. }
  536. public override object Evaluate (BaseIterator iter)
  537. {
  538. string str = arg0.EvaluateString (iter);
  539. double ich = Math.Round (arg1.EvaluateNumber (iter)) - 1;
  540. if (Double.IsNaN (ich) ||
  541. Double.IsNegativeInfinity (ich) ||
  542. ich >= (double) str.Length)
  543. return "";
  544. if (arg2 == null)
  545. {
  546. if (ich < 0)
  547. ich = 0.0;
  548. return str.Substring ((int) ich);
  549. }
  550. else
  551. {
  552. double cch = Math.Round (arg2.EvaluateNumber (iter));
  553. if (Double.IsNaN (cch))
  554. return "";
  555. if (ich < 0.0 || cch < 0.0)
  556. {
  557. cch = ich + cch;
  558. if (cch <= 0.0)
  559. return "";
  560. ich = 0.0;
  561. }
  562. double cchMax = (double) str.Length - ich;
  563. if (cch > cchMax)
  564. cch = cchMax;
  565. return str.Substring ((int) ich, (int) cch);
  566. }
  567. }
  568. public override string ToString ()
  569. {
  570. return String.Concat (new string [] {
  571. "substring(", arg0.ToString (), ",", arg1.ToString (), ",", arg2.ToString (), ")"});
  572. }
  573. }
  574. internal class XPathFunctionStringLength : XPathFunction
  575. {
  576. Expression arg0;
  577. public XPathFunctionStringLength (FunctionArguments args) : base (args)
  578. {
  579. if (args != null) {
  580. arg0 = args.Arg;
  581. if (args.Tail != null)
  582. throw new XPathException ("string-length takes 1 or zero args");
  583. }
  584. }
  585. public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
  586. internal override bool Peer {
  587. get { return arg0 != null ? arg0.Peer : true; }
  588. }
  589. public override object Evaluate (BaseIterator iter)
  590. {
  591. string str;
  592. if (arg0 != null)
  593. str = arg0.EvaluateString (iter);
  594. else
  595. str = iter.Current.Value;
  596. return (double) str.Length;
  597. }
  598. public override string ToString ()
  599. {
  600. return String.Concat (new string [] {
  601. "string-length(", arg0.ToString (), ")"});
  602. }
  603. }
  604. internal class XPathFunctionNormalizeSpace : XPathFunction
  605. {
  606. Expression arg0;
  607. public XPathFunctionNormalizeSpace (FunctionArguments args) : base (args)
  608. {
  609. if (args != null) {
  610. arg0 = args.Arg;
  611. if (args.Tail != null)
  612. throw new XPathException ("normalize-space takes 1 or zero args");
  613. }
  614. }
  615. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  616. internal override bool Peer {
  617. get { return arg0 !=null ? arg0.Peer : true; }
  618. }
  619. public override object Evaluate (BaseIterator iter)
  620. {
  621. string str;
  622. if (arg0 != null)
  623. str = arg0.EvaluateString (iter);
  624. else
  625. str = iter.Current.Value;
  626. System.Text.StringBuilder sb = new System.Text.StringBuilder ();
  627. bool fSpace = false;
  628. for (int i = 0; i < str.Length; i++) {
  629. char ch = str [i];
  630. if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
  631. {
  632. fSpace = true;
  633. }
  634. else
  635. {
  636. if (fSpace)
  637. {
  638. fSpace = false;
  639. if (sb.Length > 0)
  640. sb.Append (' ');
  641. }
  642. sb.Append (ch);
  643. }
  644. }
  645. return sb.ToString ();
  646. }
  647. public override string ToString ()
  648. {
  649. return String.Concat (new string [] {
  650. "normalize-space(",
  651. arg0 != null ? arg0.ToString () : String.Empty,
  652. ")"});
  653. }
  654. }
  655. internal class XPathFunctionTranslate : XPathFunction
  656. {
  657. Expression arg0, arg1, arg2;
  658. public XPathFunctionTranslate (FunctionArguments args) : base (args)
  659. {
  660. if (args == null || args.Tail == null || args.Tail.Tail == null || args.Tail.Tail.Tail != null)
  661. throw new XPathException ("translate takes 3 args");
  662. arg0 = args.Arg;
  663. arg1 = args.Tail.Arg;
  664. arg2= args.Tail.Tail.Arg;
  665. }
  666. public override XPathResultType ReturnType { get { return XPathResultType.String; }}
  667. internal override bool Peer {
  668. get { return arg0.Peer && arg1.Peer && arg2.Peer; }
  669. }
  670. public override object Evaluate (BaseIterator iter)
  671. {
  672. string s0 = arg0.EvaluateString (iter);
  673. string s1 = arg1.EvaluateString (iter);
  674. string s2 = arg2.EvaluateString (iter);
  675. StringBuilder ret = new StringBuilder (s0.Length);
  676. int pos = 0, len = s0.Length, s2len = s2.Length;
  677. while (pos < len) {
  678. int idx = s1.IndexOf (s0 [pos]);
  679. if (idx != -1) {
  680. if (idx < s2len)
  681. ret.Append (s2 [idx]);
  682. }
  683. else
  684. ret.Append (s0 [pos]);
  685. pos++;
  686. }
  687. return ret.ToString ();
  688. }
  689. public override string ToString ()
  690. {
  691. return String.Concat (new string [] {
  692. "string-length(",
  693. arg0.ToString (), ",",
  694. arg1.ToString (), ",",
  695. arg2.ToString (), ")"});
  696. }
  697. }
  698. internal abstract class XPathBooleanFunction : XPathFunction
  699. {
  700. public XPathBooleanFunction (FunctionArguments args) : base (args)
  701. {
  702. }
  703. public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
  704. public override object StaticValue {
  705. get { return StaticValueAsBoolean; }
  706. }
  707. }
  708. internal class XPathFunctionBoolean : XPathBooleanFunction
  709. {
  710. Expression arg0;
  711. public XPathFunctionBoolean (FunctionArguments args) : base (args)
  712. {
  713. if (args != null) {
  714. arg0 = args.Arg;
  715. if (args.Tail != null)
  716. throw new XPathException ("boolean takes 1 or zero args");
  717. }
  718. }
  719. internal override bool Peer {
  720. get { return arg0 != null ? arg0.Peer : true; }
  721. }
  722. public override object Evaluate (BaseIterator iter)
  723. {
  724. if (arg0 == null)
  725. return XPathFunctions.ToBoolean (iter.Current.Value);
  726. return arg0.EvaluateBoolean (iter);
  727. }
  728. public override string ToString ()
  729. {
  730. return String.Concat (new string [] {"boolean(", arg0.ToString (), ")"});
  731. }
  732. }
  733. internal class XPathFunctionNot : XPathBooleanFunction
  734. {
  735. Expression arg0;
  736. public XPathFunctionNot (FunctionArguments args) : base (args)
  737. {
  738. if (args == null || args.Tail != null)
  739. throw new XPathException ("not takes one arg");
  740. arg0 = args.Arg;
  741. }
  742. internal override bool Peer {
  743. get { return arg0.Peer; }
  744. }
  745. public override object Evaluate (BaseIterator iter)
  746. {
  747. return !arg0.EvaluateBoolean (iter);
  748. }
  749. public override string ToString ()
  750. {
  751. return String.Concat (new string [] {"not(", arg0.ToString (), ")"});
  752. }
  753. }
  754. internal class XPathFunctionTrue : XPathBooleanFunction
  755. {
  756. public XPathFunctionTrue (FunctionArguments args) : base (args)
  757. {
  758. if (args != null)
  759. throw new XPathException ("true takes 0 args");
  760. }
  761. public override bool HasStaticValue {
  762. get { return true; }
  763. }
  764. public override bool StaticValueAsBoolean {
  765. get { return true; }
  766. }
  767. internal override bool Peer {
  768. get { return true; }
  769. }
  770. public override object Evaluate (BaseIterator iter)
  771. {
  772. return true;
  773. }
  774. public override string ToString ()
  775. {
  776. return "true()";
  777. }
  778. }
  779. internal class XPathFunctionFalse : XPathBooleanFunction
  780. {
  781. public XPathFunctionFalse (FunctionArguments args) : base (args)
  782. {
  783. if (args != null)
  784. throw new XPathException ("false takes 0 args");
  785. }
  786. public override bool HasStaticValue {
  787. get { return true; }
  788. }
  789. public override bool StaticValueAsBoolean {
  790. get { return false; }
  791. }
  792. internal override bool Peer {
  793. get { return true; }
  794. }
  795. public override object Evaluate (BaseIterator iter)
  796. {
  797. return false;
  798. }
  799. public override string ToString ()
  800. {
  801. return "false()";
  802. }
  803. }
  804. internal class XPathFunctionLang : XPathFunction
  805. {
  806. Expression arg0;
  807. public XPathFunctionLang (FunctionArguments args) : base (args)
  808. {
  809. if (args == null || args.Tail != null)
  810. throw new XPathException ("lang takes one arg");
  811. arg0 = args.Arg;
  812. }
  813. public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
  814. internal override bool Peer {
  815. get { return arg0.Peer; }
  816. }
  817. public override object Evaluate (BaseIterator iter)
  818. {
  819. return EvaluateBoolean (iter);
  820. }
  821. public override bool EvaluateBoolean (BaseIterator iter)
  822. {
  823. string lang = arg0.EvaluateString (iter).ToLower (CultureInfo.InvariantCulture);
  824. string actualLang = iter.Current.XmlLang.ToLower (CultureInfo.InvariantCulture);
  825. return lang == actualLang || lang == (actualLang.Split ('-')[0]);
  826. }
  827. public override string ToString ()
  828. {
  829. return String.Concat (new string [] {"lang(", arg0.ToString (), ")"});
  830. }
  831. }
  832. internal abstract class XPathNumericFunction : XPathFunction
  833. {
  834. internal XPathNumericFunction (FunctionArguments args)
  835. : base (args)
  836. {
  837. }
  838. public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
  839. public override object StaticValue {
  840. get { return StaticValueAsNumber; }
  841. }
  842. }
  843. internal class XPathFunctionNumber : XPathNumericFunction
  844. {
  845. Expression arg0;
  846. public XPathFunctionNumber (FunctionArguments args) : base (args)
  847. {
  848. if (args != null) {
  849. arg0 = args.Arg;
  850. if (args.Tail != null)
  851. throw new XPathException ("number takes 1 or zero args");
  852. }
  853. }
  854. public override Expression Optimize ()
  855. {
  856. if (arg0 == null)
  857. return this;
  858. arg0 = arg0.Optimize ();
  859. return !arg0.HasStaticValue ?
  860. (Expression) this :
  861. new ExprNumber (StaticValueAsNumber);
  862. }
  863. public override bool HasStaticValue {
  864. get { return arg0 != null && arg0.HasStaticValue; }
  865. }
  866. public override double StaticValueAsNumber {
  867. get { return arg0 != null ? arg0.StaticValueAsNumber : 0; }
  868. }
  869. internal override bool Peer {
  870. get { return arg0 != null ? arg0.Peer : true; }
  871. }
  872. public override object Evaluate (BaseIterator iter)
  873. {
  874. if (arg0 == null)
  875. return XPathFunctions.ToNumber (iter.Current.Value);
  876. return arg0.EvaluateNumber (iter);
  877. }
  878. public override string ToString ()
  879. {
  880. return String.Concat (new string [] {"number(", arg0.ToString (), ")"});
  881. }
  882. }
  883. internal class XPathFunctionSum : XPathNumericFunction
  884. {
  885. Expression arg0;
  886. public XPathFunctionSum (FunctionArguments args) : base (args)
  887. {
  888. if (args == null || args.Tail != null)
  889. throw new XPathException ("sum takes one arg");
  890. arg0 = args.Arg;
  891. }
  892. internal override bool Peer {
  893. get { return arg0.Peer; }
  894. }
  895. public override object Evaluate (BaseIterator iter)
  896. {
  897. XPathNodeIterator itr = arg0.EvaluateNodeSet (iter);
  898. double sum = 0;
  899. while (itr.MoveNext ())
  900. sum += XPathFunctions.ToNumber (itr.Current.Value);
  901. return sum;
  902. }
  903. public override string ToString ()
  904. {
  905. return String.Concat (new string [] {"sum(", arg0.ToString (), ")"});
  906. }
  907. }
  908. internal class XPathFunctionFloor : XPathNumericFunction
  909. {
  910. Expression arg0;
  911. public XPathFunctionFloor (FunctionArguments args) : base (args)
  912. {
  913. if (args == null || args.Tail != null)
  914. throw new XPathException ("floor takes one arg");
  915. arg0 = args.Arg;
  916. }
  917. public override bool HasStaticValue {
  918. get { return arg0.HasStaticValue; }
  919. }
  920. public override double StaticValueAsNumber {
  921. get { return HasStaticValue ? Math.Floor (arg0.StaticValueAsNumber) : 0; }
  922. }
  923. internal override bool Peer {
  924. get { return arg0.Peer; }
  925. }
  926. public override object Evaluate (BaseIterator iter)
  927. {
  928. return Math.Floor (arg0.EvaluateNumber (iter));
  929. }
  930. public override string ToString ()
  931. {
  932. return String.Concat (new string [] {"floor(", arg0.ToString (), ")"});
  933. }
  934. }
  935. internal class XPathFunctionCeil : XPathNumericFunction
  936. {
  937. Expression arg0;
  938. public XPathFunctionCeil (FunctionArguments args) : base (args)
  939. {
  940. if (args == null || args.Tail != null)
  941. throw new XPathException ("ceil takes one arg");
  942. arg0 = args.Arg;
  943. }
  944. public override bool HasStaticValue {
  945. get { return arg0.HasStaticValue; }
  946. }
  947. public override double StaticValueAsNumber {
  948. get { return HasStaticValue ? Math.Ceiling (arg0.StaticValueAsNumber) : 0; }
  949. }
  950. internal override bool Peer {
  951. get { return arg0.Peer; }
  952. }
  953. public override object Evaluate (BaseIterator iter)
  954. {
  955. return Math.Ceiling (arg0.EvaluateNumber (iter));
  956. }
  957. public override string ToString ()
  958. {
  959. return String.Concat (new string [] {"ceil(", arg0.ToString (), ")"});
  960. }
  961. }
  962. internal class XPathFunctionRound : XPathNumericFunction
  963. {
  964. Expression arg0;
  965. public XPathFunctionRound (FunctionArguments args) : base (args)
  966. {
  967. if (args == null || args.Tail != null)
  968. throw new XPathException ("round takes one arg");
  969. arg0 = args.Arg;
  970. }
  971. public override bool HasStaticValue {
  972. get { return arg0.HasStaticValue; }
  973. }
  974. public override double StaticValueAsNumber {
  975. get { return HasStaticValue ? Round (arg0.StaticValueAsNumber) : 0; }
  976. }
  977. internal override bool Peer {
  978. get { return arg0.Peer; }
  979. }
  980. public override object Evaluate (BaseIterator iter)
  981. {
  982. return Round (arg0.EvaluateNumber (iter));
  983. }
  984. private double Round (double arg)
  985. {
  986. if (arg < -0.5 || arg > 0)
  987. return Math.Floor (arg + 0.5);
  988. return Math.Round (arg);
  989. }
  990. public override string ToString ()
  991. {
  992. return String.Concat (new string [] {"round(", arg0.ToString (), ")"});
  993. }
  994. }
  995. }