5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
9 // (C) 2003 Atsushi Enomoto
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Collections;
35 using System.Collections.Specialized;
37 using System.Xml.Schema;
38 using System.Xml.XPath;
42 using QName = System.Xml.XmlQualifiedName;
44 namespace Mono.Xml.Xsl
46 internal class ExprKeyContainer : Expression
49 public ExprKeyContainer (Expression expr)
54 public Expression BodyExpression {
58 public override object Evaluate (BaseIterator iter)
60 return expr.Evaluate (iter);
63 internal override XPathNodeType EvaluatedNodeType {
64 get { return expr.EvaluatedNodeType; }
67 public override XPathResultType ReturnType {
68 get { return expr.ReturnType; }
71 public override bool RequireSorting {
79 CompiledExpression useExpr;
82 // Hashtable mappedDocuments;
84 public XslKey (Compiler c)
86 this.name = c.ParseQNameAttribute ("name");
88 c.KeyCompilationMode = true;
89 useExpr = c.CompileExpression (c.GetAttribute ("use"));
91 useExpr = c.CompileExpression (".");
93 c.AssertAttribute ("match");
94 string matchString = c.GetAttribute ("match");
95 this.matchPattern = c.CompilePattern (matchString, c.Input);
96 c.KeyCompilationMode = false;
99 public QName Name { get { return name; }}
100 internal CompiledExpression Use { get { return useExpr; }}
101 internal Pattern Match { get { return matchPattern; }}
104 // represents part of dynamic context that holds index table for a key
105 internal class KeyIndexTable
107 XsltCompiledContext ctx;
110 Hashtable mappedDocuments;
112 public KeyIndexTable (XsltCompiledContext ctx, XslKey key)
122 private void CollectTable (XPathNavigator doc, XsltContext ctx)
124 XPathNavigator nav = doc.Clone ();
126 XPathNavigator tmp = doc.Clone ();
129 if (key.Match.Matches (nav, ctx)) {
131 CollectIndex (nav, tmp);
133 } while (MoveNavigatorToNext (nav));
135 foreach (ArrayList list in map.Values)
136 list.Sort (XPathNavigatorComparer.Instance);
139 private bool MoveNavigatorToNext (XPathNavigator nav)
141 if (nav.MoveToFirstChild ())
144 if (nav.MoveToNext ())
146 } while (nav.MoveToParent ());
150 private void CollectIndex (XPathNavigator nav, XPathNavigator target)
152 XPathNodeIterator iter;
153 switch (key.Use.ReturnType) {
154 case XPathResultType.NodeSet:
155 iter = nav.Select (key.Use);
156 while (iter.MoveNext ())
157 AddIndex (iter.Current.Value, target);
159 case XPathResultType.Any:
160 object o = nav.Evaluate (key.Use);
161 iter = o as XPathNodeIterator;
163 while (iter.MoveNext ())
164 AddIndex (iter.Current.Value, target);
167 AddIndex (XPathFunctions.ToString (o), target);
170 string keyValue = nav.EvaluateString (key.Use, null, null);
171 AddIndex (keyValue, target);
176 private void AddIndex (string key, XPathNavigator target)
178 ArrayList al = map [key] as ArrayList;
180 al = new ArrayList ();
183 for (int i = 0; i < al.Count; i++)
184 if (((XPathNavigator) al [i]).IsSamePosition (target))
186 al.Add (target.Clone ());
189 private ArrayList GetNodesByValue (XPathNavigator nav, string value, XsltContext ctx)
192 mappedDocuments = new Hashtable ();
193 map = new Hashtable ();
195 if (!mappedDocuments.ContainsKey (nav.BaseURI)) {
196 mappedDocuments.Add (nav.BaseURI, nav.BaseURI);
197 CollectTable (nav, ctx);
200 return map [value] as ArrayList;
203 public bool Matches (XPathNavigator nav, string value, XsltContext ctx)
205 ArrayList al = GetNodesByValue (nav, value, ctx);
208 for (int i = 0; i < al.Count; i++)
209 if (((XPathNavigator) al [i]).IsSamePosition (nav))
214 // Invoked from XsltKey (XPathFunction)
215 public BaseIterator Evaluate (BaseIterator iter,
216 Expression valueExpr)
219 ArrayList result = new ArrayList ();
220 object o = valueExpr.Evaluate (iter);
221 XPathNodeIterator it = o as XPathNodeIterator;
222 XsltContext ctx = iter.NamespaceManager as XsltContext;
225 while (it.MoveNext())
226 FindKeyMatch (it.Current.Value, result, iter.Current, ctx);
228 FindKeyMatch (XPathFunctions.ToString (o), result, iter.Current, ctx);
230 result.Sort (XPathNavigatorComparer.Instance);
231 return new ListIterator (result, (ctx));
234 XPathNodeIterator i = iter;
235 if (iter.CurrentPosition == 0) {
239 XPathNavigator nav = i.Current;
241 object o = valueExpr.Evaluate (iter);
242 XPathNodeIterator it = o as XPathNodeIterator;
243 XsltContext ctx = iter.NamespaceManager as XsltContext;
245 BaseIterator result = null;
248 while (it.MoveNext()) {
249 ArrayList nodes = GetNodesByValue (
250 it.Current, it.Current.Value, ctx);
254 new ListIterator (nodes, ctx);
258 result = new UnionIterator (
263 ArrayList nodes = GetNodesByValue (
264 nav, XPathFunctions.ToString (o), ctx);
266 result = new ListIterator (nodes, ctx);
269 return result != null ? result : new NullIterator (iter);
273 void FindKeyMatch (string value, ArrayList result, XPathNavigator context, XsltContext xsltContext)
275 XPathNavigator searchDoc = context;//.Clone ();
276 searchDoc.MoveToRoot ();
278 XPathNodeIterator desc = searchDoc.SelectDescendants (XPathNodeType.All, true);
280 while (desc.MoveNext ()) {
281 if (Matches (desc.Current, value, xsltContext))
282 AddResult (result, desc.Current);
284 if (!desc.Current.MoveToFirstAttribute ())
287 if (Matches (desc.Current, value, xsltContext))
288 AddResult (result, desc.Current);
289 } while (desc.Current.MoveToNextAttribute ());
291 desc.Current.MoveToParent ();
296 void AddResult (ArrayList result, XPathNavigator nav)
298 for (int i = 0; i < result.Count; i++) {
299 XmlNodeOrder docOrder = nav.ComparePosition (((XPathNavigator)result [i]));
300 if (docOrder == XmlNodeOrder.Same)
303 if (docOrder == XmlNodeOrder.Before) {
304 result.Insert(i, nav.Clone ());
308 result.Add (nav.Clone ());