1 //------------------------------------------------------------------------------
2 // <copyright file="XmlNavigatorFilter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
8 using System.Xml.XPath;
9 using System.Diagnostics;
10 using System.ComponentModel;
12 namespace System.Xml.Xsl.Runtime {
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.
20 [EditorBrowsable(EditorBrowsableState.Never)]
21 public abstract class XmlNavigatorFilter {
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.
26 public abstract bool MoveToContent(XPathNavigator navigator);
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.
32 public abstract bool MoveToNextContent(XPathNavigator navigator);
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.
38 public abstract bool MoveToFollowingSibling(XPathNavigator navigator);
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.
44 public abstract bool MoveToPreviousSibling(XPathNavigator navigator);
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.
50 public abstract bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navigatorEnd);
53 /// Return true if the navigator's current node matches the filter condition.
55 public abstract bool IsFiltered(XPathNavigator navigator);
60 /// Filters any non-element and any element with a non-matching local name or namespace uri.
62 internal class XmlNavNameFilter : XmlNavigatorFilter {
63 private string localName;
64 private string namespaceUri;
67 /// Return an XmlNavigatorFilter that skips over nodes that do not match the specified name.
69 public static XmlNavigatorFilter Create(string localName, string namespaceUri) {
70 return new XmlNavNameFilter(localName, namespaceUri);
74 /// Keep only elements with name = localName, namespaceUri.
76 private XmlNavNameFilter(string localName, string namespaceUri) {
77 this.localName = localName;
78 this.namespaceUri = namespaceUri;
82 /// Reposition the navigator on the first element child with a matching name.
84 public override bool MoveToContent(XPathNavigator navigator) {
85 return navigator.MoveToChild(this.localName, this.namespaceUri);
89 /// Reposition the navigator on the next element child with a matching name.
91 public override bool MoveToNextContent(XPathNavigator navigator) {
92 return navigator.MoveToNext(this.localName, this.namespaceUri);
96 /// Reposition the navigator on the next element sibling with a matching name.
98 public override bool MoveToFollowingSibling(XPathNavigator navigator) {
99 return navigator.MoveToNext(this.localName, this.namespaceUri);
103 /// Reposition the navigator on the previous element sibling with a matching name.
105 public override bool MoveToPreviousSibling(XPathNavigator navigator) {
106 return navigator.MoveToPrevious(this.localName, this.namespaceUri);
110 /// Reposition the navigator on the next following element with a matching name.
112 public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
113 return navigator.MoveToFollowing(this.localName, this.namespaceUri, navEnd);
117 /// Return false if the navigator is positioned on an element with a matching name.
119 public override bool IsFiltered(XPathNavigator navigator) {
120 return navigator.LocalName != this.localName || navigator.NamespaceURI != namespaceUri;
126 /// Filters any node not of the specified type (type may not be attribute or namespace).
128 internal class XmlNavTypeFilter : XmlNavigatorFilter {
129 private static XmlNavigatorFilter[] TypeFilters;
130 private XPathNodeType nodeType;
134 /// There are a limited number of types, so create all possible XmlNavTypeFilter objects just once.
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);
145 /// Return a previously constructed XmlNavigatorFilter that skips over nodes that do not match the specified type.
147 public static XmlNavigatorFilter Create(XPathNodeType nodeType) {
148 Debug.Assert(TypeFilters[(int) nodeType] != null);
149 return TypeFilters[(int) nodeType];
153 /// Keep only nodes with XPathNodeType = nodeType, where XPathNodeType.Text selects whitespace as well.
155 private XmlNavTypeFilter(XPathNodeType nodeType) {
156 Debug.Assert(nodeType != XPathNodeType.Attribute && nodeType != XPathNodeType.Namespace);
157 this.nodeType = nodeType;
158 this.mask = XPathNavigator.GetContentKindMask(nodeType);
162 /// Reposition the navigator on the first child with a matching type.
164 public override bool MoveToContent(XPathNavigator navigator) {
165 return navigator.MoveToChild(this.nodeType);
169 /// Reposition the navigator on the next child with a matching type.
171 public override bool MoveToNextContent(XPathNavigator navigator) {
172 return navigator.MoveToNext(this.nodeType);
176 /// Reposition the navigator on the next non-attribute sibling with a matching type.
178 public override bool MoveToFollowingSibling(XPathNavigator navigator) {
179 return navigator.MoveToNext(this.nodeType);
183 /// Reposition the navigator on the previous non-attribute sibling with a matching type.
185 public override bool MoveToPreviousSibling(XPathNavigator navigator) {
186 return navigator.MoveToPrevious(this.nodeType);
190 /// Reposition the navigator on the next following element with a matching kind.
192 public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
193 return navigator.MoveToFollowing(this.nodeType, navEnd);
197 /// Return false if the navigator is positioned on a node with a matching type.
199 public override bool IsFiltered(XPathNavigator navigator) {
200 return ((1 << (int) navigator.NodeType) & this.mask) == 0;
206 /// Filters all attribute nodes.
208 internal class XmlNavAttrFilter : XmlNavigatorFilter {
209 private static XmlNavigatorFilter Singleton = new XmlNavAttrFilter();
212 /// Return a singleton XmlNavigatorFilter that filters all attribute nodes.
214 public static XmlNavigatorFilter Create() {
221 private XmlNavAttrFilter() {
225 /// Reposition the navigator on the first non-attribute child.
227 public override bool MoveToContent(XPathNavigator navigator) {
228 return navigator.MoveToFirstChild();
232 /// Reposition the navigator on the next non-attribute sibling.
234 public override bool MoveToNextContent(XPathNavigator navigator) {
235 return navigator.MoveToNext();
239 /// Reposition the navigator on the next non-attribute sibling.
241 public override bool MoveToFollowingSibling(XPathNavigator navigator) {
242 return navigator.MoveToNext();
246 /// Reposition the navigator on the previous non-attribute sibling.
248 public override bool MoveToPreviousSibling(XPathNavigator navigator) {
249 return navigator.MoveToPrevious();
253 /// Reposition the navigator on the next following non-attribute.
255 public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
256 return navigator.MoveToFollowing(XPathNodeType.All, navEnd);
260 /// Return true if the navigator is positioned on an attribute.
262 public override bool IsFiltered(XPathNavigator navigator) {
263 return navigator.NodeType == XPathNodeType.Attribute;
269 /// Never filter nodes.
271 internal class XmlNavNeverFilter : XmlNavigatorFilter {
272 private static XmlNavigatorFilter Singleton = new XmlNavNeverFilter();
275 /// Return a singleton XmlNavigatorFilter that never filters any nodes.
277 public static XmlNavigatorFilter Create() {
284 private XmlNavNeverFilter() {
288 /// Reposition the navigator on the first child (attribute or non-attribute).
290 public override bool MoveToContent(XPathNavigator navigator) {
291 return MoveToFirstAttributeContent(navigator);
295 /// Reposition the navigator on the next child (attribute or non-attribute).
297 public override bool MoveToNextContent(XPathNavigator navigator) {
298 return MoveToNextAttributeContent(navigator);
302 /// Reposition the navigator on the next sibling (no attributes).
304 public override bool MoveToFollowingSibling(XPathNavigator navigator) {
305 return navigator.MoveToNext();
309 /// Reposition the navigator on the previous sibling (no attributes).
311 public override bool MoveToPreviousSibling(XPathNavigator navigator) {
312 return navigator.MoveToPrevious();
316 /// Reposition the navigator on the next following node.
318 public override bool MoveToFollowing(XPathNavigator navigator, XPathNavigator navEnd) {
319 return navigator.MoveToFollowing(XPathNodeType.All, navEnd);
323 /// Nodes are never filtered so always return false.
325 public override bool IsFiltered(XPathNavigator navigator) {
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.
333 public static bool MoveToFirstAttributeContent(XPathNavigator navigator) {
334 if (!navigator.MoveToFirstAttribute())
335 return navigator.MoveToFirstChild();
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.
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())
359 return navigator.MoveToNext();