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