The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Runtime \ XmlNavigatorFilter

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

Developer Fusion