2 // System.Xml.XPath.XPathExpression support classes
5 // Piers Haken (piersh@friskit.com)
7 // (C) 2002 Piers Haken
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
34 using System.Xml.XPath;
36 using System.Globalization;
39 using NSResolver = System.Xml.IXmlNamespaceResolver;
41 namespace System.Xml.XPath
43 internal static class ExpressionCache
45 static readonly Hashtable table_per_ctx = new Hashtable ();
46 static object dummy = new object ();
47 static object cache_lock = new object ();
49 public static XPathExpression Get (string xpath, IStaticXsltContext ctx)
51 object ctxkey = ctx != null ? ctx : dummy;
54 WeakReference wr = table_per_ctx [ctxkey] as WeakReference;
57 Hashtable table = wr.Target as Hashtable;
59 table_per_ctx [ctxkey] = null;
63 wr = table [xpath] as WeakReference;
65 XPathExpression e = wr.Target as XPathExpression;
74 public static void Set (string xpath, IStaticXsltContext ctx, XPathExpression exp)
76 object ctxkey = ctx != null ? ctx : dummy;
78 Hashtable table = null;
80 WeakReference wr = table_per_ctx [ctxkey] as WeakReference;
81 if (wr != null && wr.IsAlive)
82 table = (Hashtable) wr.Target;
84 table = new Hashtable ();
85 table_per_ctx [ctxkey] = new WeakReference (table);
87 table [xpath] = new WeakReference (exp);
93 internal class CompiledExpression : Test.Xml.XPath.XPathExpression
95 internal class CompiledExpression : XPathExpression
98 protected NSResolver _nsm;
99 protected Expression _expr;
100 XPathSorters _sorters;
101 string rawExpression;
103 public CompiledExpression (string raw, Expression expr)
105 _expr = expr.Optimize ();
108 private CompiledExpression (CompiledExpression other)
112 rawExpression = other.rawExpression;
115 public override Test.Xml.XPath.XPathExpression Clone () { return new CompiledExpression (this); }
117 public override XPathExpression Clone () { return new CompiledExpression (this); }
120 public Expression ExpressionNode { get { return _expr; }}
122 public override void SetContext (XmlNamespaceManager nsManager)
127 public override void SetContext (IXmlNamespaceResolver nsResolver)
132 internal NSResolver NamespaceManager { get { return _nsm; } }
133 public override String Expression { get { return rawExpression; }}
134 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
136 public object Evaluate (BaseIterator iter)
138 if (_sorters != null)
139 return EvaluateNodeSet (iter);
142 return _expr.Evaluate (iter);
145 return _expr.Evaluate (iter);
147 catch (XPathException) {
150 catch (XsltException) {
153 catch (Exception e) {
154 throw new XPathException ("Error during evaluation", e);
158 public XPathNodeIterator EvaluateNodeSet (BaseIterator iter)
164 BaseIterator iterResults = _expr.EvaluateNodeSet (iter);
165 if (_sorters != null)
166 return _sorters.Sort (iterResults);
170 catch (XPathException)
176 throw new XPathException ("Error during evaluation", e);
180 public double EvaluateNumber (BaseIterator iter)
183 return _expr.EvaluateNumber (iter);
187 return _expr.EvaluateNumber (iter);
189 catch (XPathException)
195 throw new XPathException ("Error during evaluation", e);
199 public string EvaluateString (BaseIterator iter)
202 return _expr.EvaluateString (iter);
206 return _expr.EvaluateString (iter);
208 catch (XPathException)
214 throw new XPathException ("Error during evaluation", e);
218 public bool EvaluateBoolean (BaseIterator iter)
221 return _expr.EvaluateBoolean (iter);
225 return _expr.EvaluateBoolean (iter);
227 catch (XPathException)
233 throw new XPathException ("Error during evaluation", e);
238 public override void AddSort (Object obj, IComparer cmp)
240 if (_sorters == null)
241 _sorters = new XPathSorters ();
242 _sorters.Add (obj, cmp);
244 public override void AddSort(object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
246 if (_sorters == null)
247 _sorters = new XPathSorters ();
248 _sorters.Add (expr, orderSort, orderCase, lang, dataType);
253 class XPathSortElement
255 public XPathNavigator Navigator;
256 public object [] Values;
259 class XPathSorters : IComparer
261 readonly ArrayList _rgSorters = new ArrayList ();
263 public void Add (object expr, IComparer cmp)
265 _rgSorters.Add (new XPathSorter (expr, cmp));
268 public void Add (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
270 _rgSorters.Add (new XPathSorter (expr, orderSort, orderCase, lang, dataType));
273 public void CopyFrom (XPathSorter [] sorters)
276 _rgSorters.AddRange (sorters);
279 public BaseIterator Sort (BaseIterator iter)
281 ArrayList rgElts = ToSortElementList (iter);
282 return Sort (rgElts, iter.NamespaceManager);
285 ArrayList ToSortElementList (BaseIterator iter)
287 ArrayList rgElts = new ArrayList ();
288 int cSorters = _rgSorters.Count;
289 while (iter.MoveNext ())
291 XPathSortElement elt = new XPathSortElement ();
292 elt.Navigator = iter.Current.Clone ();
293 elt.Values = new object [cSorters];
294 for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
296 XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
297 elt.Values [iSorter] = sorter.Evaluate (iter);
304 public BaseIterator Sort (ArrayList rgElts, NSResolver nsm)
307 XPathNavigator [] rgResults = new XPathNavigator [rgElts.Count];
308 for (int iResult = 0; iResult < rgElts.Count; ++iResult)
310 XPathSortElement elt = (XPathSortElement) rgElts [iResult];
311 rgResults [iResult] = elt.Navigator;
313 return new ListIterator (rgResults, nsm);
316 int IComparer.Compare (object o1, object o2)
318 XPathSortElement elt1 = (XPathSortElement) o1;
319 XPathSortElement elt2 = (XPathSortElement) o2;
320 for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
322 XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
323 int cmp = sorter.Compare (elt1.Values [iSorter], elt2.Values [iSorter]);
327 switch (elt1.Navigator.ComparePosition (elt2.Navigator)) {
328 case XmlNodeOrder.Same:
330 case XmlNodeOrder.After:
340 readonly Expression _expr;
341 readonly IComparer _cmp;
342 readonly XmlDataType _type;
344 public XPathSorter (object expr, IComparer cmp)
346 _expr = ExpressionFromObject (expr);
348 _type = XmlDataType.Text;
351 public XPathSorter (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
353 _expr = ExpressionFromObject (expr);
355 if (dataType == XmlDataType.Number)
356 _cmp = new XPathNumberComparer (orderSort);
358 _cmp = new XPathTextComparer (orderSort, orderCase, lang);
361 static Expression ExpressionFromObject (object expr)
363 if (expr is CompiledExpression)
364 return ((CompiledExpression) expr).ExpressionNode;
366 return new XPathParser ().Compile ((string)expr);
368 throw new XPathException ("Invalid query object");
371 public object Evaluate (BaseIterator iter)
373 if (_type == XmlDataType.Number)
374 return _expr.EvaluateNumber (iter);
375 return _expr.EvaluateString (iter);
378 public int Compare (object o1, object o2)
380 return _cmp.Compare (o1, o2);
383 class XPathNumberComparer : IComparer
387 public XPathNumberComparer (XmlSortOrder orderSort)
389 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
392 int IComparer.Compare (object o1, object o2)
394 double num1 = (double) o1;
395 double num2 = (double) o2;
402 if (double.IsNaN (num1))
403 return (double.IsNaN (num2)) ? 0 : -_nMulSort;
408 class XPathTextComparer : IComparer
412 XmlCaseOrder _orderCase;
415 public XPathTextComparer (XmlSortOrder orderSort, XmlCaseOrder orderCase, string strLang)
417 _orderCase = orderCase;
418 // FIXME: We have to set this in
419 // reverse order since currently
420 // we don't support collation.
421 _nMulCase = (orderCase == XmlCaseOrder.UpperFirst) ? -1 : 1;
422 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
424 if (strLang == null || strLang == "")
425 _ci = CultureInfo.CurrentCulture; // TODO: defer until evaluation?
427 _ci = new CultureInfo (strLang);
430 int IComparer.Compare (object o1, object o2)
432 string str1 = (string) o1;
433 string str2 = (string) o2;
434 int cmp = String.Compare (str1, str2, true, _ci);
435 if (cmp != 0 || _orderCase == XmlCaseOrder.None)
436 return cmp * _nMulSort;
437 return _nMulSort * _nMulCase * String.Compare (str1, str2, false, _ci);
443 /// Summary description for Expression.
445 internal abstract class Expression
450 public abstract XPathResultType ReturnType { get; }
451 public virtual XPathResultType GetReturnType (BaseIterator iter) { return ReturnType; }
453 public virtual Expression Optimize ()
458 public virtual bool HasStaticValue {
459 get { return false; }
462 public virtual object StaticValue {
464 switch (ReturnType) {
465 case XPathResultType.String:
466 return StaticValueAsString;
467 case XPathResultType.Number:
468 return StaticValueAsNumber;
469 case XPathResultType.Boolean:
470 return StaticValueAsBoolean;
476 public virtual string StaticValueAsString {
477 get { return HasStaticValue ? XPathFunctions.ToString (StaticValue) : null; }
480 public virtual double StaticValueAsNumber {
481 get { return HasStaticValue ? XPathFunctions.ToNumber (StaticValue) : 0; }
484 public virtual bool StaticValueAsBoolean {
485 get { return HasStaticValue ? XPathFunctions.ToBoolean (StaticValue) : false; }
488 public virtual XPathNavigator StaticValueAsNavigator {
489 get { return StaticValue as XPathNavigator; }
492 public abstract object Evaluate (BaseIterator iter);
494 public virtual BaseIterator EvaluateNodeSet (BaseIterator iter)
496 XPathResultType type = GetReturnType (iter);
498 case XPathResultType.NodeSet:
499 case XPathResultType.Any:
500 case XPathResultType.Navigator: // FIXME: It may pass not-allowed use of RTF
501 object o = Evaluate (iter);
502 XPathNodeIterator xi = o as XPathNodeIterator;
503 BaseIterator iterResult = null;
505 iterResult = xi as BaseIterator;
506 if (iterResult == null)
507 iterResult = new WrapperIterator (xi, iter.NamespaceManager);
510 XPathNavigator nav = o as XPathNavigator;
512 XPathNodeIterator xiter = nav.SelectChildren (XPathNodeType.All);
513 iterResult = xiter as BaseIterator;
514 if (iterResult == null && xiter != null)
515 iterResult = new WrapperIterator (xiter, iter.NamespaceManager);
517 if (iterResult != null)
520 return new NullIterator (iter);
521 type = GetReturnType (o);
524 throw new XPathException (String.Format ("expected nodeset but was {1}: {0}", ToString (), type));
527 protected static XPathResultType GetReturnType (object obj)
530 return XPathResultType.String;
532 return XPathResultType.Boolean;
533 if (obj is XPathNodeIterator)
534 return XPathResultType.NodeSet;
535 if (obj is double || obj is int)
536 return XPathResultType.Number;
537 if (obj is XPathNavigator)
538 return XPathResultType.Navigator;
539 throw new XPathException ("invalid node type: "+obj.GetType ().ToString ());
542 internal virtual XPathNodeType EvaluatedNodeType {
543 get { return XPathNodeType.All; }
546 internal virtual bool IsPositional {
547 get { return false; }
550 // For "peer and subtree" optimization. see:
551 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
552 internal virtual bool Peer {
553 get { return false; }
556 public virtual double EvaluateNumber (BaseIterator iter)
559 XPathResultType type = GetReturnType (iter);
560 if (type == XPathResultType.NodeSet)
562 result = EvaluateString (iter);
563 type = XPathResultType.String;
566 result = Evaluate (iter);
568 if (type == XPathResultType.Any)
569 type = GetReturnType (result);
572 case XPathResultType.Number:
573 if (result is double)
574 return (double)result;
575 else if (result is IConvertible)
576 return ((IConvertible) result).ToDouble (CultureInfo.InvariantCulture);
578 return (double) result; // most likely invalid cast
579 case XPathResultType.Boolean:
580 return ((bool) result) ? 1.0 : 0.0;
581 case XPathResultType.NodeSet:
582 return XPathFunctions.ToNumber (EvaluateString (iter));
583 case XPathResultType.String:
584 return XPathFunctions.ToNumber ((string) result);
585 case XPathResultType.Navigator:
586 return XPathFunctions.ToNumber (((XPathNavigator) (result)).Value);
588 throw new XPathException ("invalid node type");
592 public virtual string EvaluateString (BaseIterator iter)
594 object result = Evaluate (iter);
595 XPathResultType type = GetReturnType (iter);
596 if (type == XPathResultType.Any)
597 type = GetReturnType (result);
599 case XPathResultType.Number:
600 double d = (double) result;
601 return XPathFunctions.ToString (d);
602 case XPathResultType.Boolean:
603 return ((bool) result) ? "true" : "false";
604 case XPathResultType.String:
605 return (string) result;
606 case XPathResultType.NodeSet:
608 BaseIterator iterResult = (BaseIterator) result;
609 if (iterResult == null || !iterResult.MoveNext ())
611 return iterResult.Current.Value;
613 case XPathResultType.Navigator:
614 return ((XPathNavigator) result).Value;
616 throw new XPathException ("invalid node type");
620 public virtual bool EvaluateBoolean (BaseIterator iter)
622 object result = Evaluate (iter);
623 XPathResultType type = GetReturnType (iter);
624 if (type == XPathResultType.Any)
625 type = GetReturnType (result);
627 case XPathResultType.Number:
628 double num = Convert.ToDouble (result);
629 return (num != 0.0 && num != -0.0 && !Double.IsNaN (num));
630 case XPathResultType.Boolean:
631 return (bool) result;
632 case XPathResultType.String:
633 return ((string) result).Length != 0;
634 case XPathResultType.NodeSet:
635 BaseIterator iterResult = (BaseIterator) result;
636 return (iterResult != null && iterResult.MoveNext ());
637 case XPathResultType.Navigator:
638 return (((XPathNavigator) result).HasChildren);
640 throw new XPathException ("invalid node type");
644 public object EvaluateAs (BaseIterator iter, XPathResultType type)
647 case XPathResultType.Boolean:
648 return EvaluateBoolean (iter);
649 case XPathResultType.NodeSet:
650 return EvaluateNodeSet (iter);
651 case XPathResultType.String:
652 return EvaluateString (iter);
653 case XPathResultType.Number:
654 return EvaluateNumber (iter);
656 return Evaluate (iter);
659 public virtual bool RequireSorting { get { return false; } }
662 internal abstract class ExprBinary : Expression
664 protected Expression _left, _right;
666 public ExprBinary (Expression left, Expression right)
672 public override Expression Optimize ()
674 _left = _left.Optimize ();
675 _right = _right.Optimize ();
679 public override bool HasStaticValue {
680 get { return _left.HasStaticValue && _right.HasStaticValue; }
683 public override String ToString ()
685 return _left.ToString () + ' ' + Operator + ' ' + _right.ToString ();
687 protected abstract String Operator { get; }
689 internal override XPathNodeType EvaluatedNodeType {
691 if (_left.EvaluatedNodeType == _right.EvaluatedNodeType)
692 return _left.EvaluatedNodeType;
694 return XPathNodeType.All;
698 internal override bool IsPositional {
699 get { return _left.IsPositional || _right.IsPositional; }
702 internal override bool Peer {
703 get { return _left.Peer && _right.Peer; }
707 internal abstract class ExprBoolean : ExprBinary
709 public ExprBoolean (Expression left, Expression right) : base (left, right) {}
711 public override Expression Optimize ()
716 else if (StaticValueAsBoolean)
717 return new XPathFunctionTrue (null);
719 return new XPathFunctionFalse (null);
722 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
723 public override object Evaluate (BaseIterator iter)
725 return EvaluateBoolean (iter);
727 public override double EvaluateNumber (BaseIterator iter)
729 return EvaluateBoolean (iter) ? 1 : 0;
732 public override string EvaluateString (BaseIterator iter)
734 return EvaluateBoolean (iter) ? "true" : "false";
738 internal class ExprOR : ExprBoolean
740 public ExprOR (Expression left, Expression right) : base (left, right) {}
741 protected override String Operator { get { return "or"; }}
743 public override bool StaticValueAsBoolean {
744 get { return HasStaticValue ? _left.StaticValueAsBoolean || _right.StaticValueAsBoolean : false; }
747 public override bool EvaluateBoolean (BaseIterator iter)
749 if (_left.EvaluateBoolean (iter))
751 return _right.EvaluateBoolean (iter);
755 internal class ExprAND : ExprBoolean
757 public ExprAND (Expression left, Expression right) : base (left, right) {}
758 protected override String Operator { get { return "and"; }}
760 public override bool StaticValueAsBoolean {
761 get { return HasStaticValue ? _left.StaticValueAsBoolean && _right.StaticValueAsBoolean : false; }
764 public override bool EvaluateBoolean (BaseIterator iter)
766 if (!_left.EvaluateBoolean (iter))
768 return _right.EvaluateBoolean (iter);
772 internal abstract class EqualityExpr : ExprBoolean
775 public EqualityExpr (Expression left, Expression right, bool trueVal) : base (left, right)
777 this.trueVal = trueVal;
780 public override bool StaticValueAsBoolean {
784 if ((_left.ReturnType == XPathResultType.Navigator || _right.ReturnType == XPathResultType.Navigator) && _left.ReturnType == _right.ReturnType)
785 return (_left.StaticValueAsNavigator.IsSamePosition (
786 _right.StaticValueAsNavigator))
788 if (_left.ReturnType == XPathResultType.Boolean | _right.ReturnType == XPathResultType.Boolean)
789 return (_left.StaticValueAsBoolean == _right.StaticValueAsBoolean) == trueVal;
790 if (_left.ReturnType == XPathResultType.Number | _right.ReturnType == XPathResultType.Number)
791 return (_left.StaticValueAsNumber == _right.StaticValueAsNumber) == trueVal;
792 if (_left.ReturnType == XPathResultType.String | _right.ReturnType == XPathResultType.String)
793 return (_left.StaticValueAsString == _right.StaticValueAsString) == trueVal;
794 return _left.StaticValue == _right.StaticValue == trueVal;
798 // FIXME: Avoid extraneous evaluation
799 public override bool EvaluateBoolean (BaseIterator iter)
801 XPathResultType typeL = _left.GetReturnType (iter);
802 XPathResultType typeR = _right.GetReturnType (iter);
804 // TODO: avoid double evaluations
805 if (typeL == XPathResultType.Any)
806 typeL = GetReturnType (_left.Evaluate (iter));
807 if (typeR == XPathResultType.Any)
808 typeR = GetReturnType (_right.Evaluate (iter));
810 // Regard RTF as string
811 if (typeL == XPathResultType.Navigator)
812 typeL = XPathResultType.String;
813 if (typeR == XPathResultType.Navigator)
814 typeR = XPathResultType.String;
816 if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
818 Expression left, right;
819 if (typeL != XPathResultType.NodeSet)
823 XPathResultType typeTmp = typeL;
832 if (typeR == XPathResultType.Boolean)
834 return left.EvaluateBoolean (iter) == right.EvaluateBoolean (iter) == trueVal;
838 BaseIterator iterL = left.EvaluateNodeSet (iter);
839 if (typeR == XPathResultType.Number)
841 double dR = right.EvaluateNumber (iter);
842 while (iterL.MoveNext ())
843 if (XPathFunctions.ToNumber (iterL.Current.Value) == dR == trueVal)
846 else if (typeR == XPathResultType.String)
848 string strR = right.EvaluateString (iter);
849 while (iterL.MoveNext ())
850 if (iterL.Current.Value == strR == trueVal)
853 else if (typeR == XPathResultType.NodeSet)
855 BaseIterator iterR = right.EvaluateNodeSet (iter);
856 ArrayList rgNodesL = new ArrayList ();
857 while (iterL.MoveNext ())
858 rgNodesL.Add (XPathFunctions.ToString (iterL.Current.Value));
859 while (iterR.MoveNext ())
861 string strR = XPathFunctions.ToString (iterR.Current.Value);
862 for (int l = 0; l < rgNodesL.Count; l++)
863 if ((strR == (string) rgNodesL [l]) == trueVal)
870 else if (typeL == XPathResultType.Boolean || typeR == XPathResultType.Boolean)
871 return _left.EvaluateBoolean (iter) == _right.EvaluateBoolean (iter) == trueVal;
872 else if (typeL == XPathResultType.Number || typeR == XPathResultType.Number)
873 return _left.EvaluateNumber (iter) == _right.EvaluateNumber (iter) == trueVal;
875 return _left.EvaluateString (iter) == _right.EvaluateString (iter) == trueVal;
879 internal class ExprEQ : EqualityExpr
881 public ExprEQ (Expression left, Expression right) : base (left, right, true) {}
882 protected override String Operator { get { return "="; }}
885 internal class ExprNE : EqualityExpr
887 public ExprNE (Expression left, Expression right) : base (left, right, false) {}
888 protected override String Operator { get { return "!="; }}
891 internal abstract class RelationalExpr : ExprBoolean
893 public RelationalExpr (Expression left, Expression right) : base (left, right) {}
895 public override bool StaticValueAsBoolean {
896 get { return HasStaticValue ? Compare (_left.StaticValueAsNumber, _right.StaticValueAsNumber) : false; }
899 // FIXME: Avoid extraneous evaluation.
900 public override bool EvaluateBoolean (BaseIterator iter)
902 XPathResultType typeL = _left.GetReturnType (iter);
903 XPathResultType typeR = _right.GetReturnType (iter);
905 if (typeL == XPathResultType.Any)
906 typeL = GetReturnType (_left.Evaluate (iter));
907 if (typeR == XPathResultType.Any)
908 typeR = GetReturnType (_right.Evaluate (iter));
910 // Regard RTF as string
911 if (typeL == XPathResultType.Navigator)
912 typeL = XPathResultType.String;
913 if (typeR == XPathResultType.Navigator)
914 typeR = XPathResultType.String;
916 if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
918 bool fReverse = false;
919 Expression left, right;
920 if (typeL != XPathResultType.NodeSet)
925 XPathResultType typeTmp = typeL;
934 if (typeR == XPathResultType.Boolean)
936 bool fL = left.EvaluateBoolean (iter);
937 bool fR = right.EvaluateBoolean (iter);
938 return Compare (Convert.ToDouble (fL), Convert.ToDouble (fR), fReverse);
942 BaseIterator iterL = left.EvaluateNodeSet (iter);
943 if (typeR == XPathResultType.Number || typeR == XPathResultType.String)
945 double dR = right.EvaluateNumber (iter);
946 while (iterL.MoveNext ())
947 if (Compare (XPathFunctions.ToNumber (iterL.Current.Value), dR, fReverse))
950 else if (typeR == XPathResultType.NodeSet)
952 BaseIterator iterR = right.EvaluateNodeSet (iter);
953 ArrayList rgNodesL = new ArrayList ();
954 while (iterL.MoveNext ())
955 rgNodesL.Add (XPathFunctions.ToNumber (iterL.Current.Value));
956 while (iterR.MoveNext ())
958 double numR = XPathFunctions.ToNumber (iterR.Current.Value);
959 for (int l = 0; l < rgNodesL.Count; l++)
960 if (Compare ((double) rgNodesL [l], numR))
968 return Compare (_left.EvaluateNumber (iter), _right.EvaluateNumber (iter));
970 public abstract bool Compare (double arg1, double arg2);
971 public bool Compare (double arg1, double arg2, bool fReverse)
974 return Compare (arg2, arg1);
976 return Compare (arg1, arg2);
980 internal class ExprGT : RelationalExpr
982 public ExprGT (Expression left, Expression right) : base (left, right) {}
983 protected override String Operator { get { return ">"; }}
984 public override bool Compare (double arg1, double arg2)
990 internal class ExprGE : RelationalExpr
992 public ExprGE (Expression left, Expression right) : base (left, right) {}
993 protected override String Operator { get { return ">="; }}
994 public override bool Compare (double arg1, double arg2)
1000 internal class ExprLT : RelationalExpr
1002 public ExprLT (Expression left, Expression right) : base (left, right) {}
1003 protected override String Operator { get { return "<"; }}
1004 public override bool Compare (double arg1, double arg2)
1010 internal class ExprLE : RelationalExpr
1012 public ExprLE (Expression left, Expression right) : base (left, right) {}
1013 protected override String Operator { get { return "<="; }}
1014 public override bool Compare (double arg1, double arg2)
1016 return arg1 <= arg2;
1020 internal abstract class ExprNumeric : ExprBinary
1022 public ExprNumeric (Expression left, Expression right) : base (left, right) {}
1023 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1025 public override Expression Optimize ()
1028 return !HasStaticValue ?
1030 new ExprNumber (StaticValueAsNumber);
1033 public override object Evaluate (BaseIterator iter)
1035 return EvaluateNumber (iter);
1039 internal class ExprPLUS : ExprNumeric
1041 public ExprPLUS (Expression left, Expression right) : base (left, right) {}
1042 protected override String Operator { get { return "+"; }}
1044 public override double StaticValueAsNumber {
1045 get { return HasStaticValue ? _left.StaticValueAsNumber + _right.StaticValueAsNumber: 0; }
1048 public override double EvaluateNumber (BaseIterator iter)
1050 return _left.EvaluateNumber (iter) + _right.EvaluateNumber (iter);
1054 internal class ExprMINUS : ExprNumeric
1056 public ExprMINUS (Expression left, Expression right) : base (left, right) {}
1057 protected override String Operator { get { return "-"; }}
1059 public override double StaticValueAsNumber {
1060 get { return HasStaticValue ? _left.StaticValueAsNumber - _right.StaticValueAsNumber: 0; }
1063 public override double EvaluateNumber (BaseIterator iter)
1065 return _left.EvaluateNumber (iter) - _right.EvaluateNumber (iter);
1069 internal class ExprMULT : ExprNumeric
1071 public ExprMULT (Expression left, Expression right) : base (left, right) {}
1072 protected override String Operator { get { return "*"; }}
1074 public override double StaticValueAsNumber {
1075 get { return HasStaticValue ? _left.StaticValueAsNumber * _right.StaticValueAsNumber: 0; }
1078 public override double EvaluateNumber (BaseIterator iter)
1080 return _left.EvaluateNumber (iter) * _right.EvaluateNumber (iter);
1084 internal class ExprDIV : ExprNumeric
1086 public ExprDIV (Expression left, Expression right) : base (left, right) {}
1087 protected override String Operator { get { return " div "; }}
1089 public override double StaticValueAsNumber {
1090 get { return HasStaticValue ? _left.StaticValueAsNumber / _right.StaticValueAsNumber: 0; }
1093 public override double EvaluateNumber (BaseIterator iter)
1095 return _left.EvaluateNumber (iter) / _right.EvaluateNumber (iter);
1099 internal class ExprMOD : ExprNumeric
1101 public ExprMOD (Expression left, Expression right) : base (left, right) {}
1102 protected override String Operator { get { return "%"; }}
1104 public override double StaticValueAsNumber {
1105 get { return HasStaticValue ? _left.StaticValueAsNumber % _right.StaticValueAsNumber: 0; }
1108 public override double EvaluateNumber (BaseIterator iter)
1110 return _left.EvaluateNumber (iter) % _right.EvaluateNumber (iter);
1114 internal class ExprNEG : Expression
1117 public ExprNEG (Expression expr)
1121 public override String ToString () { return "- " + _expr.ToString (); }
1122 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1124 public override Expression Optimize ()
1126 _expr = _expr.Optimize ();
1127 return !HasStaticValue ?
1129 new ExprNumber (StaticValueAsNumber);
1132 internal override bool Peer {
1133 get { return _expr.Peer; }
1136 public override bool HasStaticValue {
1137 get { return _expr.HasStaticValue; }
1140 public override double StaticValueAsNumber {
1141 get { return _expr.HasStaticValue ? -1 * _expr.StaticValueAsNumber : 0; }
1144 public override object Evaluate (BaseIterator iter)
1146 return - _expr.EvaluateNumber (iter);
1149 public override double EvaluateNumber (BaseIterator iter)
1151 return - _expr.EvaluateNumber (iter);
1154 internal override bool IsPositional {
1155 get { return _expr.IsPositional; }
1160 internal abstract class NodeSet : Expression
1162 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
1164 // For "peer and subtree" optimization. see:
1165 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1166 internal abstract bool Subtree { get; }
1169 internal class ExprUNION : NodeSet
1171 internal Expression left, right;
1172 public ExprUNION (Expression left, Expression right)
1178 public override Expression Optimize ()
1180 left = left.Optimize ();
1181 right = right.Optimize ();
1185 public override String ToString () { return left.ToString ()+ " | " + right.ToString (); }
1186 public override object Evaluate (BaseIterator iter)
1188 BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1189 BaseIterator iterRight = right.EvaluateNodeSet (iter);
1190 return new UnionIterator (iter, iterLeft, iterRight);
1193 internal override XPathNodeType EvaluatedNodeType {
1194 get { return left.EvaluatedNodeType == right.EvaluatedNodeType ? left.EvaluatedNodeType : XPathNodeType.All; }
1197 internal override bool IsPositional {
1198 get { return left.IsPositional || right.IsPositional; }
1201 internal override bool Peer {
1202 get { return left.Peer && right.Peer; }
1205 internal override bool Subtree {
1207 NodeSet nl = left as NodeSet;
1208 NodeSet nr = right as NodeSet;
1209 return nl != null && nr != null && nl.Subtree && nr.Subtree;
1214 internal class ExprSLASH : NodeSet
1216 public Expression left;
1217 public NodeSet right;
1218 public ExprSLASH (Expression left, NodeSet right)
1224 public override Expression Optimize ()
1226 left = left.Optimize ();
1227 right = (NodeSet) right.Optimize ();
1231 public override String ToString () { return left.ToString ()+ "/" + right.ToString (); }
1232 public override object Evaluate (BaseIterator iter)
1234 // Peer and subtree optimization. see
1235 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1236 BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1237 if (left.Peer && right.Subtree)
1238 return new SimpleSlashIterator (iterLeft, right);
1239 BaseIterator si = new SlashIterator (iterLeft, right);
1240 return new SortedIterator (si);
1243 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1245 internal override XPathNodeType EvaluatedNodeType {
1246 get { return right.EvaluatedNodeType; }
1249 internal override bool IsPositional {
1250 get { return left.IsPositional || right.IsPositional; }
1253 internal override bool Peer {
1254 get { return left.Peer && right.Peer; }
1257 internal override bool Subtree {
1259 NodeSet n = left as NodeSet;
1260 return n != null && n.Subtree && right.Subtree;
1265 internal class ExprSLASH2 : NodeSet {
1266 public Expression left;
1267 public NodeSet right;
1269 static NodeTest DescendantOrSelfStar = new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All);
1271 public ExprSLASH2 (Expression left, NodeSet right)
1277 public override Expression Optimize ()
1279 left = left.Optimize ();
1280 right = (NodeSet) right.Optimize ();
1281 // Path A//B is equal to
1282 // A/descendant-or-self::node()/child::B, which is
1283 // equivalent to A/descendant::B. Unlike '//', '/'
1284 // could be optimized by SimpleSlashIterator.
1285 NodeTest rnt = right as NodeTest;
1286 if (rnt != null && rnt.Axis.Axis == Axes.Child) {
1287 NodeNameTest nameTest = rnt as NodeNameTest;
1288 if (nameTest != null)
1289 return new ExprSLASH (left,
1290 new NodeNameTest (nameTest, Axes.Descendant));
1291 NodeTypeTest typeTest = rnt as NodeTypeTest;
1292 if (typeTest != null)
1293 return new ExprSLASH (left,
1294 new NodeTypeTest (typeTest, Axes.Descendant));
1299 public override String ToString () { return left.ToString ()+ "//" + right.ToString (); }
1300 public override object Evaluate (BaseIterator iter)
1302 BaseIterator il = left.EvaluateNodeSet (iter);
1303 if (left.Peer && !left.RequireSorting)
1304 il = new SimpleSlashIterator (
1305 il, DescendantOrSelfStar);
1307 BaseIterator bb = new SlashIterator (il, DescendantOrSelfStar);
1308 il = left.RequireSorting ? new SortedIterator (bb) : bb;
1311 // FIXME: there could be chances to introduce sort-less
1312 // iterator, but no one could do it yet.
1313 SlashIterator b = new SlashIterator (il, right);
1314 return new SortedIterator (b);
1317 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1319 internal override XPathNodeType EvaluatedNodeType {
1320 get { return right.EvaluatedNodeType; }
1323 internal override bool IsPositional {
1324 get { return left.IsPositional || right.IsPositional; }
1327 internal override bool Peer {
1328 get { return false; }
1331 internal override bool Subtree {
1333 NodeSet n = left as NodeSet;
1334 return n != null && n.Subtree && right.Subtree;
1339 internal class ExprRoot : NodeSet
1341 public override String ToString () { return ""; }
1342 public override object Evaluate (BaseIterator iter)
1344 if (iter.CurrentPosition == 0) {
1345 iter = (BaseIterator) iter.Clone ();
1348 XPathNavigator navRoot = iter.Current.Clone ();
1349 navRoot.MoveToRoot ();
1350 return new SelfIterator (navRoot, iter.NamespaceManager);
1353 internal override XPathNodeType EvaluatedNodeType {
1354 get { return XPathNodeType.Root; }
1357 internal override bool Peer {
1358 get { return true; }
1361 internal override bool Subtree {
1362 get { return false; }
1383 internal class AxisSpecifier
1385 protected Axes _axis;
1386 public AxisSpecifier (Axes axis)
1390 public XPathNodeType NodeType
1395 case Axes.Namespace:
1396 return XPathNodeType.Namespace;
1397 case Axes.Attribute:
1398 return XPathNodeType.Attribute;
1400 return XPathNodeType.Element;
1404 public override string ToString ()
1409 case Axes.AncestorOrSelf:
1410 return "ancestor-or-self";
1411 case Axes.Attribute:
1415 case Axes.Descendant:
1416 return "descendant";
1417 case Axes.DescendantOrSelf:
1418 return "descendant-or-self";
1419 case Axes.Following:
1421 case Axes.FollowingSibling:
1422 return "following-sibling";
1423 case Axes.Namespace:
1427 case Axes.Preceding:
1429 case Axes.PrecedingSibling:
1430 return "preceding-sibling";
1434 throw new IndexOutOfRangeException ();
1437 public Axes Axis { get { return _axis; }}
1438 public BaseIterator Evaluate (BaseIterator iter)
1442 return new AncestorIterator (iter);
1443 case Axes.AncestorOrSelf:
1444 return new AncestorOrSelfIterator (iter);
1445 case Axes.Attribute:
1446 return new AttributeIterator (iter);
1448 return new ChildIterator (iter);
1449 case Axes.Descendant:
1450 return new DescendantIterator (iter);
1451 case Axes.DescendantOrSelf:
1452 return new DescendantOrSelfIterator (iter);
1453 case Axes.Following:
1454 return new FollowingIterator (iter);
1455 case Axes.FollowingSibling:
1456 return new FollowingSiblingIterator (iter);
1457 case Axes.Namespace:
1458 return new NamespaceIterator (iter);
1460 return new ParentIterator (iter);
1461 case Axes.Preceding:
1462 return new PrecedingIterator (iter);
1463 case Axes.PrecedingSibling:
1464 return new PrecedingSiblingIterator (iter);
1466 return new SelfIterator (iter);
1468 throw new IndexOutOfRangeException ();
1473 internal abstract class NodeTest : NodeSet
1475 protected AxisSpecifier _axis;
1476 public NodeTest (Axes axis)
1478 _axis = new AxisSpecifier (axis);
1480 public abstract bool Match (NSResolver nsm, XPathNavigator nav);
1481 public AxisSpecifier Axis { get { return _axis; }}
1482 public override object Evaluate (BaseIterator iter)
1484 BaseIterator iterAxis = _axis.Evaluate (iter);
1485 return new AxisIterator (iterAxis, this);
1488 public abstract void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm);
1490 public override bool RequireSorting {
1492 switch (_axis.Axis) {
1494 case Axes.AncestorOrSelf:
1495 case Axes.Preceding:
1496 case Axes.PrecedingSibling:
1497 case Axes.Attribute:
1498 case Axes.Namespace:
1507 internal override bool Peer {
1509 switch (_axis.Axis) {
1511 case Axes.AncestorOrSelf:
1512 case Axes.DescendantOrSelf:
1513 case Axes.Descendant:
1514 case Axes.Preceding:
1515 case Axes.Following:
1523 internal override bool Subtree {
1525 switch (_axis.Axis) {
1528 case Axes.AncestorOrSelf:
1529 case Axes.Preceding:
1530 case Axes.PrecedingSibling:
1531 case Axes.Following:
1532 case Axes.FollowingSibling:
1541 internal override XPathNodeType EvaluatedNodeType {
1542 get { return _axis.NodeType; }
1546 internal class NodeTypeTest : NodeTest
1548 public readonly XPathNodeType type;
1549 protected String _param;
1550 public NodeTypeTest (Axes axis) : base (axis)
1552 this.type = _axis.NodeType;
1554 public NodeTypeTest (Axes axis, XPathNodeType type) : base (axis)
1558 // FIXME: Better description
1559 public NodeTypeTest (Axes axis, XPathNodeType type, String param) : base (axis)
1563 if (param != null && type != XPathNodeType.ProcessingInstruction)
1564 throw new XPathException ("No argument allowed for "+ToString (type)+"() test"); // TODO: better description
1567 // for optimizer use
1568 internal NodeTypeTest (NodeTypeTest other, Axes axis)
1572 _param = other._param;
1575 public override String ToString ()
1577 String strType = ToString (type);
1578 if (type == XPathNodeType.ProcessingInstruction && _param != null)
1579 strType += "('" + _param + "')";
1583 return _axis.ToString () + "::" + strType;
1586 private static String ToString (XPathNodeType type)
1589 case XPathNodeType.Comment:
1591 case XPathNodeType.Text:
1593 case XPathNodeType.ProcessingInstruction:
1594 return "processing-instruction";
1595 case XPathNodeType.All:
1596 case XPathNodeType.Attribute:
1597 case XPathNodeType.Element:
1598 case XPathNodeType.Namespace:
1601 return "node-type [" + type.ToString () + "]";
1605 public override bool Match (NSResolver nsm, XPathNavigator nav)
1607 XPathNodeType nodeType = nav.NodeType;
1609 case XPathNodeType.All:
1612 case XPathNodeType.ProcessingInstruction:
1613 if (nodeType != XPathNodeType.ProcessingInstruction)
1615 if (_param != null && nav.Name != _param)
1619 case XPathNodeType.Text:
1621 case XPathNodeType.Text:
1622 case XPathNodeType.Whitespace:
1623 case XPathNodeType.SignificantWhitespace:
1629 return type == nodeType;
1633 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1641 internal class NodeNameTest : NodeTest
1643 protected XmlQualifiedName _name;
1644 protected readonly bool resolvedName = false;
1645 public NodeNameTest (Axes axis, XmlQualifiedName name, IStaticXsltContext ctx) : base (axis)
1648 name = ctx.LookupQName (name.ToString ());
1649 resolvedName = true;
1654 public NodeNameTest (Axes axis, XmlQualifiedName name, bool resolvedName) : base (axis)
1657 this.resolvedName = resolvedName;
1660 // for optimized path rewrite
1661 internal NodeNameTest (NodeNameTest source, Axes axis)
1664 _name = source._name;
1665 resolvedName = source.resolvedName;
1668 public override String ToString () { return _axis.ToString () + "::" + _name.ToString (); }
1670 public XmlQualifiedName Name { get { return _name; } }
1672 public override bool Match (NSResolver nsm, XPathNavigator nav)
1674 // must be the correct node type
1675 if (nav.NodeType != _axis.NodeType)
1678 if (_name.Name != "")
1680 // test the local part of the name first
1681 if (_name.Name != nav.LocalName)
1685 // get the prefix for the given name
1686 String strURI1 = "";
1687 if (_name.Namespace != "")
1690 strURI1 = _name.Namespace;
1691 else if (nsm != null)
1692 strURI1 = nsm.LookupNamespace (_name.Namespace);
1693 if (strURI1 == null)
1694 throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1697 // test the prefixes
1698 return strURI1 == nav.NamespaceURI;
1701 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1703 // must be the correct node type
1704 nodetype = _axis.NodeType;
1706 if (_name.Name != "")
1711 if (nsm != null && _name.Namespace != "") {
1713 ns = _name.Namespace;
1715 ns = nsm.LookupNamespace (_name.Namespace); // TODO: check to see if this returns null or ""
1717 throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1722 internal class ExprFilter : NodeSet
1724 internal Expression expr, pred;
1726 public ExprFilter (Expression expr, Expression pred)
1732 public override Expression Optimize ()
1734 expr = expr.Optimize ();
1735 pred = pred.Optimize ();
1739 internal Expression LeftHandSide {get{return expr;}}
1740 public override String ToString () { return "(" + expr.ToString () + ")[" + pred.ToString () + "]"; }
1741 public override object Evaluate (BaseIterator iter)
1743 BaseIterator iterExpr = expr.EvaluateNodeSet (iter);
1744 return new PredicateIterator (iterExpr, pred);
1747 internal override XPathNodeType EvaluatedNodeType {
1748 get { return expr.EvaluatedNodeType; }
1751 internal override bool IsPositional {
1753 if (pred.ReturnType == XPathResultType.Number)
1755 return expr.IsPositional || pred.IsPositional;
1759 internal override bool Peer {
1760 get { return expr.Peer && pred.Peer; }
1763 internal override bool Subtree {
1765 NodeSet n = expr as NodeSet;
1766 return n != null && n.Subtree;
1771 internal class ExprNumber : Expression
1773 protected double _value;
1774 public ExprNumber (double value)
1778 public override String ToString () { return _value.ToString (); }
1779 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1781 internal override bool Peer {
1782 get { return true; }
1785 public override bool HasStaticValue {
1786 get { return true; }
1789 public override double StaticValueAsNumber {
1790 get { return XPathFunctions.ToNumber (_value); }
1793 public override object Evaluate (BaseIterator iter)
1798 public override double EvaluateNumber (BaseIterator iter)
1803 internal override bool IsPositional {
1804 get { return false; }
1808 internal class BooleanConstant : Expression
1812 public BooleanConstant (bool value)
1817 public override String ToString () { return _value ? "true()" : "false()"; }
1818 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
1820 internal override bool Peer {
1821 get { return true; }
1824 public override bool HasStaticValue {
1825 get { return true; }
1828 public override bool StaticValueAsBoolean {
1829 get { return _value; }
1832 public override object Evaluate (BaseIterator iter)
1837 public override bool EvaluateBoolean (BaseIterator iter)
1843 internal class ExprLiteral : Expression
1845 protected String _value;
1846 public ExprLiteral (String value)
1850 public string Value { get { return _value; } }
1851 public override String ToString () { return "'" + _value + "'"; }
1852 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
1854 internal override bool Peer {
1855 get { return true; }
1858 public override bool HasStaticValue {
1859 get { return true; }
1862 public override string StaticValueAsString {
1863 get { return _value; }
1866 public override object Evaluate (BaseIterator iter)
1871 public override string EvaluateString (BaseIterator iter)
1877 internal class ExprVariable : Expression
1879 protected XmlQualifiedName _name;
1880 protected bool resolvedName = false;
1881 public ExprVariable (XmlQualifiedName name, IStaticXsltContext ctx)
1884 name = ctx.LookupQName (name.ToString ());
1885 resolvedName = true;
1890 public override String ToString () { return "$" + _name.ToString (); }
1891 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
1892 public override XPathResultType GetReturnType (BaseIterator iter)
1894 return XPathResultType.Any;
1897 public override object Evaluate (BaseIterator iter)
1899 IXsltContextVariable var = null;
1901 XsltContext context = iter.NamespaceManager as XsltContext;
1902 if (context != null) {
1904 var = context.ResolveVariable (_name);
1906 var = context.ResolveVariable (new XmlQualifiedName (_name.Name, _name.Namespace));
1909 throw new XPathException (String.Format ("XSLT context is required to resolve variable. Current namespace manager in current node-set '{0}' is '{1}'", iter.GetType (), iter.NamespaceManager != null ? iter.NamespaceManager.GetType () : null));
1912 throw new XPathException ("variable "+_name.ToString ()+" not found");
1913 object objResult = var.Evaluate (context);
1914 XPathNodeIterator iterResult = objResult as XPathNodeIterator;
1915 if (iterResult != null)
1916 return iterResult is BaseIterator ? iterResult : new WrapperIterator (iterResult, iter.NamespaceManager);
1920 internal override bool Peer {
1921 get { return false; }
1925 internal class ExprParens : Expression
1927 protected Expression _expr;
1928 public ExprParens (Expression expr)
1933 public override Expression Optimize ()
1939 public override bool HasStaticValue {
1940 get { return _expr.HasStaticValue; }
1943 public override object StaticValue {
1944 get { return _expr.StaticValue; }
1947 public override string StaticValueAsString {
1948 get { return _expr.StaticValueAsString; }
1951 public override double StaticValueAsNumber {
1952 get { return _expr.StaticValueAsNumber; }
1955 public override bool StaticValueAsBoolean {
1956 get { return _expr.StaticValueAsBoolean; }
1959 public override String ToString () { return "(" + _expr.ToString () + ")"; }
1960 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
1961 public override object Evaluate (BaseIterator iter)
1963 object o = (_expr.Evaluate (iter));
1964 XPathNodeIterator xi = o as XPathNodeIterator;
1965 BaseIterator predBase = xi as BaseIterator;
1966 if (predBase == null && xi != null)
1967 predBase = new WrapperIterator (xi, iter.NamespaceManager);
1968 if (predBase != null)
1969 return new ParensIterator (predBase);
1974 internal override XPathNodeType EvaluatedNodeType {
1975 get { return _expr.EvaluatedNodeType; }
1978 internal override bool IsPositional {
1979 get { return _expr.IsPositional; }
1982 internal override bool Peer {
1983 get { return _expr.Peer; }
1987 internal class FunctionArguments
1989 protected Expression _arg;
1990 protected FunctionArguments _tail;
1991 public FunctionArguments (Expression arg, FunctionArguments tail)
1996 public Expression Arg
1998 get { return _arg; }
2000 public FunctionArguments Tail
2002 get { return _tail; }
2005 public void ToArrayList (ArrayList a)
2007 FunctionArguments cur = this;
2012 } while (cur != null);
2017 internal class ExprFunctionCall : Expression
2019 protected readonly XmlQualifiedName _name;
2020 protected readonly bool resolvedName = false;
2021 protected readonly ArrayList _args = new ArrayList ();
2022 public ExprFunctionCall (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
2025 name = ctx.LookupQName (name.ToString ());
2026 resolvedName = true;
2031 args.ToArrayList (_args);
2034 public static Expression Factory (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
2036 if (name.Namespace != null && name.Namespace != "")
2037 return new ExprFunctionCall (name, args, ctx);
2039 switch (name.Name) {
2040 case "last": return new XPathFunctionLast (args);
2041 case "position": return new XPathFunctionPosition (args);
2042 case "count": return new XPathFunctionCount (args);
2043 case "id": return new XPathFunctionId (args);
2044 case "local-name": return new XPathFunctionLocalName (args);
2045 case "namespace-uri": return new XPathFunctionNamespaceUri (args);
2046 case "name": return new XPathFunctionName (args);
2047 case "string": return new XPathFunctionString (args);
2048 case "concat": return new XPathFunctionConcat (args);
2049 case "starts-with": return new XPathFunctionStartsWith (args);
2050 case "contains": return new XPathFunctionContains (args);
2051 case "substring-before": return new XPathFunctionSubstringBefore (args);
2052 case "substring-after": return new XPathFunctionSubstringAfter (args);
2053 case "substring": return new XPathFunctionSubstring (args);
2054 case "string-length": return new XPathFunctionStringLength (args);
2055 case "normalize-space": return new XPathFunctionNormalizeSpace (args);
2056 case "translate": return new XPathFunctionTranslate (args);
2057 case "boolean": return new XPathFunctionBoolean (args);
2058 case "not": return new XPathFunctionNot (args);
2059 case "true": return new XPathFunctionTrue (args);
2060 case "false": return new XPathFunctionFalse (args);
2061 case "lang": return new XPathFunctionLang (args);
2062 case "number": return new XPathFunctionNumber (args);
2063 case "sum": return new XPathFunctionSum (args);
2064 case "floor": return new XPathFunctionFloor (args);
2065 case "ceiling": return new XPathFunctionCeil (args);
2066 case "round": return new XPathFunctionRound (args);
2068 return new ExprFunctionCall (name, args, ctx);
2071 public override String ToString ()
2073 String strArgs = "";
2074 for (int i = 0; i < _args.Count; i++) {
2075 Expression arg = (Expression) _args [i];
2078 strArgs += arg.ToString ();
2080 return _name.ToString () + '(' + strArgs + ')';
2082 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
2083 public override XPathResultType GetReturnType (BaseIterator iter)
2085 return XPathResultType.Any;
2088 private XPathResultType [] GetArgTypes (BaseIterator iter)
2090 // TODO: can we cache these? what if the types depend on the nsm?
2091 XPathResultType [] rgArgs = new XPathResultType [_args.Count];
2092 for (int iArg = 0; iArg < _args.Count; iArg++)
2093 rgArgs [iArg] = ((Expression) _args [iArg]).GetReturnType (iter);
2096 public override object Evaluate (BaseIterator iter)
2098 XPathResultType [] rgTypes = GetArgTypes (iter);
2099 IXsltContextFunction func = null;
2100 XsltContext context = iter.NamespaceManager as XsltContext;
2101 if (context != null) {
2103 func = context.ResolveFunction (_name, rgTypes);
2105 func = context.ResolveFunction (_name.Namespace, _name.Name, rgTypes);
2109 throw new XPathException ("function "+_name.ToString ()+" not found");
2111 object [] rgArgs = new object [_args.Count];
2112 if (func.Maxargs != 0)
2114 XPathResultType [] rgFuncTypes = func.ArgTypes;
2115 for (int iArg = 0; iArg < _args.Count; iArg ++)
2117 XPathResultType typeArg;
2118 if (rgFuncTypes == null)
2119 typeArg = XPathResultType.Any;
2120 else if (iArg < rgFuncTypes.Length)
2121 typeArg = rgFuncTypes [iArg];
2123 typeArg = rgFuncTypes [rgFuncTypes.Length - 1];
2125 Expression arg = (Expression) _args [iArg];
2126 object result = arg.EvaluateAs (iter, typeArg);
2127 rgArgs [iArg] = result;
2130 return func.Invoke (context, rgArgs, iter.Current);
2133 internal override bool Peer {
2134 get { return false; }