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