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

xml/soap/webservice

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlHash.cs" company="Microsoft">
  3. //     Copyright (c) Microsoft Corporation.  All rights reserved.
  4. // </copyright>                                                                
  5. //------------------------------------------------------------------------------
  6. using System;
  7. using System.Xml;
  8. using System.Diagnostics;
  9. namespace Microsoft.XmlDiffPatch
  10. {
  11. internal class XmlHash
  12. {
  13. // Fields
  14.     bool _bIgnoreChildOrder = false;
  15.     bool _bIgnoreComments = false;
  16.     bool _bIgnorePI = false;
  17.     bool _bIgnoreWhitespace = false;
  18.     bool _bIgnoreNamespaces = false;
  19.     bool _bIgnorePrefixes = false;
  20.     bool _bIgnoreXmlDecl = false;
  21.     bool _bIgnoreDtd = false;
  22.     const string Delimiter = "x01";
  23. // Constructor
  24. internal XmlHash( XmlDiff xmlDiff )
  25. {
  26.         // set flags
  27.         _bIgnoreChildOrder  = xmlDiff.IgnoreChildOrder;
  28.         _bIgnoreComments    = xmlDiff.IgnoreComments;
  29.         _bIgnorePI          = xmlDiff.IgnorePI;
  30.         _bIgnoreWhitespace  = xmlDiff.IgnoreWhitespace;
  31.         _bIgnoreNamespaces  = xmlDiff.IgnoreNamespaces;
  32.         _bIgnorePrefixes    = xmlDiff.IgnorePrefixes;
  33.         _bIgnoreXmlDecl     = xmlDiff.IgnoreXmlDecl;
  34.         _bIgnoreDtd         = xmlDiff.IgnoreDtd;
  35. }
  36. internal XmlHash()
  37. {
  38. }
  39. // Methods
  40.     private void ClearFlags()
  41.     {
  42.         _bIgnoreChildOrder  = false;
  43.         _bIgnoreComments    = false;
  44.         _bIgnorePI          = false;
  45.         _bIgnoreWhitespace  = false;
  46.         _bIgnoreNamespaces  = false;
  47.         _bIgnorePrefixes    = false;
  48.         _bIgnoreXmlDecl     = false;
  49.         _bIgnoreDtd         = false;
  50.      }
  51.     internal ulong ComputeHash( XmlNode node, XmlDiffOptions options )
  52.     {
  53.         _bIgnoreChildOrder = ( ( (int)options & (int)(XmlDiffOptions.IgnoreChildOrder) ) > 0 ) ;
  54.         _bIgnoreComments   = ( ( (int)options & (int)(XmlDiffOptions.IgnoreComments)   ) > 0 ) ;
  55.         _bIgnorePI         = ( ( (int)options & (int)(XmlDiffOptions.IgnorePI)         ) > 0 ) ;
  56.         _bIgnoreWhitespace = ( ( (int)options & (int)(XmlDiffOptions.IgnoreWhitespace) ) > 0 ) ;
  57.         _bIgnoreNamespaces = ( ( (int)options & (int)(XmlDiffOptions.IgnoreNamespaces) ) > 0 ) ;
  58.         _bIgnorePrefixes   = ( ( (int)options & (int)(XmlDiffOptions.IgnorePrefixes)   ) > 0 ) ;
  59.         _bIgnoreXmlDecl    = ( ( (int)options & (int)(XmlDiffOptions.IgnoreXmlDecl)    ) > 0 ) ;
  60.         _bIgnoreDtd        = ( ( (int)options & (int)(XmlDiffOptions.IgnoreDtd)        ) > 0 ) ;
  61.         return ComputeHash( node );
  62.     }
  63.     internal ulong ComputeHash( XmlNode node)
  64.     {
  65.         switch ( node.NodeType )
  66.         {
  67.             case XmlNodeType.Document:
  68.                 return ComputeHashXmlDocument( (XmlDocument)node );
  69.             case XmlNodeType.DocumentFragment:
  70.                 return ComputeHashXmlFragment( (XmlDocumentFragment)node );
  71.             default:
  72.                 return ComputeHashXmlNode( node );
  73.         }
  74.     }
  75.     private ulong ComputeHashXmlDocument( XmlDocument doc )
  76.     {
  77.         HashAlgorithm ha = new HashAlgorithm();
  78.         HashDocument( ha );
  79.         ComputeHashXmlChildren( ha, doc );
  80.         return ha.Hash;
  81.     }
  82.     private ulong ComputeHashXmlFragment( XmlDocumentFragment frag )
  83.     {
  84.         HashAlgorithm ha = new HashAlgorithm();
  85.         ComputeHashXmlChildren( ha, frag );
  86.         return ha.Hash;
  87.     }
  88.     internal ulong ComputeHashXmlDiffDocument( XmlDiffDocument doc )
  89.     {
  90.         HashAlgorithm ha = new HashAlgorithm();
  91.         HashDocument( ha );
  92.         ComputeHashXmlDiffChildren( ha, doc );
  93.         return ha.Hash;
  94.     }
  95.     internal ulong ComputeHashXmlDiffElement( XmlDiffElement el )
  96.     {
  97.         HashAlgorithm ha = new HashAlgorithm();
  98.         HashElement( ha, el.LocalName, el.Prefix, el.NamespaceURI );
  99.         ComputeHashXmlDiffAttributes( ha, el );
  100.         ComputeHashXmlDiffChildren( ha, el );
  101.         return ha.Hash;
  102.     }
  103.     private void ComputeHashXmlDiffAttributes( HashAlgorithm ha, XmlDiffElement el )
  104.     {
  105.         int attrCount = 0;
  106.         ulong attrHashAll = 0;
  107.         XmlDiffAttributeOrNamespace curAttrOrNs = el._attributes;
  108.         while ( curAttrOrNs != null )
  109.         {
  110.             attrHashAll += curAttrOrNs.HashValue;
  111.             attrCount++;
  112.             curAttrOrNs = (XmlDiffAttributeOrNamespace)curAttrOrNs._nextSibling;
  113.         }
  114.         if ( attrCount > 0 ) 
  115.         {
  116.             ha.AddULong( attrHashAll );
  117.             ha.AddInt( attrCount );
  118.         }
  119.     }
  120.     private void ComputeHashXmlDiffChildren( HashAlgorithm ha, XmlDiffParentNode parent )
  121.     {
  122.         int childrenCount = 0;
  123. if ( _bIgnoreChildOrder )
  124. {
  125. ulong totalHash = 0;
  126.             XmlDiffNode curChild = parent.FirstChildNode;
  127. while ( curChild != null )
  128. {
  129.                 Debug.Assert( !( curChild is XmlDiffAttributeOrNamespace ) );
  130. Debug.Assert ( curChild.HashValue != 0 );
  131. totalHash += curChild.HashValue;
  132. childrenCount++;
  133. curChild = curChild._nextSibling;
  134. }
  135. ha.AddULong( totalHash );
  136. }
  137. else
  138. {
  139.             XmlDiffNode curChild = parent.FirstChildNode;
  140. while ( curChild != null )
  141. {
  142.                 Debug.Assert( !( curChild is XmlDiffAttributeOrNamespace ) );
  143. Debug.Assert ( curChild.HashValue != 0 );
  144. ha.AddULong( curChild.HashValue );
  145. childrenCount++;
  146. curChild = curChild._nextSibling;
  147. }
  148. }
  149.         if ( childrenCount != 0 )
  150.             ha.AddInt( childrenCount );
  151.     }
  152.     private void ComputeHashXmlChildren( HashAlgorithm ha, XmlNode parent )
  153.     {
  154.         XmlElement el = parent as XmlElement;
  155.         if ( el != null )
  156.         {
  157.             ulong attrHashSum = 0;
  158.             int attrsCount = 0;
  159.             XmlAttributeCollection attrs = ((XmlElement)parent).Attributes;
  160.             for ( int i = 0; i < attrs.Count; i++ )
  161.             {
  162.                 XmlAttribute attr = (XmlAttribute)attrs.Item(i);
  163.                 ulong hashValue = 0;
  164.                 // default namespace def
  165.                 if ( attr.LocalName == "xmlns" && attr.Prefix == string.Empty ) {
  166.                     if ( _bIgnoreNamespaces ) {
  167.                         continue;
  168.                     }
  169.                     hashValue = HashNamespace( string.Empty, attr.Value );
  170.                 }
  171.                 // namespace def
  172.                 else if ( attr.Prefix == "xmlns" ) {
  173.                     if ( _bIgnoreNamespaces ) {
  174.                         continue;
  175.                     }
  176.                     hashValue = HashNamespace( attr.LocalName, attr.Value );
  177.                 }
  178.                 // attribute
  179.                 else {
  180.                     if ( _bIgnoreWhitespace )
  181.                         hashValue = HashAttribute( attr.LocalName, attr.Prefix, attr.NamespaceURI, XmlDiff.NormalizeText( attr.Value ) );
  182.                     else
  183.                         hashValue = HashAttribute( attr.LocalName, attr.Prefix, attr.NamespaceURI, attr.Value );
  184.                 }
  185.                 Debug.Assert( hashValue != 0 );
  186.                 attrsCount++;
  187.                 attrHashSum += hashValue;
  188.             }
  189.             if ( attrsCount != 0 )
  190.             {
  191.                 ha.AddULong( attrHashSum );
  192.                 ha.AddInt( attrsCount );
  193.             }
  194.         }
  195. int childrenCount = 0;
  196. if ( _bIgnoreChildOrder )
  197. {
  198. ulong totalHashSum = 0;
  199. XmlNode curChild = parent.FirstChild;
  200. while ( curChild != null )
  201. {
  202. ulong hashValue = ComputeHashXmlNode( curChild );
  203. if ( hashValue != 0 )
  204. {
  205. totalHashSum += hashValue;
  206. childrenCount++;
  207. }
  208. curChild = curChild.NextSibling;
  209. }
  210. ha.AddULong( totalHashSum );
  211. }
  212. else
  213. {
  214. XmlNode curChild = parent.FirstChild;
  215. while ( curChild != null )
  216. {
  217. ulong hashValue = ComputeHashXmlNode( curChild );
  218. if ( hashValue != 0 )
  219. {
  220. ha.AddULong( hashValue );
  221. childrenCount++;
  222. }
  223. curChild = curChild.NextSibling;
  224. }
  225. }
  226.         if ( childrenCount != 0 )
  227.             ha.AddInt( childrenCount );
  228.     }
  229.     private ulong ComputeHashXmlNode( XmlNode node )
  230.     {
  231.         switch ( node.NodeType )
  232.         {
  233.             case XmlNodeType.Element:
  234.             {
  235.                 XmlElement el = (XmlElement)node;
  236.                 HashAlgorithm ha = new HashAlgorithm();
  237.                 HashElement( ha, el.LocalName, el.Prefix, el.NamespaceURI );
  238.                 ComputeHashXmlChildren( ha, el );
  239.                 return ha.Hash;
  240.             }
  241.             case XmlNodeType.Attribute:
  242.                 // attributes are hashed in ComputeHashXmlChildren;
  243.                 Debug.Assert( false );
  244.                 return 0;
  245.             case XmlNodeType.Whitespace:
  246.                 return 0;
  247.             case XmlNodeType.SignificantWhitespace:
  248.                 if ( !_bIgnoreWhitespace )
  249.                     goto case XmlNodeType.Text;
  250.                 return 0;
  251.             case XmlNodeType.Comment:
  252.                 if ( !_bIgnoreComments )
  253.                     return HashCharacterNode( XmlNodeType.Comment, ((XmlCharacterData)node).Value );
  254.                 return 0;
  255.             case XmlNodeType.Text:
  256.             {
  257.                 XmlCharacterData cd = (XmlCharacterData)node;
  258.                 if ( _bIgnoreWhitespace )
  259.                     return HashCharacterNode( cd.NodeType, XmlDiff.NormalizeText( cd.Value ) );
  260.                 else
  261.                     return HashCharacterNode( cd.NodeType, cd.Value );
  262.             }
  263.             case XmlNodeType.CDATA:
  264.             {
  265.                 XmlCharacterData cd = (XmlCharacterData)node;
  266.                 return HashCharacterNode( cd.NodeType, cd.Value );
  267.             }
  268.             case XmlNodeType.ProcessingInstruction:
  269.             {
  270.                 if ( _bIgnorePI )
  271.                     return 0;
  272.                 XmlProcessingInstruction pi = (XmlProcessingInstruction)node;
  273.                 return HashPI( pi.Target, pi.Value );
  274.             }
  275.             case XmlNodeType.EntityReference:
  276.             {
  277.                 XmlEntityReference er = (XmlEntityReference)node;
  278.                 return HashER( er.Name );
  279.             }
  280.             case XmlNodeType.XmlDeclaration:
  281.             {
  282.                 if ( _bIgnoreXmlDecl )
  283.                     return 0;
  284.                 XmlDeclaration decl = (XmlDeclaration)node;
  285.                 return HashXmlDeclaration( XmlDiff.NormalizeXmlDeclaration( decl.Value ) );
  286.             }
  287.             case XmlNodeType.DocumentType:
  288.             {
  289.                 if ( _bIgnoreDtd )
  290.                     return 0;
  291.                 XmlDocumentType docType = (XmlDocumentType)node;
  292.                 return HashDocumentType( docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset );
  293.             }
  294.             case XmlNodeType.DocumentFragment:
  295.                 return 0;
  296.             default:
  297.                 Debug.Assert( false );
  298.                 return 0;
  299.         }
  300.     }
  301.     private void HashDocument( HashAlgorithm ha )
  302.     {
  303.         // Intentionally empty
  304.     }
  305.     internal void HashElement( HashAlgorithm ha, string localName, string prefix, string ns )
  306.     {
  307.         ha.AddString( (int)(XmlNodeType.Element) + 
  308.                       Delimiter +
  309.                       ( ( _bIgnoreNamespaces || _bIgnorePrefixes ) ? string.Empty : prefix ) +
  310.                       Delimiter +
  311.                       ( _bIgnoreNamespaces ? string.Empty : ns ) +
  312.                       Delimiter +
  313.                       localName );
  314.     }
  315.     internal ulong HashAttribute( string localName, string prefix, string ns, string value )
  316.     {
  317.         return HashAlgorithm.GetHash( (int)XmlNodeType.Attribute + 
  318.                                       Delimiter +
  319.                                       ( ( _bIgnoreNamespaces || _bIgnorePrefixes ) ? string.Empty : prefix ) +
  320.                                       Delimiter +
  321.                                       ( _bIgnoreNamespaces ? string.Empty : ns ) +
  322.                                       Delimiter +
  323.                                       localName +
  324.                                       Delimiter +
  325.                                       value );
  326.     }
  327.     internal ulong HashNamespace( string prefix, string ns )
  328.     {
  329.         Debug.Assert( !_bIgnoreNamespaces );
  330.         return HashAlgorithm.GetHash( (int)XmlDiffNodeType.Namespace +
  331.                                       Delimiter +
  332.                                       ( _bIgnorePrefixes ? string.Empty : prefix ) +
  333.                                       Delimiter +
  334.                                       ns );
  335.     }
  336.     internal ulong HashCharacterNode( XmlNodeType nodeType, string value )
  337.     {
  338.         return HashAlgorithm.GetHash( ((int)nodeType).ToString() + 
  339.                                       Delimiter +
  340.                                       value );
  341.     }
  342.     internal ulong HashPI( string target, string value )
  343.     {
  344.         return HashAlgorithm.GetHash( ((int)XmlNodeType.ProcessingInstruction).ToString() + 
  345.                                       Delimiter +
  346.                                       target +
  347.                                       Delimiter +
  348.                                       value );
  349.     }
  350.     internal ulong HashER( string name )
  351.     {
  352.         return HashAlgorithm.GetHash( ((int)XmlNodeType.EntityReference).ToString() + 
  353.                                       Delimiter +
  354.                                        name );
  355.     }
  356.     internal ulong HashXmlDeclaration( string value )
  357.     {
  358.         return HashAlgorithm.GetHash( ((int)XmlNodeType.XmlDeclaration).ToString() +
  359.                                       Delimiter +
  360.                                        value );
  361.     }
  362.     internal ulong HashDocumentType( string name, string publicId, string systemId, string subset )
  363.     {
  364.         return HashAlgorithm.GetHash( ((int)XmlNodeType.DocumentType).ToString() +
  365.                                       Delimiter +
  366.                                       name +
  367.                                       Delimiter +
  368.                                       publicId + 
  369.                                       Delimiter + 
  370.                                       systemId + 
  371.                                       Delimiter +
  372.                                       subset );
  373.     }
  374. }
  375. }