2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Xml.Ext / Mono.Xml.XPath2 / XQueryExpression.cs
1 //
2 // XQueryExpression.cs - abstract syntax tree for XQuery 1.0
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.Xml;
33 using System.Xml.Query;
34 using System.Xml.Schema;
35 using System.Xml.XPath;
36 using Mono.Xml.XPath2;
37 using Mono.Xml;
38
39 namespace Mono.Xml.XQuery
40 {
41         internal abstract class XmlConstructorExpr : ExprSingle
42         {
43                 public XmlConstructorExpr (ExprSequence content)
44                 {
45                         this.content = content;
46                 }
47
48                 ExprSequence content;
49
50                 public ExprSequence Content {
51                         get { return content; }
52                 }
53
54 #region CompileAndEvaluate
55                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
56                 {
57                         if (Content != null)
58                                 for (int i = 0; i < Content.Count; i++)
59                                         Content [i] = Content [i].Compile (compiler);
60                         return this;
61                 }
62
63                 public void SerializeContent (XPathSequence iter)
64                 {
65                         if (Content != null)
66                                 foreach (ExprSingle expr in Content)
67                                         expr.Serialize (iter);
68                 }
69
70                 internal IXmlNamespaceResolver GetNSResolver (XPathSequence iter)
71                 {
72                         // FIXME: IXmlNamespaceResolver must be constructed
73                         // considering 1)static context and 2)in-scope element
74                         // construction.
75                         return iter.Context;
76                 }
77
78                 public XPathSequence EvaluateNode (XPathSequence iter)
79                 {
80                         return EvaluateNode (iter, XPathNodeType.All);
81                 }
82                 
83                 public XPathSequence EvaluateNode (XPathSequence iter, XPathNodeType moveAfterCreation)
84                 {
85                         XmlDocument doc = new XmlDocument ();
86                         XmlWriter w = iter.Context.Writer;
87                         try {
88                                 iter.Context.Writer = doc.CreateNavigator ().AppendChild ();
89                                 Serialize (iter);
90                                 iter.Context.Writer.Close ();
91                         } finally {
92                                 iter.Context.Writer = w;
93                         }
94                         XPathNavigator nav = doc.CreateNavigator ();
95                         switch (moveAfterCreation) {
96                         case XPathNodeType.Attribute:
97                                 nav.MoveToFirstAttribute ();
98                                 break;
99                         case XPathNodeType.Root:
100                                 break;
101                         default:
102                                 nav.MoveToFirstChild ();
103                                 break;
104                         }
105                         return new SingleItemIterator (nav, iter.Context);
106                 }
107 #endregion
108         }
109
110         internal class XmlAttrConstructorList : CollectionBase
111         {
112                 public XmlAttrConstructorList ()
113                 {
114                 }
115
116                 public void Add (XmlAttrConstructor item)
117                 {
118                         List.Add (item);
119                 }
120
121                 public void Insert (int pos, XmlAttrConstructor item)
122                 {
123                         List.Insert (pos, item);
124                 }
125         }
126
127         internal class XmlElemConstructor : XmlConstructorExpr
128         {
129                 XmlQualifiedName name;
130                 ExprSequence nameExpr;
131
132                 public XmlElemConstructor (XmlQualifiedName name, ExprSequence content)
133                         : base (content)
134                 {
135                         this.name = name;
136                 }
137
138                 public XmlElemConstructor (ExprSequence name, ExprSequence content)
139                         : base (content)
140                 {
141                         this.name = XmlQualifiedName.Empty;
142                         this.nameExpr = name;
143                 }
144
145                 public XmlQualifiedName Name {
146                         get { return name; }
147                 }
148                 public ExprSequence NameExpr {
149                         get { return nameExpr; }
150                 }
151
152                 internal override void CheckReference (XQueryASTCompiler compiler)
153                 {
154                         if (nameExpr != null)
155                                 nameExpr.CheckReference (compiler);
156                         if (Content != null)
157                                 Content.CheckReference (compiler);
158                 }
159
160 #region CompileAndEvaluate
161                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
162                 {
163                         if (NameExpr != null)
164                                 for (int i = 0; i < NameExpr.Count; i++)
165                                         NameExpr [i] = NameExpr [i].Compile (compiler);
166                         if (Content != null)
167                                 for (int i = 0; i < Content.Count; i++)
168                                         Content [i] = Content [i].Compile (compiler);
169                         return this;
170                 }
171
172                 // FIXME: can be optimized by checking all items in Expr
173                 public override SequenceType StaticType {
174                         get { return SequenceType.Element; }
175                 }
176
177                 public override void Serialize (XPathSequence iter)
178                 {
179                         XmlQualifiedName name = EvaluateName (iter);
180                         XmlWriter w = iter.Context.Writer;
181                         w.WriteStartElement (iter.Context.LookupPrefix (name.Namespace), name.Name, name.Namespace);
182                         SerializeContent (iter);
183                         w.WriteEndElement ();
184                 }
185
186                 public override XPathSequence Evaluate (XPathSequence iter)
187                 {
188                         return EvaluateNode (iter);
189                 }
190
191                 private XmlQualifiedName EvaluateName (XPathSequence iter)
192                 {
193                         XmlQualifiedName name = Name;
194                         if (NameExpr != null) {
195                                 XPathAtomicValue value = Atomize (new ExprSequenceIterator (iter, NameExpr));
196                                 IXmlNamespaceResolver res = iter.Context.NSResolver;
197
198                                 switch (value.XmlType.TypeCode) {
199                                 case XmlTypeCode.QName:
200                                         name = (XmlQualifiedName) value.ValueAs (typeof (XmlQualifiedName), res);
201                                         break;
202                                 case XmlTypeCode.String:
203                                         try {
204                                                 name = InternalPool.ParseQName (value.Value, res);
205                                         } catch (ArgumentException ex) {
206                                                 // FIXME: add more info
207                                                 throw new XmlQueryException (String.Format ("The evaluation result of the name expression could not be resolved as a valid QName. Evaluation result string is '{0}'.", value.Value));
208                                         }
209                                         break;
210                                 default:
211                                         // FIXME: add more info
212                                         throw new XmlQueryException ("A name of an element constructor must be resolved to either a QName or string.");
213                                 }
214                         }
215                         return name;
216                 }
217 #endregion
218         }
219
220         internal class XmlAttrConstructor : XmlConstructorExpr
221         {
222                 XmlQualifiedName name;
223                 ExprSequence nameExpr;
224
225                 public XmlAttrConstructor (XmlQualifiedName name, ExprSequence content)
226                         : base (content)
227                 {
228                         this.name = name;
229                 }
230
231                 public XmlAttrConstructor (ExprSequence name, ExprSequence content)
232                         : base (content)
233                 {
234                         this.nameExpr = name;
235                 }
236
237                 internal override void CheckReference (XQueryASTCompiler compiler)
238                 {
239                         if (nameExpr != null)
240                                 nameExpr.CheckReference (compiler);
241                         if (Content != null)
242                                 Content.CheckReference (compiler);
243                 }
244
245 #region CompileAndEvaluate
246                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
247                 {
248                         if (NameExpr != null)
249                                 for (int i = 0; i < NameExpr.Count; i++)
250                                         NameExpr [i] = NameExpr [i].Compile (compiler);
251                         if (Content != null)
252                                 for (int i = 0; i < Content.Count; i++)
253                                         Content [i] = Content [i].Compile (compiler);
254                         return this;
255                 }
256
257                 public XmlQualifiedName Name {
258                         get { return name; }
259                 }
260                 public ExprSequence NameExpr {
261                         get { return nameExpr; }
262                 }
263
264                 // FIXME: can be optimized by checking all items in Expr
265                 public override SequenceType StaticType {
266                         get { return SequenceType.Attribute; }
267                 }
268
269                 public override void Serialize (XPathSequence iter)
270                 {
271                         XmlQualifiedName name = EvaluateName (iter);
272                         XmlWriter w = iter.Context.Writer;
273                         w.WriteStartAttribute (GetNSResolver (iter).LookupPrefix (name.Namespace), name.Name, name.Namespace);
274                         SerializeContent (iter);
275                         w.WriteEndAttribute ();
276                 }
277
278                 public override XPathSequence Evaluate (XPathSequence iter)
279                 {
280                         return EvaluateNode (iter, XPathNodeType.Attribute);
281                 }
282
283                 private XmlQualifiedName EvaluateName (XPathSequence iter)
284                 {
285                         XmlQualifiedName name = Name;
286                         if (NameExpr != null) {
287                                 XPathAtomicValue value = Atomize (new ExprSequenceIterator (iter, NameExpr));
288                                 IXmlNamespaceResolver res = GetNSResolver (iter);
289
290                                 switch (value.XmlType.TypeCode) {
291                                 case XmlTypeCode.QName:
292                                         name = (XmlQualifiedName) value.ValueAs (typeof (XmlQualifiedName), res);
293                                         break;
294                                 case XmlTypeCode.String:
295                                         try {
296                                                 // nonprefixed attribute name == element's local namespace
297                                                 if (value.Value.IndexOf (':') < 0)
298                                                         name = new XmlQualifiedName (value.Value);
299                                                 else
300                                                         name = InternalPool.ParseQName (value.Value, res);
301                                         } catch (ArgumentException ex) {
302                                                 // FIXME: add more info
303                                                 throw new XmlQueryException (String.Format ("The evaluation result of the name expression could not be resolved as a valid QName. Evaluation result string is '{0}'.", value.Value));
304                                         }
305                                         break;
306                                 default:
307                                         // FIXME: add more info
308                                         throw new XmlQueryException ("A name of an attribute constructor must be resolved to either a QName or string.");
309                                 }
310                         }
311                         return name;
312                 }
313 #endregion
314         }
315
316         internal class XmlNSConstructor : XmlConstructorExpr
317         {
318                 public XmlNSConstructor (string prefix, ExprSequence content)
319                         : base (content)
320                 {
321                 }
322
323                 internal override void CheckReference (XQueryASTCompiler compiler)
324                 {
325                         Content.CheckReference (compiler);
326                 }
327
328 #region CompileAndEvaluate
329                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
330                 {
331                         if (Content != null)
332                                 for (int i = 0; i < Content.Count; i++)
333                                         Content [i] = Content [i].Compile (compiler);
334                         return this;
335                 }
336
337                 // FIXME: can be optimized by checking all items in Expr
338                 public override SequenceType StaticType {
339                         get { return SequenceType.Namespace; }
340                 }
341
342                 public override void Serialize (XPathSequence iter)
343                 {
344                         // TBD
345                         throw new NotImplementedException ();
346                 }
347
348                 public override XPathSequence Evaluate (XPathSequence iter)
349                 {
350                         // TBD
351                         throw new NotImplementedException ();
352                 }
353 #endregion
354         }
355
356         internal class XmlDocConstructor : XmlConstructorExpr
357         {
358                 public XmlDocConstructor (ExprSequence content)
359                         : base (content)
360                 {
361                 }
362
363                 internal override void CheckReference (XQueryASTCompiler compiler)
364                 {
365                         if (Content != null)
366                                 Content.CheckReference (compiler);
367                 }
368
369 #region CompileAndEvaluate
370                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
371                 {
372                         if (Content != null)
373                                 for (int i = 0; i < Content.Count; i++)
374                                         Content [i] = Content [i].Compile (compiler);
375                         return this;
376                 }
377
378                 // FIXME: can be optimized by checking all items in Expr
379                 public override SequenceType StaticType {
380                         get { return SequenceType.Document; }
381                 }
382
383                 public override void Serialize (XPathSequence iter)
384                 {
385                         XmlWriter w = iter.Context.Writer;
386                         w.WriteStartDocument ();
387                         SerializeContent (iter);
388                         w.WriteEndDocument ();
389                 }
390
391                 public override XPathSequence Evaluate (XPathSequence iter)
392                 {
393                         return EvaluateNode (iter, XPathNodeType.Root);
394                 }
395 #endregion
396         }
397
398         internal class XmlTextConstructor : XmlConstructorExpr
399         {
400                 public XmlTextConstructor (string text)
401                         : base (null)
402                 {
403                         this.text = text;
404                 }
405
406                 public XmlTextConstructor (ExprSequence content)
407                         : base (content)
408                 {
409                 }
410
411                 string text;
412
413                 public string LiteralText {
414                         get { return text; }
415                 }
416
417                 internal override void CheckReference (XQueryASTCompiler compiler)
418                 {
419                         if (Content != null)
420                                 Content.CheckReference (compiler);
421                 }
422
423 #region CompileAndEvaluate
424                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
425                 {
426                         if (Content != null)
427                                 for (int i = 0; i < Content.Count; i++)
428                                         Content [i] = Content [i].Compile (compiler);
429                         return this;
430                 }
431
432                 public override SequenceType StaticType {
433                         get { return SequenceType.Text; }
434                 }
435
436                 public override void Serialize (XPathSequence iter)
437                 {
438                         if (Content != null)
439                                 iter.Context.Writer.WriteString (Atomize (new ExprSequenceIterator (iter, Content)).Value);
440                         else
441                                 iter.Context.Writer.WriteString (LiteralText);
442                 }
443
444                 public override XPathSequence Evaluate (XPathSequence iter)
445                 {
446                         return EvaluateNode (iter);
447                 }
448 #endregion
449         }
450
451         internal class XmlCommentConstructor : XmlConstructorExpr
452         {
453                 string contentLiteral;
454
455                 public XmlCommentConstructor (string content)
456                         : base (null)
457                 {
458                         this.contentLiteral = content;
459                 }
460
461                 public XmlCommentConstructor (ExprSequence content)
462                         : base (content)
463                 {
464                 }
465
466                 internal override void CheckReference (XQueryASTCompiler compiler)
467                 {
468                         if (Content != null)
469                                 Content.CheckReference (compiler);
470                 }
471
472 #region CompileAndEvaluate
473                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
474                 {
475                         if (Content != null)
476                                 for (int i = 0; i < Content.Count; i++)
477                                         Content [i] = Content [i].Compile (compiler);
478                         return this;
479                 }
480
481                 // FIXME: can be optimized by checking all items in Expr
482                 public override SequenceType StaticType {
483                         get { return SequenceType.Comment; }
484                 }
485
486                 public override void Serialize (XPathSequence iter)
487                 {
488                         iter.Context.Writer.WriteComment (Atomize (new ExprSequenceIterator (iter, Content)).Value);
489                 }
490
491                 public override XPathSequence Evaluate (XPathSequence iter)
492                 {
493                         return EvaluateNode (iter);
494                 }
495 #endregion
496         }
497
498         internal class XmlPIConstructor : XmlConstructorExpr
499         {
500                 string name;
501                 ExprSequence nameExpr;
502
503                 string contentLiteral;
504
505                 public XmlPIConstructor (string name, string content)
506                         : base (null)
507                 {
508                         this.name = name;
509                         this.contentLiteral = content;
510                 }
511
512                 public XmlPIConstructor (string name, ExprSequence content)
513                         : base (content)
514                 {
515                         this.name = name;
516                 }
517
518                 public XmlPIConstructor (ExprSequence name, ExprSequence content)
519                         : base (content)
520                 {
521                         this.nameExpr = name;
522                 }
523
524                 internal override void CheckReference (XQueryASTCompiler compiler)
525                 {
526                         if (nameExpr != null)
527                                 nameExpr.CheckReference (compiler);
528                         if (Content != null)
529                                 Content.CheckReference (compiler);
530                 }
531
532 #region CompileAndEvaluate
533                 internal override ExprSingle CompileCore (XQueryASTCompiler compiler)
534                 {
535                         if (NameExpr != null)
536                                 for (int i = 0; i < NameExpr.Count; i++)
537                                         NameExpr [i] = NameExpr [i].Compile (compiler);
538                         if (Content != null)
539                                 for (int i = 0; i < Content.Count; i++)
540                                         Content [i] = Content [i].Compile (compiler);
541                         return this;
542                 }
543
544                 public string Name {
545                         get { return name; }
546                 }
547
548                 public ExprSequence NameExpr {
549                         get { return nameExpr; }
550                 }
551
552                 // FIXME: can be optimized by checking all items in Expr
553                 public override SequenceType StaticType {
554                         get { return SequenceType.XmlPI; }
555                 }
556
557                 public override void Serialize (XPathSequence iter)
558                 {
559                         iter.Context.Writer.WriteProcessingInstruction (
560                                 GetName (iter),
561                                 Atomize (new ExprSequenceIterator (iter, Content)).Value);
562                 }
563
564                 public override XPathSequence Evaluate (XPathSequence iter)
565                 {
566                         return EvaluateNode (iter);
567                 }
568
569                 private string GetName (XPathSequence iter)
570                 {
571                         if (Name != String.Empty)
572                                 return Name;
573                         return Atomize (new ExprSequenceIterator (iter, NameExpr)).Value;
574                 }
575 #endregion
576         }
577 }
578
579 #endif