1 //------------------------------------------------------------------------------
2 // <copyright file="FilterQuery.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace MS.Internal.Xml.XPath {
11 using System.Xml.XPath;
12 using System.Diagnostics;
13 using System.Globalization;
16 internal sealed class FilterQuery : BaseAxisQuery {
18 private bool noPosition;
20 public FilterQuery(Query qyParent, Query cond, bool noPosition) : base(qyParent) {
22 this.noPosition = noPosition;
24 private FilterQuery(FilterQuery other) : base(other) {
25 this.cond = Clone(other.cond);
26 this.noPosition = other.noPosition;
29 public override void Reset() {
34 public Query Condition { get { return cond; } }
36 public override void SetXsltContext(XsltContext input) {
37 base.SetXsltContext(input);
38 cond.SetXsltContext(input);
39 if (cond.StaticType != XPathResultType.Number && cond.StaticType != XPathResultType.Any && noPosition) {
40 // BugBug: We can do such trick at Evaluate time only.
41 // But to do this FilterQuery should stop inherit from BaseAxisQuery
42 ReversePositionQuery query = qyInput as ReversePositionQuery;
44 qyInput = query.input;
49 public override XPathNavigator Advance() {
50 while ((currentNode = qyInput.Advance()) != null) {
51 if (EvaluatePredicate()) {
59 internal bool EvaluatePredicate() {
60 object value = cond.Evaluate(qyInput);
61 if (value is XPathNodeIterator) return cond.Advance() != null;
62 if (value is string ) return ((string)value).Length != 0;
63 if (value is double ) return (((double)value) == qyInput.CurrentPosition);
64 if (value is bool ) return (bool)value;
65 Debug.Assert(value is XPathNavigator, "Unknown value type");
69 public override XPathNavigator MatchNode(XPathNavigator current) {
70 XPathNavigator context;
71 if (current == null) {
74 context = qyInput.MatchNode(current);
76 if (context != null) {
77 // In this switch we process some special case in wich we can calculate predicate faster then in generic case
78 switch (cond.StaticType) {
79 case XPathResultType.Number:
80 OperandQuery operand = cond as OperandQuery;
81 if (operand != null) {
82 double val = (double)operand.val;
83 ChildrenQuery childrenQuery = qyInput as ChildrenQuery;
84 if (childrenQuery != null) { // foo[2], but not foo[expr][2]
85 XPathNavigator result = current.Clone();
86 result.MoveToParent();
88 result.MoveToFirstChild();
90 if (childrenQuery.matches(result)) {
92 if (current.IsSamePosition(result)) {
93 return val == i ? context : null;
96 } while (result.MoveToNext());
99 AttributeQuery attributeQuery = qyInput as AttributeQuery;
100 if (attributeQuery != null) {// @foo[3], but not @foo[expr][2]
101 XPathNavigator result = current.Clone();
102 result.MoveToParent();
104 result.MoveToFirstAttribute();
106 if (attributeQuery.matches(result)) {
108 if (current.IsSamePosition(result)) {
109 return val == i ? context : null;
112 } while (result.MoveToNextAttribute());
117 case XPathResultType.NodeSet:
118 cond.Evaluate(new XPathSingletonIterator(current, /*moved:*/true));
119 return (cond.Advance() != null) ? context : null;
120 case XPathResultType.Boolean:
122 return ((bool)cond.Evaluate(new XPathSingletonIterator(current, /*moved:*/true))) ? context : null;
125 case XPathResultType.String:
127 return (((string)cond.Evaluate(new XPathSingletonIterator(current, /*moved:*/true))).Length != 0) ? context : null;
130 case XPathResultType_Navigator:
136 Evaluate(new XPathSingletonIterator(context, /*moved:*/true));
137 XPathNavigator result;
138 while ((result = Advance()) != null) {
139 if (result.IsSamePosition(current)) {
148 public override QueryProps Properties {
150 return QueryProps.Position | (qyInput.Properties & (QueryProps.Merge | QueryProps.Reverse));
154 public override XPathNodeIterator Clone() { return new FilterQuery(this); }
156 public override void PrintQuery(XmlWriter w) {
157 w.WriteStartElement(this.GetType().Name);
160 w.WriteAttributeString("position", "yes");
162 qyInput.PrintQuery(w);