Merge pull request #2922 from akoeplinger/fix-tvos
[mono.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XQueryFunction.cs
1 //
2 // XQueryFunction.cs - XQuery 1.0 and XPath 2.0 Functions implementation
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.
28 //
29
30 //
31 // See XQuery 1.0 and XPath 2.0 Functions and Operators.
32 //
33 using System;
34 using System.Collections;
35 using System.Reflection;
36 using System.Xml;
37 using System.Xml.Schema;
38 using System.Xml.Query;
39 using System.Xml.XPath;
40 using System.Xml.Xsl;
41 using Mono.Xml;
42
43 namespace Mono.Xml.XPath2
44 {
45         // It is instantiated per function definition. (e.g. fn:string(), fn:data(), fn:contat()).
46         public abstract class XQueryFunction
47         {
48                 public const string Namespace = "http://www.w3.org/2004/07/xpath-functions";
49
50                 static XQueryFunctionTable defaultFunctions = new XQueryFunctionTable ();
51
52                 static XQueryFunction ()
53                 {
54                         defaultFunctions.Add (FromName ("node-name", "FnNodeName"));
55                         defaultFunctions.Add (FromName ("nilled", "FnNilled"));
56                         defaultFunctions.Add (FromName ("string", "FnString"));
57                         defaultFunctions.Add (FromName ("data", "FnData"));
58                         defaultFunctions.Add (FromName ("base-uri", "FnBaseUri"));
59                         defaultFunctions.Add (FromName ("document-uri", "FnDocumentUri"));
60                         defaultFunctions.Add (FromName ("error", "FnError"));
61                         defaultFunctions.Add (FromName ("trace", "FnTrace"));
62                         defaultFunctions.Add (FromName ("abs", "FnAbs"));
63                         defaultFunctions.Add (FromName ("ceiling", "FnCeiling"));
64                         defaultFunctions.Add (FromName ("floor", "FnFloor"));
65                         defaultFunctions.Add (FromName ("round", "FnRound"));
66                         defaultFunctions.Add (FromName ("round-half-to-even", "FnRoundHalfToEven"));
67                         defaultFunctions.Add (FromName ("codepoints-to-string", "FnCodepointsToString"));
68                         defaultFunctions.Add (FromName ("string-to-codepoints", "FnStringToCodepoints"));
69                         defaultFunctions.Add (FromName ("compare", "FnCompare"));
70                         defaultFunctions.Add (FromName ("concat", "FnConcat"));
71                         defaultFunctions.Add (FromName ("string-join", "FnStringJoin"));
72                         defaultFunctions.Add (FromName ("substring", "FnSubstring"));
73                         defaultFunctions.Add (FromName ("string-length", "FnStringLength"));
74                         defaultFunctions.Add (FromName ("normaize-space", "FnNormalizeSpace"));
75                         defaultFunctions.Add (FromName ("normalize-unicode", "FnNormalizeUnicode"));
76                         defaultFunctions.Add (FromName ("uppercase", "FnUpperCase"));
77                         defaultFunctions.Add (FromName ("lowercase", "FnLowerCase"));
78                         defaultFunctions.Add (FromName ("translate", "FnTranslate"));
79                         defaultFunctions.Add (FromName ("escape-uri", "FnEscapeUri"));
80                         defaultFunctions.Add (FromName ("contains", "FnContains"));
81                         defaultFunctions.Add (FromName ("starts-with", "FnStartsWith"));
82                         defaultFunctions.Add (FromName ("ends-with", "FnEndsWith"));
83                         defaultFunctions.Add (FromName ("substring-before", "FnSubstringBefore"));
84                         defaultFunctions.Add (FromName ("substring-after", "FnSubstringAfter"));
85                         defaultFunctions.Add (FromName ("matches", "FnMatches"));
86                         defaultFunctions.Add (FromName ("replace", "FnReplace"));
87                         defaultFunctions.Add (FromName ("tokenize", "FnTokenize"));
88                         defaultFunctions.Add (FromName ("resolve-uri", "FnResolveUri"));
89                         defaultFunctions.Add (FromName ("true", "FnTrue"));
90                         defaultFunctions.Add (FromName ("false", "FnFalse"));
91                         defaultFunctions.Add (FromName ("not", "FnNot"));
92
93                         defaultFunctions.Add (FromName ("resolve-qname", "FnResolveQName"));
94                         defaultFunctions.Add (FromName ("expand-qname", "FnExpandQName"));
95                         defaultFunctions.Add (FromName ("namespace-uri-for-prefix", "FnNamespaceUriForPrefix"));
96                         defaultFunctions.Add (FromName ("in-scope-prefixes", "FnInScopePrefixes"));
97                         defaultFunctions.Add (FromName ("name", "FnName"));
98                         defaultFunctions.Add (FromName ("local-name", "FnLocalName"));
99                         defaultFunctions.Add (FromName ("namespace-uri", "FnNamespaceUri"));
100                         defaultFunctions.Add (FromName ("number", "FnNumber"));
101                         defaultFunctions.Add (FromName ("lang", "FnLang"));
102                         defaultFunctions.Add (FromName ("root", "FnRoot"));
103                         defaultFunctions.Add (FromName ("boolean", "FnBoolean"));
104                         defaultFunctions.Add (FromName ("indexof", "FnIndexOf"));
105                         defaultFunctions.Add (FromName ("empty", "FnEmpty"));
106                         defaultFunctions.Add (FromName ("exists", "FnExists"));
107                         defaultFunctions.Add (FromName ("distinct-values", "FnDistinctValues"));
108                         defaultFunctions.Add (FromName ("insert-before", "FnInsertBefore"));
109                         defaultFunctions.Add (FromName ("remove", "FnRemove"));
110                         defaultFunctions.Add (FromName ("reverse", "FnReverse"));
111                         defaultFunctions.Add (FromName ("subsequence", "FnSubsequence"));
112                         defaultFunctions.Add (FromName ("unordered", "FnUnordered"));
113                         defaultFunctions.Add (FromName ("zero-or-one", "FnZeroOrOne"));
114                         defaultFunctions.Add (FromName ("one-or-more", "FnOneOrMore"));
115                         defaultFunctions.Add (FromName ("exactly-one", "FnExactlyOne"));
116                         defaultFunctions.Add (FromName ("deep-equal", "FnDeepEqual"));
117                         defaultFunctions.Add (FromName ("count", "FnCount"));
118                         defaultFunctions.Add (FromName ("avg", "FnAvg"));
119                         defaultFunctions.Add (FromName ("max", "FnMax"));
120                         defaultFunctions.Add (FromName ("min", "FnMin"));
121                         defaultFunctions.Add (FromName ("sum", "FnSum"));
122                         defaultFunctions.Add (FromName ("id", "FnId"));
123                         defaultFunctions.Add (FromName ("idref", "FnIdRef"));
124                         defaultFunctions.Add (FromName ("doc", "FnDoc"));
125                         defaultFunctions.Add (FromName ("collection", "FnCollection"));
126                         defaultFunctions.Add (FromName ("position", "FnPosition"));
127                         defaultFunctions.Add (FromName ("last", "FnLast"));
128                         defaultFunctions.Add (FromName ("current-datetime", "FnCurrentDateTime"));
129                         defaultFunctions.Add (FromName ("current-date", "FnCurrentDate"));
130                         defaultFunctions.Add (FromName ("current-time", "FnCurrentTime"));
131                         defaultFunctions.Add (FromName ("default-collation", "FnDefaultCollation"));
132                         defaultFunctions.Add (FromName ("implicit-timezone", "FnImplicitTimeZone"));
133 //                      defaultFunctions.Add (FromName ("years-from-duration", "FnYearsFromDuration"));
134 /*
135                         fnAtomicConstructor,
136                         fnYearsFromDuration, fnMonthsFromDuration,
137                         fnDaysFromDuration, fnHoursFromDuration,
138                         fnMinutesFromDuration, fnSecondsFromDuration,
139                         fnYearFromDateTime, fnMonthFromDateTime,
140                         fnDayFromDateTime, fnHoursFromDateTime,
141                         fnMinutesFromDateTime, fnSecondsFromDateTime,
142                         fnTimeZoneFromDateTime, fnYearFromDate, fnMonthFromDate,
143                         fnDayFromDate, fnTimeZoneFromDate, fnHoursFromTime,
144                         fnMinutesFromTime, fnSecondsFromTime,
145                         fnTimeZoneFromTime, fnAdjustDateTimeToTimeZone,
146                         fnAdjustDateToTimeZone, fnAdjustTimeToTimeZone,
147                         fnSubtractDateTimesYieldingYearMonthDuration,
148                         fnSubtractDateTimesYieldingDayTimeDuration,
149                         fnSubtractDatesYieldingYearMonthDuration,
150                         fnSubtractDatesYieldingDayTimeDuration,
151                         fnSubtractTimes,
152 */
153                 }
154
155                 private static XQueryCliFunction FromName (string xname, string cliname)
156                 {
157                         return XQueryCliFunction.CreateFromMethodInfo (
158                                 new XmlQualifiedName (xname, XQueryFunction.Namespace),
159                                 FindNamedMethods (typeof (XQueryFunctionCliImpl), cliname)
160                                 );
161                 }
162
163                 internal static XQueryCliFunction FromQName (XmlQualifiedName qname)
164                 {
165                         return XQueryCliFunction.CreateFromMethodInfo (
166                                 qname, FindNamedMethods (Type.GetType (qname.Namespace), qname.Name));
167                 }
168
169                 private static bool FilterImpl (MemberInfo m, object filterCriteria)
170                 {
171                         return m.Name == filterCriteria.ToString ();
172                 }
173
174                 private static MemberFilter memberFilter = new MemberFilter (FilterImpl);
175
176                 private static MethodInfo [] FindNamedMethods (Type type, string name)
177                 {
178                         ArrayList al = new ArrayList (
179                                 type.FindMembers (
180                                         MemberTypes.Method,
181                                         BindingFlags.Default | BindingFlags.Public | BindingFlags.Static,
182                                         // FIXME: wait for anonymous method support
183 //                                      delegate (MemberInfo m, object filterCriteria) {
184 //                                              return m.Name == filterCriteria.ToString ();
185 //                                      },
186                                         memberFilter,
187                                         name));
188                         return al.ToArray (typeof (MethodInfo)) as MethodInfo [];
189                 }
190
191                 internal static XQueryFunction FindKnownFunction (
192                         XmlQualifiedName name)
193                 {
194                         switch (name.Namespace) {
195                         case XQueryFunction.Namespace:
196                                 return defaultFunctions [name];
197                         case InternalPool.XdtNamespace:
198                         case XmlSchema.Namespace:
199                                 XmlSchemaType type = XmlSchemaType.GetBuiltInSimpleType (name);
200                                 if (type != null)
201                                         return null; // FIXME: atomic constructor
202                                 type = XmlSchemaType.GetBuiltInComplexType (name);
203                                 if (type == null)
204                                         return null; // FIXME: atomic constructor?
205                                 return null;
206                         default:
207                                 return null;
208                         }
209                 }
210
211                 // Constructor
212
213                 internal XQueryFunction (XmlQualifiedName name, XQueryFunctionArgument [] args, SequenceType returnType)
214                 {
215                         this.name = name;
216                         this.args = args;
217                         this.returnType = returnType;
218                 }
219
220                 // Fields
221
222                 XmlQualifiedName name;
223                 XQueryFunctionArgument [] args;
224                 SequenceType returnType;
225
226                 // Properties
227
228                 public XmlQualifiedName Name {
229                         get { return name; }
230                 }
231
232                 public abstract int MinArgs { get; }
233                 public abstract int MaxArgs { get; }
234
235                 public XQueryFunctionArgument [] Args {
236                         get { return args; }
237                 }
238
239                 public SequenceType ReturnType {
240                         get { return returnType; }
241                 }
242
243                 public abstract object Invoke (XPathSequence current, object [] args);
244
245                 public virtual XPathSequence Evaluate (XPathSequence iter, ExprSequence args)
246                 {
247                         object [] instParams = new object [args.Count];
248                         for (int i = 0; i < args.Count; i++) {
249                                 XPathSequence val = args [i].Evaluate (iter);
250                                 instParams [i] = Args [i].Type.ToRuntimeType (val);
251                         }
252                         object o = Invoke (iter, instParams);
253                         if (o == null)
254                                 return new XPathEmptySequence (iter.Context);
255                         if (o is XPathSequence)
256                                 return (XPathSequence) o;
257                         XPathItem item = o as XPathItem;
258                         if (item == null)
259                                 item = new XPathAtomicValue (o, ReturnType.SchemaType);
260                         return new SingleItemIterator (item, iter.Context);
261                 }
262         }
263
264         public class XQueryFunctionArgument
265         {
266                 public XQueryFunctionArgument (XmlQualifiedName name, SequenceType type)
267                 {
268                         this.name = name;
269                         this.type = type;
270                 }
271
272                 XmlQualifiedName name;
273                 SequenceType type;
274
275                 public XmlQualifiedName Name {
276                         get { return name; }
277                 }
278
279                 public SequenceType Type {
280                         get { return type; }
281                 }
282         }
283
284         public class XQueryUserFunction : XQueryFunction
285         {
286                 ExprSequence expr;
287
288                 internal XQueryUserFunction (XmlQualifiedName name,
289                         XQueryFunctionArgument [] parameters,
290                         ExprSequence expr,
291                         SequenceType returnType)
292                         : base (name, parameters, returnType)
293                 {
294                         this.expr = expr;
295                 }
296
297                 public override int MinArgs {
298                         get { return Args.Length; }
299                 }
300
301                 public override int MaxArgs {
302                         get { return Args.Length; }
303                 }
304
305                 public override object Invoke (XPathSequence current, object [] args)
306                 {
307                         throw new SystemException ("XQuery internal error: should not happen.");
308                 }
309
310                 public override XPathSequence Evaluate (XPathSequence iter, ExprSequence args)
311                 {
312                         for (int i = 0; i < Args.Length; i++)
313                                 iter.Context.PushVariable (Args [i].Name, args [i].Evaluate (iter));
314                         XPathSequence seq = new ExprSequenceIterator (iter, expr);
315                         for (int i = 0; i < Args.Length; i++)
316                                 iter.Context.PopVariable ();
317                         return seq;
318                 }
319         }
320 }