Copied remotely
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XslKey.cs
1 //
2 // XslKey.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //      
8 // (C) 2003 Ben Maurer
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Xml;
37 using System.Xml.Schema;
38 using System.Xml.XPath;
39 using System.Xml.Xsl;
40
41 using QName = System.Xml.XmlQualifiedName;
42
43 namespace Mono.Xml.Xsl
44 {
45         internal class ExprKeyContainer : Expression
46         {
47                 Expression expr;
48                 public ExprKeyContainer (Expression expr)
49                 {
50                         this.expr = expr;
51                 }
52
53                 public Expression BodyExpression {
54                         get { return expr; }
55                 }
56
57                 public override object Evaluate (BaseIterator iter)
58                 {
59                         return expr.Evaluate (iter);
60                 }
61
62                 internal override XPathNodeType EvaluatedNodeType {\r
63                         get { return expr.EvaluatedNodeType; }\r
64                 }\r
65 \r
66                 internal override bool NeedAbsoluteMatching {\r
67                         // This must be evaluated at any point.\r
68                         get { return true; }\r
69                 }\r
70 \r
71                 public override XPathResultType ReturnType {\r
72                         get { return expr.ReturnType; }\r
73                 }
74
75                 public override bool RequireSorting {
76                         get { return true; }
77                 }
78         }
79
80         internal class XslKey
81         {
82                 QName name;
83                 CompiledExpression usePattern;
84                 CompiledExpression matchPattern;
85                 Hashtable map;
86                 Hashtable mappedDocuments;
87
88                 public XslKey (Compiler c)
89                 {
90                         this.name = c.ParseQNameAttribute ("name");
91
92                         c.KeyCompilationMode = true;
93                         usePattern = c.CompileExpression (c.GetAttribute ("use"));
94                         if (usePattern == null)
95                                 usePattern = c.CompileExpression (".");
96
97                         c.AssertAttribute ("match");
98                         string matchString = c.GetAttribute ("match");
99                         this.matchPattern = c.CompileExpression (matchString, true);
100                         c.KeyCompilationMode = false;
101                 }
102
103                 public QName Name { get { return name; }}
104                 internal CompiledExpression UsePattern { get { return usePattern; }}
105                 internal CompiledExpression MatchPattern { get { return matchPattern; }}
106
107                 internal void ClearKeyTable ()
108                 {
109                         if (map != null) {
110                                 map.Clear ();
111                                 map = null;
112                         }
113                         if (mappedDocuments != null) {
114                                 mappedDocuments.Clear ();
115                                 mappedDocuments = null;
116                         }
117                 }
118
119                 internal void CollectTable (XPathNavigator doc)
120                 {
121                         XPathNavigator nav = doc.Clone ();
122                         nav.MoveToRoot ();
123 //                      Expression expr = ((ExprKeyContainer) MatchPattern.ExpressionNode).BodyExpression;
124 //                      if (expr.NeedAbsoluteMatching)
125 //                              CollectAbsoluteMatchNodes (nav);
126 //                      else
127                                 CollectRelativeMatchNodes (nav);
128                 }
129
130                 private void CollectAbsoluteMatchNodes (XPathNavigator nav)
131                 {
132                         XPathNodeIterator iter = nav.Select (MatchPattern);
133                         while (iter.MoveNext ())
134                                 CollectIndex (iter.Current);
135                 }
136
137                 private void CollectRelativeMatchNodes (XPathNavigator nav)
138                 {
139                         do {
140                                 if (nav.NodeType != XPathNodeType.Root)
141                                         while (!nav.MoveToNext ())
142                                                 if (!nav.MoveToParent ())
143                                                         // finished
144                                                         return;
145                                 do {
146                                         do {
147                                                 if (nav.Matches (MatchPattern))
148                                                         CollectIndex (nav);
149                                         } while (nav.MoveToFirstChild ());
150                                 } while (nav.MoveToNext ());
151                         } while (nav.MoveToParent ());
152                 }
153
154                 private void CollectIndex (XPathNavigator nav)
155                 {
156                         XPathNavigator target = nav.Clone ();
157                         XPathNodeIterator iter;
158                         switch (UsePattern.ReturnType) {
159                         case XPathResultType.NodeSet:
160                                 iter = nav.Select (UsePattern);
161                                 while (iter.MoveNext ())
162                                         AddIndex (iter.Current.Value, target);
163                                 break;
164                         case XPathResultType.Any:
165                                 object o = nav.Evaluate (UsePattern);
166                                 iter = o as XPathNodeIterator;
167                                 if (iter != null) {
168                                         while (iter.MoveNext ())
169                                                 AddIndex (iter.Current.Value, target);
170                                 }
171                                 else
172                                         AddIndex (nav.EvaluateString (UsePattern, null, null), target);
173                                 break;
174                         default:
175                                 string key = nav.EvaluateString (UsePattern, null, null);
176                                 AddIndex (key, target);
177                                 break;
178                         }
179                 }
180
181                 private void AddIndex (string key, XPathNavigator target)
182                 {
183                         ArrayList al = map [key] as ArrayList;
184                         if (al == null) {
185                                 al = new ArrayList ();
186                                 map [key] = al;
187                         }
188                         al.Add (target);
189                 }
190
191                 public bool Matches (XPathNavigator nav, XmlNamespaceManager nsmgr, string value)
192                 {
193                         if (map == null) {
194                                 mappedDocuments = new Hashtable ();
195                                 map = new Hashtable ();
196                         }
197                         if (mappedDocuments [nav.BaseURI] == null) {
198                                 mappedDocuments.Add (nav.BaseURI, nav.BaseURI);
199                                 MatchPattern.SetContext (nsmgr);
200                                 UsePattern.SetContext (nsmgr);
201                                 CollectTable (nav);
202                                 MatchPattern.SetContext (null);
203                                 UsePattern.SetContext (null);
204                         }
205                         
206                         ArrayList al = map [value] as ArrayList;
207                         if (al == null)
208                                 return false;
209                         for (int i = 0; i < al.Count; i++)
210                                 if (((XPathNavigator) al [i]).IsSamePosition (nav))
211                                         return true;
212                         return false;
213                 }
214         }
215 }