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

xml/soap/webservice

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlDiffNodes.cs" company="Microsoft">
  3. //     Copyright (c) Microsoft Corporation.  All rights reserved.
  4. // </copyright>                                                                
  5. //------------------------------------------------------------------------------
  6. using System;
  7. using System.IO;
  8. using System.Xml;
  9. using System.Text;
  10. using System.Diagnostics;
  11. namespace Microsoft.XmlDiffPatch {
  12. //////////////////////////////////////////////////////////////////
  13. // XmlDiffNode
  14. //
  15. internal abstract class XmlDiffNode 
  16. {
  17. // Fields
  18.     // tree pointers
  19.     internal XmlDiffParentNode _parent;
  20. internal XmlDiffNode _nextSibling;
  21.     // original position among the other children
  22.     internal int _position;
  23.     // 'matching identical subtrees' algorithm fields:
  24.     internal ulong _hashValue = 0;
  25.     internal bool _bExpanded;
  26.     // 'tree-to-tree comparison' algorithm fields:
  27.     internal int _leftmostLeafIndex;
  28.     internal bool _bKeyRoot;
  29.     internal bool _bSomeDescendantMatches = false;
  30. #if DEBUG
  31.     internal int _index = 0;
  32. #endif
  33. //    internal bool _nodeOrDescendantMatches = false;
  34. // Constructors
  35.     internal XmlDiffNode( int position ) 
  36. {
  37.         _parent = null;
  38.         _nextSibling = null;
  39.         _position = position;
  40.         _bExpanded = false;
  41.     }
  42. // Properties
  43.     internal abstract XmlDiffNodeType NodeType { get; }
  44.     internal int Position { get { return _position; } }
  45.     internal bool IsKeyRoot { get { return _bKeyRoot; } }
  46. internal int Left { get { return _leftmostLeafIndex; } set { _leftmostLeafIndex = value; } } 
  47.     internal virtual XmlDiffNode FirstChildNode { get { return null; } }
  48.     internal virtual bool HasChildNodes { get { return false; } }
  49.     internal virtual int NodesCount { get { return 1; } set { Debug.Assert( value == 1 ); } }
  50.     internal ulong HashValue { get { return _hashValue; } }
  51.    
  52. internal virtual string OuterXml 
  53. {
  54.         get {
  55.             StringWriter sw = new StringWriter();
  56.             XmlTextWriter xw = new XmlTextWriter( sw );
  57.             WriteTo( xw );
  58.             xw.Close();
  59.             return sw.ToString();
  60.         }
  61.     }
  62.     
  63. internal virtual string InnerXml 
  64. {
  65.         get {
  66.             StringWriter sw = new StringWriter();
  67.             XmlTextWriter xw = new XmlTextWriter( sw );
  68.             WriteContentTo( xw );
  69.             xw.Close();
  70.             return sw.ToString();
  71.         }
  72.     }
  73.     internal virtual bool CanMerge {
  74.         get {
  75.             return true;
  76.         }
  77.     }   
  78. // Methods
  79.     // computes hash value of the node and stores it in the _hashValue variable
  80.     internal abstract void ComputeHashValue( XmlHash xmlHash );
  81. // compares the node to another one and returns the xmldiff operation for changing this node to the other one
  82. internal abstract XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff );
  83. // compares the node to another one and returns true, if the nodes are identical;
  84.     // on elements this method ignores namespace declarations
  85. internal virtual bool IsSameAs( XmlDiffNode node, XmlDiff xmlDiff )
  86.     {
  87.         return GetDiffOperation( node, xmlDiff ) == XmlDiffOperation.Match;
  88.     }
  89.     // Abstract methods for outputing
  90.     internal abstract void WriteTo( XmlWriter w );
  91.     internal abstract void WriteContentTo( XmlWriter w );
  92.     // Addressing
  93.     internal virtual string GetRelativeAddress()
  94.     {
  95.         return Position.ToString();
  96.     }
  97.     internal string GetAbsoluteAddress()
  98.     {
  99.         string address = GetRelativeAddress();
  100.         XmlDiffNode ancestor = _parent;
  101.         while ( ancestor.NodeType != XmlDiffNodeType.Document )
  102.         {
  103.             address = ancestor.GetRelativeAddress() + "/" + address;
  104.             ancestor = ancestor._parent;
  105.         }
  106.         
  107.         return "/" + address;
  108.     }
  109.     static internal string GetRelativeAddressOfInterval( XmlDiffNode firstNode, XmlDiffNode lastNode )
  110.     {
  111. Debug.Assert( firstNode._parent == lastNode._parent );
  112.         if ( firstNode == lastNode )
  113.             return firstNode.GetRelativeAddress();
  114.         else 
  115.         {
  116.             if ( firstNode._parent._firstChildNode == firstNode &&
  117.                  lastNode._nextSibling == null )
  118.                 return "*";
  119.             else
  120.                 return firstNode.Position.ToString() + "-" + lastNode.Position.ToString();
  121.         }
  122.     }
  123. #if DEBUG
  124.     internal abstract void Dump( string indent );
  125. #endif
  126. }
  127. //////////////////////////////////////////////////////////////////
  128. // XmlDiffParentNode
  129. //
  130. internal abstract class XmlDiffParentNode : XmlDiffNode
  131. {
  132. // Fields
  133. // first node in the list of attributes AND children 
  134.     internal XmlDiffNode _firstChildNode;
  135.     // number of nodes in the subtree rooted at this node
  136.     private int _nodesCount;
  137.     // number of child nodes - calculated on demand
  138.     private int _childNodesCount = -1;
  139.     // flag if the node contains only element children (this is used by addressing)
  140.     internal bool _elementChildrenOnly;
  141.     internal bool _bDefinesNamespaces;
  142.     internal override bool HasChildNodes { get { return (_firstChildNode != null); } }
  143. internal override int NodesCount 
  144. get 
  145. return _nodesCount; 
  146. set 
  147. Debug.Assert( value > 0 );
  148. _nodesCount = value; 
  149. }
  150.     internal int ChildNodesCount { 
  151.         get {
  152.             if ( _childNodesCount == -1 ) {
  153.                 int count = 0;
  154.                 for ( XmlDiffNode child = _firstChildNode; child != null; child = child._nextSibling )
  155.                     count++;
  156.                 _childNodesCount = count;
  157.             }
  158.             return _childNodesCount;
  159.         }
  160.     }
  161. // Constructor
  162.     internal XmlDiffParentNode( int position ) : base ( position )
  163.     {
  164.         _firstChildNode = null;
  165.         _nodesCount = 1;
  166.         _elementChildrenOnly = true;
  167.         _bDefinesNamespaces = false;
  168.         _hashValue = 0;
  169.     }
  170. // Properties
  171.     internal override XmlDiffNode FirstChildNode { get { return _firstChildNode; } }
  172. // Methods
  173.     internal virtual void InsertChildNodeAfter( XmlDiffNode childNode, XmlDiffNode newChildNode ) 
  174. {
  175.         Debug.Assert( newChildNode != null );
  176.         Debug.Assert( ! ( newChildNode is XmlDiffAttributeOrNamespace ) );
  177. Debug.Assert( childNode == null || childNode._parent == this );
  178. #if DEBUG
  179.         if ( newChildNode.NodeType == XmlDiffNodeType.Attribute )
  180.             Debug.Assert( childNode == null || 
  181.                           childNode.NodeType == XmlDiffNodeType.Attribute || 
  182.                           childNode.NodeType == XmlDiffNodeType.Namespace );
  183. #endif
  184.         newChildNode._parent = this;
  185.         if ( childNode == null ) 
  186.         {
  187.             newChildNode._nextSibling = _firstChildNode;
  188.             _firstChildNode = newChildNode;
  189.         }
  190.         else 
  191.         {
  192.             newChildNode._nextSibling = childNode._nextSibling;
  193.             childNode._nextSibling = newChildNode;
  194.         }
  195.         Debug.Assert( newChildNode.NodesCount > 0 );
  196.         _nodesCount += newChildNode.NodesCount;
  197.         if ( newChildNode.NodeType != XmlDiffNodeType.Element &&
  198.              !(newChildNode is XmlDiffAttributeOrNamespace ) )
  199.             _elementChildrenOnly = false;
  200.     }
  201. #if DEBUG
  202.     protected void DumpChildren( string indent )
  203.     {
  204.         XmlDiffNode curChild = _firstChildNode;
  205.         while ( curChild != null )
  206.         {
  207.             curChild.Dump( indent );
  208.             curChild = curChild._nextSibling;
  209.         }
  210.     }
  211. #endif
  212. }
  213.    
  214. //////////////////////////////////////////////////////////////////
  215. // XmlDiffElement
  216. //
  217. internal class XmlDiffElement : XmlDiffParentNode 
  218. {
  219. // Fields
  220. string _localName;
  221.     string _prefix;
  222. string _ns;
  223.     // attribute & namespace nodes
  224.     internal XmlDiffAttributeOrNamespace _attributes = null;
  225.     internal ulong _allAttributesHash = 0; // xor combination of hash values of all attributes and namespace nodes
  226.     internal ulong _attributesHashAH = 0;  // xol combination of hash values of attributes and namespace nodes beginning with 'a'-'h'
  227.     internal ulong _attributesHashIQ = 0;  // xol combination of hash values of attributes and namespace nodes beginning with 'i'-'q'
  228.     internal ulong _attributesHashRZ = 0;  // xol combination of hash values of attributes and namespace nodes beginning with 'r'-'z'
  229.     
  230. // Constructors
  231.     internal XmlDiffElement( int position, string localName, string prefix, string ns ) : base( position ) 
  232. {
  233.         Debug.Assert( localName != null );
  234.         Debug.Assert( prefix != null );
  235.         Debug.Assert( ns != null );
  236.         _localName = localName;
  237.         _prefix = prefix;
  238.         _ns = ns;
  239.     }
  240. // Properties
  241.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.Element; } }
  242.     internal string LocalName { get { return _localName; } }
  243.     internal string NamespaceURI { get { return _ns; } }
  244.     internal string Prefix { get { return _prefix; } }
  245. internal string Name 
  246. {
  247.         get 
  248. {
  249.             if ( _prefix.Length > 0 ) 
  250.                 return _prefix + ":" + _localName;
  251.             else
  252.                 return _localName;
  253.         }
  254.     }
  255. // Methods
  256.     // computes hash value of the node and stores it in the _hashValue variable
  257.     internal override void ComputeHashValue( XmlHash xmlHash )
  258.     {
  259.         Debug.Assert( _hashValue == 0 );
  260.         _hashValue = xmlHash.ComputeHashXmlDiffElement( this );
  261.     }
  262.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  263. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  264. {
  265. Debug.Assert( changedNode != null );
  266.         if ( changedNode.NodeType != XmlDiffNodeType.Element )
  267.             return XmlDiffOperation.Undefined;
  268.         XmlDiffElement changedElement = (XmlDiffElement)changedNode;
  269.         // name
  270.         bool bNameMatches = false;
  271. if (  LocalName == changedElement.LocalName )
  272.         {
  273.             if ( xmlDiff.IgnoreNamespaces )
  274.                 bNameMatches = true;
  275.             else
  276.             {
  277.                 if ( NamespaceURI == changedElement.NamespaceURI &&
  278.                     ( xmlDiff.IgnorePrefixes || Prefix == changedElement.Prefix ) )
  279.                 {
  280.             bNameMatches = true;
  281.                 }
  282.             }
  283.         }
  284.         // attributes
  285.         if ( changedElement._allAttributesHash == _allAttributesHash )
  286.             return bNameMatches ? XmlDiffOperation.Match : XmlDiffOperation.ChangeElementName;
  287.         
  288.         int n = ( changedElement._attributesHashAH == _attributesHashAH ? 0 : 1 ) +
  289.                 ( changedElement._attributesHashIQ == _attributesHashIQ ? 0 : 1 ) +
  290.                 ( changedElement._attributesHashRZ == _attributesHashRZ ? 0 : 1 );
  291.         Debug.Assert( (int)XmlDiffOperation.ChangeElementName  + 1 == (int)XmlDiffOperation.ChangeElementAttr1 );
  292.         Debug.Assert( (int)XmlDiffOperation.ChangeElementAttr1 + 1 == (int)XmlDiffOperation.ChangeElementAttr2 );
  293.         Debug.Assert( (int)XmlDiffOperation.ChangeElementAttr2 + 1 == (int)XmlDiffOperation.ChangeElementAttr3 );
  294.         Debug.Assert( (int)XmlDiffOperation.ChangeElementAttr3        + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr1 );
  295.         Debug.Assert( (int)XmlDiffOperation.ChangeElementNameAndAttr1 + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr2 );
  296.         Debug.Assert( (int)XmlDiffOperation.ChangeElementNameAndAttr2 + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr3 );
  297.         Debug.Assert( n != 0 );
  298.         if ( bNameMatches ) 
  299.             return (XmlDiffOperation)( ((int)XmlDiffOperation.ChangeElementName) + n );
  300.         else
  301.             return (XmlDiffOperation)( ((int)XmlDiffOperation.ChangeElementAttr3) + n );
  302.     }
  303. // compares the node to another one and returns true, if the nodes are identical;
  304.     // on elements this method ignores namespace declarations
  305. internal override bool IsSameAs( XmlDiffNode node, XmlDiff xmlDiff )
  306.     {
  307.         // check node type
  308. Debug.Assert( node != null );
  309.         if ( node.NodeType != XmlDiffNodeType.Element )
  310.             return false;
  311.         XmlDiffElement element = (XmlDiffElement)node;
  312.         // check element name
  313.         if ( LocalName != element.LocalName )
  314.             return false;
  315.         else if ( !xmlDiff.IgnoreNamespaces )
  316.             if ( NamespaceURI != element.NamespaceURI ) 
  317.                 return false;
  318.         else if ( !xmlDiff.IgnorePrefixes )
  319.             if ( Prefix != element.Prefix ) 
  320.                 return false;
  321.         // ignore namespace definitions - should be first in the list of attributes
  322.         XmlDiffAttributeOrNamespace attr1 = _attributes;
  323.         while ( attr1 != null && attr1.NodeType == XmlDiffNodeType.Namespace )
  324.             attr1 = (XmlDiffAttributeOrNamespace) attr1._nextSibling;
  325.         XmlDiffAttributeOrNamespace attr2 = _attributes;
  326.         while ( attr2 != null && attr2.NodeType == XmlDiffNodeType.Namespace )
  327.             attr2 = (XmlDiffAttributeOrNamespace) attr2._nextSibling;
  328.         // check attributes
  329.         while ( attr1 != null && attr2 != null )
  330.         {
  331.             if ( !attr1.IsSameAs( attr2, xmlDiff ) )
  332.                 return false;
  333.             attr1 = (XmlDiffAttributeOrNamespace) attr1._nextSibling;
  334.             attr2 = (XmlDiffAttributeOrNamespace) attr2._nextSibling;
  335.         }
  336.         return attr1 == null && attr2 == null;
  337.     }
  338.     internal void InsertAttributeOrNamespace( XmlDiffAttributeOrNamespace newAttrOrNs )
  339.     {
  340.         Debug.Assert( newAttrOrNs != null );
  341.         newAttrOrNs._parent = this;
  342.         
  343.         XmlDiffAttributeOrNamespace curAttr = _attributes;
  344.         XmlDiffAttributeOrNamespace prevAttr = null;
  345.         while ( curAttr != null  && 
  346.     XmlDiffDocument.OrderAttributesOrNamespaces( curAttr, newAttrOrNs ) <= 0 ) 
  347. {
  348.             prevAttr = curAttr;
  349.             curAttr = (XmlDiffAttributeOrNamespace)curAttr._nextSibling;
  350.         }
  351.         if ( prevAttr == null ) 
  352.         {
  353.             newAttrOrNs._nextSibling = _attributes;
  354.             _attributes = newAttrOrNs;
  355.         }
  356.         else 
  357.         {
  358.             newAttrOrNs._nextSibling = prevAttr._nextSibling;
  359.             prevAttr._nextSibling = newAttrOrNs;
  360.         }
  361.         // hash
  362.         Debug.Assert( newAttrOrNs.HashValue != 0 );
  363.         _allAttributesHash += newAttrOrNs.HashValue;
  364.         
  365.         char firstLetter;
  366.         if ( newAttrOrNs.NodeType == XmlDiffNodeType.Attribute ) 
  367.             firstLetter = ((XmlDiffAttribute)newAttrOrNs).LocalName[0];
  368.         else
  369.         {
  370.             XmlDiffNamespace nsNode = (XmlDiffNamespace)newAttrOrNs;
  371.             firstLetter = ( nsNode.Prefix == string.Empty ) ? 'A' : nsNode.Prefix[0];
  372.         }
  373.         firstLetter = char.ToUpper( firstLetter );
  374.         if ( firstLetter >= 'R' ) {
  375.             _attributesHashRZ += newAttrOrNs.HashValue;
  376.         }
  377.         else if ( firstLetter >= 'I' ) {
  378.             _attributesHashIQ += newAttrOrNs.HashValue;
  379.         }
  380.         else {
  381.             _attributesHashAH += newAttrOrNs.HashValue;
  382.         }
  383.         if ( newAttrOrNs.NodeType == XmlDiffNodeType.Namespace )
  384.             _bDefinesNamespaces = true;
  385.     }
  386. // Overriden abstract methods for outputting
  387.     internal override void WriteTo( XmlWriter w ) 
  388. {
  389.         w.WriteStartElement( Prefix, LocalName, NamespaceURI );
  390.         XmlDiffAttributeOrNamespace attr = _attributes;
  391.         while ( attr != null )
  392.         {
  393.             attr.WriteTo( w );
  394.             attr = (XmlDiffAttributeOrNamespace) attr._nextSibling;
  395.         }
  396.         WriteContentTo( w );
  397.         w.WriteEndElement();
  398.     }
  399.     internal override void WriteContentTo( XmlWriter w ) 
  400. {
  401.         XmlDiffNode child = _firstChildNode;
  402.         while ( child != null ) 
  403. {
  404.             child.WriteTo( w );
  405.             child = child._nextSibling;
  406.         }
  407.     }
  408. #if DEBUG
  409.     internal override void Dump( string indent )
  410.     {
  411.         Trace.Write( indent + "(" + _index + ") <" + Name );
  412.         XmlDiffAttributeOrNamespace attr = _attributes;
  413.         while ( attr != null ) {
  414.             attr.Dump( indent );
  415.             attr = (XmlDiffAttributeOrNamespace)attr._nextSibling;
  416.         }
  417.         Trace.WriteLine( "> " );
  418.         DumpChildren( indent + "   " );
  419.     }
  420. #endif
  421. }
  422. //////////////////////////////////////////////////////////////////
  423. // XmlDiffAttributeOrNamespace
  424. //
  425. internal abstract class XmlDiffAttributeOrNamespace : XmlDiffNode 
  426. {
  427. // Constructor
  428.     internal XmlDiffAttributeOrNamespace( ) : base( 0 ) 
  429.     {
  430.     }
  431. // Properties
  432.     internal abstract string LocalName { get;  }
  433.     internal abstract string NamespaceURI { get;  }
  434.     internal abstract string Prefix { get; }
  435.     internal abstract string Value { get; }
  436. }
  437. //////////////////////////////////////////////////////////////////
  438. // XmlDiffAttribute
  439. //
  440. internal class XmlDiffAttribute : XmlDiffAttributeOrNamespace 
  441. {
  442. // Fields
  443. string _localName;
  444.     string _prefix;
  445. string _ns;
  446. string _value;
  447. // Constructor
  448.     internal XmlDiffAttribute( string localName, string prefix, string ns, string value ) : base( ) 
  449.     {
  450.         Debug.Assert( localName != null );
  451.         Debug.Assert( prefix != null );
  452.         Debug.Assert( ns != null );
  453.         Debug.Assert( value != null );
  454.         _localName = localName;
  455.         _prefix = prefix;
  456.         _ns = ns;
  457.         _value = value;
  458.     }
  459. // Properties
  460.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.Attribute; } }
  461.     internal override string LocalName { get { return _localName; } }
  462.     internal override string NamespaceURI { get { return _ns; } }
  463.     internal override string Prefix { get { return _prefix; } }
  464. internal string Name 
  465. {
  466.         get 
  467. {
  468.             if ( _prefix.Length > 0 )
  469.                 return _prefix + ":" + _localName;
  470.             else
  471.                 return _localName;
  472.         }
  473.     }
  474.     internal override string Value { 
  475.         get { 
  476.             return _value; 
  477.         } 
  478.     }
  479.     internal override bool CanMerge {
  480.         get {
  481.             return false;
  482.         }
  483.     }
  484. // Methods
  485.     // computes hash value of the node and stores it in the _hashValue variable
  486.     internal override void ComputeHashValue( XmlHash xmlHash )
  487.     {
  488.         Debug.Assert( _hashValue == 0 );
  489.         _hashValue = xmlHash.HashAttribute( _localName, _prefix, _ns, _value );
  490.     }
  491. // compares the node to another one and returns true, if the nodes are identical;
  492.     // on elements this method ignores namespace declarations
  493. internal override bool IsSameAs( XmlDiffNode node, XmlDiff xmlDiff )
  494.     {
  495.         Debug.Assert( node.NodeType == XmlDiffNodeType.Attribute );
  496.         XmlDiffAttribute attr = (XmlDiffAttribute) node;
  497.         
  498.         return ( LocalName == attr.LocalName &&
  499.                  ( xmlDiff.IgnoreNamespaces || NamespaceURI == attr.NamespaceURI ) &&
  500.                  ( xmlDiff.IgnorePrefixes || Prefix == attr.Prefix ) &&
  501.                  Value == attr.Value );
  502.     }
  503.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  504. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  505. {
  506. Debug.Assert( false, "This method should be never called." );
  507.         return XmlDiffOperation.Undefined;
  508. }
  509. // Overriden abstract methods for outputting
  510.     internal override void WriteTo( XmlWriter w ) 
  511. {
  512.         w.WriteStartAttribute( Prefix, LocalName, NamespaceURI );
  513.         WriteContentTo( w );
  514.         w.WriteEndAttribute();
  515.     }
  516.     internal override void WriteContentTo( XmlWriter w ) 
  517. {
  518.         w.WriteString( Value );
  519.     }
  520.     // Addressing
  521.     internal override string GetRelativeAddress()
  522.     {
  523.         return "@" + Name;
  524.     }
  525. #if DEBUG
  526.     internal override void Dump( string indent )
  527.     {
  528.         Trace.Write( " " + Name + "=" + Value );
  529.     }
  530. #endif
  531. }
  532. //////////////////////////////////////////////////////////////////
  533. // XmlDiffNamespace
  534. //
  535. internal class XmlDiffNamespace : XmlDiffAttributeOrNamespace 
  536. {
  537. // Fields
  538. string _prefix;
  539. string _namespaceURI;
  540. // Constructor
  541.     internal XmlDiffNamespace( string prefix, string namespaceURI ) : base( ) 
  542.     {
  543.         Debug.Assert( prefix != null );
  544.         Debug.Assert( namespaceURI != null );
  545.         _prefix = prefix;
  546.         _namespaceURI = namespaceURI;
  547.     }
  548. // Properties
  549.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.Namespace; } }
  550.     internal override string Prefix { get { return _prefix; } }
  551.     internal override string NamespaceURI { get { return _namespaceURI; } }
  552.     internal override string LocalName { get { return string.Empty; }  }
  553.     internal override string Value { get { return string.Empty; } }
  554.     internal string Name 
  555. {
  556.         get 
  557. {
  558.             if ( _prefix.Length > 0 ) 
  559.                 return "xmlns:" + _prefix;
  560.             else
  561.                 return "xmlns";
  562.         }
  563.     }
  564. // Methods
  565.     // computes hash value of the node and stores it in the _hashValue variable
  566.     internal override void ComputeHashValue( XmlHash xmlHash )
  567.     {
  568.         Debug.Assert( _hashValue == 0 );
  569.         _hashValue = xmlHash.HashNamespace( _prefix, _namespaceURI );
  570.     }
  571.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  572. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  573. {
  574.         Debug.Assert( false, "This method should be never called." );
  575.         return XmlDiffOperation.Undefined;
  576. }
  577. // Overriden abstract methods for outputting
  578.     internal override void WriteTo( XmlWriter w ) 
  579. {
  580.         if ( Prefix == string.Empty ) {
  581.             w.WriteAttributeString( string.Empty, "xmlns", XmlDiff.XmlnsNamespaceUri, NamespaceURI );
  582.         }
  583.         else {
  584.             w.WriteAttributeString( "xmlns", Prefix, XmlDiff.XmlnsNamespaceUri, NamespaceURI );
  585.         }
  586.     }
  587.     internal override void WriteContentTo( XmlWriter w ) 
  588. {
  589.         Debug.Assert( false );
  590.     }
  591.     // Addressing
  592.     internal override string GetRelativeAddress()
  593.     {
  594.         return "@" + Name;
  595.     }
  596. #if DEBUG
  597.     internal override void Dump( string indent )
  598.     {
  599.         Trace.WriteLine( indent + "xmlns:" + Prefix + "=" + NamespaceURI );
  600.     }
  601. #endif
  602. }
  603. //////////////////////////////////////////////////////////////////
  604. // XmlDiffER
  605. //
  606. internal class XmlDiffER : XmlDiffNode 
  607. {
  608. // Fields
  609.     string _name;
  610. // Constructor
  611.     internal XmlDiffER( int position, string name ) : base ( position ) 
  612. {
  613.         _name = name;
  614.     }
  615. // Properties
  616.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.EntityReference; } }
  617.     
  618.     internal string Name { 
  619.         get { 
  620.             return _name; 
  621.         } 
  622.     }
  623.     
  624.     internal override bool CanMerge { 
  625.         get { 
  626.             return false;
  627.         }
  628.     }
  629. // Methods
  630.     // computes hash value of the node and stores it in the _hashValue variable
  631.     internal override void ComputeHashValue( XmlHash xmlHash )
  632.     {
  633.         Debug.Assert( _hashValue == 0 );
  634.         _hashValue = xmlHash.HashER( _name );
  635.     }
  636.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  637. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  638. {
  639. Debug.Assert( changedNode != null );
  640.         if ( changedNode.NodeType != XmlDiffNodeType.EntityReference )
  641.             return XmlDiffOperation.Undefined;
  642. if ( Name == ((XmlDiffER)changedNode).Name )
  643. return XmlDiffOperation.Match;
  644. else
  645. return XmlDiffOperation.ChangeER;
  646. }
  647. // Overriden abstract methods for outputing
  648.     internal override void WriteTo( XmlWriter w ) 
  649. {
  650.         w.WriteEntityRef( this._name );
  651.     }
  652.     internal override void WriteContentTo( XmlWriter w ) {}
  653. #if DEBUG
  654.     internal override void Dump( string indent )
  655.     {
  656.         Trace.WriteLine( indent + "(" + _index + ") &" + Name );
  657.     }
  658. #endif
  659. }
  660. //////////////////////////////////////////////////////////////////
  661. // XmlDiffCharData
  662. //
  663. internal class XmlDiffCharData : XmlDiffNode 
  664. {
  665. // Fields
  666.     string _value;
  667.     XmlDiffNodeType _nodeType;
  668. // Constructor
  669.     internal XmlDiffCharData( int position, string value, XmlDiffNodeType nodeType ) : base( position ) 
  670. {
  671.         _value = value;
  672.         _nodeType = nodeType;
  673.     }
  674. // Properties
  675.     internal override XmlDiffNodeType NodeType { get { return _nodeType; } }
  676.     internal string Value { get { return this._value; } }
  677. // Methods
  678.     // computes hash value of the node and stores it in the _hashValue variable
  679.     internal override void ComputeHashValue( XmlHash xmlHash )
  680.     {
  681.         Debug.Assert( _hashValue == 0 );
  682.         _hashValue = xmlHash.HashCharacterNode( (XmlNodeType)(int)_nodeType, _value );
  683.     }
  684.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  685. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  686. {
  687. Debug.Assert( changedNode != null );
  688. if ( NodeType != changedNode.NodeType )
  689. return XmlDiffOperation.Undefined;
  690.         XmlDiffCharData changedCD = changedNode as XmlDiffCharData;
  691. if ( changedCD == null )
  692. return XmlDiffOperation.Undefined;
  693. if ( Value == changedCD.Value )
  694. return XmlDiffOperation.Match;
  695. else
  696. return XmlDiffOperation.ChangeCharacterData;
  697. }
  698. // Overriden abstract methods for outputing
  699.     internal override void WriteTo( XmlWriter w ) 
  700. {
  701.         switch ( _nodeType ) 
  702. {
  703.             case XmlDiffNodeType.Comment:
  704.                 w.WriteComment( Value );
  705.                 break;
  706.             case XmlDiffNodeType.CDATA:
  707.                 w.WriteCData( Value );
  708.                 break;
  709.             case XmlDiffNodeType.SignificantWhitespace:
  710.             case XmlDiffNodeType.Text:
  711.                 w.WriteString( Value );
  712.                 break;
  713.             default :
  714.                 Debug.Assert( false, "Wrong type for text-like node : " + this._nodeType.ToString() );
  715.                 break;
  716.         }
  717.     }
  718.     internal override void WriteContentTo( XmlWriter w ) {}
  719. #if DEBUG
  720.     internal override void Dump( string indent )
  721.     {
  722.         switch ( _nodeType )
  723.         {
  724.             case XmlDiffNodeType.SignificantWhitespace:
  725.             case XmlDiffNodeType.Text:
  726.                 Trace.WriteLine( indent + "(" + _index + ") '" + Value + "'" );
  727.                 break;
  728.             case XmlDiffNodeType.Comment:
  729.                 Trace.WriteLine( indent + "(" + _index + ") <!--" + Value + "-->" );
  730.                 break;
  731.             case XmlDiffNodeType.CDATA:
  732.                 Trace.WriteLine( indent + "(" + _index + ") <![CDATA[" + Value + "]]>" );
  733.                 break;
  734.             default:
  735.                 Debug.Assert( false );
  736.                 break;
  737.         }
  738.     }
  739. #endif
  740. }
  741. //////////////////////////////////////////////////////////////////
  742. // XmlDiffPI
  743. //
  744. internal class XmlDiffPI : XmlDiffCharData 
  745. {
  746. // Fields
  747.     string _name;
  748. // Constructor
  749.     internal XmlDiffPI( int position, string name, string value ) 
  750.         : base( position, value, XmlDiffNodeType.ProcessingInstruction ) 
  751. {
  752.         _name = name;
  753.     }
  754. // Properties
  755. internal string Name { get { return _name; } } 
  756. // Methods
  757.     // computes the hash value of the node and saves it into the _hashValue field
  758.     internal override void ComputeHashValue( XmlHash xmlHash )
  759.     {
  760.         Debug.Assert( _hashValue == 0 );
  761.         _hashValue = xmlHash.HashPI( Name, Value );
  762.     }
  763.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  764. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  765. {
  766. Debug.Assert( changedNode != null );
  767.         if ( changedNode.NodeType != XmlDiffNodeType.ProcessingInstruction )
  768.             return XmlDiffOperation.Undefined;
  769. XmlDiffPI changedPI = (XmlDiffPI)changedNode;
  770. if ( Name == changedPI.Name )
  771. {
  772. if ( Value == changedPI.Value ) 
  773. return XmlDiffOperation.Match;
  774. else 
  775. return XmlDiffOperation.ChangePI;
  776. }
  777. else
  778. {
  779. if ( Value == changedPI.Value )
  780. return XmlDiffOperation.ChangePI;
  781. else
  782. return XmlDiffOperation.Undefined;
  783. }
  784. }
  785.     internal override void WriteTo( XmlWriter w ) 
  786. {
  787.         w.WriteProcessingInstruction( Name, Value );
  788.     }
  789.     
  790. internal override void WriteContentTo( XmlWriter w ) {}
  791. #if DEBUG
  792.     internal override void Dump( string indent )
  793.     {
  794.         Trace.WriteLine( indent + "(" + _index + ") <?" + Name + " " + Value + "?>" );
  795.     }
  796. #endif
  797. }
  798. //////////////////////////////////////////////////////////////////
  799. // XmlDiffShrankNode
  800. //
  801. internal class XmlDiffShrankNode : XmlDiffNode
  802. {
  803. // Fields
  804.     // interval of nodes it represents
  805.     internal XmlDiffNode _firstNode;
  806.     internal XmlDiffNode _lastNode;
  807. // matching nodes in target/source tree
  808. XmlDiffShrankNode _matchingShrankNode;
  809.     // address
  810.     string _localAddress;
  811. // 'move' operation id
  812. ulong _opid; 
  813. // Constructor
  814.     internal XmlDiffShrankNode(  XmlDiffNode firstNode, XmlDiffNode lastNode, ulong hashValue ) : base ( -1 )
  815.     {
  816.         Debug.Assert( firstNode != null );
  817.         Debug.Assert( lastNode != null );
  818.         Debug.Assert( firstNode.Position <= lastNode.Position );
  819.         Debug.Assert( firstNode.NodeType != XmlDiffNodeType.Attribute ||
  820.                       (firstNode.NodeType == XmlDiffNodeType.Attribute && firstNode == lastNode ) );
  821.         _firstNode = firstNode;
  822.         _lastNode = lastNode;
  823. _matchingShrankNode = null;
  824.         _hashValue = hashValue;
  825.         _localAddress = DiffgramOperation.GetRelativeAddressOfNodeset( _firstNode, _lastNode );
  826.     }
  827. // Properties
  828.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.ShrankNode; } }
  829.     internal XmlDiffShrankNode MatchingShrankNode 
  830. {
  831. get { return _matchingShrankNode; }
  832. set
  833. {
  834. Debug.Assert( value != null );
  835. Debug.Assert( _matchingShrankNode == null );
  836. _matchingShrankNode = value;
  837. }
  838. }
  839. internal ulong MoveOperationId 
  840. {
  841. get 
  842.         { 
  843.             if ( _opid == 0 )
  844.                 _opid = MatchingShrankNode._opid; 
  845.             return _opid;
  846.         }
  847. set 
  848. Debug.Assert( _opid == 0 );
  849. _opid = value;
  850. }
  851. }
  852.     internal override bool CanMerge {
  853.         get {
  854.             return false;
  855.         }
  856.     }   
  857. // Methods
  858.     // computes the hash value of the node and saves it into the _hashValue field
  859.     internal override void ComputeHashValue( XmlHash xmlHash )
  860.     {
  861.         Debug.Assert( false, "This method should bever be called." );
  862.     }
  863.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  864.     internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  865.     {
  866.         Debug.Assert( changedNode != null );
  867.         if ( changedNode.NodeType != XmlDiffNodeType.ShrankNode )
  868.             return XmlDiffOperation.Undefined;
  869.         if ( _hashValue == ((XmlDiffShrankNode)changedNode)._hashValue )
  870.             return XmlDiffOperation.Match;
  871.         else
  872.             return XmlDiffOperation.Undefined;
  873.     }
  874.     internal override void WriteTo( XmlWriter w )
  875.     {
  876.         WriteContentTo( w );
  877.     }
  878.     internal override void WriteContentTo( XmlWriter w )
  879.     {
  880.         XmlDiffNode curNode = _firstNode;
  881.         for (;;)
  882.         {
  883.             curNode.WriteTo( w );
  884.             if ( curNode == _lastNode ) 
  885.                 break;
  886.             curNode = curNode._nextSibling;
  887.         }
  888.     }
  889.     // Addressing
  890.     internal override string GetRelativeAddress()
  891.     {
  892.         return _localAddress;
  893.     }
  894. #if DEBUG
  895.     internal override void Dump( string indent )
  896.     {
  897.         Trace.Write( indent + "(" + _index + ") shrank nodes: "  );
  898.         XmlDiffNode curNode = _firstNode;
  899.         for (;;)
  900.         {
  901.             Trace.Write( curNode.OuterXml );
  902.             if ( curNode == _lastNode )
  903.                 break;
  904.             curNode = curNode._nextSibling;
  905.         }
  906.         Trace.Write( "n" );
  907.     }
  908. #endif
  909. }
  910. //////////////////////////////////////////////////////////////////
  911. // XmlDiffXmlDeclaration
  912. //
  913. internal class XmlDiffXmlDeclaration : XmlDiffNode 
  914. {
  915. // Fields
  916. string _value;
  917.     
  918. // Constructors
  919.     internal XmlDiffXmlDeclaration( int position, string value ) : base( position ) 
  920. {
  921.         Debug.Assert( value != null );
  922.         _value = value;
  923.     }
  924. // Properties
  925.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.XmlDeclaration; } }
  926.     internal string Value { get { return _value; } }
  927. // Methods
  928.     // computes the hash value of the node and saves it into the _hashValue field
  929.     internal override void ComputeHashValue( XmlHash xmlHash )
  930.     {
  931.         Debug.Assert( _hashValue == 0 );
  932.         _hashValue = xmlHash.HashXmlDeclaration( _value );
  933.     }
  934.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  935. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  936. {
  937. Debug.Assert( changedNode != null );
  938.         if ( changedNode.NodeType != XmlDiffNodeType.XmlDeclaration )
  939.             return XmlDiffOperation.Undefined;
  940. if (  Value == ((XmlDiffXmlDeclaration)changedNode).Value )
  941.             return XmlDiffOperation.Match;
  942.         else
  943.     return XmlDiffOperation.ChangeXmlDeclaration;
  944.     }
  945. // Overriden abstract methods for outputting
  946.     internal override void WriteTo( XmlWriter w ) 
  947. {
  948.         w.WriteProcessingInstruction( "xml", _value );
  949.     }
  950.     internal override void WriteContentTo( XmlWriter w )
  951.     {
  952.     }
  953. #if DEBUG
  954.     internal override void Dump( string indent )
  955.     {
  956.         Trace.WriteLine( indent + "(" + _index + ") <?xml " + Value + "?>" );
  957.     }
  958. #endif
  959. }
  960. //////////////////////////////////////////////////////////////////
  961. // XmlDiffDoctypeDeclaration
  962. //
  963. internal class XmlDiffDocumentType : XmlDiffNode 
  964. {
  965. // Fields
  966.     string _name;
  967.     string _publicId;
  968.     string _systemId;
  969. string _subset;
  970.     
  971. // Constructors
  972.     internal XmlDiffDocumentType( int position, string name, string publicId, string systemId, string subset ) : base( position ) 
  973. {
  974.         Debug.Assert( name != null );
  975.         _name = name;
  976.         _publicId = publicId;
  977.         _systemId = systemId;
  978.         _subset = subset;
  979.     }
  980. // Properties
  981.     internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.DocumentType; } }
  982.     internal string Name { get { return _name; } }
  983.     internal string PublicId { get { return _publicId; } }
  984.     internal string SystemId { get { return _systemId; } }
  985.     internal string Subset { get { return _subset; } }
  986. // Methods
  987.     // computes the hash value of the node and saves it into the _hashValue field
  988.     internal override void ComputeHashValue( XmlHash xmlHash )
  989.     {
  990.         Debug.Assert( _hashValue == 0 );
  991.         _hashValue = xmlHash.HashDocumentType( _name, _publicId, _systemId, _subset );
  992.     }
  993.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  994. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  995. {
  996. Debug.Assert( changedNode != null );
  997.         if ( changedNode.NodeType != XmlDiffNodeType.DocumentType )
  998.             return XmlDiffOperation.Undefined;
  999.         XmlDiffDocumentType changedDocType = (XmlDiffDocumentType)changedNode;
  1000. if ( Name == changedDocType.Name && PublicId == changedDocType.PublicId &&
  1001.              SystemId == changedDocType.SystemId && Subset == changedDocType.Subset ) {
  1002.             return XmlDiffOperation.Match;
  1003.         }
  1004.         else {
  1005.             return XmlDiffOperation.ChangeDTD;
  1006.         }
  1007.     }
  1008. // Overriden abstract methods for outputting
  1009.     internal override void WriteTo( XmlWriter w ) 
  1010. {
  1011.         w.WriteDocType( _name, string.Empty, string.Empty, _subset );
  1012.     }
  1013.     internal override void WriteContentTo( XmlWriter w )
  1014.     {
  1015.     }
  1016. #if DEBUG
  1017.     internal override void Dump( string indent )
  1018.     {
  1019.         Trace.WriteLine( indent + "(" + _index + ") " + Name + "(SYSTEM '" + SystemId + "', PUBLIC '" + PublicId +
  1020.                          "') [ " + Subset + " ]" );
  1021.     }
  1022. #endif
  1023. }
  1024. }