XQueryFunctionCliImpl.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. //
  2. // XQueryFunctionCliImple.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. //
  8. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  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. //
  30. // Runtime-level (native) implementation of XQuery 1.0 and XPath 2.0
  31. // Functions implementation. XQueryCliFunction
  32. // See XQuery 1.0 and XPath 2.0 Functions and Operators.
  33. //
  34. #if NET_2_0
  35. using System;
  36. using System.Collections;
  37. using System.Globalization;
  38. using System.IO;
  39. using System.Text.RegularExpressions;
  40. using System.Xml;
  41. using System.Xml.Query;
  42. using System.Xml.Schema;
  43. using System.Xml.XPath;
  44. namespace Mono.Xml.XPath2
  45. {
  46. public class XQueryFunctionCliImpl
  47. {
  48. internal static XmlSchemaType XmlTypeFromCliType (Type cliType)
  49. {
  50. switch (Type.GetTypeCode (cliType)) {
  51. case TypeCode.Int32:
  52. return XmlSchemaSimpleType.XsInt;
  53. case TypeCode.Decimal:
  54. return XmlSchemaSimpleType.XsDecimal;
  55. case TypeCode.Double:
  56. return XmlSchemaSimpleType.XsDouble;
  57. case TypeCode.Single:
  58. return XmlSchemaSimpleType.XsFloat;
  59. case TypeCode.Int64:
  60. return XmlSchemaSimpleType.XsLong;
  61. case TypeCode.Int16:
  62. return XmlSchemaSimpleType.XsShort;
  63. case TypeCode.UInt16:
  64. return XmlSchemaSimpleType.XsUnsignedShort;
  65. case TypeCode.UInt32:
  66. return XmlSchemaSimpleType.XsUnsignedInt;
  67. case TypeCode.String:
  68. return XmlSchemaSimpleType.XsString;
  69. case TypeCode.DateTime:
  70. return XmlSchemaSimpleType.XsDateTime;
  71. case TypeCode.Boolean:
  72. return XmlSchemaSimpleType.XsBoolean;
  73. }
  74. if (cliType == typeof (XmlQualifiedName))
  75. return XmlSchemaSimpleType.XsQName;
  76. return null;
  77. }
  78. private static XPathItem ToItem (object arg)
  79. {
  80. if (arg == null)
  81. return null;
  82. XPathItem item = arg as XPathItem;
  83. if (item != null)
  84. return item;
  85. XPathSequence seq = arg as XPathSequence;
  86. if (seq != null)
  87. return seq.MoveNext () ? seq.Current : null;
  88. return new XPathAtomicValue (arg, XmlTypeFromCliType (arg.GetType ()));
  89. }
  90. // Accessors
  91. public static XmlQualifiedName FnNodeName (XPathNavigator arg)
  92. {
  93. if (arg == null)
  94. return null;
  95. return arg.LocalName == String.Empty ?
  96. XmlQualifiedName.Empty :
  97. new XmlQualifiedName (arg.LocalName, arg.NamespaceURI);
  98. }
  99. public static bool FnNilled (XPathNavigator arg)
  100. {
  101. if (arg == null)
  102. throw new XmlQueryException ("Function nilled() does not allow empty sequence parameter.");
  103. IXmlSchemaInfo info = arg.NodeType == XPathNodeType.Element ? arg.SchemaInfo : null;
  104. return info != null && info.IsNil;
  105. }
  106. public static string FnString (XQueryContext context)
  107. {
  108. XPathItem item = context.CurrentItem;
  109. if (item == null)
  110. throw new ArgumentException ("FONC0001: undefined context item");
  111. return FnString (item);
  112. }
  113. [MonoTODO]
  114. public static string FnString (object arg)
  115. {
  116. if (arg == null)
  117. return String.Empty;
  118. XPathNavigator nav = arg as XPathNavigator;
  119. if (nav != null)
  120. return nav.Value;
  121. // FIXME: it should be exactly the same as "arg cast as xs:string"
  122. XPathItem item = ToItem (arg);
  123. return item != null ? XQueryConvert.ItemToString (item) : null;
  124. }
  125. [MonoTODO]
  126. public static XPathAtomicValue FnData (object arg)
  127. {
  128. // FIXME: parameter should be object []
  129. XPathNavigator nav = arg as XPathNavigator;
  130. if (nav != null) {
  131. XmlSchemaType st = nav.SchemaInfo != null ? nav.SchemaInfo.SchemaType : null;
  132. return new XPathAtomicValue (nav.TypedValue, st != null ? st : XmlSchemaComplexType.AnyType);
  133. }
  134. else
  135. return (XPathAtomicValue) arg;
  136. }
  137. public static string FnBaseUri (XPathNavigator nav)
  138. {
  139. return nav != null ? nav.BaseURI : null;
  140. }
  141. public static string FnDocumentUri (XPathNavigator nav)
  142. {
  143. if (nav == null)
  144. return null;
  145. XPathNavigator root = nav.Clone ();
  146. root.MoveToRoot ();
  147. return root.BaseURI;
  148. }
  149. // Error
  150. [MonoTODO]
  151. public static void FnError (object arg)
  152. {
  153. throw new NotImplementedException ();
  154. }
  155. // Trace
  156. [MonoTODO]
  157. public static object FnTrace (XQueryContext ctx, object value, string label)
  158. {
  159. if (value == null)
  160. return new XPathEmptySequence (ctx);
  161. XPathSequence seq = value as XPathSequence;
  162. if (seq == null) {
  163. XPathAtomicValue av = value as XPathAtomicValue;
  164. if (av == null)
  165. av = new XPathAtomicValue (value,
  166. XmlSchemaType.GetBuiltInType (
  167. XPathAtomicValue.XmlTypeCodeFromRuntimeType (
  168. value.GetType (), true)));
  169. seq = new SingleItemIterator (av, ctx);
  170. }
  171. return new TracingIterator (seq, label);
  172. }
  173. // Numeric Operation
  174. [MonoTODO]
  175. public static object FnAbs (object arg)
  176. {
  177. if (arg is int)
  178. return System.Math.Abs ((int) arg);
  179. if (arg is long)
  180. return System.Math.Abs ((long) arg);
  181. else if (arg is decimal)
  182. return System.Math.Abs ((decimal) arg);
  183. else if (arg is double)
  184. return System.Math.Abs ((double) arg);
  185. else if (arg is float)
  186. return System.Math.Abs ((float) arg);
  187. else if (arg is short)
  188. return System.Math.Abs ((short) arg);
  189. else if (arg is uint || arg is ulong || arg is ushort)
  190. return arg;
  191. return null;
  192. }
  193. [MonoTODO]
  194. public static object FnCeiling (object arg)
  195. {
  196. if (arg is decimal) {
  197. decimal d = (decimal) arg;
  198. decimal d2 = Decimal.Floor (d);
  199. return d2 != d ? d2 + 1 : d2;
  200. }
  201. else if (arg is double || arg is float)
  202. return System.Math.Ceiling ((double) arg);
  203. else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
  204. return arg;
  205. return null;
  206. }
  207. [MonoTODO]
  208. public static object FnFloor (object arg)
  209. {
  210. if (arg is decimal)
  211. return Decimal.Floor ((decimal) arg);
  212. else if (arg is double || arg is float)
  213. return System.Math.Floor ((double) arg);
  214. else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
  215. return arg;
  216. return null;
  217. }
  218. [MonoTODO]
  219. public static object FnRound (object arg)
  220. {
  221. if (arg is decimal)
  222. return Decimal.Round ((decimal) arg, 0);
  223. else if (arg is double || arg is float)
  224. return System.Math.Round ((double) arg);
  225. else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
  226. return arg;
  227. return null;
  228. }
  229. [MonoTODO]
  230. public static object FnRoundHalfToEven (object arg)
  231. {
  232. throw new NotImplementedException ();
  233. }
  234. [MonoTODO]
  235. public static string FnCodepointsToString (int [] arg)
  236. {
  237. throw new NotImplementedException ();
  238. }
  239. [MonoTODO]
  240. public static int [] FnStringToCodepoints (string arg)
  241. {
  242. throw new NotImplementedException ();
  243. }
  244. public static int FnCompare (XQueryContext ctx, string s1, string s2)
  245. {
  246. return FnCompare (s1, s2, ctx.DefaultCollation);
  247. }
  248. public static int FnCompare (XQueryContext ctx, string s1, string s2, string collation)
  249. {
  250. return FnCompare (s1, s2, ctx.GetCulture (collation));
  251. }
  252. private static int FnCompare (string s1, string s2, CultureInfo ci)
  253. {
  254. return ci.CompareInfo.Compare (s1, s2);
  255. }
  256. public static string FnConcat (object o1, object o2)
  257. {
  258. return String.Concat (o1, o2);
  259. }
  260. public static string FnStringJoin (string [] strings, string separator)
  261. {
  262. return String.Join (separator, strings);
  263. }
  264. public static string FnSubstring (string src, double loc)
  265. {
  266. return src.Substring ((int) loc);
  267. }
  268. public static string FnSubstring (string src, double loc, double length)
  269. {
  270. return src.Substring ((int) loc, (int) length);
  271. }
  272. public static int FnStringLength (XQueryContext ctx)
  273. {
  274. return FnString (ctx).Length;
  275. }
  276. public static int FnStringLength (string s)
  277. {
  278. return s.Length;
  279. }
  280. public static string FnNormalizeSpace (XQueryContext ctx)
  281. {
  282. return FnNormalizeSpace (FnString (ctx));
  283. }
  284. [MonoTODO]
  285. public static string FnNormalizeSpace (string s)
  286. {
  287. throw new NotImplementedException ();
  288. }
  289. public static string FnNormalizeUnicode (string arg)
  290. {
  291. return FnNormalizeUnicode (arg, "NFC");
  292. }
  293. [MonoTODO]
  294. public static string FnNormalizeUnicode (string arg, string normalizationForm)
  295. {
  296. throw new NotImplementedException ();
  297. }
  298. public static string FnUpperCase (string arg)
  299. {
  300. // FIXME: supply culture
  301. return arg.ToUpper ();
  302. }
  303. public static string FnLowerCase (string arg)
  304. {
  305. // FIXME: supply culture
  306. return arg.ToLower ();
  307. }
  308. public static string FnTranslate (string arg, string mapString, string transString)
  309. {
  310. return arg == null ? null : arg.Replace (mapString, transString);
  311. }
  312. [MonoTODO]
  313. public static string FnEscapeUri (string uriPart, bool escapeReserved)
  314. {
  315. throw new NotImplementedException ();
  316. }
  317. public static bool FnContains (XQueryContext ctx, string arg1, string arg2)
  318. {
  319. return FnContains (arg1, arg2, ctx.DefaultCollation);
  320. }
  321. public static bool FnContains (XQueryContext ctx, string arg1, string arg2, string collation)
  322. {
  323. return FnContains (arg1, arg2, ctx.GetCulture (collation));
  324. }
  325. private static bool FnContains (string arg1, string arg2, CultureInfo ci)
  326. {
  327. if (arg1 == null)
  328. arg1 = String.Empty;
  329. if (arg2 == null)
  330. arg2 = String.Empty;
  331. if (arg2 == String.Empty)
  332. return true;
  333. return ci.CompareInfo.IndexOf (arg1, arg2) >= 0;
  334. }
  335. public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2)
  336. {
  337. return FnStartsWith (arg1, arg2, ctx.DefaultCollation);
  338. }
  339. public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2, string collation)
  340. {
  341. return FnStartsWith (arg1, arg2, ctx.GetCulture (collation));
  342. }
  343. private static bool FnStartsWith (string arg1, string arg2, CultureInfo ci)
  344. {
  345. return ci.CompareInfo.IsPrefix (arg1, arg2);
  346. }
  347. public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2)
  348. {
  349. return FnEndsWith (arg1, arg2, ctx.DefaultCollation);
  350. }
  351. public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2, string collation)
  352. {
  353. return FnEndsWith (arg1, arg2, ctx.GetCulture (collation));
  354. }
  355. private static bool FnEndsWith (string arg1, string arg2, CultureInfo ci)
  356. {
  357. return ci.CompareInfo.IsSuffix (arg1, arg2);
  358. }
  359. public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2)
  360. {
  361. return FnSubstringBefore (arg1, arg2, ctx.DefaultCollation);
  362. }
  363. public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2, string collation)
  364. {
  365. return FnSubstringBefore (arg1, arg2, ctx.GetCulture (collation));
  366. }
  367. private static string FnSubstringBefore (string arg1, string arg2, CultureInfo ci)
  368. {
  369. int index = ci.CompareInfo.IndexOf (arg1, arg2);
  370. return arg1.Substring (0, index);
  371. }
  372. public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2)
  373. {
  374. return FnSubstringAfter (arg1, arg2, ctx.DefaultCollation);
  375. }
  376. public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2, string collation)
  377. {
  378. return FnSubstringAfter (arg1, arg2, ctx.GetCulture (collation));
  379. }
  380. private static string FnSubstringAfter (string arg1, string arg2, CultureInfo ci)
  381. {
  382. int index = ci.CompareInfo.IndexOf (arg1, arg2);
  383. return arg1.Substring (index);
  384. }
  385. public static bool FnMatches (string input, string pattern)
  386. {
  387. return new Regex (pattern).IsMatch (input);
  388. }
  389. [MonoTODO]
  390. public static bool FnMatches (string input, string pattern, string flags)
  391. {
  392. throw new NotImplementedException ();
  393. }
  394. public static string FnReplace (string input, string pattern, string replace)
  395. {
  396. return new Regex (pattern).Replace (input, replace);
  397. }
  398. [MonoTODO]
  399. public static string FnReplace (string input, string pattern, string replace, string flags)
  400. {
  401. throw new NotImplementedException ();
  402. }
  403. public static string [] FnTokenize (string input, string pattern)
  404. {
  405. return new Regex (pattern).Split (input);
  406. }
  407. [MonoTODO]
  408. public static string [] FnTokenize (string input, string pattern, string flags)
  409. {
  410. throw new NotImplementedException ();
  411. }
  412. public static string FnResolveUri (XQueryContext ctx, string relUri)
  413. {
  414. return new Uri (new Uri (ctx.StaticContext.BaseUri), relUri).ToString ();
  415. }
  416. public static string FnResolveUri (string relUri, string baseUri)
  417. {
  418. return new Uri (new Uri (baseUri), relUri).ToString ();
  419. }
  420. public static object FnTrue ()
  421. {
  422. return true;
  423. }
  424. public static object FnFalse ()
  425. {
  426. return false;
  427. }
  428. public static object FnNot (bool value)
  429. {
  430. return !value;
  431. }
  432. // FIXME: add a bunch of annoying datetime functions
  433. public static object FnResolveQName (string qname, XPathNavigator element)
  434. {
  435. if (qname == null)
  436. return null;
  437. int index = qname.IndexOf (':');
  438. string prefix = (index < 0) ? "" : qname.Substring (index);
  439. return new XmlQualifiedName (
  440. element.LookupNamespace (prefix),
  441. index < 0 ? qname : qname.Substring (index + 1));
  442. }
  443. public static object FnExpandQName (string ns, string local)
  444. {
  445. return new XmlQualifiedName (local, ns);
  446. }
  447. public static string FnLocalNameFromQName (XmlQualifiedName name)
  448. {
  449. return name != null ? name.Name : null;
  450. }
  451. public static object FnNamespaceUriFromQName (XmlQualifiedName name)
  452. {
  453. return name != null ? name.Namespace : null;
  454. }
  455. public static object FnNamespaceUriForPrefix (XQueryContext context, string prefix)
  456. {
  457. return prefix != null ? context.LookupNamespace (prefix) : null;
  458. }
  459. public static string [] FnInScopePrefixes (XQueryContext context)
  460. {
  461. IDictionary dict = context.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml);
  462. ArrayList keys = new ArrayList (dict.Keys);
  463. return keys.ToArray (typeof (string)) as string [];
  464. }
  465. public static string FnName (XPathNavigator nav)
  466. {
  467. return nav != null ? nav.Name : null;
  468. }
  469. public static string FnLocalName (XPathNavigator nav)
  470. {
  471. return nav != null ? nav.LocalName : null;
  472. }
  473. public static string FnNamespaceUri (XPathNavigator nav)
  474. {
  475. return nav != null ? nav.NamespaceURI : null;
  476. }
  477. public static double FnNumber (XQueryContext ctx)
  478. {
  479. return FnNumber (ctx.CurrentItem);
  480. }
  481. public static double FnNumber (object arg)
  482. {
  483. if (arg == null)
  484. throw new XmlQueryException ("Context item could not be ndetermined during number() evaluation.");
  485. XPathItem item = ToItem (arg);
  486. return XQueryConvert.ItemToDouble (item);
  487. }
  488. public static bool FnLang (XQueryContext ctx, string testLang)
  489. {
  490. return FnLang (testLang, ctx.CurrentNode);
  491. }
  492. public static bool FnLang (string testLang, XPathNavigator node)
  493. {
  494. return testLang == node.XmlLang;
  495. }
  496. public static XPathNavigator FnRoot (XQueryContext ctx)
  497. {
  498. if (ctx.CurrentItem == null)
  499. throw new XmlQueryException ("FONC0001: Undefined context item.");
  500. if (ctx.CurrentNode == null)
  501. throw new XmlQueryException ("FOTY0011: Context item is not a node.");
  502. return FnRoot (ctx.CurrentNode);
  503. }
  504. public static XPathNavigator FnRoot (XPathNavigator node)
  505. {
  506. if (node == null)
  507. return null;
  508. XPathNavigator root = node.Clone ();
  509. root.MoveToRoot ();
  510. return root;
  511. }
  512. public static bool FnBoolean (IEnumerator e)
  513. {
  514. if (!e.MoveNext ())
  515. return false;
  516. XPathItem item = e.Current as XPathItem;
  517. if (e.MoveNext ())
  518. return true;
  519. return XQueryConvert.ItemToBoolean (item);
  520. }
  521. public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item)
  522. {
  523. return FnIndexOf (ctx, items, item, ctx.DefaultCollation);
  524. }
  525. public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item, CultureInfo ci)
  526. {
  527. ArrayList al = new ArrayList ();
  528. IEnumerator e = items.GetEnumerator ();
  529. for (int i = 0; e.MoveNext (); i++) {
  530. XPathItem iter = e.Current as XPathItem;
  531. if (iter.XmlType.TypeCode == XmlTypeCode.String) {
  532. if (ci.CompareInfo.Compare (iter.Value, item.Value) == 0)
  533. al.Add (i);
  534. }
  535. else {
  536. IComparable ic = (IComparable) iter.TypedValue;
  537. if (ic.CompareTo ((IComparable) item.TypedValue) == 0)
  538. al.Add (i);
  539. }
  540. }
  541. return new ListIterator (ctx, al);
  542. }
  543. public static bool FnEmpty (XPathSequence e)
  544. {
  545. if (e is XPathEmptySequence)
  546. return true;
  547. return !e.GetEnumerator ().MoveNext ();
  548. }
  549. public static bool FnExists (XPathSequence e)
  550. {
  551. if (e is XPathEmptySequence)
  552. return false;
  553. return e.MoveNext ();
  554. }
  555. public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items)
  556. {
  557. return FnDistinctValuesImpl (ctx, items, ctx.DefaultCollation);
  558. }
  559. public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items, string collation)
  560. {
  561. return FnDistinctValuesImpl (ctx, items, ctx.GetCulture (collation));
  562. }
  563. private static XPathSequence FnDistinctValuesImpl (XQueryContext ctx, XPathSequence items, CultureInfo collation)
  564. {
  565. return new DistinctValueIterator (ctx, items, collation);
  566. }
  567. public static XPathSequence FnInsertBefore (XPathSequence target, int position, XPathSequence inserts)
  568. {
  569. if (position < 1)
  570. position = 1;
  571. return new InsertingIterator (target, position, inserts);
  572. }
  573. public static XPathSequence FnRemove (XPathSequence target, int position)
  574. {
  575. if (position < 1)
  576. return target;
  577. return new RemovalIterator (target, position);
  578. }
  579. [MonoTODO ("optimize")]
  580. public static XPathSequence FnReverse (XPathSequence arg)
  581. {
  582. ArrayList al = new ArrayList ();
  583. while (arg.MoveNext ())
  584. al.Add (arg.Current);
  585. al.Reverse ();
  586. return new ListIterator (arg.Context, al);
  587. }
  588. public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc)
  589. {
  590. return FnSubsequence (sourceSeq, startingLoc, double.MaxValue);
  591. }
  592. [MonoTODO]
  593. public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc, double length)
  594. {
  595. throw new NotImplementedException ();
  596. }
  597. [MonoTODO]
  598. // Basically it should be optimized by XQueryASTCompiler
  599. public static XPathSequence FnUnordered (XPathSequence e)
  600. {
  601. return e;
  602. }
  603. public static XPathItem FnZeroOrOne (XPathSequence e)
  604. {
  605. if (!e.MoveNext ())
  606. return null;
  607. XPathItem item = e.Current;
  608. if (e.MoveNext ())
  609. throw new XmlQueryException ("zero-or-one() function detected that the argument sequence contains two or more items.");
  610. return item;
  611. }
  612. public static object FnOneOrMore (XPathSequence e)
  613. {
  614. if (!e.Clone ().MoveNext ())
  615. throw new XmlQueryException ("one-or-more() function detected that the argument sequence contains no items.");
  616. return e;
  617. }
  618. public static XPathItem FnExactlyOne (XPathSequence e)
  619. {
  620. if (!e.MoveNext ())
  621. throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains no items.");
  622. XPathItem item = e.Current;
  623. if (e.MoveNext ())
  624. throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains two or more items.");
  625. return item;
  626. }
  627. public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2)
  628. {
  629. return FnDeepEqualImpl (p1, p2, ctx.DefaultCollation);
  630. }
  631. public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2, string collation)
  632. {
  633. return FnDeepEqualImpl (p1, p2, ctx.GetCulture (collation));
  634. }
  635. public static bool FnDeepEqualImpl (XPathSequence p1, XPathSequence p2, CultureInfo collation)
  636. {
  637. // FIXME: use collation
  638. while (p1.MoveNext ()) {
  639. if (!p2.MoveNext ())
  640. return false;
  641. if (!FnDeepEqualItem (p1.Current, p2.Current, collation))
  642. return false;
  643. }
  644. if (p2.MoveNext ())
  645. return false;
  646. return true;
  647. }
  648. // FIXME: Actually ValueEQ() should consider collation.
  649. [MonoTODO]
  650. private static bool FnDeepEqualItem (XPathItem i1, XPathItem i2, CultureInfo collation)
  651. {
  652. XPathAtomicValue av1 = i1 as XPathAtomicValue;
  653. XPathAtomicValue av2 = i1 as XPathAtomicValue;
  654. if (av1 != null && av2 != null) {
  655. try {
  656. return XQueryComparisonOperator.ValueEQ (av1, av2);
  657. } catch (XmlQueryException) {
  658. // not-allowed comparison never raises
  659. // an error here, just return false.
  660. return false;
  661. }
  662. }
  663. else if (av1 != null || av2 != null)
  664. return false;
  665. XPathNavigator n1 = i1 as XPathNavigator;
  666. XPathNavigator n2 = i2 as XPathNavigator;
  667. if (n1.NodeType != n2.NodeType)
  668. return false;
  669. switch (n1.NodeType) {
  670. case XPathNodeType.Root:
  671. throw new NotImplementedException ();
  672. case XPathNodeType.Element:
  673. throw new NotImplementedException ();
  674. case XPathNodeType.Attribute:
  675. return n1.Name == n2.Name && n1.TypedValue == n2.TypedValue;
  676. case XPathNodeType.ProcessingInstruction:
  677. case XPathNodeType.Namespace:
  678. return n1.Name == n2.Name && n1.Value == n2.Value;
  679. case XPathNodeType.Text:
  680. case XPathNodeType.Comment:
  681. return n1.Value == n2.Value;
  682. }
  683. return false;
  684. }
  685. public static int FnCount (XPathSequence e)
  686. {
  687. if (e == null)
  688. return 0;
  689. return e.Count;
  690. }
  691. [MonoTODO]
  692. public static object FnAvg (XPathSequence e)
  693. {
  694. if (!e.MoveNext ())
  695. return null;
  696. switch (e.Current.XmlType.TypeCode) {
  697. case XmlTypeCode.DayTimeDuration:
  698. return FnAvgDayTimeDuration (e);
  699. case XmlTypeCode.YearMonthDuration:
  700. return FnAvgYearMonthDuration (e);
  701. case XmlTypeCode.Decimal:
  702. return FnAvgDecimal (e);
  703. case XmlTypeCode.Integer:
  704. return FnAvgInteger (e);
  705. case XmlTypeCode.Float:
  706. return FnAvgFloat (e);
  707. case XmlTypeCode.UntypedAtomic:
  708. case XmlTypeCode.Double:
  709. return FnAvgDouble (e);
  710. }
  711. throw new XmlQueryException ("avg() function detected that the sequence contains an item whose type is neither of dayTimeDuration, yearMonthDuration, decimal, integer, float, double, nor untypedAtomic.");
  712. }
  713. private static TimeSpan FnAvgDayTimeDuration (XPathSequence e)
  714. {
  715. throw new NotImplementedException ();
  716. }
  717. private static TimeSpan FnAvgYearMonthDuration (XPathSequence e)
  718. {
  719. throw new NotImplementedException ();
  720. }
  721. private static TimeSpan FnAvgDecimal (XPathSequence e)
  722. {
  723. throw new NotImplementedException ();
  724. }
  725. private static TimeSpan FnAvgInteger (XPathSequence e)
  726. {
  727. throw new NotImplementedException ();
  728. }
  729. private static TimeSpan FnAvgFloat (XPathSequence e)
  730. {
  731. throw new NotImplementedException ();
  732. }
  733. private static TimeSpan FnAvgDouble (XPathSequence e)
  734. {
  735. throw new NotImplementedException ();
  736. }
  737. [MonoTODO]
  738. public static object FnMax (XQueryContext ctx, XPathSequence e)
  739. {
  740. throw new NotImplementedException ();
  741. }
  742. [MonoTODO]
  743. public static object FnMax (XQueryContext ctx, XPathSequence e, string collation)
  744. {
  745. throw new NotImplementedException ();
  746. }
  747. [MonoTODO]
  748. public static object FnMin (XQueryContext ctx, XPathSequence e)
  749. {
  750. throw new NotImplementedException ();
  751. }
  752. [MonoTODO]
  753. public static object FnMin (XQueryContext ctx, XPathSequence e, string collation)
  754. {
  755. throw new NotImplementedException ();
  756. }
  757. [MonoTODO]
  758. public static object FnSum (XPathSequence e)
  759. {
  760. throw new NotImplementedException ();
  761. }
  762. [MonoTODO]
  763. public static object FnSum (XPathSequence e, XPathItem zero)
  764. {
  765. throw new NotImplementedException ();
  766. }
  767. public static XPathNavigator FnId (XQueryContext ctx, string id)
  768. {
  769. return FnId (id, ctx.CurrentNode);
  770. }
  771. public static XPathNavigator FnId (string id, XPathNavigator nav)
  772. {
  773. XPathNavigator node = nav.Clone ();
  774. return node.MoveToId (id) ? node : null;
  775. }
  776. [MonoTODO]
  777. public static object FnIdRef (XQueryContext ctx, string arg)
  778. {
  779. return FnIdRef (arg, ctx.CurrentNode);
  780. }
  781. [MonoTODO]
  782. public static object FnIdRef (string arg, XPathNavigator node)
  783. {
  784. throw new NotImplementedException ();
  785. }
  786. public static XPathNavigator FnDoc (XQueryContext ctx, string uri)
  787. {
  788. XmlResolver res = ctx.ContextManager.ExtDocResolver;
  789. string baseUriString = ctx.StaticContext.BaseUri;
  790. Uri baseUri = null;
  791. if (baseUriString != null && baseUriString != String.Empty)
  792. baseUri = new Uri (baseUriString);
  793. Uri relUri = res.ResolveUri (baseUri, uri);
  794. Stream s = res.GetEntity (relUri, null, typeof (Stream)) as Stream;
  795. try {
  796. XPathDocument doc = new XPathDocument (new XmlValidatingReader (new XmlTextReader (s)), XmlSpace.Preserve);
  797. return doc.CreateNavigator ();
  798. } finally {
  799. s.Close ();
  800. }
  801. }
  802. public static XPathSequence FnCollection (XQueryContext ctx, string name)
  803. {
  804. return ctx.ResolveCollection (name);
  805. }
  806. [XQueryFunctionContext]
  807. public static int FnPosition (XPathSequence current)
  808. {
  809. return current.Position;
  810. }
  811. [XQueryFunctionContext]
  812. public static int FnLast (XPathSequence current)
  813. {
  814. return current.Count;
  815. }
  816. public static DateTime FnCurrentDateTime ()
  817. {
  818. return DateTime.Now;
  819. }
  820. public static DateTime FnCurrentDate ()
  821. {
  822. return DateTime.Today;
  823. }
  824. public static DateTime FnCurrentTime ()
  825. {
  826. return new DateTime (DateTime.Now.TimeOfDay.Ticks);
  827. }
  828. [MonoTODO]
  829. public static object FnDefaultCollation ()
  830. {
  831. throw new NotImplementedException ();
  832. }
  833. [MonoTODO]
  834. public static object FnImplicitTimeZone ()
  835. {
  836. throw new NotImplementedException ();
  837. }
  838. }
  839. }
  840. #endif