2002-08-17 Jason Diamond <jason@injektilo.org>
[mono.git] / mcs / class / System.XML / System.Xml.XPath / DefaultContext.cs
1 //
2 // System.Xml.XPath.DefaultContext & support classes
3 //
4 // Author:
5 //   Piers Haken (piersh@friskit.com)
6 //
7 // (C) 2002 Piers Haken
8 //
9 using System;
10 using System.Collections;
11 using System.Xml;
12 using System.Xml.XPath;
13 using System.Xml.Xsl;
14
15 namespace System.Xml.XPath
16 {
17         /// <summary>
18         /// Summary description for DefaultContext.
19         /// </summary>
20         internal class DefaultContext : XsltContext
21         {
22                 protected static Hashtable _htFunctions = new Hashtable ();
23
24                 static DefaultContext()
25                 {
26                         Add (new XPathFunctionLast ());
27                         Add (new XPathFunctionPosition ());
28                         Add (new XPathFunctionCount ());
29                         Add (new XPathFunctionId ());
30                         Add (new XPathFunctionLocalName ());
31                         Add (new XPathFunctionNamespaceUri ());
32                         Add (new XPathFunctionName ());
33                         Add (new XPathFunctionString ());
34                         Add (new XPathFunctionConcat ());
35                         Add (new XPathFunctionStartsWith ());
36                         Add (new XPathFunctionContains ());
37                         Add (new XPathFunctionSubstringBefore ());
38                         Add (new XPathFunctionSubstringAfter ());
39                         Add (new XPathFunctionSubstring ());
40                         Add (new XPathFunctionStringLength ());
41                         Add (new XPathFunctionNormalizeSpace ());
42                         Add (new XPathFunctionTranslate ());
43                         Add (new XPathFunctionBoolean ());
44                         Add (new XPathFunctionNot ());
45                         Add (new XPathFunctionTrue ());
46                         Add (new XPathFunctionFalse ());
47                         Add (new XPathFunctionLang ());
48                         Add (new XPathFunctionNumber ());
49                         Add (new XPathFunctionSum ());
50                         Add (new XPathFunctionFloor ());
51                         Add (new XPathFunctionCeil ());
52                         Add (new XPathFunctionRound ());
53                 }
54
55                 [MonoTODO]
56                 public override IXsltContextFunction ResolveFunction (string prefix, string name, XPathResultType[] ArgTypes)
57                 {
58                         // match the prefix
59                         if (prefix != null && prefix != "")     // TODO: should we allow some namespaces here?
60                                 return null;
61
62                         // match the function name
63                         XPathFunction fn = (XPathFunction) _htFunctions [name];
64                         if (fn == null)
65                                 return null;
66
67                         // check the number of arguments
68                         int cArgs = ArgTypes.Length;
69                         if (cArgs < fn.Minargs || cArgs > fn.Maxargs)
70                                 return null;
71
72                         // check the types of the arguments
73                         XPathResultType [] rgTypes = fn.ArgTypes;
74                         if (rgTypes == null)
75                         {
76                                 if (cArgs != 0)
77                                         return null;
78                         }
79                         else
80                         {
81                                 int cTypes = rgTypes.Length;
82                                 for (int iArg = 0; iArg < cArgs; iArg ++)
83                                 {
84                                         XPathResultType typeRequested = ArgTypes [iArg];
85                                         XPathResultType typeDefined = (iArg >= cTypes) ? rgTypes [cTypes - 1] : rgTypes [iArg];
86                                         if (typeDefined != XPathResultType.Any && typeDefined != typeRequested)
87                                                 return null;
88                                 }
89                         }
90                         return fn;
91                 }
92                 public override IXsltContextVariable ResolveVariable (string prefix, string name)
93                 {
94                         return null;
95                 }
96                 [MonoTODO]
97                 public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
98                 [MonoTODO]
99                 public override bool PreserveWhitespace (XPathNavigator nav) { throw new NotImplementedException (); }
100                 [MonoTODO]
101                 public override bool Whitespace { get { throw new NotImplementedException (); }}
102                 protected static void Add (XPathFunction fn)
103                 {
104                         _htFunctions.Add (fn.Name, fn);
105                 }
106         }
107
108         internal class XPathFunctions
109         {
110                 public static bool ToBoolean (object arg)
111                 {
112                         if (arg == null)
113                                 throw new ArgumentNullException ();
114                         if (arg is bool)
115                                 return (bool) arg;
116                         if (arg is double)
117                         {
118                                 double dArg = (double) arg;
119                                 return (dArg != 0.0 && !double.IsNaN (dArg));
120                         }
121                         if (arg is string)
122                                 return ((string) arg).Length != 0;
123                         if (arg is BaseIterator)
124                         {
125                                 BaseIterator iter = (BaseIterator) arg;
126                                 return iter.MoveNext ();
127                         }
128                         throw new ArgumentException ();
129                 }
130                 [MonoTODO]
131                 public static string ToString (object arg)
132                 {
133                         if (arg == null)
134                                 throw new ArgumentNullException ();
135                         if (arg is string)
136                                 return (string) arg;
137                         if (arg is bool)
138                                 return ((bool) arg) ? "true" : "false";
139                         if (arg is double)
140                                 return (string) XmlConvert.ToString ((double) arg);     // TODO: spec? convert number to string
141                         if (arg is BaseIterator)
142                         {
143                                 BaseIterator iter = (BaseIterator) arg;
144                                 if (!iter.MoveNext ())
145                                         return "";
146                                 return iter.Current.Value;
147                         }
148                         throw new ArgumentException ();
149                 }
150                 [MonoTODO]
151                 public static double ToNumber (object arg)
152                 {
153                         if (arg == null)
154                                 throw new ArgumentNullException ();
155                         if (arg is BaseIterator)
156                                 arg = ToString (arg);   // follow on
157                         if (arg is string)
158                                 return XmlConvert.ToDouble ((string) arg);      // TODO: spec? convert string to number
159                         if (arg is double)
160                                 return (double) arg;
161                         if (arg is bool)
162                                 return Convert.ToDouble ((bool) arg);
163                         throw new ArgumentException ();
164                 }
165         }
166
167         internal abstract class XPathFunction : IXsltContextFunction
168         {
169                 public abstract XPathResultType ReturnType { get; }
170                 public abstract int Minargs { get; }
171                 public abstract int Maxargs { get; }
172                 public abstract XPathResultType [] ArgTypes { get; }
173                 public object Invoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
174                 {
175                         return TypesafeInvoke (xsltContext, args, docContext);
176                 }
177
178                 public abstract string Name { get; }
179                 public abstract object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext);
180         }
181
182         internal class XPathFunctionLast : XPathFunction
183         {
184                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
185                 public override int Minargs { get { return 0; }}
186                 public override int Maxargs { get { return 0; }}
187                 public override XPathResultType [] ArgTypes { get { return null; }}
188                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
189                 {
190                         throw new NotImplementedException ();   // special-cased
191                 }
192                 public override string Name { get { return "last"; }}
193         }
194         internal class XPathFunctionPosition : XPathFunction
195         {
196                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
197                 public override int Minargs { get { return 0; }}
198                 public override int Maxargs { get { return 0; }}
199                 public override XPathResultType [] ArgTypes { get { return null; }}
200                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
201                 {
202                         throw new NotImplementedException ();   // special-cased
203                 }
204                 public override string Name { get { return "position"; }}
205         }
206         internal class XPathFunctionCount : XPathFunction
207         {
208                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
209                 public override int Minargs { get { return 1; }}
210                 public override int Maxargs { get { return 1; }}
211                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
212                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
213                 {
214                         return ((BaseIterator) args [0]).Count;
215                 }
216                 public override string Name { get { return "count"; }}
217         }
218         internal class XPathFunctionId : XPathFunction
219         {
220                 private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
221                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
222                 public override int Minargs { get { return 1; }}
223                 public override int Maxargs { get { return 1; }}
224                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
225                 [MonoTODO]
226                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
227                 {
228                         String strArgs;
229                         BaseIterator iter = args [0] as BaseIterator;
230                         if (iter != null)
231                         {
232                                 strArgs = "";
233                                 while (!iter.MoveNext ())
234                                         strArgs += iter.Current.Value + " ";
235                         }
236                         else
237                                 strArgs = XPathFunctions.ToString (args [0]);
238                         string [] rgstrArgs = strArgs.Split (rgchWhitespace);
239                         ArrayList rgNodes = new ArrayList ();
240                         foreach (string strArg in rgstrArgs)
241                         {
242                                 if (docContext.MoveToId (strArg))
243                                         rgNodes.Add (docContext.Clone ());
244                         }
245                         return new ArrayListIterator (iter, rgNodes);
246                 }
247                 public override string Name { get { return "id"; }}
248         }
249         internal class XPathFunctionLocalName : XPathFunction
250         {
251                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
252                 public override int Minargs { get { return 0; }}
253                 public override int Maxargs { get { return 1; }}
254                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
255                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
256                 {
257                         BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
258                         if (iter == null || !iter.MoveNext ())
259                                 return "";
260                         return iter.Current.LocalName;
261                 }
262                 public override string Name { get { return "local-name"; }}
263         }
264         internal class XPathFunctionNamespaceUri : XPathFunction
265         {
266                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
267                 public override int Minargs { get { return 0; }}
268                 public override int Maxargs { get { return 1; }}
269                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
270                 [MonoTODO]
271                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
272                 {
273                         BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
274                         if (iter == null || !iter.MoveNext ())
275                                 return "";
276                         return iter.Current.NamespaceURI;       // TODO: should the namespace be expanded wrt. the given context?
277                 }
278                 public override string Name { get { return "namespace-uri"; }}
279         }
280         internal class XPathFunctionName : XPathFunction
281         {
282                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
283                 public override int Minargs { get { return 0; }}
284                 public override int Maxargs { get { return 1; }}
285                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
286                 [MonoTODO]
287                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
288                 {
289                         BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
290                         if (iter == null || !iter.MoveNext ())
291                                 return "";
292                         return iter.Current.Name;
293                 }
294                 public override string Name { get { return "name"; }}
295         }
296         internal class XPathFunctionString : XPathFunction
297         {
298                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
299                 public override int Minargs { get { return 0; }}
300                 public override int Maxargs { get { return 1; }}
301                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
302                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
303                 {
304                         return XPathFunctions.ToString (args [0]);
305                 }
306                 public override string Name { get { return "string"; }}
307         }
308         internal class XPathFunctionConcat : XPathFunction
309         {
310                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
311                 public override int Minargs { get { return 2; }}
312                 public override int Maxargs { get { return int.MaxValue; }}
313                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
314                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
315                 {
316                         String str = "";
317                         foreach (string strArg in args)
318                                 str += strArg;
319                         return str;
320                 }
321                 public override string Name { get { return "concat"; }}
322         }
323         internal class XPathFunctionStartsWith : XPathFunction
324         {
325                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
326                 public override int Minargs { get { return 2; }}
327                 public override int Maxargs { get { return 2; }}
328                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
329                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
330                 {
331                         string str1 = (string) args [0];
332                         string str2 = (string) args [1];
333                         return str1.StartsWith (str2);
334                 }
335                 public override string Name { get { return "starts-with"; }}
336         }
337         internal class XPathFunctionContains : XPathFunction
338         {
339                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
340                 public override int Minargs { get { return 2; }}
341                 public override int Maxargs { get { return 2; }}
342                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
343                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
344                 {
345                         string str1 = (string) args [0];
346                         string str2 = (string) args [1];
347                         return str1.IndexOf (str2) != -1;
348                 }
349                 public override string Name { get { return "contains"; }}
350         }
351         internal class XPathFunctionSubstringBefore : XPathFunction
352         {
353                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
354                 public override int Minargs { get { return 2; }}
355                 public override int Maxargs { get { return 2; }}
356                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
357                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
358                 {
359                         string str1 = (string) args [0];
360                         string str2 = (string) args [1];
361                         int ich = str1.IndexOf (str2);
362                         if (ich <= 0)
363                                 return "";
364                         return str1.Substring (0, ich);
365                 }
366                 public override string Name { get { return "substring-before"; }}
367         }
368         internal class XPathFunctionSubstringAfter : XPathFunction
369         {
370                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
371                 public override int Minargs { get { return 2; }}
372                 public override int Maxargs { get { return 2; }}
373                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
374                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
375                 {
376                         string str1 = (string) args [0];
377                         string str2 = (string) args [1];
378                         int ich = str1.IndexOf (str2);
379                         if (ich <= 0)
380                                 return "";
381                         return str1.Substring (ich + str2.Length);
382                 }
383                 public override string Name { get { return "substring-after"; }}
384         }
385         internal class XPathFunctionSubstring : XPathFunction
386         {
387                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
388                 public override int Minargs { get { return 2; }}
389                 public override int Maxargs { get { return int.MaxValue; }}
390                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
391                 [MonoTODO]
392                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
393                 {
394                         // TODO: check this, what the hell were they smoking?
395                         string str = (string) args [0];
396                         double ich = Math.Round ((double) args [1]) - 1;
397                         if (Double.IsNaN (ich) || ich >= (double) str.Length)
398                                 return "";
399
400                         if (args.Length == 2)
401                         {
402                                 if (ich < 0)
403                                         ich = 0.0;
404                                 return str.Substring ((int) ich);
405                         }
406                         else
407                         {
408                                 double cch = Math.Round ((double) args [2]);
409                                 if (Double.IsNaN (cch))
410                                         return "";
411                                 if (ich < 0.0 || cch < 0.0) 
412                                 {
413                                         cch = ich + cch;
414                                         if (cch <= 0.0)
415                                                 return "";
416                                         ich = 0.0;
417                                 }
418                                 double cchMax = (double) str.Length - ich;
419                                 if (cch > cchMax)
420                                         cch = cchMax;
421                                 return str.Substring ((int) ich, (int) cch);
422                         }
423                 }
424                 public override string Name { get { return "substring"; }}
425         }
426         internal class XPathFunctionStringLength : XPathFunction
427         {
428                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
429                 public override int Minargs { get { return 0; }}
430                 public override int Maxargs { get { return 1; }}
431                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
432                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
433                 {
434                         string str;
435                         if (args.Length == 1)
436                                 str = (string) args [0];
437                         else
438                                 str = docContext.Value;
439                         return (double) str.Length;
440                 }
441                 public override string Name { get { return "string-length"; }}
442         }
443         internal class XPathFunctionNormalizeSpace : XPathFunction
444         {
445                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
446                 public override int Minargs { get { return 0; }}
447                 public override int Maxargs { get { return 1; }}
448                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
449                 [MonoTODO]
450                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
451                 {
452                         string str;
453                         if (args.Length == 1)
454                                 str = (string) args [0];
455                         else
456                                 str = docContext.Value;
457                         System.Text.StringBuilder sb = new System.Text.StringBuilder ();
458                         bool fSpace = false;
459                         foreach (char ch in str)
460                         {
461                                 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
462                                 {
463                                         fSpace = true;
464                                 }
465                                 else
466                                 {
467                                         if (fSpace)
468                                         {
469                                                 fSpace = false;
470                                                 if (sb.Length > 0)
471                                                         sb.Append (' ');
472                                         }
473                                         sb.Append (ch);
474                                 }
475                         }
476                         return sb.ToString ();
477                 }
478                 public override string Name { get { return "normalize-space"; }}
479         }
480         internal class XPathFunctionTranslate : XPathFunction
481         {
482                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
483                 public override int Minargs { get { return 3; }}
484                 public override int Maxargs { get { return 3; }}
485                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
486                 [MonoTODO]
487                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
488                 {
489                         throw new NotImplementedException ();
490                 }
491                 public override string Name { get { return "translate"; }}
492         }
493         internal class XPathFunctionBoolean : XPathFunction
494         {
495                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
496                 public override int Minargs { get { return 1; }}
497                 public override int Maxargs { get { return 1; }}
498                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
499                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
500                 {
501                         return XPathFunctions.ToBoolean (args [0]);
502                 }
503                 public override string Name { get { return "boolean"; }}
504         }
505         internal class XPathFunctionNot : XPathFunction
506         {
507                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
508                 public override int Minargs { get { return 1; }}
509                 public override int Maxargs { get { return 1; }}
510                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Boolean }; }}
511                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
512                 {
513                         return !((bool) args [0]);
514                 }
515                 public override string Name { get { return "not"; }}
516         }
517         internal class XPathFunctionTrue : XPathFunction
518         {
519                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
520                 public override int Minargs { get { return 0; }}
521                 public override int Maxargs { get { return 0; }}
522                 public override XPathResultType [] ArgTypes { get { return null; }}
523                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
524                 {
525                         return true;
526                 }
527                 public override string Name { get { return "true"; }}
528         }
529         internal class XPathFunctionFalse : XPathFunction
530         {
531                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
532                 public override int Minargs { get { return 0; }}
533                 public override int Maxargs { get { return 0; }}
534                 public override XPathResultType [] ArgTypes { get { return null; }}
535                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
536                 {
537                         return false;
538                 }
539                 public override string Name { get { return "false"; }}
540         }
541         internal class XPathFunctionLang : XPathFunction
542         {
543                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
544                 public override int Minargs { get { return 1; }}
545                 public override int Maxargs { get { return 1; }}
546                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
547                 [MonoTODO]
548                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
549                 {
550                         throw new NotImplementedException ();
551                 }
552                 public override string Name { get { return "lang"; }}
553         }
554         internal class XPathFunctionNumber : XPathFunction
555         {
556                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
557                 public override int Minargs { get { return 0; }}
558                 public override int Maxargs { get { return 1; }}
559                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
560                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
561                 {
562                         return XPathFunctions.ToNumber (args [0]);
563                 }
564                 public override string Name { get { return "number"; }}
565         }
566         internal class XPathFunctionSum : XPathFunction
567         {
568                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
569                 public override int Minargs { get { return 1; }}
570                 public override int Maxargs { get { return 1; }}
571                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
572                 [MonoTODO]
573                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
574                 {
575                         throw new NotImplementedException ();
576                 }
577                 public override string Name { get { return "sum"; }}
578         }
579         internal class XPathFunctionFloor : XPathFunction
580         {
581                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
582                 public override int Minargs { get { return 1; }}
583                 public override int Maxargs { get { return 1; }}
584                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
585                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
586                 {
587                         return Math.Floor ((double) args [0]);
588                 }
589                 public override string Name { get { return "floor"; }}
590         }
591         internal class XPathFunctionCeil : XPathFunction
592         {
593                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
594                 public override int Minargs { get { return 1; }}
595                 public override int Maxargs { get { return 1; }}
596                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
597                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
598                 {
599                         return Math.Ceiling ((double) args [0]);
600                 }
601                 public override string Name { get { return "ceil"; }}
602         }
603         internal class XPathFunctionRound : XPathFunction
604         {
605                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
606                 public override int Minargs { get { return 1; }}
607                 public override int Maxargs { get { return 1; }}
608                 public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
609                 public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
610                 {
611                         double arg = (double) args [0];
612                         if (arg < -0.5 || arg > 0)
613                                 return Math.Floor (arg + 0.5);
614                         return Math.Round (arg);
615                 }
616                 public override string Name { get { return "round"; }}
617         }
618 }