Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Cache / XPathDocumentIterator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XPathDocumentIterator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 using System;
8 using System.Xml;
9 using System.Xml.XPath;
10 using System.Diagnostics;
11
12 namespace MS.Internal.Xml.Cache {
13
14     /// <summary>
15     /// Base internal class of all XPathDocument XPathNodeIterator implementations.
16     /// </summary>
17     internal abstract class XPathDocumentBaseIterator : XPathNodeIterator {
18         protected XPathDocumentNavigator ctxt;
19         protected int pos;
20
21         /// <summary>
22         /// Create a new iterator that is initially positioned on the "ctxt" node.
23         /// </summary>
24         protected XPathDocumentBaseIterator(XPathDocumentNavigator ctxt) {
25             this.ctxt = new XPathDocumentNavigator(ctxt);
26         }
27
28         /// <summary>
29         /// Create a new iterator that is a copy of "iter".
30         /// </summary>
31         protected XPathDocumentBaseIterator(XPathDocumentBaseIterator iter) {
32             this.ctxt = new XPathDocumentNavigator(iter.ctxt);
33             this.pos = iter.pos;
34         }
35
36         /// <summary>
37         /// Return the current navigator.
38         /// </summary>
39         public override XPathNavigator Current {
40             get { return this.ctxt; }
41         }
42
43         /// <summary>
44         /// Return the iterator's current position.
45         /// </summary>
46         public override int CurrentPosition {
47             get { return this.pos; }
48         }
49     }
50
51
52     /// <summary>
53     /// Iterate over all element children with a particular QName.
54     /// </summary>
55     internal class XPathDocumentElementChildIterator : XPathDocumentBaseIterator {
56         private string localName, namespaceUri;
57
58         /// <summary>
59         /// Create an iterator that ranges over all element children of "parent" having the specified QName.
60         /// </summary>
61         public XPathDocumentElementChildIterator(XPathDocumentNavigator parent, string name, string namespaceURI) : base(parent) {
62             if (namespaceURI == null) throw new ArgumentNullException("namespaceURI");
63
64             this.localName = parent.NameTable.Get(name);
65             this.namespaceUri = namespaceURI;
66         }
67
68         /// <summary>
69         /// Create a new iterator that is a copy of "iter".
70         /// </summary>
71         public XPathDocumentElementChildIterator(XPathDocumentElementChildIterator iter) : base(iter) {
72             this.localName = iter.localName;
73             this.namespaceUri = iter.namespaceUri;
74         }
75
76         /// <summary>
77         /// Create a copy of this iterator.
78         /// </summary>
79         public override XPathNodeIterator Clone() {
80             return new XPathDocumentElementChildIterator(this);
81         }
82
83         /// <summary>
84         /// Position the iterator to the next matching child.
85         /// </summary>
86         public override bool MoveNext() {
87             if (this.pos == 0) {
88                 if (!this.ctxt.MoveToChild(this.localName, this.namespaceUri))
89                     return false;
90             }
91             else {
92                 if (!this.ctxt.MoveToNext(this.localName, this.namespaceUri))
93                     return false;
94             }
95
96             this.pos++;
97             return true;
98         }
99     }
100
101
102     /// <summary>
103     /// Iterate over all content children with a particular XPathNodeType.
104     /// </summary>
105     internal class XPathDocumentKindChildIterator : XPathDocumentBaseIterator {
106         private XPathNodeType typ;
107
108         /// <summary>
109         /// Create an iterator that ranges over all content children of "parent" having the specified XPathNodeType.
110         /// </summary>
111         public XPathDocumentKindChildIterator(XPathDocumentNavigator parent, XPathNodeType typ) : base(parent) {
112             this.typ = typ;
113         }
114
115         /// <summary>
116         /// Create a new iterator that is a copy of "iter".
117         /// </summary>
118         public XPathDocumentKindChildIterator(XPathDocumentKindChildIterator iter) : base(iter) {
119             this.typ = iter.typ;
120         }
121
122         /// <summary>
123         /// Create a copy of this iterator.
124         /// </summary>
125         public override XPathNodeIterator Clone() {
126             return new XPathDocumentKindChildIterator(this);
127         }
128
129         /// <summary>
130         /// Position the iterator to the next descendant.
131         /// </summary>
132         public override bool MoveNext() {
133             if (this.pos == 0) {
134                 if (!this.ctxt.MoveToChild(this.typ))
135                     return false;
136             }
137             else {
138                 if (!this.ctxt.MoveToNext(this.typ))
139                     return false;
140             }
141
142             this.pos++;
143             return true;
144         }
145     }
146
147
148     /// <summary>
149     /// Iterate over all element descendants with a particular QName.
150     /// </summary>
151     internal class XPathDocumentElementDescendantIterator : XPathDocumentBaseIterator {
152         private XPathDocumentNavigator end;
153         private string localName, namespaceUri;
154         private bool matchSelf;
155
156         /// <summary>
157         /// Create an iterator that ranges over all element descendants of "root" having the specified QName.
158         /// </summary>
159         public XPathDocumentElementDescendantIterator(XPathDocumentNavigator root, string name, string namespaceURI, bool matchSelf) : base(root) {
160             if (namespaceURI == null) throw new ArgumentNullException("namespaceURI");
161
162             this.localName = root.NameTable.Get(name);
163             this.namespaceUri = namespaceURI;
164             this.matchSelf = matchSelf;
165
166             // Find the next non-descendant node that follows "root" in document order
167             if (root.NodeType != XPathNodeType.Root) {
168                 this.end = new XPathDocumentNavigator(root);
169                 this.end.MoveToNonDescendant();
170             }
171         }
172
173         /// <summary>
174         /// Create a new iterator that is a copy of "iter".
175         /// </summary>
176         public XPathDocumentElementDescendantIterator(XPathDocumentElementDescendantIterator iter) : base(iter) {
177             this.end = iter.end;
178             this.localName = iter.localName;
179             this.namespaceUri = iter.namespaceUri;
180             this.matchSelf = iter.matchSelf;
181         }
182
183         /// <summary>
184         /// Create a copy of this iterator.
185         /// </summary>
186         public override XPathNodeIterator Clone() {
187             return new XPathDocumentElementDescendantIterator(this);
188         }
189
190         /// <summary>
191         /// Position the iterator to the next descendant.
192         /// </summary>
193         public override bool MoveNext() {
194             if (this.matchSelf) {
195                 this.matchSelf = false;
196
197                 if (this.ctxt.IsElementMatch(this.localName, this.namespaceUri)) {
198                     this.pos++;
199                     return true;
200                 }
201             }
202
203             if (!this.ctxt.MoveToFollowing(this.localName, this.namespaceUri, this.end))
204                 return false;
205
206             this.pos++;
207             return true;
208         }
209     }
210
211
212     /// <summary>
213     /// Iterate over all content descendants with a particular XPathNodeType.
214     /// </summary>
215     internal class XPathDocumentKindDescendantIterator : XPathDocumentBaseIterator {
216         private XPathDocumentNavigator end;
217         private XPathNodeType typ;
218         private bool matchSelf;
219
220         /// <summary>
221         /// Create an iterator that ranges over all content descendants of "root" having the specified XPathNodeType.
222         /// </summary>
223         public XPathDocumentKindDescendantIterator(XPathDocumentNavigator root, XPathNodeType typ, bool matchSelf) : base(root) {
224             this.typ = typ;
225             this.matchSelf = matchSelf;
226
227             // Find the next non-descendant node that follows "root" in document order
228             if (root.NodeType != XPathNodeType.Root) {
229                 this.end = new XPathDocumentNavigator(root);
230                 this.end.MoveToNonDescendant();
231             }
232         }
233
234         /// <summary>
235         /// Create a new iterator that is a copy of "iter".
236         /// </summary>
237         public XPathDocumentKindDescendantIterator(XPathDocumentKindDescendantIterator iter) : base(iter) {
238             this.end = iter.end;
239             this.typ = iter.typ;
240             this.matchSelf = iter.matchSelf;
241         }
242
243         /// <summary>
244         /// Create a copy of this iterator.
245         /// </summary>
246         public override XPathNodeIterator Clone() {
247             return new XPathDocumentKindDescendantIterator(this);
248         }
249
250         /// <summary>
251         /// Position the iterator to the next descendant.
252         /// </summary>
253         public override bool MoveNext() {
254             if (this.matchSelf) {
255                 this.matchSelf = false;
256
257                 if (this.ctxt.IsKindMatch(this.typ)) {
258                     this.pos++;
259                     return true;
260                 }
261             }
262
263             if (!this.ctxt.MoveToFollowing(this.typ, this.end))
264                 return false;
265
266             this.pos++;
267             return true;
268         }
269     }
270 }
271