initial pattern work
[mono.git] / mcs / class / System.XML / System.Xml.XPath / Iterator.cs
1 //
2 // System.Xml.XPath.BaseIterator
3 //
4 // Author:
5 //   Piers Haken (piersh@friskit.com)
6 //
7 // (C) 2002 Piers Haken
8 //
9
10 using System;
11 using System.Collections;
12 using System.Xml;
13 using System.Xml.XPath;
14 using System.Xml.Xsl;
15
16 namespace System.Xml.XPath
17 {
18         internal abstract class BaseIterator : XPathNodeIterator
19         {
20                 private XmlNamespaceManager _nsm;
21
22                 internal BaseIterator (BaseIterator other)
23                 {
24                         _nsm = other._nsm;
25                 }
26                 internal BaseIterator (XmlNamespaceManager nsm)
27                 {
28                         _nsm = nsm;
29                 }
30
31                 public XmlNamespaceManager NamespaceManager
32                 {
33                         get { return _nsm; }
34                         set { _nsm = value; }
35                 }
36                 
37                 public override string ToString ()
38                 {
39                         if (Current != null)
40                                 return Current.NodeType.ToString () + "[" + CurrentPosition + "] : " + Current.Name + " = " + Current.Value;
41                         else
42                                 return this.GetType().ToString () + "[" + CurrentPosition + "]";
43                 }
44         }
45
46         internal class MergedIterator : BaseIterator
47         {
48                 protected ArrayList _iters = new ArrayList ();
49                 protected int _pos;
50                 protected int _index;
51
52                 public MergedIterator (BaseIterator iter ) : base (iter) {}
53                 protected MergedIterator (MergedIterator other) : base (other)
54                 {
55                         foreach (XPathNodeIterator iter in other._iters)
56                                 _iters.Add (iter.Clone ());
57                         _pos = other._pos;
58                         _index = other._index;
59                 }
60                 public override XPathNodeIterator Clone () { return new MergedIterator (this); }
61
62                 public void Add (BaseIterator iter)
63                 {
64                         _iters.Add (iter);
65                 }
66
67                 public override bool MoveNext ()
68                 {
69                         while (_index < _iters.Count)
70                         {
71                                 BaseIterator iter = (BaseIterator) _iters [_index];
72                                 if (iter.MoveNext ())
73                                 {
74                                         _pos ++;
75                                         return true;
76                                 }
77                                 _index ++;
78                         }
79                         return false;
80                 }
81                 public override XPathNavigator Current
82                 {
83                         get
84                         {
85                                 if (_index >= _iters.Count)
86                                         return null;
87                                 BaseIterator iter = (BaseIterator) _iters [_index];
88                                 return iter.Current;
89                         }
90                 }
91                 public override int CurrentPosition { get { return _pos; }}
92         }
93
94         internal abstract class SimpleIterator : BaseIterator
95         {
96                 protected XPathNavigator _nav;
97                 protected int _pos;
98
99                 public SimpleIterator (BaseIterator iter) : base (iter)
100                 {
101                         _nav = iter.Current.Clone ();
102                 }
103                 protected SimpleIterator (SimpleIterator other) : base (other)
104                 {
105                         _nav = other._nav.Clone ();
106                         _pos = other._pos;
107                 }
108                 public SimpleIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nsm)
109                 {
110                         _nav = nav.Clone ();
111                 }
112
113                 public override XPathNavigator Current { get { return _nav; }}
114                 public override int CurrentPosition { get { return _pos; }}
115         }
116
117         internal class SelfIterator : SimpleIterator
118         {
119                 public SelfIterator (BaseIterator iter) : base (iter) {}
120                 public SelfIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nav, nsm) {}
121                 protected SelfIterator (SelfIterator other) : base (other) {}
122                 public override XPathNodeIterator Clone () { return new SelfIterator (this); }
123                 public override bool MoveNext ()
124                 {
125                         if (_pos == 0)
126                         {
127                                 _pos = 1;
128                                 return true;
129                         }
130                         return false;
131                 }
132         }
133
134         internal class NullIterator : SelfIterator
135         {
136                 public NullIterator (BaseIterator iter) : base (iter) {}
137                 public NullIterator (XPathNavigator nav) : this (nav, null) {}
138                 public NullIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nav, nsm) {}
139                 protected NullIterator (NullIterator other) : base (other) {}
140                 public override XPathNodeIterator Clone () { return new NullIterator (this); }
141                 public override bool MoveNext ()
142                 {
143                         return false;
144                 }
145         }
146
147         internal class ParentIterator : SimpleIterator
148         {
149                 public ParentIterator (BaseIterator iter) : base (iter) {}
150                 protected ParentIterator (ParentIterator other) : base (other) {}
151                 public ParentIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nav, nsm) {}
152                 public override XPathNodeIterator Clone () { return new ParentIterator (this); }
153                 public override bool MoveNext ()
154                 {
155                         if (_pos == 0 && _nav.MoveToParent ())
156                         {
157                                 _pos = 1;
158                                 return true;
159                         }
160                         return false;
161                 }
162         }
163
164         internal class ChildIterator : SimpleIterator
165         {
166                 public ChildIterator (BaseIterator iter) : base (iter) {}
167                 protected ChildIterator (ChildIterator other) : base (other) {}
168                 public override XPathNodeIterator Clone () { return new ChildIterator (this); }
169                 public override bool MoveNext ()
170                 {
171                         bool fSuccess = (_pos == 0) ? _nav.MoveToFirstChild () : _nav.MoveToNext ();
172                         if (fSuccess)
173                                 _pos ++;
174                         return fSuccess;
175                 }
176         }
177
178         internal class FollowingSiblingIterator : SimpleIterator
179         {
180                 public FollowingSiblingIterator (BaseIterator iter) : base (iter) {}
181                 protected FollowingSiblingIterator (FollowingSiblingIterator other) : base (other) {}
182                 public override XPathNodeIterator Clone () { return new FollowingSiblingIterator (this); }
183                 public override bool MoveNext ()
184                 {
185                         if (_nav.MoveToNext ())
186                         {
187                                 _pos ++;
188                                 return true;
189                         }
190                         return false;
191                 }
192         }
193
194         internal class PrecedingSiblingIterator : SimpleIterator
195         {
196                 public PrecedingSiblingIterator (BaseIterator iter) : base (iter) {}
197                 protected PrecedingSiblingIterator (PrecedingIterator other) : base (other) {}
198                 public override XPathNodeIterator Clone () { return new PrecedingSiblingIterator (this); }
199                 public override bool MoveNext ()
200                 {
201                         if (_nav.MoveToPrevious ())
202                         {
203                                 _pos ++;
204                                 return true;
205                         }
206                         return false;
207                 }
208         }
209
210         internal class AncestorIterator : SimpleIterator
211         {
212                 public AncestorIterator (BaseIterator iter) : base (iter) {}
213                 protected AncestorIterator (AncestorIterator other) : base (other) {}
214                 public override XPathNodeIterator Clone () { return new AncestorIterator (this); }
215                 public override bool MoveNext ()
216                 {
217                         if (_nav.MoveToParent ())
218                         {
219                                 _pos ++;
220                                 return true;
221                         }
222                         return false;
223                 }
224         }
225
226         internal class AncestorOrSelfIterator : MergedIterator
227         {
228                 public AncestorOrSelfIterator (BaseIterator iter) : base (iter)
229                 {
230                         Add (new SelfIterator (iter));
231                         Add (new AncestorIterator (iter));
232                 }
233                 protected AncestorOrSelfIterator (AncestorOrSelfIterator other) : base (other) {}
234                 public override XPathNodeIterator Clone () { return new AncestorOrSelfIterator (this); }
235         }
236
237         internal class DescendantIterator : SimpleIterator
238         {
239                 protected int _depth;
240                 public DescendantIterator (BaseIterator iter) : base (iter) {}
241                 protected DescendantIterator (DescendantIterator other) : base (other)
242                 {
243                         _depth = other._depth;
244                 }
245                 public override XPathNodeIterator Clone () { return new DescendantIterator (this); }
246                 [MonoTODO]
247                 public override bool MoveNext ()
248                 {
249                         if (_nav.MoveToFirstChild ())
250                         {
251                                 _depth ++;
252                                 _pos ++;
253                                 return true;
254                         }
255                         while (_depth != 0)
256                         {
257                                 if (_nav.MoveToNext ())
258                                 {
259                                         _pos ++;
260                                         return true;
261                                 }
262                                 if (!_nav.MoveToParent ())      // should NEVER fail!
263                                         throw new XPathException ("unexpected depth");  // TODO: better message
264                                 _depth --;
265                         }
266                         return false;
267                 }
268         }
269
270         internal class DescendantOrSelfIterator : MergedIterator
271         {
272                 public DescendantOrSelfIterator (BaseIterator iter) : base (iter)
273                 {
274                         Add (new SelfIterator (iter));
275                         Add (new DescendantIterator (iter));
276                 }
277                 protected DescendantOrSelfIterator (DescendantOrSelfIterator other) : base (other) {}
278                 public override XPathNodeIterator Clone () { return new DescendantOrSelfIterator (this); }
279         }
280
281         internal class FollowingIterator : SimpleIterator
282         {
283                 public FollowingIterator (BaseIterator iter) : base (iter) {}
284                 protected FollowingIterator (FollowingIterator other) : base (other) {}
285                 public override XPathNodeIterator Clone () { return new FollowingIterator (this); }
286                 public override bool MoveNext ()
287                 {
288                         if (_pos == 0)
289                         {
290                                 if (_nav.MoveToNext ())
291                                 {
292                                         _pos ++;
293                                         return true;
294                                 }
295                         }
296                         else
297                         {
298                                 if (_nav.MoveToFirstChild ())
299                                 {
300                                         _pos ++;
301                                         return true;
302                                 }
303                                 do
304                                 {
305                                         if (_nav.MoveToNext ())
306                                         {
307                                                 _pos ++;
308                                                 return true;
309                                         }
310                                 }
311                                 while (_nav.MoveToParent ());
312                         }
313                         return false;
314                 }
315         }
316
317         internal class PrecedingIterator : SimpleIterator
318         {
319                 public PrecedingIterator (BaseIterator iter) : base (iter) {}
320                 protected PrecedingIterator (PrecedingIterator other) : base (other) {}
321                 public override XPathNodeIterator Clone () { return new PrecedingIterator (this); }
322                 public override bool MoveNext ()
323                 {
324                         if (_pos == 0)
325                         {
326                                 if (_nav.MoveToPrevious ())
327                                 {
328                                         _pos ++;
329                                         return true;
330                                 }
331                         }
332                         else
333                         {
334                                 if (_nav.MoveToFirstChild ())
335                                 {
336                                         while (_nav.MoveToNext ())
337                                                 ;
338                                         _pos ++;
339                                         return true;
340                                 }
341                                 do
342                                 {
343                                         if (_nav.MoveToPrevious ())
344                                         {
345                                                 _pos ++;
346                                                 return true;
347                                         }
348                                 }
349                                 while (_nav.MoveToParent ());
350                         }
351                         return false;
352                 }
353         }
354
355         internal class NamespaceIterator : SimpleIterator
356         {
357                 public NamespaceIterator (BaseIterator iter) : base (iter) {}
358                 protected NamespaceIterator (NamespaceIterator other) : base (other) {}
359                 public override XPathNodeIterator Clone () { return new NamespaceIterator (this); }
360                 public override bool MoveNext ()
361                 {
362                         if (_pos == 0)
363                         {
364                                 if (_nav.MoveToFirstNamespace ())
365                                 {
366                                         _pos ++;
367                                         return true;
368                                 }
369                         }
370                         else if (_nav.MoveToNextNamespace ())
371                         {
372                                 _pos ++;
373                                 return true;
374                         }
375                         return false;
376                 }
377         }
378
379         internal class AttributeIterator : SimpleIterator
380         {
381                 public AttributeIterator (BaseIterator iter) : base (iter) {}
382                 protected AttributeIterator (AttributeIterator other) : base (other) {}
383                 public override XPathNodeIterator Clone () { return new AttributeIterator (this); }
384                 public override bool MoveNext ()
385                 {
386                         if (_pos == 0)
387                         {
388                                 if (_nav.MoveToFirstAttribute ())
389                                 {
390                                         _pos += 1;
391                                         return true;
392                                 }
393                         }
394                         else if (_nav.MoveToNextAttribute ())
395                         {
396                                 _pos ++;
397                                 return true;
398                         }
399                         return false;                   
400                 }
401         }
402
403         internal class AxisIterator : BaseIterator
404         {
405                 protected BaseIterator _iter;
406                 protected NodeTest _test;
407                 protected int _pos;
408
409                 public AxisIterator (BaseIterator iter, NodeTest test) : base (iter)
410                 {
411                         _iter = iter;
412                         _test = test;
413                 }
414
415                 protected AxisIterator (AxisIterator other) : base (other)
416                 {
417                         _iter = (BaseIterator) other._iter.Clone ();
418                         _test = other._test;
419                         _pos = other._pos;
420                 }
421                 public override XPathNodeIterator Clone () { return new AxisIterator (this); }
422
423                 public override bool MoveNext ()
424                 {
425                         while (_iter.MoveNext ())
426                         {
427                                 if (_test.Match (NamespaceManager, Current))
428                                 {
429                                         _pos ++;
430                                         return true;
431                                 }
432                         }
433                         return false;
434                 }
435                 public override XPathNavigator Current { get { return _iter.Current; }}
436                 public override int CurrentPosition { get { return _pos; }}
437         }
438
439         internal class SlashIterator : BaseIterator
440         {
441                 protected BaseIterator _iterLeft;
442                 protected BaseIterator _iterRight;
443                 protected NodeSet _expr;
444                 protected int _pos;
445
446                 public SlashIterator (BaseIterator iter, NodeSet expr) : base (iter)
447                 {
448                         _iterLeft = iter;
449                         _expr = expr;
450                 }
451
452                 protected SlashIterator (SlashIterator other) : base (other)
453                 {
454                         _iterLeft = (BaseIterator) other._iterLeft.Clone ();
455                         if (other._iterRight != null)
456                                 _iterRight = (BaseIterator) other._iterRight.Clone ();
457                         _expr = other._expr;
458                         _pos = other._pos;
459                 }
460                 public override XPathNodeIterator Clone () { return new SlashIterator (this); }
461
462                 public override bool MoveNext ()
463                 {
464                         while (_iterRight == null || !_iterRight.MoveNext ())
465                         {
466                                 if (!_iterLeft.MoveNext ())
467                                         return false;
468                                 _iterRight = _expr.EvaluateNodeSet (_iterLeft);
469                         }
470                         _pos ++;
471                         return true;
472                 }
473                 public override XPathNavigator Current { 
474                         get { 
475                                 if (_iterRight == null) return null;
476                                 
477                                 return _iterRight.Current;
478                         }
479                 }
480                 public override int CurrentPosition { get { return _pos; }}
481         }
482
483         internal class PredicateIterator : BaseIterator
484         {
485                 protected BaseIterator _iter;
486                 protected Expression _pred;
487                 protected int _pos;
488
489                 public PredicateIterator (BaseIterator iter, Expression pred) : base (iter)
490                 {
491                         _iter = iter;
492                         _pred = pred;
493                 }
494
495                 protected PredicateIterator (PredicateIterator other) : base (other)
496                 {
497                         _iter = (BaseIterator) other._iter.Clone ();
498                         _pred = other._pred;
499                         _pos = other._pos;
500                 }
501                 public override XPathNodeIterator Clone () { return new PredicateIterator (this); }
502
503                 public override bool MoveNext ()
504                 {
505                         while (_iter.MoveNext ())
506                         {
507                                 bool fTrue = true;
508                                 object result = _pred.Evaluate ((BaseIterator) _iter.Clone ());
509                                 if (result is double)
510                                 {
511                                         if ((double) result != _iter.CurrentPosition)
512                                                 continue;
513                                 }
514                                 else if (!XPathFunctions.ToBoolean (result))
515                                         continue;
516
517                                 _pos ++;
518                                 return true;
519                         }
520                         return false;
521                 }
522                 public override XPathNavigator Current { get { return _iter.Current; }}
523                 public override int CurrentPosition { get { return _pos; }}
524         }
525
526         internal class EnumeratorIterator : BaseIterator
527         {
528                 protected IEnumerator _enum;
529                 protected int _pos;
530
531                 public EnumeratorIterator (BaseIterator iter, IEnumerator enumerator) : base (iter)
532                 {
533                         _enum = enumerator;
534                 }
535                 
536                 public EnumeratorIterator (IEnumerator enumerator, XmlNamespaceManager nsm) : base (nsm)
537                 {
538                         _enum = enumerator;
539                 }
540
541                 protected EnumeratorIterator (EnumeratorIterator other) : base (other)
542                 {
543                         _enum = other._enum;
544                         _pos = other._pos;
545                 }
546                 public override XPathNodeIterator Clone () { return new EnumeratorIterator (this); }
547
548                 public override bool MoveNext ()
549                 {
550                         if (!_enum.MoveNext ())
551                                 return false;
552                         _pos++;
553                         return true;
554                 }
555                 public override XPathNavigator Current { get { return (XPathNavigator) _enum.Current; }}
556                 public override int CurrentPosition { get { return _pos; }}
557         }
558
559
560         internal class UnionIterator : BaseIterator
561         {
562                 protected ArrayList _rgNodes;
563                 protected BaseIterator _left, _right;
564                 protected int _pos;
565
566                 public UnionIterator (BaseIterator iter, BaseIterator left, BaseIterator right) : base (iter)
567                 {
568                         _rgNodes = new ArrayList ();
569                         _left = left;
570                         _right = right;
571                 }
572
573                 protected UnionIterator (UnionIterator other) : base (other)
574                 {
575                         _rgNodes = (ArrayList) other._rgNodes.Clone ();
576                         _left = other._left;
577                         _right = other._right;
578                         _pos = other._pos;
579                 }
580                 public override XPathNodeIterator Clone () { return new UnionIterator (this); }
581
582                 public override bool MoveNext ()
583                 {
584                         if (_left.MoveNext ())
585                         {
586                                 _rgNodes.Add (_left.Current.Clone ());
587                                 _pos ++;
588                                 return true;
589                         }
590
591                         while (_right.MoveNext ())
592                         {
593                                 XPathNavigator navRight = _right.Current;
594                                 bool fFound = false;
595                                 foreach (XPathNavigator navLeft in _rgNodes)
596                                 {
597                                         if (navLeft.IsSamePosition (navRight))
598                                         {
599                                                 fFound = true;
600                                                 break;
601                                         }
602                                 }
603                                 if (!fFound)
604                                 {
605                                         _pos ++;
606                                         return true;
607                                 }
608                         }
609                         return false;
610                 }
611                 public override XPathNavigator Current
612                 {
613                         get
614                         {
615                                 if (_pos < _rgNodes.Count)
616                                         throw new XPathException ("bug in UnionOperator");      // TODO: better exception
617                                 if (_pos == _rgNodes.Count)
618                                         return _left.Current;
619                                 else
620                                         return _right.Current;
621                         }
622                 }
623                 public override int CurrentPosition { get { return _pos; }}
624         }
625 }