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
;
40 using NSResolver
= System
.Xml
.IXmlNamespaceResolver
;
42 using NSResolver
= System
.Xml
.XmlNamespaceManager
;
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
;
60 table_per_ctx
[ctxkey
] = null;
63 Hashtable table
= (Hashtable
) wr
.Target
;
65 wr
= table
[xpath
] as WeakReference
;
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
;
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
;
85 table
= new Hashtable ();
86 table_per_ctx
[ctxkey
] = new WeakReference (table
);
88 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
)
128 public override void SetContext (IXmlNamespaceResolver nsResolver
)
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
);
144 return _expr
.Evaluate (iter
);
147 return _expr
.Evaluate (iter
);
149 catch (XPathException
) {
152 catch (XsltException
) {
155 catch (Exception e
) {
156 throw new XPathException ("Error during evaluation", e
);
160 public XPathNodeIterator
EvaluateNodeSet (BaseIterator iter
)
166 BaseIterator iterResults
= _expr
.EvaluateNodeSet (iter
);
167 if (_sorters
!= null)
168 return _sorters
.Sort (iterResults
);
172 catch (XPathException
)
178 throw new XPathException ("Error during evaluation", e
);
182 public double EvaluateNumber (BaseIterator iter
)
185 return _expr
.EvaluateNumber (iter
);
189 return _expr
.EvaluateNumber (iter
);
191 catch (XPathException
)
197 throw new XPathException ("Error during evaluation", e
);
201 public string EvaluateString (BaseIterator iter
)
204 return _expr
.EvaluateString (iter
);
208 return _expr
.EvaluateString (iter
);
210 catch (XPathException
)
216 throw new XPathException ("Error during evaluation", e
);
220 public bool EvaluateBoolean (BaseIterator iter
)
223 return _expr
.EvaluateBoolean (iter
);
227 return _expr
.EvaluateBoolean (iter
);
229 catch (XPathException
)
235 throw new XPathException ("Error during evaluation", e
);
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
)
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
);
306 public BaseIterator
Sort (ArrayList rgElts
, NSResolver nsm
)
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
]);
329 switch (elt1
.Navigator
.ComparePosition (elt2
.Navigator
)) {
330 case XmlNodeOrder
.Same
:
332 case XmlNodeOrder
.After
:
342 readonly Expression _expr
;
343 readonly IComparer _cmp
;
344 readonly XmlDataType _type
;
346 public XPathSorter (object expr
, IComparer cmp
)
348 _expr
= ExpressionFromObject (expr
);
350 _type
= XmlDataType
.Text
;
353 public XPathSorter (object expr
, XmlSortOrder orderSort
, XmlCaseOrder orderCase
, string lang
, XmlDataType dataType
)
355 _expr
= ExpressionFromObject (expr
);
357 if (dataType
== XmlDataType
.Number
)
358 _cmp
= new XPathNumberComparer (orderSort
);
360 _cmp
= new XPathTextComparer (orderSort
, orderCase
, lang
);
363 static Expression
ExpressionFromObject (object expr
)
365 if (expr
is CompiledExpression
)
366 return ((CompiledExpression
) expr
).ExpressionNode
;
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
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
;
404 if (double.IsNaN (num1
))
405 return (double.IsNaN (num2
)) ? 0 : -_nMulSort
;
410 class XPathTextComparer
: IComparer
414 XmlCaseOrder _orderCase
;
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?
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
);
445 /// Summary description for Expression.
447 internal abstract class Expression
452 public abstract XPathResultType ReturnType { get; }
453 public virtual XPathResultType
GetReturnType (BaseIterator iter
) { return ReturnType; }
455 public virtual Expression
Optimize ()
460 public virtual bool HasStaticValue
{
461 get { return false; }
464 public virtual object StaticValue
{
466 switch (ReturnType
) {
467 case XPathResultType
.String
:
468 return StaticValueAsString
;
469 case XPathResultType
.Number
:
470 return StaticValueAsNumber
;
471 case XPathResultType
.Boolean
:
472 return StaticValueAsBoolean
;
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
);
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;
507 iterResult
= xi
as BaseIterator
;
508 if (iterResult
== null)
509 iterResult
= new WrapperIterator (xi
, iter
.NamespaceManager
);
512 XPathNavigator nav
= o
as XPathNavigator
;
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)
522 return new NullIterator (iter
);
523 type
= GetReturnType (o
);
526 throw new XPathException (String
.Format ("expected nodeset but was {1}: {0}", ToString (), type
));
529 protected static XPathResultType
GetReturnType (object obj
)
532 return XPathResultType
.String
;
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
)
561 XPathResultType type
= GetReturnType (iter
);
562 if (type
== XPathResultType
.NodeSet
)
564 result
= EvaluateString (iter
);
565 type
= XPathResultType
.String
;
568 result
= Evaluate (iter
);
570 if (type
== XPathResultType
.Any
)
571 type
= GetReturnType (result
);
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
);
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
);
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 ())
608 return iterResult
.Current
.Value
;
610 case XPathResultType
.Navigator
:
611 return ((XPathNavigator
) result
).Value
;
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
);
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
);
637 throw new XPathException ("invalid node type");
641 public object EvaluateAs (BaseIterator iter
, XPathResultType 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
)
669 public override Expression
Optimize ()
671 _left
= _left
.Optimize ();
672 _right
= _right
.Optimize ();
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
{
688 if (_left
.EvaluatedNodeType
== _right
.EvaluatedNodeType
)
689 return _left
.EvaluatedNodeType
;
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 ()
713 else if (StaticValueAsBoolean
)
714 return new XPathFunctionTrue (null);
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
))
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
))
765 return _right
.EvaluateBoolean (iter
);
769 internal abstract class EqualityExpr
: ExprBoolean
772 public EqualityExpr (Expression left
, Expression right
, bool trueVal
) : base (left
, right
)
774 this.trueVal
= trueVal
;
777 public override bool StaticValueAsBoolean
{
781 if ((_left
.ReturnType
== XPathResultType
.Navigator
|| _right
.ReturnType
== XPathResultType
.Navigator
) && _left
.ReturnType
== _right
.ReturnType
)
782 return (_left
.StaticValueAsNavigator
.IsSamePosition (
783 _right
.StaticValueAsNavigator
))
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
)
820 XPathResultType typeTmp
= typeL
;
829 if (typeR
== XPathResultType
.Boolean
)
831 return left
.EvaluateBoolean (iter
) == right
.EvaluateBoolean (iter
) == trueVal
;
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
)
843 else if (typeR
== XPathResultType
.String
)
845 string strR
= right
.EvaluateString (iter
);
846 while (iterL
.MoveNext ())
847 if (iterL
.Current
.Value
== strR
== trueVal
)
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
)
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
;
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
)
922 XPathResultType typeTmp
= typeL
;
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
);
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
))
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
))
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
)
971 return Compare (arg2
, arg1
);
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
)
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
)
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
)
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 ()
1025 return !HasStaticValue
?
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
1114 public ExprNEG (Expression 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
?
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
)
1175 public override Expression
Optimize ()
1177 left
= left
.Optimize ();
1178 right
= right
.Optimize ();
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
{
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
)
1221 public override Expression
Optimize ()
1223 left
= left
.Optimize ();
1224 right
= (NodeSet
) right
.Optimize ();
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
{
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
)
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
));
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
);
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
{
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 ();
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; }
1380 internal class AxisSpecifier
1382 protected Axes _axis
;
1383 public AxisSpecifier (Axes axis
)
1387 public XPathNodeType NodeType
1392 case Axes
.Namespace
:
1393 return XPathNodeType
.Namespace
;
1394 case Axes
.Attribute
:
1395 return XPathNodeType
.Attribute
;
1397 return XPathNodeType
.Element
;
1401 public override string ToString ()
1406 case Axes
.AncestorOrSelf
:
1407 return "ancestor-or-self";
1408 case Axes
.Attribute
:
1412 case Axes
.Descendant
:
1413 return "descendant";
1414 case Axes
.DescendantOrSelf
:
1415 return "descendant-or-self";
1416 case Axes
.Following
:
1418 case Axes
.FollowingSibling
:
1419 return "following-sibling";
1420 case Axes
.Namespace
:
1424 case Axes
.Preceding
:
1426 case Axes
.PrecedingSibling
:
1427 return "preceding-sibling";
1431 throw new IndexOutOfRangeException ();
1434 public Axes Axis { get { return _axis; }}
1435 public BaseIterator
Evaluate (BaseIterator iter
)
1439 return new AncestorIterator (iter
);
1440 case Axes
.AncestorOrSelf
:
1441 return new AncestorOrSelfIterator (iter
);
1442 case Axes
.Attribute
:
1443 return new AttributeIterator (iter
);
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
);
1457 return new ParentIterator (iter
);
1458 case Axes
.Preceding
:
1459 return new PrecedingIterator (iter
);
1460 case Axes
.PrecedingSibling
:
1461 return new PrecedingSiblingIterator (iter
);
1463 return new SelfIterator (iter
);
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
{
1489 switch (_axis
.Axis
) {
1491 case Axes
.AncestorOrSelf
:
1492 case Axes
.Preceding
:
1493 case Axes
.PrecedingSibling
:
1494 case Axes
.Attribute
:
1495 case Axes
.Namespace
:
1504 internal override bool Peer
{
1506 switch (_axis
.Axis
) {
1508 case Axes
.AncestorOrSelf
:
1509 case Axes
.DescendantOrSelf
:
1510 case Axes
.Descendant
:
1511 case Axes
.Preceding
:
1512 case Axes
.Following
:
1520 internal override bool Subtree
{
1522 switch (_axis
.Axis
) {
1525 case Axes
.AncestorOrSelf
:
1526 case Axes
.Preceding
:
1527 case Axes
.PrecedingSibling
:
1528 case Axes
.Following
:
1529 case Axes
.FollowingSibling
:
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
)
1555 // FIXME: Better description
1556 public NodeTypeTest (Axes axis
, XPathNodeType type
, String param
) : base (axis
)
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
)
1569 _param
= other
._param
;
1572 public override String
ToString ()
1574 String strType
= ToString (type
);
1575 if (type
== XPathNodeType
.ProcessingInstruction
&& _param
!= null)
1576 strType
+= "('" + _param
+ "')";
1580 return _axis
.ToString () + "::" + strType
;
1583 private static String
ToString (XPathNodeType type
)
1586 case XPathNodeType
.Comment
:
1588 case XPathNodeType
.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
:
1598 return "node-type [" + type
.ToString () + "]";
1602 public override bool Match (NSResolver nsm
, XPathNavigator nav
)
1604 XPathNodeType nodeType
= nav
.NodeType
;
1606 case XPathNodeType
.All
:
1609 case XPathNodeType
.ProcessingInstruction
:
1610 if (nodeType
!= XPathNodeType
.ProcessingInstruction
)
1612 if (_param
!= null && nav
.Name
!= _param
)
1616 case XPathNodeType
.Text
:
1618 case XPathNodeType
.Text
:
1619 case XPathNodeType
.Whitespace
:
1620 case XPathNodeType
.SignificantWhitespace
:
1626 return type
== nodeType
;
1630 public override void GetInfo (out string name
, out string ns
, out XPathNodeType nodetype
, NSResolver nsm
)
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
)
1645 name
= ctx
.LookupQName (name
.ToString ());
1646 resolvedName
= true;
1651 public NodeNameTest (Axes axis
, XmlQualifiedName name
, bool resolvedName
) : base (axis
)
1654 this.resolvedName
= resolvedName
;
1657 // for optimized path rewrite
1658 internal NodeNameTest (NodeNameTest source
, Axes 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
)
1675 if (_name
.Name
!= "")
1677 // test the local part of the name first
1678 if (_name
.Name
!= nav
.LocalName
)
1682 // get the prefix for the given name
1683 String strURI1
= "";
1684 if (_name
.Namespace
!= "")
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
1693 strURI1
= nsm
.LookupNamespace (_name
.Namespace
);
1695 strURI1
= nsm
.LookupNamespace (_name
.Namespace
, false);
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
!= "")
1715 if (nsm
!= null && _name
.Namespace
!= "") {
1717 ns
= _name
.Namespace
;
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
1723 ns
= nsm
.LookupNamespace (_name
.Namespace
); // TODO: check to see if this returns null or ""
1725 ns
= nsm
.LookupNamespace (_name
.Namespace
, false); // TODO: check to see if this returns null or ""
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
)
1743 public override Expression
Optimize ()
1745 expr
= expr
.Optimize ();
1746 pred
= pred
.Optimize ();
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
{
1764 if (pred
.ReturnType
== XPathResultType
.Number
)
1766 return expr
.IsPositional
|| pred
.IsPositional
;
1770 internal override bool Peer
{
1771 get { return expr.Peer && pred.Peer; }
1774 internal override bool Subtree
{
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)
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
)
1809 public override double EvaluateNumber (BaseIterator iter
)
1814 internal override bool IsPositional
{
1815 get { return false; }
1819 internal class BooleanConstant
: Expression
1823 public BooleanConstant (bool 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
)
1848 public override bool EvaluateBoolean (BaseIterator iter
)
1854 internal class ExprLiteral
: Expression
1856 protected String _value
;
1857 public ExprLiteral (String
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
)
1882 public override string EvaluateString (BaseIterator iter
)
1888 internal class ExprVariable
: Expression
1890 protected XmlQualifiedName _name
;
1891 protected bool resolvedName
= false;
1892 public ExprVariable (XmlQualifiedName name
, IStaticXsltContext ctx
)
1895 name
= ctx
.LookupQName (name
.ToString ());
1896 resolvedName
= true;
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) {
1915 var = context
.ResolveVariable (_name
);
1917 var = context
.ResolveVariable (new XmlQualifiedName (_name
.Name
, _name
.Namespace
));
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));
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
);
1931 internal override bool Peer
{
1932 get { return false; }
1936 internal class ExprParens
: Expression
1938 protected Expression _expr
;
1939 public ExprParens (Expression expr
)
1944 public override Expression
Optimize ()
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
);
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
)
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;
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
)
2036 name
= ctx
.LookupQName (name
.ToString ());
2037 resolvedName
= true;
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
];
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
);
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) {
2114 func
= context
.ResolveFunction (_name
, rgTypes
);
2116 func
= context
.ResolveFunction (_name
.Namespace
, _name
.Name
, rgTypes
);
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
];
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; }