2003-09-20 Ben Maurer <bmaurer@users.sourceforge.net>
[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 using System;
11 using System.Collections;
12 using System.IO;
13 using System.Xml;
14 using System.Xml.Schema;
15 using System.Xml.XPath;
16 using System.Xml.Xsl;
17
18 namespace Mono.Xml.XPath {
19         internal class LocationPathPattern : Pattern {
20                 
21                 internal LocationPathPattern patternPrevious;
22                 internal bool isAncestor;
23                 internal NodeTest nodeTest;
24                 ExprFilter filter;
25                 
26                 public LocationPathPattern (NodeTest nodeTest)
27                 {
28                         this.nodeTest = nodeTest;
29                 }
30                 
31                 public LocationPathPattern (ExprFilter filter)
32                 {
33                         this.filter = filter;
34                         
35                         while (! (filter.expr is NodeTest))
36                                 filter = (ExprFilter)filter.expr;
37                         
38                         this.nodeTest = (NodeTest)filter.expr;
39                 }
40
41                 internal void SetPreviousPattern (Pattern prev, bool isAncestor)
42                 {
43                         LocationPathPattern toSet = LastPathPattern;
44                         toSet.patternPrevious = (LocationPathPattern)prev;
45                         toSet.isAncestor = isAncestor;
46                 }
47                 
48                 public override double DefaultPriority { 
49                         get { 
50                                 if (patternPrevious == null && filter == null) {
51                                         NodeNameTest t = nodeTest as NodeNameTest;
52                                         if (t != null) {
53                                                 if (t.Name.Name == "*")
54                                                         return -.25;
55                                                 return 0;
56                                         }
57
58                                         return -.5;
59                                 }
60                                 return .5;
61                         }
62                 }
63                 
64                 public override bool Matches (XPathNavigator node, XsltContext ctx)
65                 {
66                         if (! nodeTest.Match (ctx, node))
67                                 return false;
68                         
69                         if (nodeTest is NodeTypeTest) {
70                                 // node () is different in xslt patterns
71                                 if (((NodeTypeTest)nodeTest).type == XPathNodeType.All && 
72                                         (node.NodeType == XPathNodeType.Root ||
73                                         node.NodeType == XPathNodeType.Attribute)
74                                 )
75                                 return false;
76                         }
77                         
78                         if (filter == null && patternPrevious == null)
79                                 return true;
80                         
81                         if (patternPrevious != null) {
82                                 if (!isAncestor) {
83                                         XPathNavigator parent = node.Clone ();
84                                         parent.MoveToParent ();
85                                         if (!patternPrevious.Matches (parent, ctx))
86                                                 return false;
87                                 } else {
88                                         XPathNavigator anc = node.Clone ();
89                                         while (true) {
90                                                 if (!anc.MoveToParent ())
91                                                         return false;
92                                                 
93                                                 if (patternPrevious.Matches (anc, ctx))
94                                                         break;
95                                         }
96                                 }
97                         }
98
99                                                 
100                         if (filter == null)
101                                 return true;
102                         
103                         XPathNavigator p = node.Clone ();
104                         p.MoveToParent ();
105                         BaseIterator matches = filter.EvaluateNodeSet (new NullIterator (p, ctx));
106                         
107                         while (matches.MoveNext ()) {
108                                 if (node.IsSamePosition (matches.Current))
109                                         return true;
110                         }
111                         
112                         return false;
113                 }
114                 
115                 public override string ToString ()
116                 {
117                         string ret = "";
118                         if (patternPrevious != null) ret = patternPrevious.ToString () + (isAncestor ? "//" : "/");
119                         if (filter != null) ret += filter.ToString ();
120                         else ret += nodeTest.ToString ();
121                         
122                         return ret;
123                 }
124                 
125                 public LocationPathPattern LastPathPattern {
126                         get {
127                                 LocationPathPattern ret = this;
128                                 
129                                 while (ret.patternPrevious != null)
130                                         ret = ret.patternPrevious;
131                                 
132                                 return ret;
133                         }
134                 }
135         }
136 }