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; }
75 CompiledExpression useExpr;
78 public XslKey (Compiler c)
80 this.name = c.ParseQNameAttribute ("name");
82 c.KeyCompilationMode = true;
83 useExpr = c.CompileExpression (c.GetAttribute ("use"));
85 useExpr = c.CompileExpression (".");
87 c.AssertAttribute ("match");
88 string matchString = c.GetAttribute ("match");
89 this.matchPattern = c.CompilePattern (matchString, c.Input);
90 c.KeyCompilationMode = false;
93 public QName Name { get { return name; }}
94 internal CompiledExpression Use { get { return useExpr; }}
95 internal Pattern Match { get { return matchPattern; }}
98 // represents part of dynamic context that holds index table for a key
99 internal class KeyIndexTable
101 XsltCompiledContext ctx;
104 Hashtable mappedDocuments;
106 public KeyIndexTable (XsltCompiledContext ctx, XslKey key)
116 private void CollectTable (XPathNavigator doc, XsltContext ctx)
118 XPathNavigator nav = doc.Clone ();
120 XPathNavigator tmp = doc.Clone ();
123 if (key.Match.Matches (nav, ctx)) {
125 CollectIndex (nav, tmp);
127 } while (MoveNavigatorToNext (nav));
129 foreach (ArrayList list in map.Values)
130 list.Sort (XPathNavigatorComparer.Instance);
133 private bool MoveNavigatorToNext (XPathNavigator nav)
135 if (nav.MoveToFirstChild ())
138 if (nav.MoveToNext ())
140 } while (nav.MoveToParent ());
144 private void CollectIndex (XPathNavigator nav, XPathNavigator target)
146 XPathNodeIterator iter;
147 switch (key.Use.ReturnType) {
148 case XPathResultType.NodeSet:
149 iter = nav.Select (key.Use);
150 while (iter.MoveNext ())
151 AddIndex (iter.Current.Value, target);
153 case XPathResultType.Any:
154 object o = nav.Evaluate (key.Use);
155 iter = o as XPathNodeIterator;
157 while (iter.MoveNext ())
158 AddIndex (iter.Current.Value, target);
161 AddIndex (XPathFunctions.ToString (o), target);
164 string keyValue = nav.EvaluateString (key.Use, null, null);
165 AddIndex (keyValue, target);
170 private void AddIndex (string key, XPathNavigator target)
172 ArrayList al = map [key] as ArrayList;
174 al = new ArrayList ();
177 for (int i = 0; i < al.Count; i++)
178 if (((XPathNavigator) al [i]).IsSamePosition (target))
180 al.Add (target.Clone ());
183 private ArrayList GetNodesByValue (XPathNavigator nav, string value, XsltContext ctx)
186 mappedDocuments = new Hashtable ();
187 map = new Hashtable ();
189 if (!mappedDocuments.ContainsKey (nav.BaseURI)) {
190 mappedDocuments.Add (nav.BaseURI, nav.BaseURI);
191 CollectTable (nav, ctx);
194 return map [value] as ArrayList;
197 public bool Matches (XPathNavigator nav, string value, XsltContext ctx)
199 ArrayList al = GetNodesByValue (nav, value, ctx);
202 for (int i = 0; i < al.Count; i++)
203 if (((XPathNavigator) al [i]).IsSamePosition (nav))
208 // Invoked from XsltKey (XPathFunction)
209 public BaseIterator Evaluate (BaseIterator iter,
210 Expression valueExpr)
212 XPathNodeIterator i = iter;
213 if (iter.CurrentPosition == 0) {
217 XPathNavigator nav = i.Current;
219 object o = valueExpr.Evaluate (iter);
220 XPathNodeIterator it = o as XPathNodeIterator;
221 XsltContext ctx = iter.NamespaceManager as XsltContext;
223 BaseIterator result = null;
226 while (it.MoveNext()) {
227 ArrayList nodes = GetNodesByValue (
228 it.Current, it.Current.Value, ctx);
232 new ListIterator (nodes, ctx);
236 result = new UnionIterator (
241 ArrayList nodes = GetNodesByValue (
242 nav, XPathFunctions.ToString (o), ctx);
244 result = new ListIterator (nodes, ctx);
247 return result != null ? result : new NullIterator (iter);