2007-02-18 Marek Sieradzki <marek.sieradzki@gmail.com>
[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 XPathNodeType EvaluatedNodeType {
87                         get { return nodeTest.EvaluatedNodeType; }
88                 }
89                 
90                 public override bool Matches (XPathNavigator node, XsltContext ctx)
91                 {
92                         if (! nodeTest.Match (ctx, node))
93                                 return false;
94                         
95                         if (nodeTest is NodeTypeTest) {
96                                 // node () is different in xslt patterns
97                                 if (((NodeTypeTest)nodeTest).type == XPathNodeType.All && 
98                                         (node.NodeType == XPathNodeType.Root ||
99                                         node.NodeType == XPathNodeType.Attribute)
100                                 )
101                                 return false;
102                         }
103                         
104                         if (filter == null && patternPrevious == null)
105                                 return true;
106                         
107                         XPathNavigator tmpNav;
108                         if (patternPrevious != null) {
109                                 tmpNav = ((XsltCompiledContext) ctx).GetNavCache (this, node);
110                                 if (!isAncestor) {
111                                         tmpNav.MoveToParent ();
112                                         if (!patternPrevious.Matches (tmpNav, ctx))
113                                                 return false;
114                                 } else {
115                                         while (true) {
116                                                 if (!tmpNav.MoveToParent ())
117                                                         return false;
118                                                 
119                                                 if (patternPrevious.Matches (tmpNav, ctx))
120                                                         break;
121                                         }
122                                 }
123                         }
124
125                                                 
126                         if (filter == null)
127                                 return true;
128
129                         // Optimization for non-positional predicate
130                         if (!filter.IsPositional && !(filter.expr is ExprFilter)) {
131                                 return filter.pred.EvaluateBoolean (new NullIterator (node, ctx));
132                         }
133
134                         tmpNav = ((XsltCompiledContext) ctx).GetNavCache (this, node);
135                         tmpNav.MoveToParent ();
136
137                         BaseIterator matches = filter.EvaluateNodeSet (new NullIterator (tmpNav, ctx));
138                         
139                         while (matches.MoveNext ()) {
140                                 if (node.IsSamePosition (matches.Current))
141                                         return true;
142                         }
143                         
144                         return false;
145                 }
146                 
147                 public override string ToString ()
148                 {
149                         string ret = "";
150                         if (patternPrevious != null) ret = patternPrevious.ToString () + (isAncestor ? "//" : "/");
151                         if (filter != null) ret += filter.ToString ();
152                         else ret += nodeTest.ToString ();
153                         
154                         return ret;
155                 }
156                 
157                 public LocationPathPattern LastPathPattern {
158                         get {
159                                 LocationPathPattern ret = this;
160                                 
161                                 while (ret.patternPrevious != null)
162                                         ret = ret.patternPrevious;
163                                 
164                                 return ret;
165                         }
166                 }
167         }
168 }