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

xml/soap/webservice

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // <copyright file="DiffgramOperation.cs" company="Microsoft">
  3. //     Copyright (c) Microsoft Corporation.  All rights reserved.
  4. // </copyright>                                                                
  5. //------------------------------------------------------------------------------
  6. using System;
  7. using System.Xml;
  8. using System.Text;
  9. using System.Diagnostics;
  10. using System.Collections;
  11. namespace Microsoft.XmlDiffPatch
  12. {
  13. //////////////////////////////////////////////////////////////////
  14. // DiffgramOperation
  15. //
  16. internal abstract class DiffgramOperation
  17. {
  18. // Fields
  19.     internal DiffgramOperation _nextSiblingOp;
  20.     protected ulong _operationID;
  21.     internal DiffgramOperation _parent;
  22. internal DiffgramOperation( ulong operationID )
  23. {
  24.         _nextSiblingOp = null;
  25.         _operationID = operationID;
  26. }
  27.     internal abstract XmlDiffOperation Operation { get; }
  28. // Methods
  29.     internal abstract void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff );
  30.     internal static string GetRelativeAddressOfNodeset( XmlDiffNode firstNode, XmlDiffNode lastNode )
  31.     {
  32. Debug.Assert( !( firstNode is XmlDiffAttributeOrNamespace ) &&
  33.           !( lastNode is XmlDiffAttributeOrNamespace ) );
  34.         int prevPosition = -1;
  35.         bool bInterval = false;
  36.         StringBuilder sb = new StringBuilder();
  37.         XmlDiffNode curNode = firstNode;
  38.         for (;;)
  39.         {
  40. Debug.Assert( curNode.Position > 0 );
  41.             if ( curNode.Position != prevPosition + 1 ) {
  42.                 if ( bInterval ) {
  43.                     sb.Append( prevPosition );
  44.                     bInterval = false;
  45.                     sb.Append( '|' );
  46.                 }
  47.                 sb.Append( curNode.Position );
  48.                 if ( curNode != lastNode ) {
  49.                     if ( curNode._nextSibling.Position == curNode.Position + 1 ) {
  50.                         sb.Append( "-" );
  51.                         bInterval = true;
  52.                     }
  53.                     else
  54.                         sb.Append( '|' );
  55.                 }
  56.             }
  57.             if ( curNode == lastNode )
  58.                 break;
  59.             prevPosition = curNode.Position;
  60.             curNode = curNode._nextSibling;
  61.         }
  62.         
  63.         if ( bInterval )
  64.             sb.Append( lastNode.Position );
  65.         return sb.ToString();
  66.     }
  67. internal static void GetAddressOfAttributeInterval( AttributeInterval interval, XmlWriter xmlWriter )
  68. {
  69. Debug.Assert( interval != null );
  70. if ( interval._next == null )
  71. {
  72. if ( interval._firstAttr == interval._lastAttr )
  73. {
  74. xmlWriter.WriteAttributeString( "match", interval._firstAttr.GetRelativeAddress() );
  75. return;
  76. }
  77.             if ( interval._firstAttr._parent._firstChildNode == interval._firstAttr && 
  78.  ( interval._lastAttr._nextSibling == null || 
  79.    interval._lastAttr._nextSibling.NodeType != XmlDiffNodeType.Attribute ) )
  80. {
  81. xmlWriter.WriteAttributeString( "match", "@*" );
  82. return;
  83. }
  84. }
  85. string match = string.Empty;
  86. for(;;)
  87. {
  88. XmlDiffAttribute attr = (XmlDiffAttribute) interval._firstAttr;
  89. for (;;)
  90. {
  91. match += attr.GetRelativeAddress();
  92. if ( attr == interval._lastAttr )
  93. break;
  94. match += "|";
  95. attr = (XmlDiffAttribute) attr._nextSibling;
  96. Debug.Assert( attr != null );
  97. }
  98. interval = interval._next;
  99. if ( interval == null )
  100. {
  101. xmlWriter.WriteAttributeString( "match", match );
  102. return;
  103. }
  104. match += "|";
  105. }
  106. }
  107. internal static void WriteAbsoluteMatchAttribute( XmlDiffNode node, XmlWriter xmlWriter )
  108.     {
  109.         XmlDiffAttribute attr = node as XmlDiffAttribute;
  110.         
  111.         if ( attr != null  && attr.NamespaceURI != string.Empty )
  112.             WriteNamespaceDefinition( attr, xmlWriter );
  113.         xmlWriter.WriteAttributeString( "match", node.GetAbsoluteAddress() );
  114.     }
  115.     private static void WriteNamespaceDefinition( XmlDiffAttribute attr, XmlWriter xmlWriter )
  116.     {
  117.         Debug.Assert( attr.NamespaceURI != string.Empty );
  118.         if ( attr.Prefix != string.Empty )
  119.             xmlWriter.WriteAttributeString( "xmlns", attr.Prefix, XmlDiff.XmlnsNamespaceUri, attr.NamespaceURI );
  120.         else
  121.             xmlWriter.WriteAttributeString( string.Empty, "xmlns", XmlDiff.XmlnsNamespaceUri, attr.NamespaceURI );
  122.     }
  123. }
  124. //////////////////////////////////////////////////////////////////
  125. // DiffgramParentOperation
  126. //
  127. internal abstract class DiffgramParentOperation : DiffgramOperation
  128. {
  129. // Fields
  130.     internal DiffgramOperation _firstChildOp;
  131.     internal DiffgramOperation _lastChildOp;
  132. // Constructor
  133. internal DiffgramParentOperation( ulong operationID ) : base ( operationID )
  134. {
  135.         _firstChildOp = null;
  136.         _lastChildOp = null;
  137. }
  138. // Methods
  139.     internal void InsertAtBeginning( DiffgramOperation newOp )
  140.     {
  141.         newOp._nextSiblingOp = _firstChildOp;
  142.         _firstChildOp = newOp;
  143.         newOp._parent = this;
  144.         if ( newOp._nextSiblingOp == null )
  145.             _lastChildOp = newOp;
  146.     }
  147.     internal void InsertAtEnd( DiffgramOperation newOp )
  148.     {
  149.         newOp._nextSiblingOp = null;
  150.         if ( _lastChildOp == null ) 
  151.         {
  152.             Debug.Assert( _firstChildOp == null );
  153.             _firstChildOp = _lastChildOp = newOp;
  154.         }
  155.         else
  156.         {
  157.             _lastChildOp._nextSiblingOp = newOp;
  158.             _lastChildOp = newOp;
  159.         }
  160.         newOp._parent = this;
  161.     }
  162.     internal void InsertAfter( DiffgramOperation newOp, DiffgramOperation refOp )
  163.     {
  164.         Debug.Assert( newOp._nextSiblingOp == null );
  165.         if ( refOp == null )
  166.         {
  167.         }
  168.         else
  169.         {
  170.             newOp._nextSiblingOp = refOp._nextSiblingOp;
  171.             refOp._nextSiblingOp = newOp;
  172.         }
  173.         newOp._parent = this;
  174.     }
  175.     internal void InsertOperationAtBeginning( DiffgramOperation op )
  176.     {
  177.         Debug.Assert( op._nextSiblingOp == null );
  178.         op._nextSiblingOp = _firstChildOp;
  179.         _firstChildOp = op;
  180.         op._parent = this;
  181.     }
  182.     internal void WriteChildrenTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  183.     {
  184.         DiffgramOperation curOp = _firstChildOp;
  185.         while ( curOp != null )
  186.         {
  187.             curOp.WriteTo( xmlWriter, xmlDiff );
  188.             curOp = curOp._nextSiblingOp;
  189.         }
  190.     }
  191. internal bool MergeRemoveSubtreeAtBeginning( XmlDiffNode subtreeRoot )
  192. {
  193. Debug.Assert( !( subtreeRoot is XmlDiffAttributeOrNamespace ) );
  194. DiffgramRemoveSubtrees remSubtrees = _firstChildOp as DiffgramRemoveSubtrees;
  195. return ( remSubtrees != null &&
  196.      remSubtrees.SetNewFirstNode( subtreeRoot ) );
  197. }
  198. internal bool MergeRemoveSubtreeAtEnd( XmlDiffNode subtreeRoot )
  199. {
  200. Debug.Assert( !( subtreeRoot is XmlDiffAttributeOrNamespace ) );
  201. DiffgramRemoveSubtrees remSubtrees = _lastChildOp as DiffgramRemoveSubtrees;
  202. return ( remSubtrees != null &&
  203.      remSubtrees.SetNewLastNode( subtreeRoot ) );
  204. }
  205. internal bool MergeRemoveAttributeAtBeginning( XmlDiffNode subtreeRoot )
  206. {
  207. if ( subtreeRoot.NodeType != XmlDiffNodeType.Attribute )
  208.             return false;
  209. DiffgramRemoveAttributes remAttrs = _firstChildOp as DiffgramRemoveAttributes;
  210. return ( remAttrs != null &&
  211.      remAttrs.AddAttribute( (XmlDiffAttribute)subtreeRoot ) );
  212. }
  213.     internal bool MergeAddSubtreeAtBeginning( XmlDiffNode subtreeRoot )
  214.     {
  215.         Debug.Assert( subtreeRoot.NodeType != XmlDiffNodeType.Attribute );
  216.         DiffgramAddSubtrees addSubtrees = _firstChildOp as DiffgramAddSubtrees;
  217.         return ( addSubtrees != null &&
  218.                  addSubtrees.SetNewFirstNode( subtreeRoot ) );
  219.     }
  220.     internal bool MergeAddSubtreeAtEnd( XmlDiffNode subtreeRoot )
  221.     {
  222.         Debug.Assert( subtreeRoot.NodeType != XmlDiffNodeType.Attribute );
  223.         DiffgramAddSubtrees addSubtrees = _lastChildOp as DiffgramAddSubtrees;
  224.         return ( addSubtrees != null &&
  225.                  addSubtrees.SetNewLastNode( subtreeRoot ) );
  226.     }
  227. }
  228. //////////////////////////////////////////////////////////////////
  229. // DiffgramAddNode
  230. //
  231. internal class DiffgramAddNode : DiffgramParentOperation
  232. {
  233. // Fields
  234.     XmlDiffNode _targetNode;
  235. // Constructor
  236.     internal DiffgramAddNode( XmlDiffNode targetNode, ulong operationID ) : base ( operationID )
  237.     {
  238.         Debug.Assert( targetNode != null );
  239.         Debug.Assert( targetNode.NodeType == XmlDiffNodeType.Element ||
  240.                       targetNode.NodeType == XmlDiffNodeType.Attribute ||
  241.                       targetNode.NodeType == XmlDiffNodeType.Namespace ||
  242.                       targetNode.NodeType == XmlDiffNodeType.XmlDeclaration || 
  243.                       targetNode.NodeType == XmlDiffNodeType.DocumentType || 
  244.                       targetNode.NodeType == XmlDiffNodeType.EntityReference );
  245.         _targetNode = targetNode;
  246.     }
  247. // Properties
  248.     internal override XmlDiffOperation Operation { 
  249.         get { 
  250.             return XmlDiffOperation.Add; 
  251.         }
  252.     }
  253. // Methods
  254.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  255.     {
  256.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "add", XmlDiff.NamespaceUri );
  257.         switch ( _targetNode.NodeType )
  258.         {
  259.             case XmlDiffNodeType.Element:
  260.             {
  261.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.Element).ToString() );
  262.                 XmlDiffElement el = _targetNode as XmlDiffElement;
  263.                 xmlWriter.WriteAttributeString( "name", el.LocalName );
  264.                 if ( el.NamespaceURI != string.Empty )
  265.                     xmlWriter.WriteAttributeString( "ns", el.NamespaceURI );
  266.                 if ( el.Prefix != string.Empty )
  267.                     xmlWriter.WriteAttributeString( "prefix", el.Prefix );
  268.                 if ( _operationID != 0 ) 
  269.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  270.                 WriteChildrenTo( xmlWriter, xmlDiff );
  271.                 break;
  272.             }
  273.             case XmlDiffNodeType.Attribute:
  274.             {
  275.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.Attribute).ToString() );
  276.                 XmlDiffAttribute at = _targetNode as XmlDiffAttribute;
  277.                 xmlWriter.WriteAttributeString( "name", at.LocalName );
  278.                 if ( at.NamespaceURI != string.Empty )
  279.                     xmlWriter.WriteAttributeString( "ns", at.NamespaceURI );
  280.                 if ( at.Prefix != string.Empty )
  281.                     xmlWriter.WriteAttributeString( "prefix", at.Prefix );
  282.                 if ( _operationID != 0 ) 
  283.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  284.                 xmlWriter.WriteString( at.Value );
  285.                 break;
  286.             }
  287.             case XmlDiffNodeType.Namespace:
  288.             {
  289.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.Attribute).ToString() );
  290.                 XmlDiffNamespace ns = _targetNode as XmlDiffNamespace;
  291.                 if ( ns.Prefix != string.Empty )
  292.                 {
  293.                     xmlWriter.WriteAttributeString( "prefix", "xmlns" );
  294.                     xmlWriter.WriteAttributeString( "name", ns.Prefix );
  295.                 }
  296.                 else
  297.                     xmlWriter.WriteAttributeString( "name", "xmlns" );
  298.                 if ( _operationID != 0 ) 
  299.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  300.                 xmlWriter.WriteString( ns.NamespaceURI );
  301.                 break;
  302.             }
  303.             case XmlDiffNodeType.CDATA:
  304.             {
  305.                 Debug.Assert( false, "CDATA nodes should be added with DiffgramAddSubtrees class." );
  306.                 xmlWriter.WriteAttributeString( "type", ((int)_targetNode.NodeType).ToString() );
  307.                 if ( _operationID != 0 ) 
  308.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  309.                 xmlWriter.WriteCData( (_targetNode as XmlDiffCharData).Value );
  310.                 break;
  311.             }
  312.             case XmlDiffNodeType.Comment:
  313.             {
  314.                 Debug.Assert( false, "Comment nodes should be added with DiffgramAddSubtrees class." );
  315.                 xmlWriter.WriteAttributeString( "type", ((int)_targetNode.NodeType).ToString() );
  316.                 if ( _operationID != 0 ) 
  317.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  318.                 xmlWriter.WriteComment( (_targetNode as XmlDiffCharData).Value );
  319.                 break;
  320.             }
  321.             case XmlDiffNodeType.Text:
  322.             {
  323.                 Debug.Assert( false, "Text nodes should be added with DiffgramAddSubtrees class." );
  324.                 xmlWriter.WriteAttributeString( "type", ((int)_targetNode.NodeType).ToString() );
  325.                 if ( _operationID != 0 ) 
  326.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  327.                 xmlWriter.WriteString( (_targetNode as XmlDiffCharData).Value );
  328.                 break;
  329.             }
  330.             case XmlDiffNodeType.ProcessingInstruction:
  331.             {
  332.                 Debug.Assert( false, "Processing instruction nodes should be added with DiffgramAddSubtrees class." );
  333.                 xmlWriter.WriteAttributeString( "type", ((int)_targetNode.NodeType).ToString() );
  334.                 if ( _operationID != 0 ) 
  335.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  336.                 XmlDiffPI pi = _targetNode as XmlDiffPI;
  337.                 xmlWriter.WriteProcessingInstruction( pi.Name, pi.Value );
  338.                 break;
  339.             }
  340.             case XmlDiffNodeType.EntityReference:
  341.             {
  342.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.EntityReference).ToString() );
  343.                 if ( _operationID != 0 ) 
  344.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  345.                 xmlWriter.WriteAttributeString( "name", ((XmlDiffER)_targetNode).Name );
  346.                 break;
  347.             }
  348.             case XmlDiffNodeType.SignificantWhitespace:
  349.             {
  350.                 Debug.Assert( false, "Significant whitespace nodes should be added with DiffgramAddSubtrees class." );
  351.                 xmlWriter.WriteAttributeString( "type", ((int)_targetNode.NodeType).ToString() );
  352.                 if ( _operationID != 0 ) 
  353.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  354.                 xmlWriter.WriteString( ((XmlDiffCharData)_targetNode).Value );
  355.                 break;
  356.             }
  357.             case XmlDiffNodeType.XmlDeclaration:
  358.             {
  359.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.XmlDeclaration).ToString() );
  360.                 if ( _operationID != 0 )
  361.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  362.                 xmlWriter.WriteString( ((XmlDiffXmlDeclaration)_targetNode).Value ); 
  363.                 break;
  364.             }
  365.             case XmlDiffNodeType.DocumentType:
  366.             {
  367.                 xmlWriter.WriteAttributeString( "type", ((int)XmlNodeType.DocumentType).ToString() );
  368.                 XmlDiffDocumentType docType = (XmlDiffDocumentType)_targetNode;
  369.                 if ( _operationID != 0 )
  370.                     xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  371.                 xmlWriter.WriteAttributeString( "name", docType.Name );
  372.                 if ( docType.PublicId != string.Empty )
  373.                     xmlWriter.WriteAttributeString( "publicId", docType.PublicId );
  374.                 if ( docType.SystemId != string.Empty )
  375.                     xmlWriter.WriteAttributeString( "systemId", docType.SystemId );
  376.                 if ( docType.Subset != string.Empty )
  377.                     xmlWriter.WriteCData( docType.Subset );
  378.                 break;
  379.             }
  380.             default:
  381.                 Debug.Assert( false );
  382.                 break;
  383.         }
  384.         xmlWriter.WriteEndElement();
  385.     }
  386. }
  387. //////////////////////////////////////////////////////////////////
  388. // DiffgramAddSubtrees
  389. //
  390. internal class DiffgramAddSubtrees : DiffgramOperation
  391. {
  392. // Fields
  393.     internal XmlDiffNode _firstTargetNode;
  394.     internal XmlDiffNode _lastTargetNode;
  395.     private bool _bSorted;
  396.     private bool _bNeedNamespaces;
  397. // Constructor
  398.     internal DiffgramAddSubtrees( XmlDiffNode subtreeRoot, ulong operationID, bool bSorted ) : base ( operationID )
  399.     {
  400.         Debug.Assert( subtreeRoot != null );
  401.         _firstTargetNode = subtreeRoot;
  402.         _lastTargetNode = subtreeRoot;
  403.         _bSorted = bSorted;
  404.         _bNeedNamespaces = subtreeRoot.NodeType == XmlDiffNodeType.Element;
  405.     }
  406. // Properties
  407.     internal override XmlDiffOperation Operation {
  408.         get {
  409.             return XmlDiffOperation.Add;
  410.         }
  411.     }
  412. // Methods
  413.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  414.     {
  415.         if ( !_bSorted )
  416.             Sort();
  417.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "add", XmlDiff.NamespaceUri );
  418.         if ( _operationID != 0 ) 
  419.             xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  420.         // namespaces
  421.         if ( _bNeedNamespaces ) {
  422.             Hashtable definedPrefixes = new Hashtable(); 
  423.             XmlDiffParentNode parent = _firstTargetNode._parent;
  424.             while ( parent != null ) {
  425.                 if ( parent._bDefinesNamespaces ) {
  426.                     XmlDiffElement el = (XmlDiffElement)parent;
  427.                     XmlDiffAttributeOrNamespace curNs = el._attributes;
  428.                     while ( curNs != null && curNs.NodeType == XmlDiffNodeType.Namespace ) {
  429.                         if ( definedPrefixes[curNs.Prefix] == null ) {
  430.                             if ( curNs.Prefix == string.Empty )
  431.                                 xmlWriter.WriteAttributeString( "xmlns", XmlDiff.XmlnsNamespaceUri, curNs.NamespaceURI );
  432.                             else
  433.                                 xmlWriter.WriteAttributeString( "xmlns", curNs.Prefix, XmlDiff.XmlnsNamespaceUri, curNs.NamespaceURI );
  434.                             definedPrefixes[curNs.Prefix] = curNs.Prefix;
  435.                         }
  436.                         curNs = (XmlDiffAttributeOrNamespace)curNs._nextSibling;
  437.                     }
  438.                 }
  439.                 parent = parent._parent;
  440.             }
  441.         }
  442.         
  443.         // output nodes
  444.         XmlDiffNode node = _firstTargetNode;
  445.         for (;;)
  446.         {
  447.             node.WriteTo( xmlWriter );
  448.             if ( node == _lastTargetNode )
  449.                 break;
  450.             node = node._nextSibling;
  451.         }
  452.         xmlWriter.WriteEndElement();
  453.     }
  454.     private void Sort() {
  455.         XmlDiffNode prevSibling = null;
  456.         XmlDiff.SortNodesByPosition( ref _firstTargetNode, ref _lastTargetNode, ref prevSibling );
  457.         _bSorted = true;
  458.     }
  459. internal bool SetNewFirstNode( XmlDiffNode targetNode )
  460. {
  461. if ( _operationID != 0 ||
  462.  targetNode._nextSibling != _firstTargetNode ||
  463.              ( targetNode.NodeType == XmlDiffNodeType.Text && _firstTargetNode.NodeType == XmlDiffNodeType.Text ) ||
  464.      !targetNode.CanMerge ||
  465.      !_firstTargetNode.CanMerge )
  466. return false;
  467. _firstTargetNode = targetNode;
  468.         if ( targetNode.NodeType == XmlDiffNodeType.Element )
  469.             _bNeedNamespaces = true;
  470. return true;
  471. }
  472. internal bool SetNewLastNode( XmlDiffNode targetNode )
  473. {
  474. if ( _operationID != 0 ||
  475.  _lastTargetNode._nextSibling != targetNode ||
  476.              ( targetNode.NodeType == XmlDiffNodeType.Text && _lastTargetNode.NodeType == XmlDiffNodeType.Text ) ||
  477.      !targetNode.CanMerge ||
  478.      !_lastTargetNode.CanMerge )
  479. return false;
  480. _lastTargetNode = targetNode;
  481.         if ( targetNode.NodeType == XmlDiffNodeType.Element )
  482.             _bNeedNamespaces = true;
  483. return true;
  484. }
  485. }
  486. //////////////////////////////////////////////////////////////////
  487. // DiffgramCopy
  488. //
  489. internal class DiffgramCopy : DiffgramParentOperation
  490. {
  491. // Fields
  492.     XmlDiffNode _sourceNode;
  493.     bool _bSubtree;
  494. // Constructor
  495.     internal DiffgramCopy( XmlDiffNode sourceNode, bool bSubtree, ulong operationID ) : base ( operationID )
  496.     {
  497.         Debug.Assert( sourceNode != null );
  498.         _sourceNode = sourceNode;
  499.         _bSubtree = bSubtree;
  500.     }
  501. // Properties
  502.     internal override XmlDiffOperation Operation {
  503.         get {
  504.             return XmlDiffOperation.Add;
  505.         }
  506.     }
  507. // Methods
  508.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  509.     {
  510.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "add", XmlDiff.NamespaceUri );
  511.         WriteAbsoluteMatchAttribute( _sourceNode, xmlWriter );
  512.         if ( !_bSubtree )
  513.             xmlWriter.WriteAttributeString( "subtree", "no" );
  514.         if ( _operationID != 0 ) 
  515.             xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  516.         WriteChildrenTo( xmlWriter, xmlDiff );
  517.         xmlWriter.WriteEndElement();
  518.     }
  519. }
  520. //////////////////////////////////////////////////////////////////
  521. // DiffgramRemoveNode
  522. //
  523. internal class DiffgramRemoveNode : DiffgramParentOperation
  524. {
  525. // Fields
  526.     internal XmlDiffNode _sourceNode;
  527.     bool _bSubtree;
  528. // Costructor
  529.     internal DiffgramRemoveNode( XmlDiffNode sourceNode, bool bSubtree, ulong operationID ) : base ( operationID )
  530.     {
  531.         Debug.Assert( sourceNode != null );
  532.         _sourceNode = sourceNode;
  533.         _bSubtree = bSubtree;
  534.     }
  535. // Properties
  536.     internal override XmlDiffOperation Operation {
  537.         get {
  538.             return XmlDiffOperation.Remove;
  539.         }
  540.     }
  541. // Methods
  542.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  543.     {
  544.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "remove", XmlDiff.NamespaceUri );
  545.         xmlWriter.WriteAttributeString( "match", _sourceNode.GetRelativeAddress() );
  546.         if ( !_bSubtree )
  547.             xmlWriter.WriteAttributeString( "subtree", "no" );
  548.         if ( _operationID != 0 ) 
  549.             xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  550.         WriteChildrenTo( xmlWriter, xmlDiff );
  551.         xmlWriter.WriteEndElement();
  552.     }
  553. }
  554. //////////////////////////////////////////////////////////////////
  555. // DiffgramRemoveSubtrees
  556. //
  557. internal class DiffgramRemoveSubtrees : DiffgramOperation
  558. {
  559. // Fields
  560.     XmlDiffNode _firstSourceNode;
  561. XmlDiffNode _lastSourceNode;
  562.     bool _bSorted;
  563. // Constructor
  564.     internal DiffgramRemoveSubtrees( XmlDiffNode sourceNode, ulong operationID, bool bSorted ) : base ( operationID )
  565.     {
  566.         Debug.Assert( sourceNode != null );
  567.         _firstSourceNode = sourceNode;
  568. _lastSourceNode = sourceNode;
  569.         _bSorted = bSorted;
  570.     }
  571. // Properties
  572.     internal override XmlDiffOperation Operation {
  573.         get {
  574.             return XmlDiffOperation.Remove;
  575.         }
  576.     }
  577. // Methods
  578.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  579.     {
  580.         if ( !_bSorted ) 
  581.             Sort();
  582.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "remove", XmlDiff.NamespaceUri );
  583. if ( _firstSourceNode == _lastSourceNode ) 
  584. xmlWriter.WriteAttributeString( "match", _firstSourceNode.GetRelativeAddress() );
  585. else
  586. xmlWriter.WriteAttributeString( "match", GetRelativeAddressOfNodeset( _firstSourceNode, _lastSourceNode ) );
  587.         if ( _operationID != 0 ) 
  588.             xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  589.         xmlWriter.WriteEndElement();
  590.     }
  591.     private void Sort() {
  592.         XmlDiffNode prevSibling = null;
  593.         XmlDiff.SortNodesByPosition( ref _firstSourceNode, ref _lastSourceNode, ref prevSibling );
  594.         _bSorted = true;
  595.     }
  596. internal bool SetNewFirstNode( XmlDiffNode srcNode )
  597. {
  598. if ( _operationID != 0 ||
  599.  srcNode._nextSibling != _firstSourceNode ||
  600.  !srcNode.CanMerge ||
  601.  !_firstSourceNode.CanMerge )
  602. return false;
  603. _firstSourceNode = srcNode;
  604. return true;
  605. }
  606. internal bool SetNewLastNode( XmlDiffNode srcNode )
  607. {
  608. if ( _operationID != 0 ||
  609.  _lastSourceNode._nextSibling != srcNode ||
  610.  !srcNode.CanMerge ||
  611.              !_firstSourceNode.CanMerge )
  612. return false;
  613. _lastSourceNode = srcNode;
  614. return true;
  615. }
  616. }
  617. //////////////////////////////////////////////////////////////////
  618. // DiffgramRemoveAttributes
  619. //
  620. internal class DiffgramRemoveAttributes : DiffgramOperation
  621. {
  622. // Fields
  623.     AttributeInterval _attributes;
  624. // Constructor
  625.     internal DiffgramRemoveAttributes( XmlDiffAttribute sourceAttr ) : base ( 0 )
  626.     {
  627.         Debug.Assert( sourceAttr != null );
  628. _attributes = new AttributeInterval( sourceAttr, null );
  629.     }
  630. // Properties
  631.     internal override XmlDiffOperation Operation {
  632.         get {
  633.             return XmlDiffOperation.Remove;
  634.         }
  635.     }
  636. // Methods
  637.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  638.     {
  639.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "remove", XmlDiff.NamespaceUri );
  640.         GetAddressOfAttributeInterval( _attributes, xmlWriter );
  641.         Debug.Assert( _operationID == 0 );
  642.         xmlWriter.WriteEndElement();
  643.     }
  644. internal bool AddAttribute( XmlDiffAttribute srcAttr )
  645. {
  646. if ( _operationID != 0 ||
  647.  srcAttr._parent != _attributes._firstAttr._parent )
  648. return false;
  649. if ( srcAttr._nextSibling == _attributes._firstAttr )
  650. _attributes._firstAttr = srcAttr;
  651. else
  652. _attributes = new AttributeInterval( srcAttr, _attributes );
  653. return true;
  654. }
  655. }
  656. //////////////////////////////////////////////////////////////////
  657. // DiffgramChangeNode
  658. //
  659. internal class DiffgramChangeNode : DiffgramParentOperation
  660. {
  661. // Fields
  662.     internal XmlDiffNode _sourceNode;
  663.     internal XmlDiffNode _targetNode;
  664.     internal XmlDiffOperation _op;
  665. // Constructor
  666.     internal DiffgramChangeNode( XmlDiffNode sourceNode, XmlDiffNode targetNode, XmlDiffOperation op, ulong operationID ) 
  667.         : base ( operationID )
  668.     {
  669.         Debug.Assert( sourceNode != null );
  670.         Debug.Assert( targetNode != null );
  671.         Debug.Assert( XmlDiff.IsChangeOperation( op ) || op == XmlDiffOperation.ChangeAttr);
  672.         _sourceNode = sourceNode;
  673.         _targetNode = targetNode;
  674.         _op = op;
  675.     }
  676. // Properties
  677.     internal override XmlDiffOperation Operation {
  678.         get {
  679.             return _op;
  680.         }
  681.     }
  682. // Methods
  683.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  684.     {
  685.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "change", XmlDiff.NamespaceUri );
  686.         xmlWriter.WriteAttributeString( "match", _sourceNode.GetRelativeAddress() );
  687.         if ( _operationID != 0 ) 
  688.             xmlWriter.WriteAttributeString( "opid", _operationID.ToString() );
  689.         switch ( _op )
  690.         {
  691.             case XmlDiffOperation.ChangeAttr:
  692.             {
  693.                 XmlDiffAttribute sourceAttr = (XmlDiffAttribute) _sourceNode;
  694.                 XmlDiffAttribute targetAttr = (XmlDiffAttribute) _targetNode;
  695.                 if ( sourceAttr.Prefix != targetAttr.Prefix && !xmlDiff.IgnorePrefixes && !xmlDiff.IgnoreNamespaces )
  696.                     xmlWriter.WriteAttributeString( "prefix", targetAttr.Prefix );
  697.                 if ( sourceAttr.NamespaceURI != targetAttr.NamespaceURI && !xmlDiff.IgnoreNamespaces )
  698.                     xmlWriter.WriteAttributeString( "ns", targetAttr.NamespaceURI );
  699.                 xmlWriter.WriteString( targetAttr.Value );
  700.                 break;
  701.             }
  702.         case XmlDiffOperation.ChangeElementName:
  703.             {
  704.                 XmlDiffElement sourceEl = (XmlDiffElement) _sourceNode;
  705.                 XmlDiffElement targetEl = (XmlDiffElement) _targetNode;
  706.                 if ( sourceEl.LocalName != targetEl.LocalName )
  707.                     xmlWriter.WriteAttributeString( "name", targetEl.LocalName );
  708.                 if ( sourceEl.Prefix != targetEl.Prefix && !xmlDiff.IgnorePrefixes && !xmlDiff.IgnoreNamespaces )
  709.                     xmlWriter.WriteAttributeString( "prefix", targetEl.Prefix );
  710.                 if ( sourceEl.NamespaceURI != targetEl.NamespaceURI && !xmlDiff.IgnoreNamespaces )
  711.                     xmlWriter.WriteAttributeString( "ns", targetEl.NamespaceURI );
  712.                 WriteChildrenTo( xmlWriter, xmlDiff );
  713.                 break;
  714.             }
  715.         case XmlDiffOperation.ChangePI:
  716.             {
  717. XmlDiffPI sourcePi = (XmlDiffPI)_sourceNode;
  718.                 XmlDiffPI targetPi = (XmlDiffPI)_targetNode;
  719.                 if ( sourcePi.Value == targetPi.Value ) {
  720.                     Debug.Assert( sourcePi.Name != targetPi.Name );
  721.          xmlWriter.WriteAttributeString( "name", targetPi.Name );
  722.                 }
  723.                 else {
  724. xmlWriter.WriteProcessingInstruction( targetPi.Name, targetPi.Value );
  725.                 }
  726.                 break;
  727.             }
  728.             case XmlDiffOperation.ChangeCharacterData:
  729.             {
  730.                 XmlDiffCharData chd = (XmlDiffCharData)_targetNode;
  731.                 switch ( _targetNode.NodeType ) {
  732.                     case XmlDiffNodeType.Text:
  733.                     case XmlDiffNodeType.SignificantWhitespace:
  734.                         xmlWriter.WriteString( chd.Value );
  735.                         break;
  736.                     case XmlDiffNodeType.Comment:
  737.                         xmlWriter.WriteComment( chd.Value );
  738.                         break;
  739.                     case XmlDiffNodeType.CDATA:
  740.                         xmlWriter.WriteCData( chd.Value );
  741.                         break;
  742.                     default:
  743.                         Debug.Assert( false );
  744.                         break;
  745.                 }
  746.                 break;
  747.             }
  748.             case XmlDiffOperation.ChangeER:
  749.             {
  750.                 xmlWriter.WriteAttributeString( "name", ((XmlDiffER)_targetNode).Name );
  751.                 break;
  752.             }
  753.             case XmlDiffOperation.ChangeXmlDeclaration:
  754.             {
  755.                 xmlWriter.WriteString( ((XmlDiffXmlDeclaration)_targetNode).Value );
  756.                 break;
  757.             }
  758.             case XmlDiffOperation.ChangeDTD:
  759.             {
  760. XmlDiffDocumentType sourceDtd = (XmlDiffDocumentType)_sourceNode;
  761.                 XmlDiffDocumentType targetDtd = (XmlDiffDocumentType)_targetNode;
  762. if ( sourceDtd.Name != targetDtd.Name )
  763. xmlWriter.WriteAttributeString( "name", targetDtd.Name );
  764. if ( sourceDtd.SystemId != targetDtd.SystemId )
  765. xmlWriter.WriteAttributeString( "systemId", targetDtd.SystemId );
  766. if ( sourceDtd.PublicId != targetDtd.PublicId )
  767. xmlWriter.WriteAttributeString( "publicId", targetDtd.PublicId );
  768. if ( sourceDtd.Subset != targetDtd.Subset )
  769. xmlWriter.WriteCData( targetDtd.Subset );
  770.                 break;
  771.             }
  772.             default:
  773.                 Debug.Assert( false );
  774.                 break;
  775.         }
  776.         xmlWriter.WriteEndElement();
  777.     }
  778. }
  779. //////////////////////////////////////////////////////////////////
  780. // DiffgramRemoveNode
  781. //
  782. internal class DiffgramPosition : DiffgramParentOperation
  783. {
  784. // Fields
  785.     internal XmlDiffNode _sourceNode;
  786.     internal XmlDiffNode _targetNode;
  787. // Costructor
  788.     internal DiffgramPosition( XmlDiffNode sourceNode, XmlDiffNode targetNode ) 
  789.         : this (  sourceNode ) {
  790.         _targetNode = targetNode;
  791.     }
  792.     internal DiffgramPosition( XmlDiffNode sourceNode ) : base( 0 )
  793.     {
  794.         Debug.Assert( !( sourceNode is XmlDiffAttributeOrNamespace ) );
  795.         if ( sourceNode is XmlDiffShrankNode ) 
  796.         {
  797.      Debug.Assert( sourceNode != null );
  798. sourceNode = ((XmlDiffShrankNode)sourceNode)._lastNode;
  799.         }
  800.         _sourceNode = sourceNode;
  801.     }
  802. // Properties
  803.     internal override XmlDiffOperation Operation {
  804.         get {
  805.             return XmlDiffOperation.Match;
  806.         }
  807.     }
  808. // Methods
  809.     internal override void WriteTo( XmlWriter xmlWriter, XmlDiff xmlDiff )
  810.     {
  811.         xmlWriter.WriteStartElement( XmlDiff.Prefix, "node", XmlDiff.NamespaceUri );
  812.         xmlWriter.WriteAttributeString( "match", _sourceNode.GetRelativeAddress() );
  813.         WriteChildrenTo( xmlWriter, xmlDiff );
  814.         xmlWriter.WriteEndElement();
  815.     }
  816. }
  817. //////////////////////////////////////////////////////////////////
  818. // AttributeInterval
  819. //
  820. internal class AttributeInterval
  821. {
  822. internal XmlDiffAttribute _firstAttr;
  823. internal XmlDiffAttribute _lastAttr;
  824. internal AttributeInterval _next;
  825. internal AttributeInterval( XmlDiffAttribute attr, AttributeInterval next )
  826. {
  827. _firstAttr = attr;
  828. _lastAttr = attr;
  829. _next = next;
  830. }
  831. }
  832. }