2 // XQueryFunctionCliImple.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
37 using System
.Collections
;
38 using System
.Globalization
;
40 using System
.Text
.RegularExpressions
;
42 using System
.Xml
.Query
;
43 using System
.Xml
.Schema
;
44 using System
.Xml
.XPath
;
47 namespace Mono
.Xml
.XPath2
49 public class XQueryFunctionCliImpl
51 internal static XmlSchemaType
XmlTypeFromCliType (Type cliType
)
53 switch (Type
.GetTypeCode (cliType
)) {
55 return InternalPool
.XsInt
;
56 case TypeCode
.Decimal
:
57 return InternalPool
.XsDecimal
;
59 return InternalPool
.XsDouble
;
61 return InternalPool
.XsFloat
;
63 return InternalPool
.XsLong
;
65 return InternalPool
.XsShort
;
67 return InternalPool
.XsUnsignedShort
;
69 return InternalPool
.XsUnsignedInt
;
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
;
82 private static XPathItem
ToItem (object arg
)
86 XPathItem item
= arg
as XPathItem
;
89 XPathSequence seq
= arg
as XPathSequence
;
91 return seq
.MoveNext () ? seq
.Current
: null;
92 return new XPathAtomicValue (arg
, XmlTypeFromCliType (arg
.GetType ()));
97 public static XmlQualifiedName
FnNodeName (XPathNavigator arg
)
102 return arg
.LocalName
== String
.Empty
?
103 XmlQualifiedName
.Empty
:
104 new XmlQualifiedName (arg
.LocalName
, arg
.NamespaceURI
);
107 public static bool FnNilled (XPathNavigator arg
)
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
;
120 throw new ArgumentException ("FONC0001: undefined context item");
121 return FnString (item
);
125 public static string FnString (object arg
)
129 XPathNavigator nav
= arg
as XPathNavigator
;
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;
138 public static XPathAtomicValue
FnData (object arg
)
140 // FIXME: parameter should be object []
141 XPathNavigator nav
= arg
as XPathNavigator
;
143 XmlSchemaType st
= nav
.SchemaInfo
!= null ? nav
.SchemaInfo
.SchemaType
: null;
144 return new XPathAtomicValue (nav
.TypedValue
, st
!= null ? st
: InternalPool
.XsAnyType
);
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
)
159 XPathNavigator root
= nav
.Clone ();
167 public static void FnError (object arg
)
169 throw new NotImplementedException ();
175 public static object FnTrace (XQueryContext ctx
, object value, string label
)
178 return new XPathEmptySequence (ctx
);
179 XPathSequence seq
= value as XPathSequence
;
181 XPathAtomicValue av
= value as XPathAtomicValue
;
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
);
195 public static object FnAbs (object arg
)
198 return System
.Math
.Abs ((int) arg
);
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)
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)
230 public static object FnFloor (object arg
)
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)
242 public static object FnRound (object arg
)
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)
254 public static object FnRoundHalfToEven (object arg
)
256 throw new NotImplementedException ();
260 public static string FnCodepointsToString (int [] arg
)
262 throw new NotImplementedException ();
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
)
316 public static string FnNormalizeSpace (XQueryContext ctx
)
318 return FnNormalizeSpace (FnString (ctx
));
322 public static string FnNormalizeSpace (string s
)
324 throw new NotImplementedException ();
327 public static string FnNormalizeUnicode (string arg
)
329 return FnNormalizeUnicode (arg
, "NFC");
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
);
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
)
377 if (arg2
== String
.Empty
)
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
);
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
);
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
);
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 ()
492 public static object FnFalse ()
497 public static object FnNot (bool value)
502 // FIXME: add a bunch of annoying datetime functions
504 public static object FnResolveQName (string qname
, XPathNavigator element
)
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
)
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
)
594 XPathNavigator root
= node
.Clone ();
599 public static bool FnBoolean (IEnumerator e
)
603 XPathItem item
= e
.Current
as XPathItem
;
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)
625 IComparable ic
= (IComparable
) iter
.TypedValue
;
626 if (ic
.CompareTo ((IComparable
) item
.TypedValue
) == 0)
630 return new ListIterator (ctx
, al
);
633 public static bool FnEmpty (XPathSequence e
)
635 if (e
is XPathEmptySequence
)
637 return !e
.GetEnumerator ().MoveNext ();
640 public static bool FnExists (XPathSequence e
)
642 if (e
is XPathEmptySequence
)
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
)
666 return new InsertingIterator (target
, position
, inserts
);
669 public static XPathSequence
FnRemove (XPathSequence target
, int position
)
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
);
683 return new ListIterator (arg
.Context
, al
);
686 public static object FnSubsequence (XPathSequence sourceSeq
, double startingLoc
)
688 return FnSubsequence (sourceSeq
, startingLoc
, double.MaxValue
);
692 public static object FnSubsequence (XPathSequence sourceSeq
, double startingLoc
, double length
)
694 throw new NotImplementedException ();
698 // Basically it should be optimized by XQueryASTCompiler
699 public static XPathSequence
FnUnordered (XPathSequence e
)
704 public static XPathItem
FnZeroOrOne (XPathSequence e
)
708 XPathItem item
= e
.Current
;
710 throw new XmlQueryException ("zero-or-one() function detected that the argument sequence contains two or more items.");
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.");
721 public static XPathItem
FnExactlyOne (XPathSequence e
)
724 throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains no items.");
725 XPathItem item
= e
.Current
;
727 throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains two or more items.");
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 ()) {
747 if (!FnDeepEqualItem (p1
.Current
, p2
.Current
, collation
))
755 // FIXME: Actually ValueEQ() should consider collation.
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) {
763 return XQueryComparisonOperator
.ValueEQ (av1
, av2
);
764 } catch (XmlQueryException
) {
765 // not-allowed comparison never raises
766 // an error here, just return false.
770 else if (av1
!= null || av2
!= null)
773 XPathNavigator n1
= i1
as XPathNavigator
;
774 XPathNavigator n2
= i2
as XPathNavigator
;
775 if (n1
.NodeType
!= n2
.NodeType
)
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
;
794 public static int FnCount (XPathSequence e
)
802 public static object FnAvg (XPathSequence e
)
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
)
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
;
891 TimeSpan ts
= (TimeSpan
) e
.Current
.TypedValue
;
894 } while (e
.MoveNext ());
898 private static TimeSpan
FnMaxYearMonthDuration (XPathSequence e
)
900 // FIXME: reject dTD (but is it possible...?)
901 TimeSpan ret
= TimeSpan
.Zero
;
903 TimeSpan ts
= (TimeSpan
) e
.Current
.TypedValue
;
906 } while (e
.MoveNext ());
910 private static decimal FnMaxDecimal (XPathSequence e
)
912 decimal ret
= decimal.MinValue
;
914 ret
= System
.Math
.Max (e
.Current
.ValueAsDecimal
, ret
);
915 } while (e
.MoveNext ());
919 private static int FnMaxInteger (XPathSequence e
)
921 int ret
= int.MinValue
;
923 ret
= System
.Math
.Max (e
.Current
.ValueAsInt32
, ret
);
924 } while (e
.MoveNext ());
928 private static float FnMaxFloat (XPathSequence e
)
930 float ret
= float.MinValue
;
932 ret
= System
.Math
.Max (e
.Current
.ValueAsSingle
, ret
);
933 } while (e
.MoveNext ());
937 private static double FnMaxDouble (XPathSequence e
)
939 double ret
= double.MinValue
;
941 ret
= System
.Math
.Max (e
.Current
.ValueAsDouble
, ret
);
942 } while (e
.MoveNext ());
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
)
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
;
983 TimeSpan ts
= (TimeSpan
) e
.Current
.TypedValue
;
986 } while (e
.MoveNext ());
990 private static TimeSpan
FnMinYearMonthDuration (XPathSequence e
)
992 // FIXME: reject dTD (but is it possible...?)
993 TimeSpan ret
= TimeSpan
.Zero
;
995 TimeSpan ts
= (TimeSpan
) e
.Current
.TypedValue
;
998 } while (e
.MoveNext ());
1002 private static decimal FnMinDecimal (XPathSequence e
)
1004 decimal ret
= decimal.MaxValue
;
1006 ret
= System
.Math
.Min (e
.Current
.ValueAsDecimal
, ret
);
1007 } while (e
.MoveNext ());
1011 private static int FnMinInteger (XPathSequence e
)
1013 int ret
= int.MaxValue
;
1015 ret
= System
.Math
.Min (e
.Current
.ValueAsInt32
, ret
);
1016 } while (e
.MoveNext ());
1020 private static float FnMinFloat (XPathSequence e
)
1022 float ret
= float.MaxValue
;
1024 ret
= System
.Math
.Min (e
.Current
.ValueAsSingle
, ret
);
1025 } while (e
.MoveNext ());
1029 private static double FnMinDouble (XPathSequence e
)
1031 double ret
= double.MaxValue
;
1033 ret
= System
.Math
.Min (e
.Current
.ValueAsDouble
, ret
);
1034 } while (e
.MoveNext ());
1039 public static object FnSum (XPathSequence e
)
1041 throw new NotImplementedException ();
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;
1062 public static object FnIdRef (XQueryContext ctx
, string arg
)
1064 return FnIdRef (arg
, ctx
.CurrentNode
);
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
;
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
;
1083 XPathDocument doc
= new XPathDocument (new XmlValidatingReader (new XmlTextReader (s
)), XmlSpace
.Preserve
);
1084 return doc
.CreateNavigator ();
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
);
1123 public static object FnDefaultCollation ()
1125 throw new NotImplementedException ();
1129 public static object FnImplicitTimeZone ()
1131 throw new NotImplementedException ();