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