2009-04-22 Sebastien Pouliot <sebastien@ximian.com>
[mono-project.git] / mcs / class / System.XML / System.Xml.XPath / Expression.cs
blobf8c4e4c07165ae3b12cfb6a01f9958d2e3c27660
1 //
2 // System.Xml.XPath.XPathExpression support classes
3 //
4 // Author:
5 // Piers Haken (piersh@friskit.com)
6 //
7 // (C) 2002 Piers Haken
8 //
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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.
30 using System;
31 using System.IO;
32 using System.Collections;
33 using System.Xml;
34 using System.Xml.XPath;
35 using System.Xml.Xsl;
36 using System.Globalization;
37 using Mono.Xml.XPath;
39 #if NET_2_0
40 using NSResolver = System.Xml.IXmlNamespaceResolver;
41 #else
42 using NSResolver = System.Xml.XmlNamespaceManager;
43 #endif
45 namespace System.Xml.XPath
47 internal static class ExpressionCache
49 static readonly Hashtable table_per_ctx = new Hashtable ();
50 static object dummy = new object ();
52 public static XPathExpression Get (string xpath, IStaticXsltContext ctx)
54 object ctxkey = ctx != null ? ctx : dummy;
56 WeakReference wr = table_per_ctx [ctxkey] as WeakReference;
57 if (wr == null)
58 return null;
59 if (!wr.IsAlive) {
60 table_per_ctx [ctxkey] = null;
61 return null;
63 Hashtable table = (Hashtable) wr.Target;
65 wr = table [xpath] as WeakReference;
66 if (wr != null) {
67 if (wr.IsAlive)
68 // it may return null (as it might be GC-ed), but we don't have to worrt about it here.
69 return (XPathExpression) wr.Target;
70 table [xpath] = null;
72 return null;
75 public static void Set (string xpath, IStaticXsltContext ctx, XPathExpression exp)
77 object ctxkey = ctx != null ? ctx : dummy;
79 Hashtable table = null;
81 WeakReference wr = table_per_ctx [ctxkey] as WeakReference;
82 if (wr != null && wr.IsAlive)
83 table = (Hashtable) wr.Target;
84 if (table == null) {
85 table = new Hashtable ();
86 table_per_ctx [ctxkey] = new WeakReference (table);
88 table [xpath] = new WeakReference (exp);
92 #if XPATH_DEBUG
93 internal class CompiledExpression : Test.Xml.XPath.XPathExpression
94 #else
95 internal class CompiledExpression : XPathExpression
96 #endif
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 ();
106 rawExpression = raw;
108 private CompiledExpression (CompiledExpression other)
110 _nsm = other._nsm;
111 _expr = other._expr;
112 rawExpression = other.rawExpression;
114 #if XPATH_DEBUG
115 public override Test.Xml.XPath.XPathExpression Clone () { return new CompiledExpression (this); }
116 #else
117 public override XPathExpression Clone () { return new CompiledExpression (this); }
118 #endif
120 public Expression ExpressionNode { get { return _expr; }}
122 public override void SetContext (XmlNamespaceManager nsManager)
124 _nsm = nsManager;
127 #if NET_2_0
128 public override void SetContext (IXmlNamespaceResolver nsResolver)
130 _nsm = nsResolver;
132 #endif
134 internal NSResolver NamespaceManager { get { return _nsm; } }
135 public override String Expression { get { return rawExpression; }}
136 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
138 public object Evaluate (BaseIterator iter)
140 if (_sorters != null)
141 return EvaluateNodeSet (iter);
143 #if false
144 return _expr.Evaluate (iter);
145 #else
146 try {
147 return _expr.Evaluate (iter);
149 catch (XPathException) {
150 throw;
152 catch (XsltException) {
153 throw;
155 catch (Exception e) {
156 throw new XPathException ("Error during evaluation", e);
158 #endif
160 public XPathNodeIterator EvaluateNodeSet (BaseIterator iter)
162 #if false
165 #endif
166 BaseIterator iterResults = _expr.EvaluateNodeSet (iter);
167 if (_sorters != null)
168 return _sorters.Sort (iterResults);
169 return iterResults;
170 #if false
172 catch (XPathException)
174 throw;
176 catch (Exception e)
178 throw new XPathException ("Error during evaluation", e);
180 #endif
182 public double EvaluateNumber (BaseIterator iter)
184 #if true
185 return _expr.EvaluateNumber (iter);
186 #else
189 return _expr.EvaluateNumber (iter);
191 catch (XPathException)
193 throw;
195 catch (Exception e)
197 throw new XPathException ("Error during evaluation", e);
199 #endif
201 public string EvaluateString (BaseIterator iter)
203 #if true
204 return _expr.EvaluateString (iter);
205 #else
208 return _expr.EvaluateString (iter);
210 catch (XPathException)
212 throw;
214 catch (Exception e)
216 throw new XPathException ("Error during evaluation", e);
218 #endif
220 public bool EvaluateBoolean (BaseIterator iter)
222 #if true
223 return _expr.EvaluateBoolean (iter);
224 #else
227 return _expr.EvaluateBoolean (iter);
229 catch (XPathException)
231 throw;
233 catch (Exception e)
235 throw new XPathException ("Error during evaluation", e);
237 #endif
240 public override void AddSort (Object obj, IComparer cmp)
242 if (_sorters == null)
243 _sorters = new XPathSorters ();
244 _sorters.Add (obj, cmp);
246 public override void AddSort(object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
248 if (_sorters == null)
249 _sorters = new XPathSorters ();
250 _sorters.Add (expr, orderSort, orderCase, lang, dataType);
255 class XPathSortElement
257 public XPathNavigator Navigator;
258 public object [] Values;
261 class XPathSorters : IComparer
263 readonly ArrayList _rgSorters = new ArrayList ();
265 public void Add (object expr, IComparer cmp)
267 _rgSorters.Add (new XPathSorter (expr, cmp));
270 public void Add (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
272 _rgSorters.Add (new XPathSorter (expr, orderSort, orderCase, lang, dataType));
275 public void CopyFrom (XPathSorter [] sorters)
277 _rgSorters.Clear ();
278 _rgSorters.AddRange (sorters);
281 public BaseIterator Sort (BaseIterator iter)
283 ArrayList rgElts = ToSortElementList (iter);
284 return Sort (rgElts, iter.NamespaceManager);
287 ArrayList ToSortElementList (BaseIterator iter)
289 ArrayList rgElts = new ArrayList ();
290 int cSorters = _rgSorters.Count;
291 while (iter.MoveNext ())
293 XPathSortElement elt = new XPathSortElement ();
294 elt.Navigator = iter.Current.Clone ();
295 elt.Values = new object [cSorters];
296 for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
298 XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
299 elt.Values [iSorter] = sorter.Evaluate (iter);
301 rgElts.Add (elt);
303 return rgElts;
306 public BaseIterator Sort (ArrayList rgElts, NSResolver nsm)
308 rgElts.Sort (this);
309 XPathNavigator [] rgResults = new XPathNavigator [rgElts.Count];
310 for (int iResult = 0; iResult < rgElts.Count; ++iResult)
312 XPathSortElement elt = (XPathSortElement) rgElts [iResult];
313 rgResults [iResult] = elt.Navigator;
315 return new ListIterator (rgResults, nsm);
318 int IComparer.Compare (object o1, object o2)
320 XPathSortElement elt1 = (XPathSortElement) o1;
321 XPathSortElement elt2 = (XPathSortElement) o2;
322 for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
324 XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
325 int cmp = sorter.Compare (elt1.Values [iSorter], elt2.Values [iSorter]);
326 if (cmp != 0)
327 return cmp;
329 switch (elt1.Navigator.ComparePosition (elt2.Navigator)) {
330 case XmlNodeOrder.Same:
331 return 0;
332 case XmlNodeOrder.After:
333 return 1;
334 default:
335 return -1;
340 class XPathSorter
342 readonly Expression _expr;
343 readonly IComparer _cmp;
344 readonly XmlDataType _type;
346 public XPathSorter (object expr, IComparer cmp)
348 _expr = ExpressionFromObject (expr);
349 _cmp = cmp;
350 _type = XmlDataType.Text;
353 public XPathSorter (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
355 _expr = ExpressionFromObject (expr);
356 _type = dataType;
357 if (dataType == XmlDataType.Number)
358 _cmp = new XPathNumberComparer (orderSort);
359 else
360 _cmp = new XPathTextComparer (orderSort, orderCase, lang);
363 static Expression ExpressionFromObject (object expr)
365 if (expr is CompiledExpression)
366 return ((CompiledExpression) expr).ExpressionNode;
367 if (expr is string)
368 return new XPathParser ().Compile ((string)expr);
370 throw new XPathException ("Invalid query object");
373 public object Evaluate (BaseIterator iter)
375 if (_type == XmlDataType.Number)
376 return _expr.EvaluateNumber (iter);
377 return _expr.EvaluateString (iter);
380 public int Compare (object o1, object o2)
382 return _cmp.Compare (o1, o2);
385 class XPathNumberComparer : IComparer
387 int _nMulSort;
389 public XPathNumberComparer (XmlSortOrder orderSort)
391 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
394 int IComparer.Compare (object o1, object o2)
396 double num1 = (double) o1;
397 double num2 = (double) o2;
398 if (num1 < num2)
399 return -_nMulSort;
400 if (num1 > num2)
401 return _nMulSort;
402 if (num1 == num2)
403 return 0;
404 if (double.IsNaN (num1))
405 return (double.IsNaN (num2)) ? 0 : -_nMulSort;
406 return _nMulSort;
410 class XPathTextComparer : IComparer
412 int _nMulSort;
413 int _nMulCase;
414 XmlCaseOrder _orderCase;
415 CultureInfo _ci;
417 public XPathTextComparer (XmlSortOrder orderSort, XmlCaseOrder orderCase, string strLang)
419 _orderCase = orderCase;
420 // FIXME: We have to set this in
421 // reverse order since currently
422 // we don't support collation.
423 _nMulCase = (orderCase == XmlCaseOrder.UpperFirst) ? -1 : 1;
424 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
426 if (strLang == null || strLang == "")
427 _ci = CultureInfo.CurrentCulture; // TODO: defer until evaluation?
428 else
429 _ci = new CultureInfo (strLang);
432 int IComparer.Compare (object o1, object o2)
434 string str1 = (string) o1;
435 string str2 = (string) o2;
436 int cmp = String.Compare (str1, str2, true, _ci);
437 if (cmp != 0 || _orderCase == XmlCaseOrder.None)
438 return cmp * _nMulSort;
439 return _nMulSort * _nMulCase * String.Compare (str1, str2, false, _ci);
444 /// <summary>
445 /// Summary description for Expression.
446 /// </summary>
447 internal abstract class Expression
449 public Expression ()
452 public abstract XPathResultType ReturnType { get; }
453 public virtual XPathResultType GetReturnType (BaseIterator iter) { return ReturnType; }
455 public virtual Expression Optimize ()
457 return this;
460 public virtual bool HasStaticValue {
461 get { return false; }
464 public virtual object StaticValue {
465 get {
466 switch (ReturnType) {
467 case XPathResultType.String:
468 return StaticValueAsString;
469 case XPathResultType.Number:
470 return StaticValueAsNumber;
471 case XPathResultType.Boolean:
472 return StaticValueAsBoolean;
474 return null;
478 public virtual string StaticValueAsString {
479 get { return HasStaticValue ? XPathFunctions.ToString (StaticValue) : null; }
482 public virtual double StaticValueAsNumber {
483 get { return HasStaticValue ? XPathFunctions.ToNumber (StaticValue) : 0; }
486 public virtual bool StaticValueAsBoolean {
487 get { return HasStaticValue ? XPathFunctions.ToBoolean (StaticValue) : false; }
490 public virtual XPathNavigator StaticValueAsNavigator {
491 get { return StaticValue as XPathNavigator; }
494 public abstract object Evaluate (BaseIterator iter);
496 public virtual BaseIterator EvaluateNodeSet (BaseIterator iter)
498 XPathResultType type = GetReturnType (iter);
499 switch (type) {
500 case XPathResultType.NodeSet:
501 case XPathResultType.Any:
502 case XPathResultType.Navigator: // FIXME: It may pass not-allowed use of RTF
503 object o = Evaluate (iter);
504 XPathNodeIterator xi = o as XPathNodeIterator;
505 BaseIterator iterResult = null;
506 if (xi != null) {
507 iterResult = xi as BaseIterator;
508 if (iterResult == null)
509 iterResult = new WrapperIterator (xi, iter.NamespaceManager);
510 return iterResult;
512 XPathNavigator nav = o as XPathNavigator;
513 if (nav != null) {
514 XPathNodeIterator xiter = nav.SelectChildren (XPathNodeType.All);
515 iterResult = xiter as BaseIterator;
516 if (iterResult == null && xiter != null)
517 iterResult = new WrapperIterator (xiter, iter.NamespaceManager);
519 if (iterResult != null)
520 return iterResult;
521 if (o == null)
522 return new NullIterator (iter);
523 type = GetReturnType (o);
524 break;
526 throw new XPathException (String.Format ("expected nodeset but was {1}: {0}", ToString (), type));
529 protected static XPathResultType GetReturnType (object obj)
531 if (obj is string)
532 return XPathResultType.String;
533 if (obj is bool)
534 return XPathResultType.Boolean;
535 if (obj is XPathNodeIterator)
536 return XPathResultType.NodeSet;
537 if (obj is double || obj is int)
538 return XPathResultType.Number;
539 if (obj is XPathNavigator)
540 return XPathResultType.Navigator;
541 throw new XPathException ("invalid node type: "+obj.GetType ().ToString ());
544 internal virtual XPathNodeType EvaluatedNodeType {
545 get { return XPathNodeType.All; }
548 internal virtual bool IsPositional {
549 get { return false; }
552 // For "peer and subtree" optimization. see:
553 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
554 internal virtual bool Peer {
555 get { return false; }
558 public virtual double EvaluateNumber (BaseIterator iter)
560 object result;
561 XPathResultType type = GetReturnType (iter);
562 if (type == XPathResultType.NodeSet)
564 result = EvaluateString (iter);
565 type = XPathResultType.String;
567 else
568 result = Evaluate (iter);
570 if (type == XPathResultType.Any)
571 type = GetReturnType (result);
573 switch (type) {
574 case XPathResultType.Number:
575 return (double)result;
576 case XPathResultType.Boolean:
577 return ((bool) result) ? 1.0 : 0.0;
578 case XPathResultType.NodeSet:
579 return XPathFunctions.ToNumber (EvaluateString (iter));
580 case XPathResultType.String:
581 return XPathFunctions.ToNumber ((string) result);
582 case XPathResultType.Navigator:
583 return XPathFunctions.ToNumber (((XPathNavigator) (result)).Value);
584 default:
585 throw new XPathException ("invalid node type");
589 public virtual string EvaluateString (BaseIterator iter)
591 object result = Evaluate (iter);
592 XPathResultType type = GetReturnType (iter);
593 if (type == XPathResultType.Any)
594 type = GetReturnType (result);
595 switch (type) {
596 case XPathResultType.Number:
597 double d = (double) result;
598 return XPathFunctions.ToString (d);
599 case XPathResultType.Boolean:
600 return ((bool) result) ? "true" : "false";
601 case XPathResultType.String:
602 return (string) result;
603 case XPathResultType.NodeSet:
605 BaseIterator iterResult = (BaseIterator) result;
606 if (iterResult == null || !iterResult.MoveNext ())
607 return "";
608 return iterResult.Current.Value;
610 case XPathResultType.Navigator:
611 return ((XPathNavigator) result).Value;
612 default:
613 throw new XPathException ("invalid node type");
617 public virtual bool EvaluateBoolean (BaseIterator iter)
619 object result = Evaluate (iter);
620 XPathResultType type = GetReturnType (iter);
621 if (type == XPathResultType.Any)
622 type = GetReturnType (result);
623 switch (type) {
624 case XPathResultType.Number:
625 double num = Convert.ToDouble (result);
626 return (num != 0.0 && num != -0.0 && !Double.IsNaN (num));
627 case XPathResultType.Boolean:
628 return (bool) result;
629 case XPathResultType.String:
630 return ((string) result).Length != 0;
631 case XPathResultType.NodeSet:
632 BaseIterator iterResult = (BaseIterator) result;
633 return (iterResult != null && iterResult.MoveNext ());
634 case XPathResultType.Navigator:
635 return (((XPathNavigator) result).HasChildren);
636 default:
637 throw new XPathException ("invalid node type");
641 public object EvaluateAs (BaseIterator iter, XPathResultType type)
643 switch (type) {
644 case XPathResultType.Boolean:
645 return EvaluateBoolean (iter);
646 case XPathResultType.NodeSet:
647 return EvaluateNodeSet (iter);
648 case XPathResultType.String:
649 return EvaluateString (iter);
650 case XPathResultType.Number:
651 return EvaluateNumber (iter);
653 return Evaluate (iter);
656 public virtual bool RequireSorting { get { return false; } }
659 internal abstract class ExprBinary : Expression
661 protected Expression _left, _right;
663 public ExprBinary (Expression left, Expression right)
665 _left = left;
666 _right = right;
669 public override Expression Optimize ()
671 _left = _left.Optimize ();
672 _right = _right.Optimize ();
673 return this;
676 public override bool HasStaticValue {
677 get { return _left.HasStaticValue && _right.HasStaticValue; }
680 public override String ToString ()
682 return _left.ToString () + ' ' + Operator + ' ' + _right.ToString ();
684 protected abstract String Operator { get; }
686 internal override XPathNodeType EvaluatedNodeType {
687 get {
688 if (_left.EvaluatedNodeType == _right.EvaluatedNodeType)
689 return _left.EvaluatedNodeType;
690 else
691 return XPathNodeType.All;
695 internal override bool IsPositional {
696 get { return _left.IsPositional || _right.IsPositional; }
699 internal override bool Peer {
700 get { return _left.Peer && _right.Peer; }
704 internal abstract class ExprBoolean : ExprBinary
706 public ExprBoolean (Expression left, Expression right) : base (left, right) {}
708 public override Expression Optimize ()
710 base.Optimize ();
711 if (!HasStaticValue)
712 return this;
713 else if (StaticValueAsBoolean)
714 return new XPathFunctionTrue (null);
715 else
716 return new XPathFunctionFalse (null);
719 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
720 public override object Evaluate (BaseIterator iter)
722 return EvaluateBoolean (iter);
724 public override double EvaluateNumber (BaseIterator iter)
726 return EvaluateBoolean (iter) ? 1 : 0;
729 public override string EvaluateString (BaseIterator iter)
731 return EvaluateBoolean (iter) ? "true" : "false";
735 internal class ExprOR : ExprBoolean
737 public ExprOR (Expression left, Expression right) : base (left, right) {}
738 protected override String Operator { get { return "or"; }}
740 public override bool StaticValueAsBoolean {
741 get { return HasStaticValue ? _left.StaticValueAsBoolean || _right.StaticValueAsBoolean : false; }
744 public override bool EvaluateBoolean (BaseIterator iter)
746 if (_left.EvaluateBoolean (iter))
747 return true;
748 return _right.EvaluateBoolean (iter);
752 internal class ExprAND : ExprBoolean
754 public ExprAND (Expression left, Expression right) : base (left, right) {}
755 protected override String Operator { get { return "and"; }}
757 public override bool StaticValueAsBoolean {
758 get { return HasStaticValue ? _left.StaticValueAsBoolean && _right.StaticValueAsBoolean : false; }
761 public override bool EvaluateBoolean (BaseIterator iter)
763 if (!_left.EvaluateBoolean (iter))
764 return false;
765 return _right.EvaluateBoolean (iter);
769 internal abstract class EqualityExpr : ExprBoolean
771 bool trueVal;
772 public EqualityExpr (Expression left, Expression right, bool trueVal) : base (left, right)
774 this.trueVal = trueVal;
777 public override bool StaticValueAsBoolean {
778 get {
779 if (!HasStaticValue)
780 return false;
781 if ((_left.ReturnType == XPathResultType.Navigator || _right.ReturnType == XPathResultType.Navigator) && _left.ReturnType == _right.ReturnType)
782 return (_left.StaticValueAsNavigator.IsSamePosition (
783 _right.StaticValueAsNavigator))
784 == trueVal;
785 if (_left.ReturnType == XPathResultType.Boolean | _right.ReturnType == XPathResultType.Boolean)
786 return (_left.StaticValueAsBoolean == _right.StaticValueAsBoolean) == trueVal;
787 if (_left.ReturnType == XPathResultType.Number | _right.ReturnType == XPathResultType.Number)
788 return (_left.StaticValueAsNumber == _right.StaticValueAsNumber) == trueVal;
789 if (_left.ReturnType == XPathResultType.String | _right.ReturnType == XPathResultType.String)
790 return (_left.StaticValueAsString == _right.StaticValueAsString) == trueVal;
791 return _left.StaticValue == _right.StaticValue == trueVal;
795 // FIXME: Avoid extraneous evaluation
796 public override bool EvaluateBoolean (BaseIterator iter)
798 XPathResultType typeL = _left.GetReturnType (iter);
799 XPathResultType typeR = _right.GetReturnType (iter);
801 // TODO: avoid double evaluations
802 if (typeL == XPathResultType.Any)
803 typeL = GetReturnType (_left.Evaluate (iter));
804 if (typeR == XPathResultType.Any)
805 typeR = GetReturnType (_right.Evaluate (iter));
807 // Regard RTF as string
808 if (typeL == XPathResultType.Navigator)
809 typeL = XPathResultType.String;
810 if (typeR == XPathResultType.Navigator)
811 typeR = XPathResultType.String;
813 if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
815 Expression left, right;
816 if (typeL != XPathResultType.NodeSet)
818 left = _right;
819 right = _left;
820 XPathResultType typeTmp = typeL;
821 typeL = typeR;
822 typeR = typeTmp;
824 else
826 left = _left;
827 right = _right;
829 if (typeR == XPathResultType.Boolean)
831 return left.EvaluateBoolean (iter) == right.EvaluateBoolean (iter) == trueVal;
833 else
835 BaseIterator iterL = left.EvaluateNodeSet (iter);
836 if (typeR == XPathResultType.Number)
838 double dR = right.EvaluateNumber (iter);
839 while (iterL.MoveNext ())
840 if (XPathFunctions.ToNumber (iterL.Current.Value) == dR == trueVal)
841 return true;
843 else if (typeR == XPathResultType.String)
845 string strR = right.EvaluateString (iter);
846 while (iterL.MoveNext ())
847 if (iterL.Current.Value == strR == trueVal)
848 return true;
850 else if (typeR == XPathResultType.NodeSet)
852 BaseIterator iterR = right.EvaluateNodeSet (iter);
853 ArrayList rgNodesL = new ArrayList ();
854 while (iterL.MoveNext ())
855 rgNodesL.Add (XPathFunctions.ToString (iterL.Current.Value));
856 while (iterR.MoveNext ())
858 string strR = XPathFunctions.ToString (iterR.Current.Value);
859 for (int l = 0; l < rgNodesL.Count; l++)
860 if ((strR == (string) rgNodesL [l]) == trueVal)
861 return true;
864 return false;
867 else if (typeL == XPathResultType.Boolean || typeR == XPathResultType.Boolean)
868 return _left.EvaluateBoolean (iter) == _right.EvaluateBoolean (iter) == trueVal;
869 else if (typeL == XPathResultType.Number || typeR == XPathResultType.Number)
870 return _left.EvaluateNumber (iter) == _right.EvaluateNumber (iter) == trueVal;
871 else
872 return _left.EvaluateString (iter) == _right.EvaluateString (iter) == trueVal;
876 internal class ExprEQ : EqualityExpr
878 public ExprEQ (Expression left, Expression right) : base (left, right, true) {}
879 protected override String Operator { get { return "="; }}
882 internal class ExprNE : EqualityExpr
884 public ExprNE (Expression left, Expression right) : base (left, right, false) {}
885 protected override String Operator { get { return "!="; }}
888 internal abstract class RelationalExpr : ExprBoolean
890 public RelationalExpr (Expression left, Expression right) : base (left, right) {}
892 public override bool StaticValueAsBoolean {
893 get { return HasStaticValue ? Compare (_left.StaticValueAsNumber, _right.StaticValueAsNumber) : false; }
896 // FIXME: Avoid extraneous evaluation.
897 public override bool EvaluateBoolean (BaseIterator iter)
899 XPathResultType typeL = _left.GetReturnType (iter);
900 XPathResultType typeR = _right.GetReturnType (iter);
902 if (typeL == XPathResultType.Any)
903 typeL = GetReturnType (_left.Evaluate (iter));
904 if (typeR == XPathResultType.Any)
905 typeR = GetReturnType (_right.Evaluate (iter));
907 // Regard RTF as string
908 if (typeL == XPathResultType.Navigator)
909 typeL = XPathResultType.String;
910 if (typeR == XPathResultType.Navigator)
911 typeR = XPathResultType.String;
913 if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
915 bool fReverse = false;
916 Expression left, right;
917 if (typeL != XPathResultType.NodeSet)
919 fReverse = true;
920 left = _right;
921 right = _left;
922 XPathResultType typeTmp = typeL;
923 typeL = typeR;
924 typeR = typeTmp;
926 else
928 left = _left;
929 right = _right;
931 if (typeR == XPathResultType.Boolean)
933 bool fL = left.EvaluateBoolean (iter);
934 bool fR = right.EvaluateBoolean (iter);
935 return Compare (Convert.ToDouble (fL), Convert.ToDouble (fR), fReverse);
937 else
939 BaseIterator iterL = left.EvaluateNodeSet (iter);
940 if (typeR == XPathResultType.Number || typeR == XPathResultType.String)
942 double dR = right.EvaluateNumber (iter);
943 while (iterL.MoveNext ())
944 if (Compare (XPathFunctions.ToNumber (iterL.Current.Value), dR, fReverse))
945 return true;
947 else if (typeR == XPathResultType.NodeSet)
949 BaseIterator iterR = right.EvaluateNodeSet (iter);
950 ArrayList rgNodesL = new ArrayList ();
951 while (iterL.MoveNext ())
952 rgNodesL.Add (XPathFunctions.ToNumber (iterL.Current.Value));
953 while (iterR.MoveNext ())
955 double numR = XPathFunctions.ToNumber (iterR.Current.Value);
956 for (int l = 0; l < rgNodesL.Count; l++)
957 if (Compare ((double) rgNodesL [l], numR))
958 return true;
961 return false;
964 else
965 return Compare (_left.EvaluateNumber (iter), _right.EvaluateNumber (iter));
967 public abstract bool Compare (double arg1, double arg2);
968 public bool Compare (double arg1, double arg2, bool fReverse)
970 if (fReverse)
971 return Compare (arg2, arg1);
972 else
973 return Compare (arg1, arg2);
977 internal class ExprGT : RelationalExpr
979 public ExprGT (Expression left, Expression right) : base (left, right) {}
980 protected override String Operator { get { return ">"; }}
981 public override bool Compare (double arg1, double arg2)
983 return arg1 > arg2;
987 internal class ExprGE : RelationalExpr
989 public ExprGE (Expression left, Expression right) : base (left, right) {}
990 protected override String Operator { get { return ">="; }}
991 public override bool Compare (double arg1, double arg2)
993 return arg1 >= arg2;
997 internal class ExprLT : RelationalExpr
999 public ExprLT (Expression left, Expression right) : base (left, right) {}
1000 protected override String Operator { get { return "<"; }}
1001 public override bool Compare (double arg1, double arg2)
1003 return arg1 < arg2;
1007 internal class ExprLE : RelationalExpr
1009 public ExprLE (Expression left, Expression right) : base (left, right) {}
1010 protected override String Operator { get { return "<="; }}
1011 public override bool Compare (double arg1, double arg2)
1013 return arg1 <= arg2;
1017 internal abstract class ExprNumeric : ExprBinary
1019 public ExprNumeric (Expression left, Expression right) : base (left, right) {}
1020 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1022 public override Expression Optimize ()
1024 base.Optimize ();
1025 return !HasStaticValue ?
1026 (Expression) this :
1027 new ExprNumber (StaticValueAsNumber);
1030 public override object Evaluate (BaseIterator iter)
1032 return EvaluateNumber (iter);
1036 internal class ExprPLUS : ExprNumeric
1038 public ExprPLUS (Expression left, Expression right) : base (left, right) {}
1039 protected override String Operator { get { return "+"; }}
1041 public override double StaticValueAsNumber {
1042 get { return HasStaticValue ? _left.StaticValueAsNumber + _right.StaticValueAsNumber: 0; }
1045 public override double EvaluateNumber (BaseIterator iter)
1047 return _left.EvaluateNumber (iter) + _right.EvaluateNumber (iter);
1051 internal class ExprMINUS : ExprNumeric
1053 public ExprMINUS (Expression left, Expression right) : base (left, right) {}
1054 protected override String Operator { get { return "-"; }}
1056 public override double StaticValueAsNumber {
1057 get { return HasStaticValue ? _left.StaticValueAsNumber - _right.StaticValueAsNumber: 0; }
1060 public override double EvaluateNumber (BaseIterator iter)
1062 return _left.EvaluateNumber (iter) - _right.EvaluateNumber (iter);
1066 internal class ExprMULT : ExprNumeric
1068 public ExprMULT (Expression left, Expression right) : base (left, right) {}
1069 protected override String Operator { get { return "*"; }}
1071 public override double StaticValueAsNumber {
1072 get { return HasStaticValue ? _left.StaticValueAsNumber * _right.StaticValueAsNumber: 0; }
1075 public override double EvaluateNumber (BaseIterator iter)
1077 return _left.EvaluateNumber (iter) * _right.EvaluateNumber (iter);
1081 internal class ExprDIV : ExprNumeric
1083 public ExprDIV (Expression left, Expression right) : base (left, right) {}
1084 protected override String Operator { get { return " div "; }}
1086 public override double StaticValueAsNumber {
1087 get { return HasStaticValue ? _left.StaticValueAsNumber / _right.StaticValueAsNumber: 0; }
1090 public override double EvaluateNumber (BaseIterator iter)
1092 return _left.EvaluateNumber (iter) / _right.EvaluateNumber (iter);
1096 internal class ExprMOD : ExprNumeric
1098 public ExprMOD (Expression left, Expression right) : base (left, right) {}
1099 protected override String Operator { get { return "%"; }}
1101 public override double StaticValueAsNumber {
1102 get { return HasStaticValue ? _left.StaticValueAsNumber % _right.StaticValueAsNumber: 0; }
1105 public override double EvaluateNumber (BaseIterator iter)
1107 return _left.EvaluateNumber (iter) % _right.EvaluateNumber (iter);
1111 internal class ExprNEG : Expression
1113 Expression _expr;
1114 public ExprNEG (Expression expr)
1116 _expr = expr;
1118 public override String ToString () { return "- " + _expr.ToString (); }
1119 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1121 public override Expression Optimize ()
1123 _expr = _expr.Optimize ();
1124 return !HasStaticValue ?
1125 (Expression) this :
1126 new ExprNumber (StaticValueAsNumber);
1129 internal override bool Peer {
1130 get { return _expr.Peer; }
1133 public override bool HasStaticValue {
1134 get { return _expr.HasStaticValue; }
1137 public override double StaticValueAsNumber {
1138 get { return _expr.HasStaticValue ? -1 * _expr.StaticValueAsNumber : 0; }
1141 public override object Evaluate (BaseIterator iter)
1143 return - _expr.EvaluateNumber (iter);
1146 public override double EvaluateNumber (BaseIterator iter)
1148 return - _expr.EvaluateNumber (iter);
1151 internal override bool IsPositional {
1152 get { return _expr.IsPositional; }
1157 internal abstract class NodeSet : Expression
1159 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
1161 // For "peer and subtree" optimization. see:
1162 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1163 internal abstract bool Subtree { get; }
1166 internal class ExprUNION : NodeSet
1168 internal Expression left, right;
1169 public ExprUNION (Expression left, Expression right)
1171 this.left = left;
1172 this.right = right;
1175 public override Expression Optimize ()
1177 left = left.Optimize ();
1178 right = right.Optimize ();
1179 return this;
1182 public override String ToString () { return left.ToString ()+ " | " + right.ToString (); }
1183 public override object Evaluate (BaseIterator iter)
1185 BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1186 BaseIterator iterRight = right.EvaluateNodeSet (iter);
1187 return new UnionIterator (iter, iterLeft, iterRight);
1190 internal override XPathNodeType EvaluatedNodeType {
1191 get { return left.EvaluatedNodeType == right.EvaluatedNodeType ? left.EvaluatedNodeType : XPathNodeType.All; }
1194 internal override bool IsPositional {
1195 get { return left.IsPositional || right.IsPositional; }
1198 internal override bool Peer {
1199 get { return left.Peer && right.Peer; }
1202 internal override bool Subtree {
1203 get {
1204 NodeSet nl = left as NodeSet;
1205 NodeSet nr = right as NodeSet;
1206 return nl != null && nr != null && nl.Subtree && nr.Subtree;
1211 internal class ExprSLASH : NodeSet
1213 public Expression left;
1214 public NodeSet right;
1215 public ExprSLASH (Expression left, NodeSet right)
1217 this.left = left;
1218 this.right = right;
1221 public override Expression Optimize ()
1223 left = left.Optimize ();
1224 right = (NodeSet) right.Optimize ();
1225 return this;
1228 public override String ToString () { return left.ToString ()+ "/" + right.ToString (); }
1229 public override object Evaluate (BaseIterator iter)
1231 // Peer and subtree optimization. see
1232 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1233 BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1234 if (left.Peer && right.Subtree)
1235 return new SimpleSlashIterator (iterLeft, right);
1236 BaseIterator si = new SlashIterator (iterLeft, right);
1237 return new SortedIterator (si);
1240 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1242 internal override XPathNodeType EvaluatedNodeType {
1243 get { return right.EvaluatedNodeType; }
1246 internal override bool IsPositional {
1247 get { return left.IsPositional || right.IsPositional; }
1250 internal override bool Peer {
1251 get { return left.Peer && right.Peer; }
1254 internal override bool Subtree {
1255 get {
1256 NodeSet n = left as NodeSet;
1257 return n != null && n.Subtree && right.Subtree;
1262 internal class ExprSLASH2 : NodeSet {
1263 public Expression left;
1264 public NodeSet right;
1266 static NodeTest DescendantOrSelfStar = new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All);
1268 public ExprSLASH2 (Expression left, NodeSet right)
1270 this.left = left;
1271 this.right = right;
1274 public override Expression Optimize ()
1276 left = left.Optimize ();
1277 right = (NodeSet) right.Optimize ();
1278 // Path A//B is equal to
1279 // A/descendant-or-self::node()/child::B, which is
1280 // equivalent to A/descendant::B. Unlike '//', '/'
1281 // could be optimized by SimpleSlashIterator.
1282 NodeTest rnt = right as NodeTest;
1283 if (rnt != null && rnt.Axis.Axis == Axes.Child) {
1284 NodeNameTest nameTest = rnt as NodeNameTest;
1285 if (nameTest != null)
1286 return new ExprSLASH (left,
1287 new NodeNameTest (nameTest, Axes.Descendant));
1288 NodeTypeTest typeTest = rnt as NodeTypeTest;
1289 if (typeTest != null)
1290 return new ExprSLASH (left,
1291 new NodeTypeTest (typeTest, Axes.Descendant));
1293 return this;
1296 public override String ToString () { return left.ToString ()+ "//" + right.ToString (); }
1297 public override object Evaluate (BaseIterator iter)
1299 BaseIterator il = left.EvaluateNodeSet (iter);
1300 if (left.Peer && !left.RequireSorting)
1301 il = new SimpleSlashIterator (
1302 il, DescendantOrSelfStar);
1303 else {
1304 BaseIterator bb = new SlashIterator (il, DescendantOrSelfStar);
1305 il = left.RequireSorting ? new SortedIterator (bb) : bb;
1308 // FIXME: there could be chances to introduce sort-less
1309 // iterator, but no one could do it yet.
1310 SlashIterator b = new SlashIterator (il, right);
1311 return new SortedIterator (b);
1314 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1316 internal override XPathNodeType EvaluatedNodeType {
1317 get { return right.EvaluatedNodeType; }
1320 internal override bool IsPositional {
1321 get { return left.IsPositional || right.IsPositional; }
1324 internal override bool Peer {
1325 get { return false; }
1328 internal override bool Subtree {
1329 get {
1330 NodeSet n = left as NodeSet;
1331 return n != null && n.Subtree && right.Subtree;
1336 internal class ExprRoot : NodeSet
1338 public override String ToString () { return ""; }
1339 public override object Evaluate (BaseIterator iter)
1341 if (iter.CurrentPosition == 0) {
1342 iter = (BaseIterator) iter.Clone ();
1343 iter.MoveNext ();
1345 XPathNavigator navRoot = iter.Current.Clone ();
1346 navRoot.MoveToRoot ();
1347 return new SelfIterator (navRoot, iter.NamespaceManager);
1350 internal override XPathNodeType EvaluatedNodeType {
1351 get { return XPathNodeType.Root; }
1354 internal override bool Peer {
1355 get { return true; }
1358 internal override bool Subtree {
1359 get { return false; }
1363 internal enum Axes
1365 Ancestor,
1366 AncestorOrSelf,
1367 Attribute,
1368 Child,
1369 Descendant,
1370 DescendantOrSelf,
1371 Following,
1372 FollowingSibling,
1373 Namespace,
1374 Parent,
1375 Preceding,
1376 PrecedingSibling,
1377 Self,
1380 internal class AxisSpecifier
1382 protected Axes _axis;
1383 public AxisSpecifier (Axes axis)
1385 _axis = axis;
1387 public XPathNodeType NodeType
1391 switch (_axis) {
1392 case Axes.Namespace:
1393 return XPathNodeType.Namespace;
1394 case Axes.Attribute:
1395 return XPathNodeType.Attribute;
1396 default:
1397 return XPathNodeType.Element;
1401 public override string ToString ()
1403 switch (_axis) {
1404 case Axes.Ancestor:
1405 return "ancestor";
1406 case Axes.AncestorOrSelf:
1407 return "ancestor-or-self";
1408 case Axes.Attribute:
1409 return "attribute";
1410 case Axes.Child:
1411 return "child";
1412 case Axes.Descendant:
1413 return "descendant";
1414 case Axes.DescendantOrSelf:
1415 return "descendant-or-self";
1416 case Axes.Following:
1417 return "following";
1418 case Axes.FollowingSibling:
1419 return "following-sibling";
1420 case Axes.Namespace:
1421 return "namespace";
1422 case Axes.Parent:
1423 return "parent";
1424 case Axes.Preceding:
1425 return "preceding";
1426 case Axes.PrecedingSibling:
1427 return "preceding-sibling";
1428 case Axes.Self:
1429 return "self";
1430 default:
1431 throw new IndexOutOfRangeException ();
1434 public Axes Axis { get { return _axis; }}
1435 public BaseIterator Evaluate (BaseIterator iter)
1437 switch (_axis) {
1438 case Axes.Ancestor:
1439 return new AncestorIterator (iter);
1440 case Axes.AncestorOrSelf:
1441 return new AncestorOrSelfIterator (iter);
1442 case Axes.Attribute:
1443 return new AttributeIterator (iter);
1444 case Axes.Child:
1445 return new ChildIterator (iter);
1446 case Axes.Descendant:
1447 return new DescendantIterator (iter);
1448 case Axes.DescendantOrSelf:
1449 return new DescendantOrSelfIterator (iter);
1450 case Axes.Following:
1451 return new FollowingIterator (iter);
1452 case Axes.FollowingSibling:
1453 return new FollowingSiblingIterator (iter);
1454 case Axes.Namespace:
1455 return new NamespaceIterator (iter);
1456 case Axes.Parent:
1457 return new ParentIterator (iter);
1458 case Axes.Preceding:
1459 return new PrecedingIterator (iter);
1460 case Axes.PrecedingSibling:
1461 return new PrecedingSiblingIterator (iter);
1462 case Axes.Self:
1463 return new SelfIterator (iter);
1464 default:
1465 throw new IndexOutOfRangeException ();
1470 internal abstract class NodeTest : NodeSet
1472 protected AxisSpecifier _axis;
1473 public NodeTest (Axes axis)
1475 _axis = new AxisSpecifier (axis);
1477 public abstract bool Match (NSResolver nsm, XPathNavigator nav);
1478 public AxisSpecifier Axis { get { return _axis; }}
1479 public override object Evaluate (BaseIterator iter)
1481 BaseIterator iterAxis = _axis.Evaluate (iter);
1482 return new AxisIterator (iterAxis, this);
1485 public abstract void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm);
1487 public override bool RequireSorting {
1488 get {
1489 switch (_axis.Axis) {
1490 case Axes.Ancestor:
1491 case Axes.AncestorOrSelf:
1492 case Axes.Preceding:
1493 case Axes.PrecedingSibling:
1494 case Axes.Attribute:
1495 case Axes.Namespace:
1496 return true;
1497 default:
1498 return false;
1504 internal override bool Peer {
1505 get {
1506 switch (_axis.Axis) {
1507 case Axes.Ancestor:
1508 case Axes.AncestorOrSelf:
1509 case Axes.DescendantOrSelf:
1510 case Axes.Descendant:
1511 case Axes.Preceding:
1512 case Axes.Following:
1513 return false;
1514 default:
1515 return true;
1520 internal override bool Subtree {
1521 get {
1522 switch (_axis.Axis) {
1523 case Axes.Parent:
1524 case Axes.Ancestor:
1525 case Axes.AncestorOrSelf:
1526 case Axes.Preceding:
1527 case Axes.PrecedingSibling:
1528 case Axes.Following:
1529 case Axes.FollowingSibling:
1530 return false;
1531 default:
1532 return true;
1538 internal override XPathNodeType EvaluatedNodeType {
1539 get { return _axis.NodeType; }
1543 internal class NodeTypeTest : NodeTest
1545 public readonly XPathNodeType type;
1546 protected String _param;
1547 public NodeTypeTest (Axes axis) : base (axis)
1549 this.type = _axis.NodeType;
1551 public NodeTypeTest (Axes axis, XPathNodeType type) : base (axis)
1553 this.type = type;
1555 // FIXME: Better description
1556 public NodeTypeTest (Axes axis, XPathNodeType type, String param) : base (axis)
1558 this.type = type;
1559 _param = param;
1560 if (param != null && type != XPathNodeType.ProcessingInstruction)
1561 throw new XPathException ("No argument allowed for "+ToString (type)+"() test"); // TODO: better description
1564 // for optimizer use
1565 internal NodeTypeTest (NodeTypeTest other, Axes axis)
1566 : base (axis)
1568 type = other.type;
1569 _param = other._param;
1572 public override String ToString ()
1574 String strType = ToString (type);
1575 if (type == XPathNodeType.ProcessingInstruction && _param != null)
1576 strType += "('" + _param + "')";
1577 else
1578 strType += "()";
1580 return _axis.ToString () + "::" + strType;
1583 private static String ToString (XPathNodeType type)
1585 switch (type) {
1586 case XPathNodeType.Comment:
1587 return "comment";
1588 case XPathNodeType.Text:
1589 return "text";
1590 case XPathNodeType.ProcessingInstruction:
1591 return "processing-instruction";
1592 case XPathNodeType.All:
1593 case XPathNodeType.Attribute:
1594 case XPathNodeType.Element:
1595 case XPathNodeType.Namespace:
1596 return "node";
1597 default:
1598 return "node-type [" + type.ToString () + "]";
1602 public override bool Match (NSResolver nsm, XPathNavigator nav)
1604 XPathNodeType nodeType = nav.NodeType;
1605 switch (type) {
1606 case XPathNodeType.All:
1607 return true;
1609 case XPathNodeType.ProcessingInstruction:
1610 if (nodeType != XPathNodeType.ProcessingInstruction)
1611 return false;
1612 if (_param != null && nav.Name != _param)
1613 return false;
1614 return true;
1616 case XPathNodeType.Text:
1617 switch (nodeType) {
1618 case XPathNodeType.Text:
1619 case XPathNodeType.Whitespace:
1620 case XPathNodeType.SignificantWhitespace:
1621 return true;
1622 default:
1623 return false;
1625 default:
1626 return type == nodeType;
1630 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1632 name = _param;
1633 ns = null;
1634 nodetype = type;
1638 internal class NodeNameTest : NodeTest
1640 protected XmlQualifiedName _name;
1641 protected readonly bool resolvedName = false;
1642 public NodeNameTest (Axes axis, XmlQualifiedName name, IStaticXsltContext ctx) : base (axis)
1644 if (ctx != null) {
1645 name = ctx.LookupQName (name.ToString ());
1646 resolvedName = true;
1648 _name = name;
1651 public NodeNameTest (Axes axis, XmlQualifiedName name, bool resolvedName) : base (axis)
1653 _name = name;
1654 this.resolvedName = resolvedName;
1657 // for optimized path rewrite
1658 internal NodeNameTest (NodeNameTest source, Axes axis)
1659 : base (axis)
1661 _name = source._name;
1662 resolvedName = source.resolvedName;
1665 public override String ToString () { return _axis.ToString () + "::" + _name.ToString (); }
1667 public XmlQualifiedName Name { get { return _name; } }
1669 public override bool Match (NSResolver nsm, XPathNavigator nav)
1671 // must be the correct node type
1672 if (nav.NodeType != _axis.NodeType)
1673 return false;
1675 if (_name.Name != "")
1677 // test the local part of the name first
1678 if (_name.Name != nav.LocalName)
1679 return false;
1682 // get the prefix for the given name
1683 String strURI1 = "";
1684 if (_name.Namespace != "")
1686 if (resolvedName)
1687 strURI1 = _name.Namespace;
1688 else if (nsm != null)
1689 // We still need to have such tricky switch, because the behavior is
1690 // inconsistent between .NET 1.x and 2.0 when the argument is not
1691 // atomic string.
1692 #if NET_2_0
1693 strURI1 = nsm.LookupNamespace (_name.Namespace);
1694 #else
1695 strURI1 = nsm.LookupNamespace (_name.Namespace, false);
1696 #endif
1697 if (strURI1 == null)
1698 throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1701 // test the prefixes
1702 return strURI1 == nav.NamespaceURI;
1705 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1707 // must be the correct node type
1708 nodetype = _axis.NodeType;
1710 if (_name.Name != "")
1711 name = _name.Name;
1712 else
1713 name = null;
1714 ns = "";
1715 if (nsm != null && _name.Namespace != "") {
1716 if (resolvedName)
1717 ns = _name.Namespace;
1718 else
1719 // We still need to have such tricky switch, because the behavior is
1720 // inconsistent between .NET 1.x and 2.0 when the argument is not
1721 // atomic string.
1722 #if NET_2_0
1723 ns = nsm.LookupNamespace (_name.Namespace); // TODO: check to see if this returns null or ""
1724 #else
1725 ns = nsm.LookupNamespace (_name.Namespace, false); // TODO: check to see if this returns null or ""
1726 #endif
1727 if (ns == null)
1728 throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1733 internal class ExprFilter : NodeSet
1735 internal Expression expr, pred;
1737 public ExprFilter (Expression expr, Expression pred)
1739 this.expr = expr;
1740 this.pred = pred;
1743 public override Expression Optimize ()
1745 expr = expr.Optimize ();
1746 pred = pred.Optimize ();
1747 return this;
1750 internal Expression LeftHandSide {get{return expr;}}
1751 public override String ToString () { return "(" + expr.ToString () + ")[" + pred.ToString () + "]"; }
1752 public override object Evaluate (BaseIterator iter)
1754 BaseIterator iterExpr = expr.EvaluateNodeSet (iter);
1755 return new PredicateIterator (iterExpr, pred);
1758 internal override XPathNodeType EvaluatedNodeType {
1759 get { return expr.EvaluatedNodeType; }
1762 internal override bool IsPositional {
1763 get {
1764 if (pred.ReturnType == XPathResultType.Number)
1765 return true;
1766 return expr.IsPositional || pred.IsPositional;
1770 internal override bool Peer {
1771 get { return expr.Peer && pred.Peer; }
1774 internal override bool Subtree {
1775 get {
1776 NodeSet n = expr as NodeSet;
1777 return n != null && n.Subtree;
1782 internal class ExprNumber : Expression
1784 protected double _value;
1785 public ExprNumber (double value)
1787 _value = value;
1789 public override String ToString () { return _value.ToString (); }
1790 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1792 internal override bool Peer {
1793 get { return true; }
1796 public override bool HasStaticValue {
1797 get { return true; }
1800 public override double StaticValueAsNumber {
1801 get { return XPathFunctions.ToNumber (_value); }
1804 public override object Evaluate (BaseIterator iter)
1806 return _value;
1809 public override double EvaluateNumber (BaseIterator iter)
1811 return _value;
1814 internal override bool IsPositional {
1815 get { return false; }
1819 internal class BooleanConstant : Expression
1821 bool _value;
1823 public BooleanConstant (bool value)
1825 _value = value;
1828 public override String ToString () { return _value ? "true()" : "false()"; }
1829 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
1831 internal override bool Peer {
1832 get { return true; }
1835 public override bool HasStaticValue {
1836 get { return true; }
1839 public override bool StaticValueAsBoolean {
1840 get { return _value; }
1843 public override object Evaluate (BaseIterator iter)
1845 return _value;
1848 public override bool EvaluateBoolean (BaseIterator iter)
1850 return _value;
1854 internal class ExprLiteral : Expression
1856 protected String _value;
1857 public ExprLiteral (String value)
1859 _value = value;
1861 public string Value { get { return _value; } }
1862 public override String ToString () { return "'" + _value + "'"; }
1863 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
1865 internal override bool Peer {
1866 get { return true; }
1869 public override bool HasStaticValue {
1870 get { return true; }
1873 public override string StaticValueAsString {
1874 get { return _value; }
1877 public override object Evaluate (BaseIterator iter)
1879 return _value;
1882 public override string EvaluateString (BaseIterator iter)
1884 return _value;
1888 internal class ExprVariable : Expression
1890 protected XmlQualifiedName _name;
1891 protected bool resolvedName = false;
1892 public ExprVariable (XmlQualifiedName name, IStaticXsltContext ctx)
1894 if (ctx != null) {
1895 name = ctx.LookupQName (name.ToString ());
1896 resolvedName = true;
1899 _name = name;
1901 public override String ToString () { return "$" + _name.ToString (); }
1902 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
1903 public override XPathResultType GetReturnType (BaseIterator iter)
1905 return XPathResultType.Any;
1908 public override object Evaluate (BaseIterator iter)
1910 IXsltContextVariable var = null;
1912 XsltContext context = iter.NamespaceManager as XsltContext;
1913 if (context != null) {
1914 if (resolvedName)
1915 var = context.ResolveVariable (_name);
1916 else
1917 var = context.ResolveVariable (new XmlQualifiedName (_name.Name, _name.Namespace));
1919 else
1920 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));
1922 if (var == null)
1923 throw new XPathException ("variable "+_name.ToString ()+" not found");
1924 object objResult = var.Evaluate (context);
1925 XPathNodeIterator iterResult = objResult as XPathNodeIterator;
1926 if (iterResult != null)
1927 return iterResult is BaseIterator ? iterResult : new WrapperIterator (iterResult, iter.NamespaceManager);
1928 return objResult;
1931 internal override bool Peer {
1932 get { return false; }
1936 internal class ExprParens : Expression
1938 protected Expression _expr;
1939 public ExprParens (Expression expr)
1941 _expr = expr;
1944 public override Expression Optimize ()
1946 _expr.Optimize ();
1947 return this;
1950 public override bool HasStaticValue {
1951 get { return _expr.HasStaticValue; }
1954 public override object StaticValue {
1955 get { return _expr.StaticValue; }
1958 public override string StaticValueAsString {
1959 get { return _expr.StaticValueAsString; }
1962 public override double StaticValueAsNumber {
1963 get { return _expr.StaticValueAsNumber; }
1966 public override bool StaticValueAsBoolean {
1967 get { return _expr.StaticValueAsBoolean; }
1970 public override String ToString () { return "(" + _expr.ToString () + ")"; }
1971 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
1972 public override object Evaluate (BaseIterator iter)
1974 object o = (_expr.Evaluate (iter));
1975 XPathNodeIterator xi = o as XPathNodeIterator;
1976 BaseIterator predBase = xi as BaseIterator;
1977 if (predBase == null && xi != null)
1978 predBase = new WrapperIterator (xi, iter.NamespaceManager);
1979 if (predBase != null)
1980 return new ParensIterator (predBase);
1981 else
1982 return o;
1985 internal override XPathNodeType EvaluatedNodeType {
1986 get { return _expr.EvaluatedNodeType; }
1989 internal override bool IsPositional {
1990 get { return _expr.IsPositional; }
1993 internal override bool Peer {
1994 get { return _expr.Peer; }
1998 internal class FunctionArguments
2000 protected Expression _arg;
2001 protected FunctionArguments _tail;
2002 public FunctionArguments (Expression arg, FunctionArguments tail)
2004 _arg = arg;
2005 _tail = tail;
2007 public Expression Arg
2009 get { return _arg; }
2011 public FunctionArguments Tail
2013 get { return _tail; }
2016 public void ToArrayList (ArrayList a)
2018 FunctionArguments cur = this;
2020 do {
2021 a.Add (cur._arg);
2022 cur = cur._tail;
2023 } while (cur != null);
2028 internal class ExprFunctionCall : Expression
2030 protected readonly XmlQualifiedName _name;
2031 protected readonly bool resolvedName = false;
2032 protected readonly ArrayList _args = new ArrayList ();
2033 public ExprFunctionCall (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
2035 if (ctx != null) {
2036 name = ctx.LookupQName (name.ToString ());
2037 resolvedName = true;
2040 _name = name;
2041 if (args != null)
2042 args.ToArrayList (_args);
2045 public static Expression Factory (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
2047 if (name.Namespace != null && name.Namespace != "")
2048 return new ExprFunctionCall (name, args, ctx);
2050 switch (name.Name) {
2051 case "last": return new XPathFunctionLast (args);
2052 case "position": return new XPathFunctionPosition (args);
2053 case "count": return new XPathFunctionCount (args);
2054 case "id": return new XPathFunctionId (args);
2055 case "local-name": return new XPathFunctionLocalName (args);
2056 case "namespace-uri": return new XPathFunctionNamespaceUri (args);
2057 case "name": return new XPathFunctionName (args);
2058 case "string": return new XPathFunctionString (args);
2059 case "concat": return new XPathFunctionConcat (args);
2060 case "starts-with": return new XPathFunctionStartsWith (args);
2061 case "contains": return new XPathFunctionContains (args);
2062 case "substring-before": return new XPathFunctionSubstringBefore (args);
2063 case "substring-after": return new XPathFunctionSubstringAfter (args);
2064 case "substring": return new XPathFunctionSubstring (args);
2065 case "string-length": return new XPathFunctionStringLength (args);
2066 case "normalize-space": return new XPathFunctionNormalizeSpace (args);
2067 case "translate": return new XPathFunctionTranslate (args);
2068 case "boolean": return new XPathFunctionBoolean (args);
2069 case "not": return new XPathFunctionNot (args);
2070 case "true": return new XPathFunctionTrue (args);
2071 case "false": return new XPathFunctionFalse (args);
2072 case "lang": return new XPathFunctionLang (args);
2073 case "number": return new XPathFunctionNumber (args);
2074 case "sum": return new XPathFunctionSum (args);
2075 case "floor": return new XPathFunctionFloor (args);
2076 case "ceiling": return new XPathFunctionCeil (args);
2077 case "round": return new XPathFunctionRound (args);
2079 return new ExprFunctionCall (name, args, ctx);
2082 public override String ToString ()
2084 String strArgs = "";
2085 for (int i = 0; i < _args.Count; i++) {
2086 Expression arg = (Expression) _args [i];
2087 if (strArgs != "")
2088 strArgs += ", ";
2089 strArgs += arg.ToString ();
2091 return _name.ToString () + '(' + strArgs + ')';
2093 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
2094 public override XPathResultType GetReturnType (BaseIterator iter)
2096 return XPathResultType.Any;
2099 private XPathResultType [] GetArgTypes (BaseIterator iter)
2101 // TODO: can we cache these? what if the types depend on the nsm?
2102 XPathResultType [] rgArgs = new XPathResultType [_args.Count];
2103 for (int iArg = 0; iArg < _args.Count; iArg++)
2104 rgArgs [iArg] = ((Expression) _args [iArg]).GetReturnType (iter);
2105 return rgArgs;
2107 public override object Evaluate (BaseIterator iter)
2109 XPathResultType [] rgTypes = GetArgTypes (iter);
2110 IXsltContextFunction func = null;
2111 XsltContext context = iter.NamespaceManager as XsltContext;
2112 if (context != null) {
2113 if (resolvedName)
2114 func = context.ResolveFunction (_name, rgTypes);
2115 else
2116 func = context.ResolveFunction (_name.Namespace, _name.Name, rgTypes);
2119 if (func == null)
2120 throw new XPathException ("function "+_name.ToString ()+" not found");
2122 object [] rgArgs = new object [_args.Count];
2123 if (func.Maxargs != 0)
2125 XPathResultType [] rgFuncTypes = func.ArgTypes;
2126 for (int iArg = 0; iArg < _args.Count; iArg ++)
2128 XPathResultType typeArg;
2129 if (rgFuncTypes == null)
2130 typeArg = XPathResultType.Any;
2131 else if (iArg < rgFuncTypes.Length)
2132 typeArg = rgFuncTypes [iArg];
2133 else
2134 typeArg = rgFuncTypes [rgFuncTypes.Length - 1];
2136 Expression arg = (Expression) _args [iArg];
2137 object result = arg.EvaluateAs (iter, typeArg);
2138 rgArgs [iArg] = result;
2141 return func.Invoke (context, rgArgs, iter.Current);
2144 internal override bool Peer {
2145 get { return false; }