**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XQueryFunctionCliImpl.cs
blob690851a3147bb3ab6e4fe77ddf17c5d0fc6461f9
1 //
2 // XQueryFunctionCliImple.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
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.
31 // Runtime-level (native) implementation of XQuery 1.0 and XPath 2.0
32 // Functions implementation. XQueryCliFunction
33 // See XQuery 1.0 and XPath 2.0 Functions and Operators.
35 #if NET_2_0
36 using System;
37 using System.Collections;
38 using System.Globalization;
39 using System.IO;
40 using System.Text.RegularExpressions;
41 using System.Xml;
42 using System.Xml.Query;
43 using System.Xml.Schema;
44 using System.Xml.XPath;
45 using Mono.Xml;
47 namespace Mono.Xml.XPath2
49 public class XQueryFunctionCliImpl
51 internal static XmlSchemaType XmlTypeFromCliType (Type cliType)
53 switch (Type.GetTypeCode (cliType)) {
54 case TypeCode.Int32:
55 return InternalPool.XsInt;
56 case TypeCode.Decimal:
57 return InternalPool.XsDecimal;
58 case TypeCode.Double:
59 return InternalPool.XsDouble;
60 case TypeCode.Single:
61 return InternalPool.XsFloat;
62 case TypeCode.Int64:
63 return InternalPool.XsLong;
64 case TypeCode.Int16:
65 return InternalPool.XsShort;
66 case TypeCode.UInt16:
67 return InternalPool.XsUnsignedShort;
68 case TypeCode.UInt32:
69 return InternalPool.XsUnsignedInt;
70 case TypeCode.String:
71 return InternalPool.XsString;
72 case TypeCode.DateTime:
73 return InternalPool.XsDateTime;
74 case TypeCode.Boolean:
75 return InternalPool.XsBoolean;
77 if (cliType == typeof (XmlQualifiedName))
78 return InternalPool.XsQName;
79 return null;
82 private static XPathItem ToItem (object arg)
84 if (arg == null)
85 return null;
86 XPathItem item = arg as XPathItem;
87 if (item != null)
88 return item;
89 XPathSequence seq = arg as XPathSequence;
90 if (seq != null)
91 return seq.MoveNext () ? seq.Current : null;
92 return new XPathAtomicValue (arg, XmlTypeFromCliType (arg.GetType ()));
95 // Accessors
97 public static XmlQualifiedName FnNodeName (XPathNavigator arg)
99 if (arg == null)
100 return null;
102 return arg.LocalName == String.Empty ?
103 XmlQualifiedName.Empty :
104 new XmlQualifiedName (arg.LocalName, arg.NamespaceURI);
107 public static bool FnNilled (XPathNavigator arg)
109 if (arg == null)
110 throw new XmlQueryException ("Function nilled() does not allow empty sequence parameter.");
112 IXmlSchemaInfo info = arg.NodeType == XPathNodeType.Element ? arg.SchemaInfo : null;
113 return info != null && info.IsNil;
116 public static string FnString (XQueryContext context)
118 XPathItem item = context.CurrentItem;
119 if (item == null)
120 throw new ArgumentException ("FONC0001: undefined context item");
121 return FnString (item);
124 [MonoTODO]
125 public static string FnString (object arg)
127 if (arg == null)
128 return String.Empty;
129 XPathNavigator nav = arg as XPathNavigator;
130 if (nav != null)
131 return nav.Value;
132 // FIXME: it should be exactly the same as "arg cast as xs:string"
133 XPathItem item = ToItem (arg);
134 return item != null ? XQueryConvert.ItemToString (item) : null;
137 [MonoTODO]
138 public static XPathAtomicValue FnData (object arg)
140 // FIXME: parameter should be object []
141 XPathNavigator nav = arg as XPathNavigator;
142 if (nav != null) {
143 XmlSchemaType st = nav.SchemaInfo != null ? nav.SchemaInfo.SchemaType : null;
144 return new XPathAtomicValue (nav.TypedValue, st != null ? st : InternalPool.XsAnyType);
146 else
147 return (XPathAtomicValue) arg;
150 public static string FnBaseUri (XPathNavigator nav)
152 return nav != null ? nav.BaseURI : null;
155 public static string FnDocumentUri (XPathNavigator nav)
157 if (nav == null)
158 return null;
159 XPathNavigator root = nav.Clone ();
160 root.MoveToRoot ();
161 return root.BaseURI;
164 // Error
166 [MonoTODO]
167 public static void FnError (object arg)
169 throw new NotImplementedException ();
172 // Trace
174 [MonoTODO]
175 public static object FnTrace (XQueryContext ctx, object value, string label)
177 if (value == null)
178 return new XPathEmptySequence (ctx);
179 XPathSequence seq = value as XPathSequence;
180 if (seq == null) {
181 XPathAtomicValue av = value as XPathAtomicValue;
182 if (av == null)
183 av = new XPathAtomicValue (value,
184 InternalPool.GetBuiltInType (
185 InternalPool.XmlTypeCodeFromRuntimeType (
186 value.GetType (), true)));
187 seq = new SingleItemIterator (av, ctx);
189 return new TracingIterator (seq, label);
192 // Numeric Operation
194 [MonoTODO]
195 public static object FnAbs (object arg)
197 if (arg is int)
198 return System.Math.Abs ((int) arg);
199 if (arg is long)
200 return System.Math.Abs ((long) arg);
201 else if (arg is decimal)
202 return System.Math.Abs ((decimal) arg);
203 else if (arg is double)
204 return System.Math.Abs ((double) arg);
205 else if (arg is float)
206 return System.Math.Abs ((float) arg);
207 else if (arg is short)
208 return System.Math.Abs ((short) arg);
209 else if (arg is uint || arg is ulong || arg is ushort)
210 return arg;
211 return null;
214 [MonoTODO]
215 public static object FnCeiling (object arg)
217 if (arg is decimal) {
218 decimal d = (decimal) arg;
219 decimal d2 = Decimal.Floor (d);
220 return d2 != d ? d2 + 1 : d2;
222 else if (arg is double || arg is float)
223 return System.Math.Ceiling ((double) arg);
224 else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
225 return arg;
226 return null;
229 [MonoTODO]
230 public static object FnFloor (object arg)
232 if (arg is decimal)
233 return Decimal.Floor ((decimal) arg);
234 else if (arg is double || arg is float)
235 return System.Math.Floor ((double) arg);
236 else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
237 return arg;
238 return null;
241 [MonoTODO]
242 public static object FnRound (object arg)
244 if (arg is decimal)
245 return Decimal.Round ((decimal) arg, 0);
246 else if (arg is double || arg is float)
247 return System.Math.Round ((double) arg);
248 else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort)
249 return arg;
250 return null;
253 [MonoTODO]
254 public static object FnRoundHalfToEven (object arg)
256 throw new NotImplementedException ();
259 [MonoTODO]
260 public static string FnCodepointsToString (int [] arg)
262 throw new NotImplementedException ();
265 [MonoTODO]
266 public static int [] FnStringToCodepoints (string arg)
268 throw new NotImplementedException ();
271 public static int FnCompare (XQueryContext ctx, string s1, string s2)
273 return FnCompare (s1, s2, ctx.DefaultCollation);
276 public static int FnCompare (XQueryContext ctx, string s1, string s2, string collation)
278 return FnCompare (s1, s2, ctx.GetCulture (collation));
281 private static int FnCompare (string s1, string s2, CultureInfo ci)
283 return ci.CompareInfo.Compare (s1, s2);
286 public static string FnConcat (object o1, object o2)
288 return String.Concat (o1, o2);
291 public static string FnStringJoin (string [] strings, string separator)
293 return String.Join (separator, strings);
296 public static string FnSubstring (string src, double loc)
298 return src.Substring ((int) loc);
301 public static string FnSubstring (string src, double loc, double length)
303 return src.Substring ((int) loc, (int) length);
306 public static int FnStringLength (XQueryContext ctx)
308 return FnString (ctx).Length;
311 public static int FnStringLength (string s)
313 return s.Length;
316 public static string FnNormalizeSpace (XQueryContext ctx)
318 return FnNormalizeSpace (FnString (ctx));
321 [MonoTODO]
322 public static string FnNormalizeSpace (string s)
324 throw new NotImplementedException ();
327 public static string FnNormalizeUnicode (string arg)
329 return FnNormalizeUnicode (arg, "NFC");
332 [MonoTODO]
333 public static string FnNormalizeUnicode (string arg, string normalizationForm)
335 throw new NotImplementedException ();
338 public static string FnUpperCase (string arg)
340 // FIXME: supply culture
341 return arg.ToUpper ();
344 public static string FnLowerCase (string arg)
346 // FIXME: supply culture
347 return arg.ToLower ();
350 public static string FnTranslate (string arg, string mapString, string transString)
352 return arg == null ? null : arg.Replace (mapString, transString);
355 [MonoTODO]
356 public static string FnEscapeUri (string uriPart, bool escapeReserved)
358 throw new NotImplementedException ();
361 public static bool FnContains (XQueryContext ctx, string arg1, string arg2)
363 return FnContains (arg1, arg2, ctx.DefaultCollation);
366 public static bool FnContains (XQueryContext ctx, string arg1, string arg2, string collation)
368 return FnContains (arg1, arg2, ctx.GetCulture (collation));
371 private static bool FnContains (string arg1, string arg2, CultureInfo ci)
373 if (arg1 == null)
374 arg1 = String.Empty;
375 if (arg2 == null)
376 arg2 = String.Empty;
377 if (arg2 == String.Empty)
378 return true;
379 return ci.CompareInfo.IndexOf (arg1, arg2) >= 0;
382 public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2)
384 return FnStartsWith (arg1, arg2, ctx.DefaultCollation);
387 public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2, string collation)
389 return FnStartsWith (arg1, arg2, ctx.GetCulture (collation));
392 private static bool FnStartsWith (string arg1, string arg2, CultureInfo ci)
394 return ci.CompareInfo.IsPrefix (arg1, arg2);
397 public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2)
399 return FnEndsWith (arg1, arg2, ctx.DefaultCollation);
402 public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2, string collation)
404 return FnEndsWith (arg1, arg2, ctx.GetCulture (collation));
407 private static bool FnEndsWith (string arg1, string arg2, CultureInfo ci)
409 return ci.CompareInfo.IsSuffix (arg1, arg2);
412 public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2)
414 return FnSubstringBefore (arg1, arg2, ctx.DefaultCollation);
417 public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2, string collation)
419 return FnSubstringBefore (arg1, arg2, ctx.GetCulture (collation));
422 private static string FnSubstringBefore (string arg1, string arg2, CultureInfo ci)
424 int index = ci.CompareInfo.IndexOf (arg1, arg2);
425 return arg1.Substring (0, index);
428 public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2)
430 return FnSubstringAfter (arg1, arg2, ctx.DefaultCollation);
433 public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2, string collation)
435 return FnSubstringAfter (arg1, arg2, ctx.GetCulture (collation));
438 private static string FnSubstringAfter (string arg1, string arg2, CultureInfo ci)
440 int index = ci.CompareInfo.IndexOf (arg1, arg2);
441 return arg1.Substring (index);
444 public static bool FnMatches (string input, string pattern)
446 return new Regex (pattern).IsMatch (input);
449 [MonoTODO]
450 public static bool FnMatches (string input, string pattern, string flags)
452 throw new NotImplementedException ();
455 public static string FnReplace (string input, string pattern, string replace)
457 return new Regex (pattern).Replace (input, replace);
460 [MonoTODO]
461 public static string FnReplace (string input, string pattern, string replace, string flags)
463 throw new NotImplementedException ();
466 public static string [] FnTokenize (string input, string pattern)
468 return new Regex (pattern).Split (input);
471 [MonoTODO]
472 public static string [] FnTokenize (string input, string pattern, string flags)
474 throw new NotImplementedException ();
477 public static string FnResolveUri (XQueryContext ctx, string relUri)
479 return new Uri (new Uri (ctx.StaticContext.BaseUri), relUri).ToString ();
482 public static string FnResolveUri (string relUri, string baseUri)
484 return new Uri (new Uri (baseUri), relUri).ToString ();
487 public static object FnTrue ()
489 return true;
492 public static object FnFalse ()
494 return false;
497 public static object FnNot (bool value)
499 return !value;
502 // FIXME: add a bunch of annoying datetime functions
504 public static object FnResolveQName (string qname, XPathNavigator element)
506 if (qname == null)
507 return null;
509 int index = qname.IndexOf (':');
510 string prefix = (index < 0) ? "" : qname.Substring (index);
511 return new XmlQualifiedName (
512 element.LookupNamespace (prefix),
513 index < 0 ? qname : qname.Substring (index + 1));
516 public static object FnExpandQName (string ns, string local)
518 return new XmlQualifiedName (local, ns);
521 public static string FnLocalNameFromQName (XmlQualifiedName name)
523 return name != null ? name.Name : null;
526 public static object FnNamespaceUriFromQName (XmlQualifiedName name)
528 return name != null ? name.Namespace : null;
531 public static object FnNamespaceUriForPrefix (XQueryContext context, string prefix)
533 return prefix != null ? context.LookupNamespace (prefix) : null;
536 public static string [] FnInScopePrefixes (XQueryContext context)
538 IDictionary dict = context.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml);
539 ArrayList keys = new ArrayList (dict.Keys);
540 return keys.ToArray (typeof (string)) as string [];
543 public static string FnName (XPathNavigator nav)
545 return nav != null ? nav.Name : null;
548 public static string FnLocalName (XPathNavigator nav)
550 return nav != null ? nav.LocalName : null;
553 public static string FnNamespaceUri (XPathNavigator nav)
555 return nav != null ? nav.NamespaceURI : null;
558 public static double FnNumber (XQueryContext ctx)
560 return FnNumber (ctx.CurrentItem);
563 public static double FnNumber (object arg)
565 if (arg == null)
566 throw new XmlQueryException ("Context item could not be ndetermined during number() evaluation.");
567 XPathItem item = ToItem (arg);
568 return XQueryConvert.ItemToDouble (item);
571 public static bool FnLang (XQueryContext ctx, string testLang)
573 return FnLang (testLang, ctx.CurrentNode);
576 public static bool FnLang (string testLang, XPathNavigator node)
578 return testLang == node.XmlLang;
581 public static XPathNavigator FnRoot (XQueryContext ctx)
583 if (ctx.CurrentItem == null)
584 throw new XmlQueryException ("FONC0001: Undefined context item.");
585 if (ctx.CurrentNode == null)
586 throw new XmlQueryException ("FOTY0011: Context item is not a node.");
587 return FnRoot (ctx.CurrentNode);
590 public static XPathNavigator FnRoot (XPathNavigator node)
592 if (node == null)
593 return null;
594 XPathNavigator root = node.Clone ();
595 root.MoveToRoot ();
596 return root;
599 public static bool FnBoolean (IEnumerator e)
601 if (!e.MoveNext ())
602 return false;
603 XPathItem item = e.Current as XPathItem;
604 if (e.MoveNext ())
605 return true;
606 return XQueryConvert.ItemToBoolean (item);
609 public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item)
611 return FnIndexOf (ctx, items, item, ctx.DefaultCollation);
614 public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item, CultureInfo ci)
616 ArrayList al = new ArrayList ();
617 IEnumerator e = items.GetEnumerator ();
618 for (int i = 0; e.MoveNext (); i++) {
619 XPathItem iter = e.Current as XPathItem;
620 if (iter.XmlType.TypeCode == XmlTypeCode.String) {
621 if (ci.CompareInfo.Compare (iter.Value, item.Value) == 0)
622 al.Add (i);
624 else {
625 IComparable ic = (IComparable) iter.TypedValue;
626 if (ic.CompareTo ((IComparable) item.TypedValue) == 0)
627 al.Add (i);
630 return new ListIterator (ctx, al);
633 public static bool FnEmpty (XPathSequence e)
635 if (e is XPathEmptySequence)
636 return true;
637 return !e.GetEnumerator ().MoveNext ();
640 public static bool FnExists (XPathSequence e)
642 if (e is XPathEmptySequence)
643 return false;
644 return e.MoveNext ();
647 public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items)
649 return FnDistinctValuesImpl (ctx, items, ctx.DefaultCollation);
652 public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items, string collation)
654 return FnDistinctValuesImpl (ctx, items, ctx.GetCulture (collation));
657 private static XPathSequence FnDistinctValuesImpl (XQueryContext ctx, XPathSequence items, CultureInfo collation)
659 return new DistinctValueIterator (ctx, items, collation);
662 public static XPathSequence FnInsertBefore (XPathSequence target, int position, XPathSequence inserts)
664 if (position < 1)
665 position = 1;
666 return new InsertingIterator (target, position, inserts);
669 public static XPathSequence FnRemove (XPathSequence target, int position)
671 if (position < 1)
672 return target;
673 return new RemovalIterator (target, position);
676 [MonoTODO ("optimize")]
677 public static XPathSequence FnReverse (XPathSequence arg)
679 ArrayList al = new ArrayList ();
680 while (arg.MoveNext ())
681 al.Add (arg.Current);
682 al.Reverse ();
683 return new ListIterator (arg.Context, al);
686 public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc)
688 return FnSubsequence (sourceSeq, startingLoc, double.MaxValue);
691 [MonoTODO]
692 public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc, double length)
694 throw new NotImplementedException ();
697 [MonoTODO]
698 // Basically it should be optimized by XQueryASTCompiler
699 public static XPathSequence FnUnordered (XPathSequence e)
701 return e;
704 public static XPathItem FnZeroOrOne (XPathSequence e)
706 if (!e.MoveNext ())
707 return null;
708 XPathItem item = e.Current;
709 if (e.MoveNext ())
710 throw new XmlQueryException ("zero-or-one() function detected that the argument sequence contains two or more items.");
711 return item;
714 public static object FnOneOrMore (XPathSequence e)
716 if (!e.Clone ().MoveNext ())
717 throw new XmlQueryException ("one-or-more() function detected that the argument sequence contains no items.");
718 return e;
721 public static XPathItem FnExactlyOne (XPathSequence e)
723 if (!e.MoveNext ())
724 throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains no items.");
725 XPathItem item = e.Current;
726 if (e.MoveNext ())
727 throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains two or more items.");
728 return item;
731 public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2)
733 return FnDeepEqualImpl (p1, p2, ctx.DefaultCollation);
736 public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2, string collation)
738 return FnDeepEqualImpl (p1, p2, ctx.GetCulture (collation));
741 public static bool FnDeepEqualImpl (XPathSequence p1, XPathSequence p2, CultureInfo collation)
743 // FIXME: use collation
744 while (p1.MoveNext ()) {
745 if (!p2.MoveNext ())
746 return false;
747 if (!FnDeepEqualItem (p1.Current, p2.Current, collation))
748 return false;
750 if (p2.MoveNext ())
751 return false;
752 return true;
755 // FIXME: Actually ValueEQ() should consider collation.
756 [MonoTODO]
757 private static bool FnDeepEqualItem (XPathItem i1, XPathItem i2, CultureInfo collation)
759 XPathAtomicValue av1 = i1 as XPathAtomicValue;
760 XPathAtomicValue av2 = i1 as XPathAtomicValue;
761 if (av1 != null && av2 != null) {
762 try {
763 return XQueryComparisonOperator.ValueEQ (av1, av2);
764 } catch (XmlQueryException) {
765 // not-allowed comparison never raises
766 // an error here, just return false.
767 return false;
770 else if (av1 != null || av2 != null)
771 return false;
773 XPathNavigator n1 = i1 as XPathNavigator;
774 XPathNavigator n2 = i2 as XPathNavigator;
775 if (n1.NodeType != n2.NodeType)
776 return false;
777 switch (n1.NodeType) {
778 case XPathNodeType.Root:
779 throw new NotImplementedException ();
780 case XPathNodeType.Element:
781 throw new NotImplementedException ();
782 case XPathNodeType.Attribute:
783 return n1.Name == n2.Name && n1.TypedValue == n2.TypedValue;
784 case XPathNodeType.ProcessingInstruction:
785 case XPathNodeType.Namespace:
786 return n1.Name == n2.Name && n1.Value == n2.Value;
787 case XPathNodeType.Text:
788 case XPathNodeType.Comment:
789 return n1.Value == n2.Value;
791 return false;
794 public static int FnCount (XPathSequence e)
796 if (e == null)
797 return 0;
798 return e.Count;
801 [MonoTODO]
802 public static object FnAvg (XPathSequence e)
804 if (!e.MoveNext ())
805 return null;
806 switch (e.Current.XmlType.TypeCode) {
807 case XmlTypeCode.DayTimeDuration:
808 return FnAvgDayTimeDuration (e);
809 case XmlTypeCode.YearMonthDuration:
810 return FnAvgYearMonthDuration (e);
811 case XmlTypeCode.Decimal:
812 return FnAvgDecimal (e);
813 case XmlTypeCode.Integer:
814 return FnAvgInteger (e);
815 case XmlTypeCode.Float:
816 return FnAvgFloat (e);
817 case XmlTypeCode.UntypedAtomic:
818 case XmlTypeCode.Double:
819 return FnAvgDouble (e);
821 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.");
824 private static TimeSpan FnAvgDayTimeDuration (XPathSequence e)
826 throw new NotImplementedException ();
829 private static TimeSpan FnAvgYearMonthDuration (XPathSequence e)
831 throw new NotImplementedException ();
834 private static TimeSpan FnAvgDecimal (XPathSequence e)
836 throw new NotImplementedException ();
839 private static TimeSpan FnAvgInteger (XPathSequence e)
841 throw new NotImplementedException ();
844 private static TimeSpan FnAvgFloat (XPathSequence e)
846 throw new NotImplementedException ();
849 private static TimeSpan FnAvgDouble (XPathSequence e)
851 throw new NotImplementedException ();
854 public static object FnMax (XQueryContext ctx, XPathSequence e)
856 return FnMaxImpl (e, ctx.DefaultCollation);
859 public static object FnMax (XQueryContext ctx, XPathSequence e, string collation)
861 return FnMaxImpl (e, ctx.GetCulture (collation));
864 private static object FnMaxImpl (XPathSequence e, CultureInfo collation)
866 if (!e.MoveNext ())
867 return null;
868 switch (e.Current.XmlType.TypeCode) {
869 case XmlTypeCode.DayTimeDuration:
870 return FnMaxDayTimeDuration (e);
871 case XmlTypeCode.YearMonthDuration:
872 return FnMaxYearMonthDuration (e);
873 case XmlTypeCode.Decimal:
874 return FnMaxDecimal (e);
875 case XmlTypeCode.Integer:
876 return FnMaxInteger (e);
877 case XmlTypeCode.Float:
878 return FnMaxFloat (e);
879 case XmlTypeCode.UntypedAtomic:
880 case XmlTypeCode.Double:
881 return FnMaxDouble (e);
883 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.");
886 private static TimeSpan FnMaxDayTimeDuration (XPathSequence e)
888 // FIXME: reject yMD (but is it possible...?)
889 TimeSpan ret = TimeSpan.Zero;
890 do {
891 TimeSpan ts = (TimeSpan) e.Current.TypedValue;
892 if (ts > ret)
893 ret = ts;
894 } while (e.MoveNext ());
895 return ret;
898 private static TimeSpan FnMaxYearMonthDuration (XPathSequence e)
900 // FIXME: reject dTD (but is it possible...?)
901 TimeSpan ret = TimeSpan.Zero;
902 do {
903 TimeSpan ts = (TimeSpan) e.Current.TypedValue;
904 if (ts > ret)
905 ret = ts;
906 } while (e.MoveNext ());
907 return ret;
910 private static decimal FnMaxDecimal (XPathSequence e)
912 decimal ret = decimal.MinValue;
913 do {
914 ret = System.Math.Max (e.Current.ValueAsDecimal, ret);
915 } while (e.MoveNext ());
916 return ret;
919 private static int FnMaxInteger (XPathSequence e)
921 int ret = int.MinValue;
922 do {
923 ret = System.Math.Max (e.Current.ValueAsInt32, ret);
924 } while (e.MoveNext ());
925 return ret;
928 private static float FnMaxFloat (XPathSequence e)
930 float ret = float.MinValue;
931 do {
932 ret = System.Math.Max (e.Current.ValueAsSingle, ret);
933 } while (e.MoveNext ());
934 return ret;
937 private static double FnMaxDouble (XPathSequence e)
939 double ret = double.MinValue;
940 do {
941 ret = System.Math.Max (e.Current.ValueAsDouble, ret);
942 } while (e.MoveNext ());
943 return ret;
946 public static object FnMin (XQueryContext ctx, XPathSequence e)
948 return FnMinImpl (e, ctx.DefaultCollation);
951 public static object FnMin (XQueryContext ctx, XPathSequence e, string collation)
953 return FnMinImpl (e, ctx.GetCulture (collation));
956 private static object FnMinImpl (XPathSequence e, CultureInfo collation)
958 if (!e.MoveNext ())
959 return null;
960 switch (e.Current.XmlType.TypeCode) {
961 case XmlTypeCode.DayTimeDuration:
962 return FnMinDayTimeDuration (e);
963 case XmlTypeCode.YearMonthDuration:
964 return FnMinYearMonthDuration (e);
965 case XmlTypeCode.Decimal:
966 return FnMinDecimal (e);
967 case XmlTypeCode.Integer:
968 return FnMinInteger (e);
969 case XmlTypeCode.Float:
970 return FnMinFloat (e);
971 case XmlTypeCode.UntypedAtomic:
972 case XmlTypeCode.Double:
973 return FnMinDouble (e);
975 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.");
978 private static TimeSpan FnMinDayTimeDuration (XPathSequence e)
980 // FIXME: reject yMD (but is it possible...?)
981 TimeSpan ret = TimeSpan.Zero;
982 do {
983 TimeSpan ts = (TimeSpan) e.Current.TypedValue;
984 if (ts > ret)
985 ret = ts;
986 } while (e.MoveNext ());
987 return ret;
990 private static TimeSpan FnMinYearMonthDuration (XPathSequence e)
992 // FIXME: reject dTD (but is it possible...?)
993 TimeSpan ret = TimeSpan.Zero;
994 do {
995 TimeSpan ts = (TimeSpan) e.Current.TypedValue;
996 if (ts > ret)
997 ret = ts;
998 } while (e.MoveNext ());
999 return ret;
1002 private static decimal FnMinDecimal (XPathSequence e)
1004 decimal ret = decimal.MaxValue;
1005 do {
1006 ret = System.Math.Min (e.Current.ValueAsDecimal, ret);
1007 } while (e.MoveNext ());
1008 return ret;
1011 private static int FnMinInteger (XPathSequence e)
1013 int ret = int.MaxValue;
1014 do {
1015 ret = System.Math.Min (e.Current.ValueAsInt32, ret);
1016 } while (e.MoveNext ());
1017 return ret;
1020 private static float FnMinFloat (XPathSequence e)
1022 float ret = float.MaxValue;
1023 do {
1024 ret = System.Math.Min (e.Current.ValueAsSingle, ret);
1025 } while (e.MoveNext ());
1026 return ret;
1029 private static double FnMinDouble (XPathSequence e)
1031 double ret = double.MaxValue;
1032 do {
1033 ret = System.Math.Min (e.Current.ValueAsDouble, ret);
1034 } while (e.MoveNext ());
1035 return ret;
1038 [MonoTODO]
1039 public static object FnSum (XPathSequence e)
1041 throw new NotImplementedException ();
1044 [MonoTODO]
1045 public static object FnSum (XPathSequence e, XPathItem zero)
1047 throw new NotImplementedException ();
1050 public static XPathNavigator FnId (XQueryContext ctx, string id)
1052 return FnId (id, ctx.CurrentNode);
1055 public static XPathNavigator FnId (string id, XPathNavigator nav)
1057 XPathNavigator node = nav.Clone ();
1058 return node.MoveToId (id) ? node : null;
1061 [MonoTODO]
1062 public static object FnIdRef (XQueryContext ctx, string arg)
1064 return FnIdRef (arg, ctx.CurrentNode);
1067 [MonoTODO]
1068 public static object FnIdRef (string arg, XPathNavigator node)
1070 throw new NotImplementedException ();
1073 public static XPathNavigator FnDoc (XQueryContext ctx, string uri)
1075 XmlResolver res = ctx.ContextManager.ExtDocResolver;
1076 string baseUriString = ctx.StaticContext.BaseUri;
1077 Uri baseUri = null;
1078 if (baseUriString != null && baseUriString != String.Empty)
1079 baseUri = new Uri (baseUriString);
1080 Uri relUri = res.ResolveUri (baseUri, uri);
1081 Stream s = res.GetEntity (relUri, null, typeof (Stream)) as Stream;
1082 try {
1083 XPathDocument doc = new XPathDocument (new XmlValidatingReader (new XmlTextReader (s)), XmlSpace.Preserve);
1084 return doc.CreateNavigator ();
1085 } finally {
1086 s.Close ();
1090 public static XPathSequence FnCollection (XQueryContext ctx, string name)
1092 return ctx.ResolveCollection (name);
1095 [XQueryFunctionContext]
1096 public static int FnPosition (XPathSequence current)
1098 return current.Position;
1101 [XQueryFunctionContext]
1102 public static int FnLast (XPathSequence current)
1104 return current.Count;
1107 public static DateTime FnCurrentDateTime ()
1109 return DateTime.Now;
1112 public static DateTime FnCurrentDate ()
1114 return DateTime.Today;
1117 public static DateTime FnCurrentTime ()
1119 return new DateTime (DateTime.Now.TimeOfDay.Ticks);
1122 [MonoTODO]
1123 public static object FnDefaultCollation ()
1125 throw new NotImplementedException ();
1128 [MonoTODO]
1129 public static object FnImplicitTimeZone ()
1131 throw new NotImplementedException ();
1135 #endif