Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Runtime / XmlNavigatorFilter.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlNavigatorFilter.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
7 using System.Xml;
8 using System.Xml.XPath;
9 using System.Diagnostics;
10 using System.ComponentModel;
11
12 namespace System.Xml.Xsl.Runtime {
13
14     /// <summary>
15     /// XmlNavigatorFilter provides a flexible filtering abstraction over XPathNavigator.  Callers do
16     /// not know what type of filtering will occur; they simply call MoveToContent or MoveToSibling.
17     /// The filter implementation invokes appropriate operation(s) on the XPathNavigator in order
18     /// to skip over filtered nodes.
19     /// </summary>
20     [EditorBrowsable(EditorBrowsableState.Never)]
21     public abstract class XmlNavigatorFilter {
22         /// <summary>
23         /// Reposition the navigator to the first matching content node (inc. attributes); skip over
24         /// filtered nodes.  If there are no matching nodes, then don't move navigator and return false.
25         /// </summary>
26         public abstract bool MoveToContent(XPathNavigator navigator);
27
28         /// <summary>
29         /// Reposition the navigator to the next matching content node (inc. attributes); skip over
30         /// filtered nodes.  If there are no matching nodes, then don't move navigator and return false.
31         /// </summary>
32         public abstract bool MoveToNextContent(XPathNavigator navigator);
33
34         /// <summary>
35         /// Reposition the navigator to the next following sibling node (no attributes); skip over
36         /// filtered nodes.  If there are no matching nodes, then don't move navigator and return false.
37         /// </summary>
38         public abstract bool MoveToFollowingSibling(XPathNavigator navigator);
39
40         /// <summary>
41         /// Reposition the navigator to the previous sibling node (no attributes); skip over filtered
42         /// nodes.  If there are no matching nodes, then don't move navigator and return false.
43         /// </summary>
44         public abstract bool MoveToPreviousSibling(XPathNavigator navigator);
45
46         /// <summary>
47         /// Reposition the navigator to the next following node (inc. descendants); skip over filtered nodes.
48         /// If there are no matching nodes, then return false.
49         /// </summary>
50         public abstract bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navigatorEnd);
51
52         /// <summary>
53         /// Return true if the navigator's current node matches the filter condition.
54         /// </summary>
55         public abstract bool IsFiltered(XPathNavigator navigator);
56     }
57
58
59     /// <summary>
60     /// Filters any non-element and any element with a non-matching local name or namespace uri.
61     /// </summary>
62     internal class XmlNavNameFilter : XmlNavigatorFilter {
63         private string localName;
64         private string namespaceUri;
65
66         /// <summary>
67         /// Return an XmlNavigatorFilter that skips over nodes that do not match the specified name.
68         /// </summary>
69         public static XmlNavigatorFilter Create(string localName, string namespaceUri) {
70             return new XmlNavNameFilter(localName, namespaceUri);
71         }
72
73         /// <summary>
74         /// Keep only elements with name = localName, namespaceUri.
75         /// </summary>
76         private XmlNavNameFilter(string localName, string namespaceUri) {
77             this.localName = localName;
78             this.namespaceUri = namespaceUri;
79         }
80
81         /// <summary>
82         /// Reposition the navigator on the first element child with a matching name.
83         /// </summary>
84         public override bool MoveToContent(XPathNavigator navigator) {
85             return navigator.MoveToChild(this.localName, this.namespaceUri);
86         }
87
88         /// <summary>
89         /// Reposition the navigator on the next element child with a matching name.
90         /// </summary>
91         public override bool MoveToNextContent(XPathNavigator navigator) {
92             return navigator.MoveToNext(this.localName, this.namespaceUri);
93         }
94
95         /// <summary>
96         /// Reposition the navigator on the next element sibling with a matching name.
97         /// </summary>
98         public override bool MoveToFollowingSibling(XPathNavigator navigator) {
99             return navigator.MoveToNext(this.localName, this.namespaceUri);
100         }
101
102         /// <summary>
103         /// Reposition the navigator on the previous element sibling with a matching name.
104         /// </summary>
105         public override bool MoveToPreviousSibling(XPathNavigator navigator) {
106             return navigator.MoveToPrevious(this.localName, this.namespaceUri);
107         }
108
109         /// <summary>
110         /// Reposition the navigator on the next following element with a matching name.
111         /// </summary>
112         public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
113             return navigator.MoveToFollowing(this.localName, this.namespaceUri, navEnd);
114         }
115
116         /// <summary>
117         /// Return false if the navigator is positioned on an element with a matching name.
118         /// </summary>
119         public override bool IsFiltered(XPathNavigator navigator) {
120             return navigator.LocalName != this.localName || navigator.NamespaceURI != namespaceUri;
121         }
122     }
123
124
125     /// <summary>
126     /// Filters any node not of the specified type (type may not be attribute or namespace).
127     /// </summary>
128     internal class XmlNavTypeFilter : XmlNavigatorFilter {
129         private static XmlNavigatorFilter[] TypeFilters;
130         private XPathNodeType nodeType;
131         private int mask;
132
133         /// <summary>
134         /// There are a limited number of types, so create all possible XmlNavTypeFilter objects just once.
135         /// </summary>
136         static XmlNavTypeFilter() {
137             TypeFilters = new XmlNavigatorFilter[(int) XPathNodeType.Comment + 1];
138             TypeFilters[(int) XPathNodeType.Element] = new XmlNavTypeFilter(XPathNodeType.Element);
139             TypeFilters[(int) XPathNodeType.Text] = new XmlNavTypeFilter(XPathNodeType.Text);
140             TypeFilters[(int) XPathNodeType.ProcessingInstruction] = new XmlNavTypeFilter(XPathNodeType.ProcessingInstruction);
141             TypeFilters[(int) XPathNodeType.Comment] = new XmlNavTypeFilter(XPathNodeType.Comment);
142         }
143
144         /// <summary>
145         /// Return a previously constructed XmlNavigatorFilter that skips over nodes that do not match the specified type.
146         /// </summary>
147         public static XmlNavigatorFilter Create(XPathNodeType nodeType) {
148             Debug.Assert(TypeFilters[(int) nodeType] != null);
149             return TypeFilters[(int) nodeType];
150         }
151
152         /// <summary>
153         /// Keep only nodes with XPathNodeType = nodeType, where XPathNodeType.Text selects whitespace as well.
154         /// </summary>
155         private XmlNavTypeFilter(XPathNodeType nodeType) {
156             Debug.Assert(nodeType != XPathNodeType.Attribute && nodeType != XPathNodeType.Namespace);
157             this.nodeType = nodeType;
158             this.mask = XPathNavigator.GetContentKindMask(nodeType);
159         }
160
161         /// <summary>
162         /// Reposition the navigator on the first child with a matching type.
163         /// </summary>
164         public override bool MoveToContent(XPathNavigator navigator) {
165             return navigator.MoveToChild(this.nodeType);
166         }
167
168         /// <summary>
169         /// Reposition the navigator on the next child with a matching type.
170         /// </summary>
171         public override bool MoveToNextContent(XPathNavigator navigator) {
172             return navigator.MoveToNext(this.nodeType);
173         }
174
175         /// <summary>
176         /// Reposition the navigator on the next non-attribute sibling with a matching type.
177         /// </summary>
178         public override bool MoveToFollowingSibling(XPathNavigator navigator) {
179             return navigator.MoveToNext(this.nodeType);
180         }
181
182         /// <summary>
183         /// Reposition the navigator on the previous non-attribute sibling with a matching type.
184         /// </summary>
185         public override bool MoveToPreviousSibling(XPathNavigator navigator) {
186             return navigator.MoveToPrevious(this.nodeType);
187         }
188
189         /// <summary>
190         /// Reposition the navigator on the next following element with a matching kind.
191         /// </summary>
192         public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
193             return navigator.MoveToFollowing(this.nodeType, navEnd);
194         }
195
196         /// <summary>
197         /// Return false if the navigator is positioned on a node with a matching type.
198         /// </summary>
199         public override bool IsFiltered(XPathNavigator navigator) {
200             return ((1 << (int) navigator.NodeType) & this.mask) == 0;
201         }
202     }
203
204
205     /// <summary>
206     /// Filters all attribute nodes.
207     /// </summary>
208     internal class XmlNavAttrFilter : XmlNavigatorFilter {
209         private static XmlNavigatorFilter Singleton = new XmlNavAttrFilter();
210
211         /// <summary>
212         /// Return a singleton XmlNavigatorFilter that filters all attribute nodes.
213         /// </summary>
214         public static XmlNavigatorFilter Create() {
215             return Singleton;
216         }
217
218         /// <summary>
219         /// Constructor.
220         /// </summary>
221         private XmlNavAttrFilter() {
222         }
223
224         /// <summary>
225         /// Reposition the navigator on the first non-attribute child.
226         /// </summary>
227         public override bool MoveToContent(XPathNavigator navigator) {
228             return navigator.MoveToFirstChild();
229         }
230
231         /// <summary>
232         /// Reposition the navigator on the next non-attribute sibling.
233         /// </summary>
234         public override bool MoveToNextContent(XPathNavigator navigator) {
235             return navigator.MoveToNext();
236         }
237
238         /// <summary>
239         /// Reposition the navigator on the next non-attribute sibling.
240         /// </summary>
241         public override bool MoveToFollowingSibling(XPathNavigator navigator) {
242             return navigator.MoveToNext();
243         }
244
245         /// <summary>
246         /// Reposition the navigator on the previous non-attribute sibling.
247         /// </summary>
248         public override bool MoveToPreviousSibling(XPathNavigator navigator) {
249             return navigator.MoveToPrevious();
250         }
251
252         /// <summary>
253         /// Reposition the navigator on the next following non-attribute.
254         /// </summary>
255         public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
256             return navigator.MoveToFollowing(XPathNodeType.All, navEnd);
257         }
258
259         /// <summary>
260         /// Return true if the navigator is positioned on an attribute.
261         /// </summary>
262         public override bool IsFiltered(XPathNavigator navigator) {
263             return navigator.NodeType == XPathNodeType.Attribute;
264         }
265     }
266
267
268     /// <summary>
269     /// Never filter nodes.
270     /// </summary>
271     internal class XmlNavNeverFilter : XmlNavigatorFilter {
272         private static XmlNavigatorFilter Singleton = new XmlNavNeverFilter();
273
274         /// <summary>
275         /// Return a singleton XmlNavigatorFilter that never filters any nodes.
276         /// </summary>
277         public static XmlNavigatorFilter Create() {
278             return Singleton;
279         }
280
281         /// <summary>
282         /// Constructor.
283         /// </summary>
284         private XmlNavNeverFilter() {
285         }
286
287         /// <summary>
288         /// Reposition the navigator on the first child (attribute or non-attribute).
289         /// </summary>
290         public override bool MoveToContent(XPathNavigator navigator) {
291             return MoveToFirstAttributeContent(navigator);
292         }
293
294         /// <summary>
295         /// Reposition the navigator on the next child (attribute or non-attribute).
296         /// </summary>
297         public override bool MoveToNextContent(XPathNavigator navigator) {
298             return MoveToNextAttributeContent(navigator);
299         }
300
301         /// <summary>
302         /// Reposition the navigator on the next sibling (no attributes).
303         /// </summary>
304         public override bool MoveToFollowingSibling(XPathNavigator navigator) {
305             return navigator.MoveToNext();
306         }
307
308         /// <summary>
309         /// Reposition the navigator on the previous sibling (no attributes).
310         /// </summary>
311         public override bool MoveToPreviousSibling(XPathNavigator navigator) {
312             return navigator.MoveToPrevious();
313         }
314
315         /// <summary>
316         /// Reposition the navigator on the next following node.
317         /// </summary>
318         public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
319             return navigator.MoveToFollowing(XPathNodeType.All, navEnd);
320         }
321
322         /// <summary>
323         /// Nodes are never filtered so always return false.
324         /// </summary>
325         public override bool IsFiltered(XPathNavigator navigator) {
326             return false;
327         }
328
329         /// <summary>
330         /// Move to navigator's first attribute node.  If no attribute's exist, move to the first content node.
331         /// If no content nodes exist, return null.  Otherwise, return navigator.
332         /// </summary>
333         public static bool MoveToFirstAttributeContent(XPathNavigator navigator) {
334             if (!navigator.MoveToFirstAttribute())
335                 return navigator.MoveToFirstChild();
336             return true;
337         }
338
339         /// <summary>
340         /// If navigator is positioned on an attribute, move to the next attribute node.  If there are no more
341         /// attributes, move to the first content node.  If navigator is positioned on a content node, move to
342         /// the next content node.  If there are no more attributes and content nodes, return null.
343         /// Otherwise, return navigator.
344         /// </summary>
345         public static bool MoveToNextAttributeContent(XPathNavigator navigator) {
346             if (navigator.NodeType == XPathNodeType.Attribute) {
347                 if (!navigator.MoveToNextAttribute()) {
348                     navigator.MoveToParent();
349                     if (!navigator.MoveToFirstChild()) {
350                         // No children, so reposition on original attribute
351                         navigator.MoveToFirstAttribute();
352                         while (navigator.MoveToNextAttribute())
353                             ;
354                         return false;
355                     }
356                 }
357                 return true;
358             }
359             return navigator.MoveToNext();
360         }
361     }
362 }