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