2004-06-18 Atsushi Enomoto <atsushi@ximian.com>
[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.Globalization;\r
12 using System.Xml;
13 using System.Xml.XPath;
14 using System.Xml.Xsl;
15 using System.Text;
16
17 namespace System.Xml.XPath
18 {
19         internal class XPathFunctions
20         {
21                 public static bool ToBoolean (object arg)
22                 {
23                         if (arg == null)
24                                 throw new ArgumentNullException ();
25                         if (arg is bool)
26                                 return (bool) arg;
27                         if (arg is double)
28                         {
29                                 double dArg = (double) arg;
30                                 return (dArg != 0.0 && !double.IsNaN (dArg));
31                         }
32                         if (arg is string)
33                                 return ((string) arg).Length != 0;
34                         if (arg is BaseIterator)
35                         {
36                                 BaseIterator iter = (BaseIterator) arg;
37                                 return iter.MoveNext ();
38                         }
39                         if (arg is XPathNavigator)
40                         {
41                                 return ToBoolean (((XPathNavigator) arg).SelectChildren (XPathNodeType.All));
42                         }
43                         throw new ArgumentException ();
44                 }
45
46                 public static bool ToBoolean (bool b)
47                 {
48                         return b;
49                 }
50
51                 public static bool ToBoolean (double d)
52                 {
53                         return d != 0.0 && d != double.NaN;
54                 }
55
56                 public static bool ToBoolean (string s)
57                 {
58                         return s != null && s.Length > 0;
59                 }
60
61                 public static bool ToBoolean (BaseIterator iter)
62                 {
63                         return iter != null && iter.MoveNext ();
64                 }
65
66                 public static string ToString (object arg)
67                 {
68                         if (arg == null)
69                                 throw new ArgumentNullException ();
70                         if (arg is string)
71                                 return (string) arg;
72                         if (arg is bool)
73                                 return ((bool) arg) ? "true" : "false";
74                         if (arg is double)
75                                 return ((double) arg).ToString ("R", System.Globalization.NumberFormatInfo.InvariantInfo);
76                         if (arg is BaseIterator)
77                         {
78                                 BaseIterator iter = (BaseIterator) arg;
79                                 if (!iter.MoveNext ())
80                                         return "";
81                                 return iter.Current.Value;
82                         }
83                         if (arg is XPathNavigator)
84                         {
85                                 return ((XPathNavigator) arg).Value;
86                         }
87                         throw new ArgumentException ();
88                 }
89
90                 public static double ToNumber (object arg)
91                 {
92                         if (arg == null)
93                                 throw new ArgumentNullException ();
94                         if (arg is BaseIterator || arg is XPathNavigator)
95                                 arg = ToString (arg);   // follow on
96                         if (arg is string) {
97                                 string s = arg as string;
98                                 return ToNumber (s); // use explicit overload
99                         }
100                         if (arg is double)
101                                 return (double) arg;
102                         if (arg is bool)
103                                 return Convert.ToDouble ((bool) arg);
104                         throw new ArgumentException ();
105                 }
106                 
107                 public static double ToNumber (string arg)
108                 {
109                         if (arg == null)
110                                 throw new ArgumentNullException ();
111                         string s = arg.Trim (XmlChar.WhitespaceChars);
112                         if (s.Length == 0)
113                                 return double.NaN;
114                         try {
115                                 return XmlConvert.ToDouble (s);
116                         } catch (System.OverflowException) {
117                                 return double.NaN;
118                         } catch (System.FormatException) {
119                                 return double.NaN;
120                         }
121                 }
122         }
123
124         internal abstract class XPathFunction : Expression
125         {
126                 public XPathFunction (FunctionArguments args) {}
127         }
128
129
130         internal class XPathFunctionLast : XPathFunction
131         {
132                 public XPathFunctionLast (FunctionArguments args) : base (args)
133                 {
134                         if (args != null)
135                                 throw new XPathException ("last takes 0 args");
136                 }
137                 
138                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
139
140                 public override object Evaluate (BaseIterator iter)
141                 {
142                         return (double) iter.Count;
143                 }
144
145                 public override string ToString ()
146                 {
147                         return "last()";
148                 }
149
150                 internal override bool IsPositional {
151                         get { return true; }
152                 }
153         }
154
155
156         internal class XPathFunctionPosition : XPathFunction
157         {
158                 public XPathFunctionPosition (FunctionArguments args) : base (args)
159                 {
160                         if (args != null)
161                                 throw new XPathException ("position takes 0 args");
162                 }
163                 
164                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
165
166                 public override object Evaluate (BaseIterator iter)
167                 {
168                         return (double) iter.CurrentPosition;
169                 }
170
171                 public override string ToString ()
172                 {
173                         return "position()";
174                 }
175
176                 internal override bool IsPositional {
177                         get { return true; }
178                 }
179         }
180
181
182         internal class XPathFunctionCount : XPathFunction
183         {
184                 Expression arg0;
185                 
186                 public XPathFunctionCount (FunctionArguments args) : base (args)
187                 {
188                         if (args == null || args.Tail != null)
189                                 throw new XPathException ("count takes 1 arg");
190                         
191                         arg0 = args.Arg;
192                 }
193
194                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
195                 
196                 public override object Evaluate (BaseIterator iter)
197                 {
198                         return (double) arg0.EvaluateNodeSet (iter).Count;
199                 }
200                 
201                 public override bool EvaluateBoolean (BaseIterator iter)
202                 {
203                         if (arg0.GetReturnType (iter) == XPathResultType.NodeSet)
204                                 return arg0.EvaluateBoolean (iter);
205                         
206                         return arg0.EvaluateNodeSet (iter).MoveNext ();
207                 }
208
209                 public override string ToString ()
210                 {
211                         return "count(" + arg0.ToString () + ")";
212                 }
213         }
214
215
216         internal class XPathFunctionId : XPathFunction
217         {
218                 Expression arg0;
219                 
220                 public XPathFunctionId (FunctionArguments args) : base (args)
221                 {
222                         if (args == null || args.Tail != null)
223                                 throw new XPathException ("id takes 1 arg");
224                         
225                         arg0 = args.Arg;
226                 }
227
228                 public Expression Id { get { return arg0; } }
229                 
230                 private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
231                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
232
233                 public override object Evaluate (BaseIterator iter)
234                 {
235                         String strArgs;
236                         object val = arg0.Evaluate (iter);
237                         
238                         BaseIterator valItr = val as BaseIterator;
239                         if (valItr != null)
240                         {
241                                 strArgs = "";
242                                 while (valItr.MoveNext ())
243                                         strArgs += valItr.Current.Value + " ";
244                         }
245                         else
246                                 strArgs = XPathFunctions.ToString (val);
247                         
248                         XPathNavigator n = iter.Current.Clone ();
249                         ArrayList rgNodes = new ArrayList ();
250                         string [] ids = strArgs.Split (rgchWhitespace);
251                         for (int i = 0; i < ids.Length; i++)
252                                 if (n.MoveToId (ids [i]))
253                                         rgNodes.Add (n.Clone ());
254
255                         rgNodes.Sort (XPathNavigatorComparer.Instance);
256                         return new ListIterator (iter, rgNodes, true);
257                 }
258
259                 public override string ToString ()
260                 {
261                         return "id(" + arg0.ToString () + ")";
262                 }
263         }
264
265         internal class XPathFunctionLocalName : XPathFunction
266         {
267                 Expression arg0;
268                 
269                 public XPathFunctionLocalName (FunctionArguments args) : base (args)
270                 {
271                         if (args != null) {
272                                 arg0 = args.Arg;
273                                 if (args.Tail != null)
274                                         throw new XPathException ("local-name takes 1 or zero args");
275                         }
276                 }
277                 
278                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
279                 
280                 public override object Evaluate (BaseIterator iter)
281                 {
282                         if (arg0 == null)
283                                 return iter.Current.LocalName;
284                         
285                         BaseIterator argNs = arg0.EvaluateNodeSet (iter);
286                         if (argNs == null || !argNs.MoveNext ())
287                                 return "";
288                         return argNs.Current.LocalName;
289                 }
290
291                 public override string ToString ()
292                 {
293                         return "local-name(" + arg0.ToString () + ")";
294                 }
295         }
296
297
298         internal class XPathFunctionNamespaceUri : XPathFunction
299         {
300                 Expression arg0;
301                 
302                 public XPathFunctionNamespaceUri (FunctionArguments args) : base (args)
303                 {
304                         if (args != null) {
305                                 arg0 = args.Arg;
306                                 if (args.Tail != null)
307                                         throw new XPathException ("namespace-uri takes 1 or zero args");
308                         }
309                 }
310                 
311                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
312                 
313                 public override object Evaluate (BaseIterator iter)
314                 {
315                         if (arg0 == null)
316                                 return iter.Current.NamespaceURI;
317                         
318                         BaseIterator argNs = arg0.EvaluateNodeSet (iter);
319                         if (argNs == null || !argNs.MoveNext ())
320                                 return "";
321                         return argNs.Current.NamespaceURI;
322                 }
323
324                 public override string ToString ()
325                 {
326                         return "namespace-uri(" + arg0.ToString () + ")";
327                 }
328         }
329
330
331         internal class XPathFunctionName : XPathFunction
332         {
333                 Expression arg0;
334                 
335                 public XPathFunctionName (FunctionArguments args) : base (args)
336                 {
337                         if (args != null) {
338                                 arg0 = args.Arg;
339                                 if (args.Tail != null)
340                                         throw new XPathException ("name takes 1 or zero args");
341                         }
342                 }
343                 
344                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
345                 
346                 public override object Evaluate (BaseIterator iter)
347                 {
348                         if (arg0 == null)
349                                 return iter.Current.Name;
350                         
351                         BaseIterator argNs = arg0.EvaluateNodeSet (iter);
352                         if (argNs == null || !argNs.MoveNext ())
353                                 return "";
354                         return argNs.Current.Name;
355                 }
356
357                 public override string ToString ()
358                 {
359                         return "name(" + arg0.ToString () + ")";
360                 }
361         }
362
363
364         internal class XPathFunctionString : XPathFunction
365         {
366                 Expression arg0;
367                 
368                 public XPathFunctionString (FunctionArguments args) : base (args)
369                 {
370                         if (args != null) {
371                                 arg0 = args.Arg;
372                                 if (args.Tail != null)
373                                         throw new XPathException ("boolean takes 1 or zero args");
374                         }
375                 }
376                 
377                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
378
379                 public override object Evaluate (BaseIterator iter)
380                 {
381                         if (arg0 == null)
382                                 return iter.Current.Value;
383                         return arg0.EvaluateString (iter);
384                 }
385
386                 public override string ToString ()
387                 {
388                         return "string(" + arg0.ToString () + ")";
389                 }
390         }
391
392
393         internal class XPathFunctionConcat : XPathFunction
394         {
395                 ArrayList rgs;
396                 
397                 public XPathFunctionConcat (FunctionArguments args) : base (args)
398                 {
399                         if (args == null || args.Tail == null)
400                                 throw new XPathException ("concat takes 2 or more args");
401                         
402                         args.ToArrayList (rgs = new ArrayList ());
403                 }
404                 
405                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
406                 
407                 public override object Evaluate (BaseIterator iter)
408                 {
409                         StringBuilder sb = new StringBuilder ();
410                         
411                         int len = rgs.Count;
412                         for (int i = 0; i < len; i++)
413                                 sb.Append (((Expression)rgs[i]).EvaluateString (iter));
414                         
415                         return sb.ToString ();
416                 }
417
418                 public override string ToString ()
419                 {
420                         StringBuilder sb = new StringBuilder ();
421                         sb.Append ("concat(");
422                         for (int i = 0; i < rgs.Count - 1; i++) {
423                                 sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [i].ToString ());
424                                 sb.Append (',');
425                         }
426                         sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [rgs.Count - 1].ToString ());
427                         sb.Append (')');
428                         return sb.ToString ();
429                 }
430         }
431
432
433         internal class XPathFunctionStartsWith : XPathFunction
434         {
435                 Expression arg0, arg1;
436                 
437                 public XPathFunctionStartsWith (FunctionArguments args) : base (args)
438                 {
439                         if (args == null || args.Tail == null || args.Tail.Tail != null)
440                                 throw new XPathException ("starts-with takes 2 args");
441                         
442                         arg0 = args.Arg;
443                         arg1 = args.Tail.Arg;
444                 }
445                 
446                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
447                 
448                 public override object Evaluate (BaseIterator iter)
449                 {
450                         return arg0.EvaluateString (iter).StartsWith (arg1.EvaluateString (iter));
451                 }
452
453                 public override string ToString ()
454                 {
455                         return String.Concat ("starts-with(", arg0.ToString (), ",", arg1.ToString (), ")");
456                 }
457         }
458
459
460         internal class XPathFunctionContains : XPathFunction
461         {
462                 Expression arg0, arg1;
463                 
464                 public XPathFunctionContains (FunctionArguments args) : base (args)
465                 {
466                         if (args == null || args.Tail == null || args.Tail.Tail != null)
467                                 throw new XPathException ("contains takes 2 args");
468                         
469                         arg0 = args.Arg;
470                         arg1 = args.Tail.Arg;
471                 }
472                 
473                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
474                 
475                 public override object Evaluate (BaseIterator iter)
476                 {
477                         return arg0.EvaluateString (iter).IndexOf (arg1.EvaluateString (iter)) != -1;
478                 }
479
480                 public override string ToString ()
481                 {
482                         return String.Concat ("contains(", arg0.ToString (), ",", arg1.ToString (), ")");
483                 }
484         }
485
486
487         internal class XPathFunctionSubstringBefore : XPathFunction
488         {
489                 Expression arg0, arg1;
490                 
491                 public XPathFunctionSubstringBefore (FunctionArguments args) : base (args)
492                 {
493                         if (args == null || args.Tail == null || args.Tail.Tail != null)
494                                 throw new XPathException ("substring-before takes 2 args");
495                         
496                         arg0 = args.Arg;
497                         arg1 = args.Tail.Arg;
498                 }
499                 
500                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
501                 
502                 public override object Evaluate (BaseIterator iter)
503                 {
504                         string str1 = arg0.EvaluateString (iter);
505                         string str2 = arg1.EvaluateString (iter);
506                         int ich = str1.IndexOf (str2);
507                         if (ich <= 0)
508                                 return "";
509                         return str1.Substring (0, ich);
510                 }
511
512                 public override string ToString ()
513                 {
514                         return String.Concat ("substring-before(", arg0.ToString (), ",", arg1.ToString (), ")");
515                 }
516         }
517
518
519         internal class XPathFunctionSubstringAfter : XPathFunction
520         {
521                 Expression arg0, arg1;
522                 
523                 public XPathFunctionSubstringAfter (FunctionArguments args) : base (args)
524                 {
525                         if (args == null || args.Tail == null || args.Tail.Tail != null)
526                                 throw new XPathException ("substring-after takes 2 args");
527                         
528                         arg0 = args.Arg;
529                         arg1 = args.Tail.Arg;
530                 }
531                 
532                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
533                 
534                 public override object Evaluate (BaseIterator iter)
535                 {
536                         string str1 = arg0.EvaluateString (iter);
537                         string str2 = arg1.EvaluateString (iter);
538                         int ich = str1.IndexOf (str2);
539                         if (ich < 0)
540                                 return "";
541                         return str1.Substring (ich + str2.Length);
542                 }
543
544                 public override string ToString ()
545                 {
546                         return String.Concat ("substring-after(", arg0.ToString (), ",", arg1.ToString (), ")");
547                 }
548         }
549
550
551         internal class XPathFunctionSubstring : XPathFunction
552         {
553                 Expression arg0, arg1, arg2;
554                 
555                 public XPathFunctionSubstring (FunctionArguments args) : base (args)
556                 {
557                         if (args == null || args.Tail == null || (args.Tail.Tail != null && args.Tail.Tail.Tail != null))
558                                 throw new XPathException ("substring takes 2 or 3 args");
559                         
560                         arg0 = args.Arg;
561                         arg1 = args.Tail.Arg;
562                         if (args.Tail.Tail != null)
563                                 arg2= args.Tail.Tail.Arg;
564                 }
565                 
566                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
567                 
568                 public override object Evaluate (BaseIterator iter)
569                 {
570                         string str = arg0.EvaluateString (iter);
571                         double ich = Math.Round (arg1.EvaluateNumber (iter)) - 1;
572                         if (Double.IsNaN (ich) ||
573                                 Double.IsNegativeInfinity (ich) ||
574                                 ich >= (double) str.Length)
575                                 return "";
576
577                         if (arg2 == null)
578                         {
579                                 if (ich < 0)
580                                         ich = 0.0;
581                                 return str.Substring ((int) ich);
582                         }
583                         else
584                         {
585                                 double cch = Math.Round (arg2.EvaluateNumber (iter));
586                                 if (Double.IsNaN (cch))
587                                         return "";
588                                 if (ich < 0.0 || cch < 0.0) 
589                                 {
590                                         cch = ich + cch;
591                                         if (cch <= 0.0)
592                                                 return "";
593                                         ich = 0.0;
594                                 }
595                                 double cchMax = (double) str.Length - ich;
596                                 if (cch > cchMax)
597                                         cch = cchMax;
598                                 return str.Substring ((int) ich, (int) cch);
599                         }
600                 }
601
602                 public override string ToString ()
603                 {
604                         return String.Concat (new string [] {
605                                 "substring(", arg0.ToString (), ",", arg1.ToString (), ",", arg2.ToString (), ")"});
606                 }
607         }
608
609
610         internal class XPathFunctionStringLength : XPathFunction
611         {
612                 Expression arg0;
613                 
614                 public XPathFunctionStringLength (FunctionArguments args) : base (args)
615                 {
616                         if (args != null) {
617                                 arg0 = args.Arg;
618                                 if (args.Tail != null)
619                                         throw new XPathException ("string-length takes 1 or zero args");
620                         }
621                 }
622                 
623                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
624                 
625                 public override object Evaluate (BaseIterator iter)
626                 {
627                         string str;
628                         if (arg0 != null)
629                                 str = arg0.EvaluateString (iter);
630                         else
631                                 str = iter.Current.Value;
632                         return (double) str.Length;
633                 }
634
635                 public override string ToString ()
636                 {
637                         return String.Concat (new string [] {
638                                 "string-length(", arg0.ToString (), ")"});
639                 }
640         }
641
642
643         internal class XPathFunctionNormalizeSpace : XPathFunction
644         {
645                 Expression arg0;
646                 
647                 public XPathFunctionNormalizeSpace (FunctionArguments args) : base (args)
648                 {
649                         if (args != null) {
650                                 arg0 = args.Arg;
651                                 if (args.Tail != null)
652                                         throw new XPathException ("normalize-space takes 1 or zero args");
653                         }
654                 }
655                 
656                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
657
658                 public override object Evaluate (BaseIterator iter)
659                 {
660                         string str;
661                         if (arg0 != null)
662                                 str = arg0.EvaluateString (iter);
663                         else
664                                 str = iter.Current.Value;
665                         System.Text.StringBuilder sb = new System.Text.StringBuilder ();
666                         bool fSpace = false;
667                         for (int i = 0; i < str.Length; i++) {
668                                 char ch = str [i];
669                                 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
670                                 {
671                                         fSpace = true;
672                                 }
673                                 else
674                                 {
675                                         if (fSpace)
676                                         {
677                                                 fSpace = false;
678                                                 if (sb.Length > 0)
679                                                         sb.Append (' ');
680                                         }
681                                         sb.Append (ch);
682                                 }
683                         }
684                         return sb.ToString ();
685                 }
686
687                 public override string ToString ()
688                 {
689                         return String.Concat (new string [] {
690                                 "normalize-space(",
691                                 arg0 != null ? arg0.ToString () : String.Empty,
692                                 ")"});
693                 }
694         }
695
696
697         internal class XPathFunctionTranslate : XPathFunction
698         {
699                 Expression arg0, arg1, arg2;
700                 
701                 public XPathFunctionTranslate (FunctionArguments args) : base (args)
702                 {
703                         if (args == null || args.Tail == null || args.Tail.Tail == null || args.Tail.Tail.Tail != null)
704                                 throw new XPathException ("translate takes 3 args");
705                         
706                         arg0 = args.Arg;
707                         arg1 = args.Tail.Arg;
708                         arg2= args.Tail.Tail.Arg;
709                 }
710                 
711                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
712                 
713                 public override object Evaluate (BaseIterator iter)
714                 {
715                         string s0 = arg0.EvaluateString (iter);
716                         string s1 = arg1.EvaluateString (iter);
717                         string s2 = arg2.EvaluateString (iter);
718                         
719                         StringBuilder ret = new StringBuilder (s0.Length);
720                                 
721                         int pos = 0, len = s0.Length, s2len = s2.Length;
722                         
723                         while (pos < len) {
724                                 int idx = s1.IndexOf (s0 [pos]);
725                                 
726                                 if (idx != -1) {
727                                         if (idx < s2len)
728                                                 ret.Append (s2 [idx]);
729                                 }
730                                 else
731                                         ret.Append (s0 [pos]);
732                                 
733                                 pos++;
734                         }
735                         
736                         return ret.ToString ();
737                 }
738
739                 public override string ToString ()
740                 {
741                         return String.Concat (new string [] {
742                                 "string-length(",
743                                 arg0.ToString (), ",",
744                                 arg1.ToString (), ",",
745                                 arg2.ToString (), ")"});
746                 }
747         }
748
749
750         internal class XPathFunctionBoolean : XPathFunction
751         {
752                 Expression arg0;
753                 
754                 public XPathFunctionBoolean (FunctionArguments args) : base (args)
755                 {
756                         if (args != null) {
757                                 arg0 = args.Arg;
758                                 if (args.Tail != null)
759                                         throw new XPathException ("boolean takes 1 or zero args");
760                         }
761                 }
762                 
763                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
764
765                 public override object Evaluate (BaseIterator iter)
766                 {
767                         if (arg0 == null)
768                                 return XPathFunctions.ToBoolean (iter.Current.Value);
769                         return arg0.EvaluateBoolean (iter);
770                 }
771
772                 public override string ToString ()
773                 {
774                         return String.Concat (new string [] {"boolean(", arg0.ToString (), ")"});
775                 }
776         }
777
778
779         internal class XPathFunctionNot : XPathFunction
780         {
781                 Expression arg0;
782                 
783                 public XPathFunctionNot (FunctionArguments args) : base (args)
784                 {
785                         if (args == null || args.Tail != null)
786                                 throw new XPathException ("not takes one arg");
787                         arg0 = args.Arg;
788                 }
789                 
790                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
791
792                 public override object Evaluate (BaseIterator iter)
793                 {
794                         return !arg0.EvaluateBoolean (iter);
795                 }
796
797                 public override string ToString ()
798                 {
799                         return String.Concat (new string [] {"not(", arg0.ToString (), ")"});
800                 }
801         }
802
803
804         internal class XPathFunctionTrue : XPathFunction
805         {
806                 public XPathFunctionTrue (FunctionArguments args) : base (args)
807                 {
808                         if (args != null)
809                                 throw new XPathException ("true takes 0 args");
810                 }
811                 
812                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
813
814                 public override object Evaluate (BaseIterator iter)
815                 {
816                         return true;
817                 }
818
819                 public override string ToString ()
820                 {
821                         return "true()";
822                 }
823         }
824
825
826         internal class XPathFunctionFalse : XPathFunction
827         {
828                 public XPathFunctionFalse (FunctionArguments args) : base (args)
829                 {
830                         if (args != null)
831                                 throw new XPathException ("false takes 0 args");
832                 }
833                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
834
835                 public override object Evaluate (BaseIterator iter)
836                 {
837                         return false;
838                 }
839
840                 public override string ToString ()
841                 {
842                         return "false()";
843                 }
844         }
845
846
847         internal class XPathFunctionLang : XPathFunction
848         {
849                 Expression arg0;
850                 
851                 public XPathFunctionLang (FunctionArguments args) : base (args)
852                 {
853                         if (args == null || args.Tail != null)
854                                 throw new XPathException ("lang takes one arg");
855                         arg0 = args.Arg;
856                 }
857                 
858                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
859
860                 public override object Evaluate (BaseIterator iter)
861                 {
862                         string lang = arg0.EvaluateString (iter).ToLower (CultureInfo.InvariantCulture);
863                         string actualLang = iter.Current.XmlLang.ToLower (CultureInfo.InvariantCulture);
864                         
865                         return lang == actualLang || lang == (actualLang.Split ('-')[0]);
866                 }
867
868                 public override string ToString ()
869                 {
870                         return String.Concat (new string [] {"lang(", arg0.ToString (), ")"});
871                 }
872         }
873
874
875         internal class XPathFunctionNumber : XPathFunction
876         {
877                 Expression arg0;
878                 
879                 public XPathFunctionNumber (FunctionArguments args) : base (args)
880                 {
881                         if (args != null) {
882                                 arg0 = args.Arg;
883                                 if (args.Tail != null)
884                                         throw new XPathException ("number takes 1 or zero args");
885                         }
886                 }
887                 
888                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
889
890                 public override object Evaluate (BaseIterator iter)
891                 {
892                         if (arg0 == null)
893                                 return XPathFunctions.ToNumber (iter.Current.Value);
894                         return arg0.EvaluateNumber (iter);
895                 }
896
897                 public override string ToString ()
898                 {
899                         return String.Concat (new string [] {"number(", arg0.ToString (), ")"});
900                 }
901         }
902
903
904         internal class XPathFunctionSum : XPathFunction
905         {
906                 Expression arg0;
907                 
908                 public XPathFunctionSum (FunctionArguments args) : base (args)
909                 {
910                         if (args == null || args.Tail != null)
911                                 throw new XPathException ("sum takes one arg");
912                         arg0 = args.Arg;
913                 }
914                 
915                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
916
917                 public override object Evaluate (BaseIterator iter)
918                 {
919                         XPathNodeIterator itr = arg0.EvaluateNodeSet (iter);
920                         
921                         double sum = 0;
922                         while (itr.MoveNext ())
923                                 sum += XPathFunctions.ToNumber (itr.Current.Value);
924                         
925                         return sum;
926                 }
927
928                 public override string ToString ()
929                 {
930                         return String.Concat (new string [] {"sum(", arg0.ToString (), ")"});
931                 }
932         }
933
934
935         internal class XPathFunctionFloor : XPathFunction
936         {
937                 Expression arg0;
938                 
939                 public XPathFunctionFloor (FunctionArguments args) : base (args)
940                 {
941                         if (args == null || args.Tail != null)
942                                 throw new XPathException ("floor takes one arg");
943                         arg0 = args.Arg;
944                 }
945                 
946                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
947
948                 public override object Evaluate (BaseIterator iter)
949                 {
950                         return Math.Floor (arg0.EvaluateNumber (iter));
951                 }
952
953                 public override string ToString ()
954                 {
955                         return String.Concat (new string [] {"floor(", arg0.ToString (), ")"});
956                 }
957         }
958
959
960         internal class XPathFunctionCeil : XPathFunction
961         {
962                 Expression arg0;
963                 
964                 public XPathFunctionCeil (FunctionArguments args) : base (args)
965                 {
966                         if (args == null || args.Tail != null)
967                                 throw new XPathException ("ceil takes one arg");
968                         arg0 = args.Arg;
969                 }
970                 
971                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
972
973                 public override object Evaluate (BaseIterator iter)
974                 {
975                         return Math.Ceiling (arg0.EvaluateNumber (iter));
976                 }
977
978                 public override string ToString ()
979                 {
980                         return String.Concat (new string [] {"ceil(", arg0.ToString (), ")"});
981                 }
982         }
983
984
985         internal class XPathFunctionRound : XPathFunction
986         {
987                 Expression arg0;
988                 
989                 public XPathFunctionRound (FunctionArguments args) : base (args)
990                 {
991                         if (args == null || args.Tail != null)
992                                 throw new XPathException ("round takes one arg");
993                         arg0 = args.Arg;
994                 }
995                 
996                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
997
998                 public override object Evaluate (BaseIterator iter)
999                 {
1000                         double arg = arg0.EvaluateNumber (iter);
1001                         if (arg < -0.5 || arg > 0)
1002                                 return Math.Floor (arg + 0.5);
1003                         return Math.Round (arg);
1004                 }
1005
1006                 public override string ToString ()
1007                 {
1008                         return String.Concat (new string [] {"round(", arg0.ToString (), ")"});
1009                 }
1010         }
1011 }