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;
103 Hashtable mappedDocuments;
105 public KeyIndexTable (XsltCompiledContext ctx, ArrayList keys)
111 public ArrayList Keys {
115 private void CollectTable (XPathNavigator doc, XsltContext ctx, Hashtable map)
117 for (int i = 0; i < keys.Count; i++)
118 CollectTable (doc, ctx, map, (XslKey) keys[i]);
121 private void CollectTable (XPathNavigator doc, XsltContext ctx, Hashtable map, XslKey key)
123 XPathNavigator nav = doc.Clone ();
125 XPathNavigator tmp = doc.Clone ();
127 bool matchesAttributes = false;
128 switch (key.Match.EvaluatedNodeType) {
129 case XPathNodeType.All:
130 case XPathNodeType.Attribute:
131 matchesAttributes = true;
136 if (key.Match.Matches (nav, ctx)) {
138 CollectIndex (nav, tmp, map);
140 } while (MoveNavigatorToNext (nav, matchesAttributes));
142 foreach (ArrayList list in map.Values)
143 list.Sort (XPathNavigatorComparer.Instance);
146 private bool MoveNavigatorToNext (XPathNavigator nav, bool matchesAttributes)
148 if (matchesAttributes) {
149 if (nav.NodeType != XPathNodeType.Attribute &&
150 nav.MoveToFirstAttribute ())
152 else if (nav.NodeType == XPathNodeType.Attribute) {
153 if (nav.MoveToNextAttribute ())
158 if (nav.MoveToFirstChild ())
161 if (nav.MoveToNext ())
163 } while (nav.MoveToParent ());
167 private void CollectIndex (XPathNavigator nav, XPathNavigator target, Hashtable map)
169 for (int i = 0; i < keys.Count; i++)
170 CollectIndex (nav, target, map, (XslKey) keys[i]);
173 private void CollectIndex (XPathNavigator nav, XPathNavigator target, Hashtable map, XslKey key)
175 XPathNodeIterator iter;
176 switch (key.Use.ReturnType) {
177 case XPathResultType.NodeSet:
178 iter = nav.Select (key.Use);
179 while (iter.MoveNext ())
180 AddIndex (iter.Current.Value, target, map);
182 case XPathResultType.Any:
183 object o = nav.Evaluate (key.Use);
184 iter = o as XPathNodeIterator;
186 while (iter.MoveNext ())
187 AddIndex (iter.Current.Value, target, map);
190 AddIndex (XPathFunctions.ToString (o), target, map);
193 string keyValue = nav.EvaluateString (key.Use, null, null);
194 AddIndex (keyValue, target, map);
199 private void AddIndex (string key, XPathNavigator target, Hashtable map)
201 ArrayList al = map [key] as ArrayList;
203 al = new ArrayList ();
206 for (int i = 0; i < al.Count; i++)
207 if (((XPathNavigator) al [i]).IsSamePosition (target))
209 al.Add (target.Clone ());
212 private ArrayList GetNodesByValue (XPathNavigator nav, string value, XsltContext ctx)
214 if (mappedDocuments == null)
215 mappedDocuments = new Hashtable ();
216 Hashtable map = (Hashtable) mappedDocuments [nav.BaseURI];
218 map = new Hashtable ();
219 mappedDocuments.Add (nav.BaseURI, map);
220 CollectTable (nav, ctx, map);
223 return map [value] as ArrayList;
226 public bool Matches (XPathNavigator nav, string value, XsltContext ctx)
228 ArrayList al = GetNodesByValue (nav, value, ctx);
231 for (int i = 0; i < al.Count; i++)
232 if (((XPathNavigator) al [i]).IsSamePosition (nav))
237 // Invoked from XsltKey (XPathFunction)
238 public BaseIterator Evaluate (BaseIterator iter,
239 Expression valueExpr)
241 XPathNodeIterator i = iter;
242 if (iter.CurrentPosition == 0) {
246 XPathNavigator nav = i.Current;
248 object o = valueExpr.Evaluate (iter);
249 XPathNodeIterator it = o as XPathNodeIterator;
250 XsltContext ctx = iter.NamespaceManager as XsltContext;
252 BaseIterator result = null;
255 while (it.MoveNext()) {
256 ArrayList nodes = GetNodesByValue (
257 nav, it.Current.Value, ctx);
261 new ListIterator (nodes, ctx);
265 result = new UnionIterator (
269 else if (nav != null) {
270 ArrayList nodes = GetNodesByValue (
271 nav, XPathFunctions.ToString (o), ctx);
273 result = new ListIterator (nodes, ctx);
276 return result != null ? result : new NullIterator (iter);