2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / 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 using Mono.Xml;
39
40 namespace Mono.Xml.XPath2
41 {
42         internal class XQueryContextManager
43         {
44                 XQueryStaticContext staticContext;
45
46                 // Fixed dynamic context during evaluation
47                 XmlArgumentList args;
48                 XmlResolver extDocResolver;
49
50                 Stack<XQueryContext> contextStack = new Stack<XQueryContext> ();
51                 XQueryContext currentContext;
52 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
53 #else
54                 Stack<XPathSequence> contextSequenceStack = new Stack<XPathSequence> ();
55 #endif
56                 XmlWriter currentWriter;
57                 XPathItem input; // source input item(node)
58                 XPathSequence currentSequence;
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                         namespaceManager = new XmlNamespaceManager (ctx.NameTable);
71                         foreach (DictionaryEntry de in ctx.NSResolver.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml))
72                                 namespaceManager.AddNamespace (de.Key.ToString (), de.Value.ToString ());
73                         namespaceManager.PushScope ();
74
75                         currentContext = new XQueryContext (this, null, new Hashtable ());
76                         if (input != null) {
77                                 currentSequence = new SingleItemIterator (input, currentContext);
78                                 currentSequence.MoveNext ();
79                         }
80                         currentContext = new XQueryContext (this, currentSequence, new Hashtable ());
81                 }
82
83                 public bool Initialized {
84                         get { return currentContext != null; }
85                 }
86
87                 public XmlResolver ExtDocResolver {
88                         get { return extDocResolver; }
89                 }
90
91                 public XmlArgumentList Arguments {
92                         get { return args; }
93                 }
94
95                 public XmlWriter Writer {
96                         get { return currentWriter; }
97                         // FIXME: might be better avoid setter as public
98                         set { currentWriter = value; }
99                 }
100
101                 internal XQueryContext CurrentContext {
102                         get { return currentContext; }
103                 }
104
105                 internal XQueryStaticContext StaticContext {
106                         get { return staticContext; }
107                 }
108
109                 internal CultureInfo GetCulture (string collation)
110                 {
111                         CultureInfo ci = staticContext.GetCulture (collation);
112                         if (ci == null)
113                                 ci = (CultureInfo) localCollationCache [collation];
114                         if (ci != null)
115                                 return ci;
116                         ci = new CultureInfo (collation);
117                         localCollationCache [collation] = ci;
118                         return ci;
119                 }
120
121                 public void PushCurrentSequence (XPathSequence sequence)
122                 {
123                         if (sequence == null)
124                                 throw new ArgumentNullException ();
125 //                      sequence = sequence.Clone ();
126 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
127                         contextStack.Push (currentContext);
128                         currentsequence = sequence;
129                         currentContext = new XQueryContext (this);
130 #else
131                         contextSequenceStack.Push (currentSequence);
132                         currentSequence = sequence;
133 #endif
134                 }
135
136                 public void PopCurrentSequence ()
137                 {
138 #if SEEMS_CONTEXT_FOR_CURRENT_REQURED
139                         PopContext ();
140 #else
141                         currentSequence = contextSequenceStack.Pop ();
142 #endif
143                         if (currentSequence == null)
144                                 throw new SystemException ("XQuery error: should not happen.");
145                 }
146
147                 internal void PushContext ()
148                 {
149                         contextStack.Push (currentContext);
150                         currentContext = new XQueryContext (this);
151                 }
152
153                 internal void PopContext ()
154                 {
155                         currentContext = contextStack.Pop ();
156                 }
157
158                 internal void PushVariable (XmlQualifiedName name, object iter)
159                 {
160                         PushContext ();
161                         CurrentContext.SetVariable (name, iter);
162                 }
163
164                 internal void PopVariable ()
165                 {
166                         PopContext ();
167                 }
168
169                 internal XmlNamespaceManager NSManager {
170                         get { return namespaceManager; }
171                 }
172
173                 internal XPathSequence CurrentSequence {
174                         get { return currentSequence; }
175                 }
176         }
177
178         public class XQueryContext : IXmlNamespaceResolver
179         {
180                 XQueryContextManager contextManager;
181                 Hashtable currentVariables;
182                 XPathSequence currentSequence;
183
184                 internal XQueryContext (XQueryContextManager manager)
185                         : this (manager,
186                                 manager.CurrentSequence,
187                                 (Hashtable) manager.CurrentContext.currentVariables.Clone ())
188                 {
189                 }
190
191                 internal XQueryContext (XQueryContextManager manager, XPathSequence currentSequence, Hashtable currentVariables)
192                 {
193                         contextManager = manager;
194                         this.currentSequence = currentSequence;
195 /*
196                         if (manager.CurrentContext != null)
197                                 currentVariables = (Hashtable) manager.CurrentContext.currentVariables.Clone ();
198                         else
199                                 currentVariables = new Hashtable ();
200 */
201                         this.currentVariables = currentVariables;
202                 }
203
204                 internal XmlWriter Writer {
205                         get { return contextManager.Writer; }
206                         // FIXME: might be better avoid public setter.
207                         set { contextManager.Writer = value; }
208                 }
209
210                 internal XQueryStaticContext StaticContext {
211                         get { return contextManager.StaticContext; }
212                 }
213
214                 internal CultureInfo DefaultCollation {
215                         get { return StaticContext.DefaultCollation; }
216                 }
217
218                 internal XQueryContextManager ContextManager {
219                         get { return contextManager; }
220                 }
221
222                 public XPathItem CurrentItem {
223                         get {
224                                 if (currentSequence == null)
225                                         throw new XmlQueryException ("This XQuery dynamic context has no context item.");
226                                 return CurrentSequence.Current;
227                         }
228                 }
229
230                 public XPathNavigator CurrentNode {
231                         get { return CurrentItem as XPathNavigator; }
232                 }
233
234                 public XPathSequence CurrentSequence {
235                         get { return currentSequence; }
236                 }
237
238                 internal CultureInfo GetCulture (string collation)
239                 {
240                         return contextManager.GetCulture (collation);
241                 }
242
243                 internal void PushVariable (XmlQualifiedName name, object iter)
244                 {
245                         contextManager.PushVariable (name, iter);
246                 }
247
248                 // FIXME: Hmm... this design is annoying.
249                 internal void SetVariable (XmlQualifiedName name, object iter)
250                 {
251                         currentVariables [name] = iter;
252                 }
253
254                 internal void PopVariable ()
255                 {
256                         contextManager.PopVariable ();
257                 }
258
259                 internal XPathSequence ResolveVariable (XmlQualifiedName name)
260                 {
261                         object obj = currentVariables [name];
262                         if (obj == null && contextManager.Arguments != null)
263                                 obj = contextManager.Arguments.GetParameter (name.Name, name.Namespace);
264                         if (obj == null)
265                                 return new XPathEmptySequence (this);
266                         XPathSequence seq = obj as XPathSequence;
267                         if (seq != null)
268                                 return seq;
269                         XPathItem item = obj as XPathItem;
270                         if (item == null)
271                                 item = new XPathAtomicValue (obj, InternalPool.GetBuiltInType (InternalPool.XmlTypeCodeFromRuntimeType (obj.GetType (), true)));
272                         return new SingleItemIterator (item, this);
273                 }
274
275                 internal XPathSequence ResolveCollection (string name)
276                 {
277                         // FIXME: support later.
278                         return new XPathEmptySequence (currentSequence.Context);
279                 }
280
281                 public IXmlNamespaceResolver NSResolver {
282                         get { return contextManager.NSManager; }
283                 }
284
285                 #region IXmlNamespaceResolver implementation
286                 public XmlNameTable NameTable {
287                         get { return contextManager.NSManager.NameTable; }
288                 }
289
290                 public string LookupPrefix (string ns)
291                 {
292                         return contextManager.NSManager.LookupPrefix (ns);
293                 }
294
295                 public string LookupPrefix (string ns, bool atomized)
296                 {
297                         return contextManager.NSManager.LookupPrefix (ns, atomized);
298                 }
299
300                 public string LookupNamespace (string prefix)
301                 {
302                         return contextManager.NSManager.LookupNamespace (prefix);
303                 }
304
305                 public string LookupNamespace (string prefix, bool atomized)
306                 {
307                         return contextManager.NSManager.LookupNamespace (prefix, atomized);
308                 }
309
310                 public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
311                 {
312                         return contextManager.NSManager.GetNamespacesInScope (scope);
313                 }
314                 #endregion
315         }
316 }
317
318 #endif