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