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 ();
122 bool matchesAttributes = false;
123 switch (key.Match.EvaluatedNodeType) {
124 case XPathNodeType.All:
125 case XPathNodeType.Attribute:
126 matchesAttributes = true;
131 if (key.Match.Matches (nav, ctx)) {
133 CollectIndex (nav, tmp);
135 } while (MoveNavigatorToNext (nav, matchesAttributes));
137 foreach (ArrayList list in map.Values)
138 list.Sort (XPathNavigatorComparer.Instance);
141 private bool MoveNavigatorToNext (XPathNavigator nav, bool matchesAttributes)
143 if (matchesAttributes) {
144 if (nav.NodeType != XPathNodeType.Attribute &&
145 nav.MoveToFirstAttribute ())
147 else if (nav.NodeType == XPathNodeType.Attribute) {
148 if (nav.MoveToNextAttribute ())
153 if (nav.MoveToFirstChild ())
156 if (nav.MoveToNext ())
158 } while (nav.MoveToParent ());
162 private void CollectIndex (XPathNavigator nav, XPathNavigator target)
164 XPathNodeIterator iter;
165 switch (key.Use.ReturnType) {
166 case XPathResultType.NodeSet:
167 iter = nav.Select (key.Use);
168 while (iter.MoveNext ())
169 AddIndex (iter.Current.Value, target);
171 case XPathResultType.Any:
172 object o = nav.Evaluate (key.Use);
173 iter = o as XPathNodeIterator;
175 while (iter.MoveNext ())
176 AddIndex (iter.Current.Value, target);
179 AddIndex (XPathFunctions.ToString (o), target);
182 string keyValue = nav.EvaluateString (key.Use, null, null);
183 AddIndex (keyValue, target);
188 private void AddIndex (string key, XPathNavigator target)
190 ArrayList al = map [key] as ArrayList;
192 al = new ArrayList ();
195 for (int i = 0; i < al.Count; i++)
196 if (((XPathNavigator) al [i]).IsSamePosition (target))
198 al.Add (target.Clone ());
201 private ArrayList GetNodesByValue (XPathNavigator nav, string value, XsltContext ctx)
204 mappedDocuments = new Hashtable ();
205 map = new Hashtable ();
207 if (!mappedDocuments.ContainsKey (nav.BaseURI)) {
208 mappedDocuments.Add (nav.BaseURI, nav.BaseURI);
209 CollectTable (nav, ctx);
212 return map [value] as ArrayList;
215 public bool Matches (XPathNavigator nav, string value, XsltContext ctx)
217 ArrayList al = GetNodesByValue (nav, value, ctx);
220 for (int i = 0; i < al.Count; i++)
221 if (((XPathNavigator) al [i]).IsSamePosition (nav))
226 // Invoked from XsltKey (XPathFunction)
227 public BaseIterator Evaluate (BaseIterator iter,
228 Expression valueExpr)
230 XPathNodeIterator i = iter;
231 if (iter.CurrentPosition == 0) {
235 XPathNavigator nav = i.Current;
237 object o = valueExpr.Evaluate (iter);
238 XPathNodeIterator it = o as XPathNodeIterator;
239 XsltContext ctx = iter.NamespaceManager as XsltContext;
241 BaseIterator result = null;
244 while (it.MoveNext()) {
245 ArrayList nodes = GetNodesByValue (
246 it.Current, it.Current.Value, ctx);
250 new ListIterator (nodes, ctx);
254 result = new UnionIterator (
259 ArrayList nodes = GetNodesByValue (
260 nav, XPathFunctions.ToString (o), ctx);
262 result = new ListIterator (nodes, ctx);
265 return result != null ? result : new NullIterator (iter);