2004-08-23 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Query / XQueryContext.cs
1 //
2 // XQueryContext.cs - XQuery/XPath2 dynamic context
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 #if NET_2_0
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Globalization;
34 using System.Xml;
35 using System.Xml.Schema;
36 using System.Xml.XPath;
37 using System.Xml.Query;
38
39 namespace Mono.Xml.XPath2
40 {
41         internal class XQueryContextManager
42         {
43                 XQueryStaticContext staticContext;
44
45                 // Fixed dynamic context during evaluation
46                 XmlArgumentList args;
47                 XmlResolver extDocResolver;
48
49                 Stack<XQueryContext> contextStack = new Stack<XQueryContext> ();
50                 XQueryContext currentContext;
51 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
52 #else
53                 Stack<XPathSequence> contextSequenceStack = new Stack<XPathSequence> ();
54 #endif
55                 XmlWriter currentWriter;
56                 XPathItem input; // source input item(node)
57                 XPathSequence currentSequence;
58                 Hashtable currentVariables = new Hashtable ();
59                 XmlNamespaceManager namespaceManager;
60                 Hashtable localCollationCache = new Hashtable ();
61
62                 internal XQueryContextManager (XQueryStaticContext ctx, XPathItem input, XmlWriter writer, XmlResolver resolver, XmlArgumentList args)
63                 {
64                         this.input = input;
65                         this.staticContext = ctx;
66                         this.args = args;
67                         currentWriter = writer;
68                         this.extDocResolver = resolver;
69
70                         currentContext = new XQueryContext (this);
71
72                         namespaceManager = new XmlNamespaceManager (ctx.NameTable);
73                         foreach (DictionaryEntry de in ctx.NSResolver.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml))
74                                 namespaceManager.AddNamespace (de.Key.ToString (), de.Value.ToString ());
75                         namespaceManager.PushScope ();
76
77                         this.currentSequence = new SingleItemIterator (input, currentContext);
78                 }
79
80                 public bool Initialized {
81                         get { return currentContext != null; }
82                 }
83
84                 public XmlResolver ExtDocResolver {
85                         get { return extDocResolver; }
86                 }
87
88                 public XmlArgumentList Arguments {
89                         get { return args; }
90                 }
91
92                 public Hashtable LocalVariables {
93                         get { return currentVariables; }
94                 }
95
96                 public XmlWriter Writer {
97                         get { return currentWriter; }
98                         // FIXME: might be better avoid setter as public
99                         set { currentWriter = value; }
100                 }
101
102                 internal XQueryContext CurrentContext {
103                         get { return currentContext; }
104                 }
105
106                 internal XQueryStaticContext StaticContext {
107                         get { return staticContext; }
108                 }
109
110                 internal CultureInfo GetCulture (string collation)
111                 {
112                         CultureInfo ci = staticContext.GetCulture (collation);
113                         if (ci == null)
114                                 ci = (CultureInfo) localCollationCache [collation];
115                         if (ci != null)
116                                 return ci;
117                         ci = new CultureInfo (collation);
118                         localCollationCache [collation] = ci;
119                         return ci;
120                 }
121
122                 public void PushCurrentSequence (XPathSequence sequence)
123                 {
124 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
125                         contextStack.Push (currentContext);
126                         currentsequence = sequence;
127                         currentContext = new XQueryContext (this);
128 #else
129                         contextSequenceStack.Push (currentSequence);
130                         currentSequence = sequence;
131 #endif
132                 }
133
134                 public void PopCurrentSequence ()
135                 {
136 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
137                         PopContext ();
138 #else
139                         currentSequence = contextSequenceStack.Pop ();
140 #endif
141                 }
142
143                 // FIXME: According to the spec 3.8.1, variales bindings in
144                 // FLWOR is not necesarrily bound to the order of bindings. 
145                 // Thus, we might not have to create every XQueryContext for
146                 // each variable binding (not sure for other kind of bindings).
147                 public void PushVariable (XmlQualifiedName name, XPathSequence iter)
148                 {
149                         contextStack.Push (currentContext);
150                         currentVariables.Add (name, iter);
151                         currentContext = new XQueryContext (this);
152                 }
153
154                 public void PopVariable ()
155                 {
156                         PopContext ();
157                 }
158
159                 private void PopContext ()
160                 {
161                         currentContext = contextStack.Pop ();
162                 }
163
164                 internal XmlNamespaceManager NSManager {
165                         get { return namespaceManager; }
166                 }
167         }
168
169         public class XQueryContext : IXmlNamespaceResolver
170         {
171                 XQueryContextManager contextManager;
172                 Hashtable currentVariables;
173                 XPathSequence currentSequence;
174
175                 internal XQueryContext (XQueryContextManager manager)
176                 {
177                         contextManager = manager;
178                         if (manager.Initialized) // this condition is not filled on initial creation.
179                                 currentSequence = manager.CurrentContext.currentSequence;
180                         currentVariables = (Hashtable) manager.LocalVariables.Clone ();
181                 }
182
183                 internal XmlWriter Writer {
184                         get { return contextManager.Writer; }
185                         // FIXME: might be better avoid public setter.
186                         set { contextManager.Writer = value; }
187                 }
188
189                 internal XQueryStaticContext StaticContext {
190                         get { return contextManager.StaticContext; }
191                 }
192
193                 internal CultureInfo DefaultCollation {
194                         get { return StaticContext.DefaultCollation; }
195                 }
196
197                 internal XQueryContextManager ContextManager {
198                         get { return contextManager; }
199                 }
200
201                 public XPathItem CurrentItem {
202                         get { return currentSequence.Current; }
203                 }
204
205                 public XPathNavigator CurrentNode {
206                         get { return CurrentItem as XPathNavigator; }
207                 }
208
209                 public XPathSequence CurrentSequence {
210                         get { return currentSequence; }
211                 }
212
213                 internal CultureInfo GetCulture (string collation)
214                 {
215                         return contextManager.GetCulture (collation);
216                 }
217
218                 internal void PushVariable (XmlQualifiedName name, XPathSequence iter)
219                 {
220                         contextManager.PushVariable (name, iter);
221                 }
222
223                 internal void PopVariable ()
224                 {
225                         contextManager.PopVariable ();
226                 }
227
228                 internal XPathSequence ResolveVariable (XmlQualifiedName name, XPathSequence context)
229                 {
230                         object obj = currentVariables [name];
231                         if (obj == null)
232                                 obj = contextManager.Arguments.GetParameter (name.Name, name.Namespace);
233                         if (obj == null)
234                                 // FIXME: location
235                                 throw new XmlQueryException (String.Format ("Cannot resolve variable '{0}'.", name));
236                         XPathSequence seq = obj as XPathSequence;
237                         if (seq != null)
238                                 return seq;
239                         XPathItem item = obj as XPathItem;
240                         if (item == null)
241                                 item = new XPathAtomicValue (obj, null);
242                         return new SingleItemIterator (item, context);
243                 }
244
245                 internal XPathSequence ResolveCollection (string name)
246                 {
247                         // FIXME: support later.
248                         return new XPathEmptySequence (currentSequence);
249                 }
250
251                 public IXmlNamespaceResolver NSResolver {
252                         get { return contextManager.NSManager; }
253                 }
254
255                 #region IXmlNamespaceResolver implementation
256                 public XmlNameTable NameTable {
257                         get { return contextManager.NSManager.NameTable; }
258                 }
259
260                 public string LookupPrefix (string ns)
261                 {
262                         return contextManager.NSManager.LookupPrefix (ns);
263                 }
264
265                 public string LookupPrefix (string ns, bool atomized)
266                 {
267                         return contextManager.NSManager.LookupPrefix (ns, atomized);
268                 }
269
270                 public string LookupNamespace (string prefix)
271                 {
272                         return contextManager.NSManager.LookupNamespace (prefix);
273                 }
274
275                 public string LookupNamespace (string prefix, bool atomized)
276                 {
277                         return contextManager.NSManager.LookupNamespace (prefix, atomized);
278                 }
279
280                 public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
281                 {
282                         return contextManager.NSManager.GetNamespacesInScope (scope);
283                 }
284                 #endregion
285         }
286 }
287
288 #endif