8a6133a708b5f7c3ae04110e0001a7160af13782
[mono.git] / mcs / class / System.XML / Mono.Xml.XPath / LocationPathPattern.cs
1 //
2 // Mono.Xml.XPath.LocationPathPattern
3 //
4 // Author:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //
7 // (C) 2003 Ben Maurer
8 //
9
10 //
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.
29 //
30
31 using System;
32 using System.Collections;
33 using System.IO;
34 using System.Xml;
35 using System.Xml.Schema;
36 using System.Xml.XPath;
37 using System.Xml.Xsl;
38 using Mono.Xml.Xsl;
39
40 namespace Mono.Xml.XPath {
41         internal class LocationPathPattern : Pattern {
42                 
43                 LocationPathPattern patternPrevious;
44                 bool isAncestor;
45                 NodeTest nodeTest;
46                 ExprFilter filter;
47                 
48                 public LocationPathPattern (NodeTest nodeTest)
49                 {
50                         this.nodeTest = nodeTest;
51                 }
52                 
53                 public LocationPathPattern (ExprFilter filter)
54                 {
55                         this.filter = filter;
56                         
57                         while (! (filter.expr is NodeTest))
58                                 filter = (ExprFilter)filter.expr;
59                         
60                         this.nodeTest = (NodeTest)filter.expr;
61                 }
62
63                 internal void SetPreviousPattern (Pattern prev, bool isAncestor)
64                 {
65                         LocationPathPattern toSet = LastPathPattern;
66                         toSet.patternPrevious = (LocationPathPattern)prev;
67                         toSet.isAncestor = isAncestor;
68                 }
69                 
70                 public override double DefaultPriority { 
71                         get { 
72                                 if (patternPrevious == null && filter == null) {
73                                         NodeNameTest t = nodeTest as NodeNameTest;
74                                         if (t != null) {
75                                                 if (t.Name.Name == "*" || t.Name.Name.Length == 0)
76                                                         return -.25;
77                                                 return 0;
78                                         }
79
80                                         return -.5;
81                                 }
82                                 return .5;
83                         }
84                 }
85                 
86                 public override bool Matches (XPathNavigator node, XsltContext ctx)
87                 {
88                         if (! nodeTest.Match (ctx, node))
89                                 return false;
90                         
91                         if (nodeTest is NodeTypeTest) {
92                                 // node () is different in xslt patterns
93                                 if (((NodeTypeTest)nodeTest).type == XPathNodeType.All && 
94                                         (node.NodeType == XPathNodeType.Root ||
95                                         node.NodeType == XPathNodeType.Attribute)
96                                 )
97                                 return false;
98                         }
99                         
100                         if (filter == null && patternPrevious == null)
101                                 return true;
102                         
103                         XPathNavigator tmpNav;
104                         if (patternPrevious != null) {
105                                 tmpNav = ((XsltCompiledContext) ctx).GetNavCache (this, node);
106                                 if (!isAncestor) {
107                                         tmpNav.MoveToParent ();
108                                         if (!patternPrevious.Matches (tmpNav, ctx))
109                                                 return false;
110                                 } else {
111                                         while (true) {
112                                                 if (!tmpNav.MoveToParent ())
113                                                         return false;
114                                                 
115                                                 if (patternPrevious.Matches (tmpNav, ctx))
116                                                         break;
117                                         }
118                                 }
119                         }
120
121                                                 
122                         if (filter == null)
123                                 return true;
124
125                         // Optimization for non-positional predicate
126                         if (!filter.IsPositional && !(filter.expr is ExprFilter)) {
127                                 return filter.pred.EvaluateBoolean (new NullIterator (node, ctx));
128                         }
129
130                         tmpNav = ((XsltCompiledContext) ctx).GetNavCache (this, node);
131                         tmpNav.MoveToParent ();
132
133                         BaseIterator matches = filter.EvaluateNodeSet (new NullIterator (tmpNav, ctx));
134                         
135                         while (matches.MoveNext ()) {
136                                 if (node.IsSamePosition (matches.Current))
137                                         return true;
138                         }
139                         
140                         return false;
141                 }
142                 
143                 public override string ToString ()
144                 {
145                         string ret = "";
146                         if (patternPrevious != null) ret = patternPrevious.ToString () + (isAncestor ? "//" : "/");
147                         if (filter != null) ret += filter.ToString ();
148                         else ret += nodeTest.ToString ();
149                         
150                         return ret;
151                 }
152                 
153                 public LocationPathPattern LastPathPattern {
154                         get {
155                                 LocationPathPattern ret = this;
156                                 
157                                 while (ret.patternPrevious != null)
158                                         ret = ret.patternPrevious;
159                                 
160                                 return ret;
161                         }
162                 }
163         }
164 }