XmlDiffPath.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:13k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. //  ---------------------------------------------------------------------------
  2. // <copyright company="Microsoft Corporation" file="XmlDiffPath.cs">
  3. //     Copyright (c) Microsoft Corporation 2005
  4. // </copyright>
  5. // <project>
  6. //     XmlDiffView
  7. // </project>
  8. // <summary>
  9. //     Provide lists of nodes and attributes
  10. //     based on proprietary alphanumeric path statements.
  11. // </summary>
  12. // <history>
  13. //      [barryw] 03MAR15 Created
  14. // </history>
  15. //  ---------------------------------------------------------------------------
  16. namespace Microsoft.XmlDiffPatch {
  17.     #region Using directives
  18.     using System;
  19.     using System.Diagnostics;
  20.     #endregion
  21.     /// <summary>
  22.     /// Class to provide lists of nodes and attributes
  23.     /// based on proprietary alphanumeric path statements
  24.     /// </summary>
  25.     internal class XmlDiffPath {
  26.         #region Member variables section
  27.         private static char[] delimites = new
  28.             char[] {
  29.                        '|', '-', '/'
  30.                    };
  31.         #endregion
  32.         #region Methods section
  33.         /// <summary>
  34.         /// Gets the list of nodes or attributes below the position indicated
  35.         /// </summary>
  36.         /// <param name="rootNode">The root node for the xml data</param>
  37.         /// <param name="currentParentNode">The current node</param>
  38.         /// <param name="xmlDiffPathExpr">Proprietary path statement separator or character</param>
  39.         /// <returns>List of nodes or attributes</returns>
  40.         public static XmlDiffPathNodeList SelectNodes(
  41.             XmlDiffViewParentNode rootNode,
  42.             XmlDiffViewParentNode currentParentNode,
  43.             string xmlDiffPathExpr) {
  44.             switch (xmlDiffPathExpr[0]) {
  45.                 case '/':
  46.                     return SelectAbsoluteNodes(rootNode, xmlDiffPathExpr);
  47.                 case '@':
  48.                     if (xmlDiffPathExpr.Length < 2) {
  49.                         OnInvalidExpression(xmlDiffPathExpr);
  50.                     }
  51.                     if (xmlDiffPathExpr[1] == '*') {
  52.                         return SelectAllAttributes(
  53.                             (XmlDiffViewElement)currentParentNode);
  54.                     } else {
  55.                         return SelectAttributes(
  56.                             (XmlDiffViewElement)currentParentNode, xmlDiffPathExpr);
  57.                     }
  58.                 case '*':
  59.                     if (xmlDiffPathExpr.Length == 1) {
  60.                         return SelectAllChildren(currentParentNode);
  61.                     } else {
  62.                         OnInvalidExpression(xmlDiffPathExpr);
  63.                         return null;
  64.                     }
  65.                 default:
  66.                     int startPosition = 0;
  67.                     return SelectChildNodes(
  68.                         currentParentNode,
  69.                         xmlDiffPathExpr,
  70.                         startPosition);
  71.             }
  72.         }
  73.         /// <summary>
  74.         /// Gets a list of node objects corresponding to
  75.         /// the proprietary path reference provided. 
  76.         /// </summary>
  77.         /// <param name="rootNode">The starting node</param>
  78.         /// <param name="path">Absolute path reference to node of interest</param>
  79.         /// <returns>list of node objects</returns>
  80.         private static XmlDiffPathNodeList SelectAbsoluteNodes(
  81.             XmlDiffViewParentNode rootNode,
  82.             string path) {
  83.             Debug.Assert(path[0] == '/');
  84.             int pos = 1;
  85.             XmlDiffViewNode node = rootNode;
  86.             for (; ; ) {
  87.                 int startPos = pos;
  88.                 int nodePos = ReadPosition(path, ref pos);
  89.                 if (pos == path.Length || path[pos] == '/') {
  90.                     if (node.FirstChildNode == null) {
  91.                         OnNoMatchingNode(path);
  92.                     }
  93.                     XmlDiffViewParentNode parentNode = (XmlDiffViewParentNode)node;
  94.                     if (nodePos <= 0 || nodePos > parentNode.
  95.                         SourceChildNodesCount) {
  96.                         OnNoMatchingNode(path);
  97.                     }
  98.                     node = parentNode.GetSourceChildNode(nodePos - 1);
  99.                     if (pos == path.Length) {
  100.                         XmlDiffPathNodeList list = new
  101.                             XmlDiffPathSingleNodeList();
  102.                         list.AddNode(node);
  103.                         return list;
  104.                     }
  105.                     pos++;
  106.                 } else {
  107.                     if (path[pos] == '-' || path[pos] == '|') {
  108.                         if (node.FirstChildNode == null) {
  109.                             OnNoMatchingNode(path);
  110.                         }
  111.                         return SelectChildNodes(
  112.                             ((XmlDiffViewParentNode)node),
  113.                             path,
  114.                             startPos);
  115.                     }
  116.                     OnInvalidExpression(path);
  117.                 }
  118.             }
  119.         }
  120.         /// <summary>
  121.         /// Gets a list of the attributes for the specifed node
  122.         /// and if applicable, its children.
  123.         /// </summary>
  124.         /// <param name="parentElement">The node which 
  125.         /// contains the attributes</param>
  126.         /// <returns>List of attributes</returns>
  127.         private static XmlDiffPathNodeList SelectAllAttributes(
  128.             XmlDiffViewElement parentElement) {
  129.             if (parentElement.Attributes == null) {
  130.                 OnNoMatchingNode("@*");
  131.                 return null;
  132.             } else if (parentElement.Attributes.NextSibbling == null) {
  133.                 XmlDiffPathNodeList nodeList = new XmlDiffPathSingleNodeList();
  134.                 nodeList.AddNode(parentElement.Attributes);
  135.                 return nodeList;
  136.             } else {
  137.                 XmlDiffPathNodeList nodeList = new XmlDiffPathMultiNodeList();
  138.                 XmlDiffViewAttribute curAttr = parentElement.Attributes;
  139.                 while (curAttr != null) {
  140.                     nodeList.AddNode(curAttr);
  141.                 }
  142.                 return nodeList;
  143.             }
  144.         }
  145.         /// <summary>
  146.         /// Gets a list of attribute objects based on the location
  147.         /// specified.
  148.         /// </summary>
  149.         /// <param name="parentElement">Node at which to start the path search</param>
  150.         /// <param name="path">Proprietary alphanumeric path statement</param>
  151.         /// <returns>list of attribute objects</returns>
  152.         private static XmlDiffPathNodeList SelectAttributes(
  153.             XmlDiffViewElement parentElement,
  154.             string path) {
  155.             Debug.Assert(path[0] == '@');
  156.             int pos = 1;
  157.             XmlDiffPathNodeList nodeList = null;
  158.             for (; ; ) {
  159.                 string name = ReadAttrName(path, ref pos);
  160.                 if (nodeList == null) {
  161.                     if (pos == path.Length) {
  162.                         nodeList = new XmlDiffPathSingleNodeList();
  163.                     } else {
  164.                         nodeList = new XmlDiffPathMultiNodeList();
  165.                     }
  166.                 }
  167.                 XmlDiffViewAttribute attr = parentElement.GetAttribute(name);
  168.                 if (attr == null) {
  169.                     OnNoMatchingNode(path);
  170.                 }
  171.                 nodeList.AddNode(attr);
  172.                 if (pos == path.Length) {
  173.                     break;
  174.                 } else if (path[pos] == '|') {
  175.                     pos++;
  176.                     if (path[pos] != '@') {
  177.                         OnInvalidExpression(path);
  178.                     }
  179.                     pos++;
  180.                 } else {
  181.                     OnInvalidExpression(path);
  182.                 }
  183.             }
  184.             return nodeList;
  185.         }
  186.         /// <summary>
  187.         /// Gets a list of all node objects at and below the location
  188.         /// specified.
  189.         /// </summary>
  190.         /// <param name="parentNode">Node at which to start</param>
  191.         /// <returns>list of node objects</returns>
  192.         private static XmlDiffPathNodeList SelectAllChildren(
  193.             XmlDiffViewParentNode parentNode) {
  194.             if (parentNode.ChildNodes == null) {
  195.                 OnNoMatchingNode("*");
  196.                 return null;
  197.             } else if (parentNode.ChildNodes.NextSibbling == null) {
  198.                 XmlDiffPathNodeList nodeList = new XmlDiffPathSingleNodeList();
  199.                 nodeList.AddNode(parentNode.ChildNodes);
  200.                 return nodeList;
  201.             } else {
  202.                 XmlDiffPathNodeList nodeList = new XmlDiffPathMultiNodeList();
  203.                 XmlDiffViewNode childNode = parentNode.ChildNodes;
  204.                 while (childNode != null) {
  205.                     nodeList.AddNode(childNode);
  206.                     childNode = childNode.NextSibbling;
  207.                 }
  208.                 return nodeList;
  209.             }
  210.         }
  211.         /// <summary>
  212.         /// Gets the list of child nodes below the position indicated
  213.         /// </summary>
  214.         /// <param name="parentNode">The current node</param>
  215.         /// <param name="path">Proprietary path statement</param>
  216.         /// <param name="startPos">Position in the path statement 
  217.         /// at which to start collecting node objects.</param>
  218.         /// <returns>list of child nodes</returns>
  219.         /// <returns>List of nodes or attributes</returns>
  220.         private static XmlDiffPathNodeList SelectChildNodes(
  221.             XmlDiffViewParentNode parentNode,
  222.             string path,
  223.             int startPos) {
  224.             int pos = startPos;
  225.             XmlDiffPathNodeList nodeList = null;
  226.             for (; ; ) {
  227.                 int nodePos = ReadPosition(path, ref pos);
  228.                 if (pos == path.Length) {
  229.                     nodeList = new XmlDiffPathSingleNodeList();
  230.                 } else {
  231.                     nodeList = new XmlDiffPathMultiNodeList();
  232.                 }
  233.                 if (nodePos <= 0 || nodePos > parentNode.SourceChildNodesCount) {
  234.                     OnNoMatchingNode(path);
  235.                 }
  236.                 nodeList.AddNode(parentNode.GetSourceChildNode(nodePos - 1));
  237.                 if (pos == path.Length) {
  238.                     break;
  239.                 } else if (path[pos] == '|') {
  240.                     pos++;
  241.                 } else if (path[pos] == '-') {
  242.                     pos++;
  243.                     int endNodePos = ReadPosition(path, ref pos);
  244.                     if (endNodePos <= 0 || endNodePos > parentNode.SourceChildNodesCount) {
  245.                         OnNoMatchingNode(path);
  246.                     }
  247.                     while (nodePos < endNodePos) {
  248.                         nodePos++;
  249.                         nodeList.AddNode(parentNode.GetSourceChildNode(nodePos - 1));
  250.                     }
  251.                     if (pos == path.Length) {
  252.                         break;
  253.                     } else if (path[pos] == '|') {
  254.                         pos++;
  255.                     } else {
  256.                         OnInvalidExpression(path);
  257.                     }
  258.                 }
  259.             }
  260.             return nodeList;
  261.         }
  262.         /// <summary>
  263.         /// Gets the numeric value at the specified
  264.         /// position in the statement
  265.         /// </summary>
  266.         /// <param name="str">Statement to search</param>
  267.         /// <param name="pos">Position at which to start the search</param>
  268.         /// <returns>Representation of the position in the absolute path to the node</returns>
  269.         private static int ReadPosition(string str, ref int pos) {
  270.             Debug.Assert(pos <= str.Length);
  271.             int end = str.IndexOfAny(delimites, pos);
  272.             if (end < 0) {
  273.                 end = str.Length;
  274.             }
  275.             // TODO: better error handling if this should be shipped
  276.             int nodePos = int.Parse(str.Substring(pos, end - pos));
  277.             pos = end;
  278.             return nodePos;
  279.         }
  280.         /// <summary>
  281.         /// Returns the sub-string representing the attribute name which
  282.         /// starts at the specified position in the provided statement
  283.         /// and ends just before a vertical bar character or the end 
  284.         /// of the specifed statement.
  285.         /// </summary>
  286.         /// <param name="str">Statement to search</param>
  287.         /// <param name="pos">Position at which to start the search</param>
  288.         /// <returns>attribute name</returns>
  289.         private static string ReadAttrName(string str, ref int pos) {
  290.             Debug.Assert(pos <= str.Length);
  291.             int end = str.IndexOf('|', pos);
  292.             if (end < 0) {
  293.                 end = str.Length;
  294.             }
  295.             // TODO: better error handling if this should be shipped
  296.             string name = str.Substring(pos, end - pos);
  297.             pos = end;
  298.             return name;
  299.         }
  300.         /// <summary>
  301.         /// Throws an 'invalid XmlDiffPath expression' exception.
  302.         /// </summary>
  303.         /// <param name="path">Proprietary alphanumeric path statement</param>
  304.         private static void OnInvalidExpression(string path) {
  305.             throw new Exception("Invalid XmlDiffPath expression: " + path);
  306.         }
  307.         /// <summary>
  308.         /// Throws an 'no matching node' exception.
  309.         /// </summary>
  310.         /// <param name="path">Proprietary alphanumeric path statement</param>
  311.         private static void OnNoMatchingNode(string path) {
  312.             throw new Exception("No matching node:" + path);
  313.         }
  314.         #endregion
  315.     }
  316. }