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

xml/soap/webservice

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlPatchOperations.cs" company="Microsoft">
  3. //     Copyright (c) Microsoft Corporation.  All rights reserved.
  4. // </copyright>                                                                
  5. //------------------------------------------------------------------------------
  6. namespace Microsoft.XmlDiffPatch
  7. {
  8. using System;
  9. using System.Diagnostics;
  10. using System.Xml;
  11. using System.IO;
  12. using System.Text;
  13. using System.Collections;
  14. //////////////////////////////////////////////////////////////////
  15. // XmlPatchOperation
  16. //
  17. internal abstract class XmlPatchOperation
  18. {
  19. // Fields
  20.     internal XmlPatchOperation _nextOp;
  21. // Methods
  22.     internal abstract void Apply( XmlNode parent, ref XmlNode currentPosition );
  23. }
  24. //////////////////////////////////////////////////////////////////
  25. // XmlPatchParentOperation 
  26. //
  27. internal abstract class XmlPatchParentOperation : XmlPatchOperation
  28. {
  29. // Fields
  30.     internal XmlPatchOperation _firstChild;
  31. // Methods
  32.     internal void InsertChildAfter( XmlPatchOperation child, XmlPatchOperation newChild )
  33.     {
  34.         Debug.Assert( newChild != null );
  35.         if ( child == null )
  36.         {
  37.             newChild._nextOp = _firstChild;
  38.             _firstChild = newChild;
  39.         }
  40.         else
  41.         {
  42.             newChild._nextOp = child._nextOp;
  43.             child._nextOp = newChild;
  44.         }
  45.     }
  46.     protected void ApplyChildren( XmlNode parent )
  47.     {
  48.         XmlNode curPos = null;
  49.         XmlPatchOperation curOp = _firstChild;
  50.         while ( curOp != null )
  51.         {
  52.             curOp.Apply( parent, ref curPos );
  53.             curOp = curOp._nextOp;
  54.         }
  55.     }
  56. }
  57. //////////////////////////////////////////////////////////////////
  58. // PatchSetPosition
  59. //
  60. internal class PatchSetPosition : XmlPatchParentOperation
  61. {
  62. // Fields
  63.     XmlNode _matchNode;
  64. // Constructor
  65.     internal PatchSetPosition( XmlNode matchNode ) 
  66.     {
  67.         Debug.Assert( matchNode != null );
  68.         _matchNode = matchNode;
  69.     }
  70. // Methods
  71.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  72.     {
  73.         Debug.Assert( _matchNode.NodeType != XmlNodeType.DocumentType );
  74.         Debug.Assert( _matchNode.ParentNode == parent );
  75.         if ( _matchNode.NodeType == XmlNodeType.Element )
  76.             ApplyChildren( (XmlElement)_matchNode );
  77.         currentPosition = _matchNode;
  78.     }
  79. }
  80. //////////////////////////////////////////////////////////////////
  81. // PatchCopy
  82. //
  83. internal class PatchCopy : XmlPatchParentOperation
  84. {
  85. // Fields
  86.     XmlNodeList _matchNodes;
  87.     bool _bSubtree;
  88. // Constructor
  89.     internal PatchCopy( XmlNodeList matchNodes, bool bSubtree ) 
  90.     {
  91.         Debug.Assert( matchNodes != null );
  92.         Debug.Assert( matchNodes.Count != 0 );
  93.         _matchNodes = matchNodes;
  94.         _bSubtree = bSubtree;
  95.     }
  96. // Methods
  97.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  98.     {
  99.         IEnumerator e = _matchNodes.GetEnumerator();
  100.         e.Reset();
  101.         while ( e.MoveNext() )
  102.         {
  103.             XmlNode srcNode = (XmlNode)e.Current;
  104.             Debug.Assert( srcNode.NodeType != XmlNodeType.Attribute );
  105.             XmlNode newNode;
  106.             if ( _bSubtree )
  107.                 newNode = srcNode.Clone();
  108.             else
  109.             {
  110.                 newNode = srcNode.CloneNode( false );
  111.                 ApplyChildren( newNode );
  112.             }
  113.             parent.InsertAfter( newNode, currentPosition );
  114.             currentPosition = newNode;
  115.         }
  116.     }
  117. }
  118. //////////////////////////////////////////////////////////////////
  119. // PatchAddNode
  120. //
  121. internal class PatchAddNode : XmlPatchParentOperation
  122. {
  123. // Fields
  124.     XmlNodeType _nodeType;
  125.     string _name;
  126.     string _ns;         // == systemId if DocumentType node
  127.     string _prefix;     // == publicId if DocumentType node
  128.     string _value;      // == internal subset if DocumentType node
  129.     bool   _ignoreChildOrder;
  130. // Constructor
  131.     internal PatchAddNode( XmlNodeType nodeType, string name, string ns, string prefix, string value, bool ignoreChildOrder ) 
  132.     {
  133.         Debug.Assert( (int)nodeType > 0 && (int)nodeType <= (int)XmlNodeType.XmlDeclaration );
  134.         _nodeType = nodeType;
  135.         _name = name;
  136.         _ns = ns;
  137.         _prefix = prefix;
  138.         _value = value;
  139.         _ignoreChildOrder = ignoreChildOrder;
  140.     }
  141. // Methods
  142.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  143.     {
  144.         XmlNode newNode = null;
  145. if ( _nodeType == XmlNodeType.Attribute )
  146. {
  147. Debug.Assert( _name != string.Empty );
  148. if ( _prefix == "xmlns" )
  149. newNode = parent.OwnerDocument.CreateAttribute( _prefix + ":" + _name );
  150. else if (_prefix == "" && _name == "xmlns" ) 
  151. newNode = parent.OwnerDocument.CreateAttribute( _name );
  152. else
  153. newNode = parent.OwnerDocument.CreateAttribute( _prefix, _name, _ns );
  154. ((XmlAttribute)newNode).Value = _value;
  155.             Debug.Assert( currentPosition == null );
  156.             parent.Attributes.Append( (XmlAttribute) newNode );
  157. }
  158. else
  159. {
  160. switch ( _nodeType )
  161. {
  162. case XmlNodeType.Element:
  163. Debug.Assert( _name != string.Empty );
  164. Debug.Assert( _value == string.Empty );
  165. newNode = parent.OwnerDocument.CreateElement( _prefix, _name, _ns );
  166. ApplyChildren( newNode );
  167. break;
  168. case XmlNodeType.Text:
  169. Debug.Assert( _value != string.Empty );
  170. newNode = parent.OwnerDocument.CreateTextNode( _value );
  171. break;
  172. case XmlNodeType.CDATA:
  173. Debug.Assert( _value != string.Empty );
  174. newNode = parent.OwnerDocument.CreateCDataSection( _value );
  175. break;
  176. case XmlNodeType.Comment:
  177. Debug.Assert( _value != string.Empty );
  178. newNode = parent.OwnerDocument.CreateComment( _value );
  179. break;
  180. case XmlNodeType.ProcessingInstruction:
  181. Debug.Assert( _value != string.Empty );
  182. Debug.Assert( _name != string.Empty );
  183. newNode = parent.OwnerDocument.CreateProcessingInstruction( _name, _value );
  184. break;
  185. case XmlNodeType.EntityReference:
  186. Debug.Assert( _name != string.Empty );
  187. newNode = parent.OwnerDocument.CreateEntityReference( _name );
  188. break;
  189.                 case XmlNodeType.XmlDeclaration:
  190.                 {
  191.                     Debug.Assert( _value != string.Empty );
  192.                     XmlDocument doc = parent.OwnerDocument;
  193.                     XmlDeclaration decl = doc.CreateXmlDeclaration( "1.0", string.Empty, string.Empty );
  194.                     decl.Value = _value;
  195.                     doc.InsertBefore( decl, doc.FirstChild );
  196.                     return;
  197.                 }
  198.                 case XmlNodeType.DocumentType:
  199.                 {
  200.                     XmlDocument doc = parent.OwnerDocument;
  201.                     if ( _prefix == string.Empty )
  202.                         _prefix = null;
  203.                     if ( _ns == string.Empty ) 
  204.                         _ns = null;
  205.                     XmlDocumentType docType = doc.CreateDocumentType( _name, _prefix, _ns, _value );
  206.                     if ( doc.FirstChild.NodeType == XmlNodeType.XmlDeclaration )
  207.                         doc.InsertAfter( docType, doc.FirstChild );
  208.                     else
  209.                         doc.InsertBefore( docType, doc.FirstChild );
  210.                     return;
  211.                 }
  212. default:
  213. Debug.Assert( false ); 
  214. break;
  215. }
  216. Debug.Assert( currentPosition == null || currentPosition.NodeType != XmlNodeType.Attribute );
  217.             if ( _ignoreChildOrder ) {
  218.                 parent.AppendChild( newNode );
  219.             }
  220.             else {
  221.                 parent.InsertAfter( newNode, currentPosition );
  222.             }
  223. currentPosition = newNode;
  224. }
  225.     }
  226. }
  227. //////////////////////////////////////////////////////////////////
  228. // PatchAddXmlFragment
  229. //
  230. internal class PatchAddXmlFragment : XmlPatchOperation
  231. {
  232. // Fields
  233.     XmlNodeList _nodes;
  234. // Constructor
  235.     internal PatchAddXmlFragment( XmlNodeList nodes ) 
  236.     {
  237.         Debug.Assert( nodes != null );
  238.         _nodes = nodes;
  239.     }
  240. // Methods
  241.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  242.     {
  243.         XmlDocument doc = parent.OwnerDocument;
  244.         IEnumerator enumerator = _nodes.GetEnumerator();
  245.         while ( enumerator.MoveNext() ) 
  246.         {
  247.             XmlNode newNode = doc.ImportNode( (XmlNode)enumerator.Current, true );
  248.             parent.InsertAfter( newNode, currentPosition );
  249.             currentPosition = newNode;
  250.         }
  251.     }
  252. }
  253. //////////////////////////////////////////////////////////////////
  254. // PatchRemove
  255. //
  256. internal class PatchRemove : XmlPatchParentOperation
  257. {
  258. // Fields
  259.     XmlNodeList _sourceNodes;
  260.     bool _bSubtree;
  261. // Constructor
  262.     internal PatchRemove( XmlNodeList sourceNodes, bool bSubtree ) 
  263.     {
  264.         Debug.Assert( sourceNodes != null );
  265.         Debug.Assert( sourceNodes.Count > 0 );
  266.         _sourceNodes = sourceNodes;
  267.         _bSubtree = bSubtree;
  268.     }
  269. // Methods
  270.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  271.     {
  272.         if ( !_bSubtree )
  273.         {
  274.             Debug.Assert( _sourceNodes.Count == 1 );
  275. XmlNode remNode = _sourceNodes.Item(0);
  276.             ApplyChildren( remNode );
  277.             currentPosition = remNode.PreviousSibling;
  278.         }
  279.         IEnumerator e = _sourceNodes.GetEnumerator();
  280.         e.Reset();
  281.         while ( e.MoveNext() )
  282.         {
  283.             XmlNode node = (XmlNode)e.Current;
  284.             Debug.Assert( node.ParentNode == parent ||
  285.                         ( node.ParentNode == null && node.NodeType == XmlNodeType.Attribute ) ||
  286.                         ( node.NodeType == XmlNodeType.XmlDeclaration && node.ParentNode == node.OwnerDocument ) ||
  287.                         ( node.NodeType == XmlNodeType.DocumentType && node.ParentNode == node.OwnerDocument) );
  288.             
  289.             if ( node.NodeType == XmlNodeType.Attribute )
  290.             {
  291.                 Debug.Assert( parent.NodeType == XmlNodeType.Element );
  292.                 ((XmlElement)parent).RemoveAttributeNode( (XmlAttribute) node );
  293.             }
  294.             else
  295.             {
  296.                 if ( !_bSubtree )
  297.                 {
  298.                     // move all children to grandparent
  299.                     while ( node.FirstChild != null )
  300.                     {
  301.                         XmlNode child = node.FirstChild;
  302.                         node.RemoveChild( child );
  303.                         parent.InsertAfter( child, currentPosition );
  304.                         currentPosition = child;
  305.                     }
  306.                 }
  307.                 // remove node
  308.                 node.ParentNode.RemoveChild( node );  // this is node.ParentNode instead of node.parent because of the xml declaration
  309.             }
  310.         }
  311.     }
  312. }
  313. //////////////////////////////////////////////////////////////////
  314. // PatchChange
  315. //
  316. internal class PatchChange : XmlPatchParentOperation
  317. {
  318. // Fields
  319.     XmlNode _matchNode;
  320.     string _name;
  321.     string _ns;      // = systemId if DocumentType node
  322.     string _prefix;  // = publicId if DocumentType node
  323.     string _value;   // = internal subset if DocumentType node
  324. // Constructor
  325.     internal PatchChange( XmlNode matchNode, string name, string ns, string prefix, XmlNode diffChangeNode ) 
  326.     {
  327.         Debug.Assert( matchNode != null );
  328.         _matchNode = matchNode;
  329.         _name = name;
  330.         _ns = ns;
  331.         _prefix = prefix;
  332.         if ( diffChangeNode == null ) {
  333.             _value = null;
  334.         }
  335.         else {
  336.             switch ( matchNode.NodeType ) {
  337.                 case XmlNodeType.Comment:
  338.                     Debug.Assert( diffChangeNode.FirstChild != null && diffChangeNode.FirstChild.NodeType == XmlNodeType.Comment );
  339.                     _value = diffChangeNode.FirstChild.Value;
  340.                     break;
  341.                 case XmlNodeType.ProcessingInstruction:
  342.                     if ( name == null ) {
  343.                         Debug.Assert( diffChangeNode.FirstChild != null && diffChangeNode.FirstChild.NodeType == XmlNodeType.ProcessingInstruction );
  344.                         _name = diffChangeNode.FirstChild.Name;
  345.                         _value = diffChangeNode.FirstChild.Value;
  346.                     }
  347.                     break;
  348.                 default:
  349.                     _value = diffChangeNode.InnerText;
  350.                     break;
  351.             }
  352.         }
  353.     }
  354. // Methods
  355.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  356.     {
  357.         Debug.Assert( _matchNode.ParentNode == parent ||
  358.                      ( _matchNode.ParentNode == null && _matchNode.NodeType == XmlNodeType.Attribute ) || 
  359.                        _matchNode.NodeType == XmlNodeType.XmlDeclaration ||
  360.                        _matchNode.NodeType == XmlNodeType.DocumentType );
  361.         switch ( _matchNode.NodeType )
  362.         {
  363.             case XmlNodeType.Element:
  364.             {
  365.                 Debug.Assert( _value == null );
  366.                 if ( _name == null )   _name = ((XmlElement)_matchNode).LocalName;
  367.                 if ( _ns == null )     _ns = ((XmlElement)_matchNode).NamespaceURI;
  368.                 if ( _prefix == null ) _prefix = ((XmlElement)_matchNode).Prefix;
  369.                 XmlElement newEl = parent.OwnerDocument.CreateElement( _prefix, _name, _ns );
  370. // move attributes
  371. XmlAttributeCollection attrs = _matchNode.Attributes;
  372. while ( attrs.Count > 0 )
  373. {
  374. XmlAttribute attr = (XmlAttribute)attrs.Item( 0 );
  375. attrs.RemoveAt( 0 );
  376. newEl.Attributes.Append( attr );
  377. }
  378. // move children
  379.                 XmlNode curChild = _matchNode.FirstChild;
  380.                 while ( curChild != null )
  381.                 {
  382.                     XmlNode nextSibling = curChild.NextSibling;
  383.                     _matchNode.RemoveChild( curChild );
  384.                     newEl.AppendChild( curChild );
  385.                     curChild = nextSibling;
  386.                 }
  387.                 parent.ReplaceChild( newEl, _matchNode );
  388.                 currentPosition = newEl;
  389.                 ApplyChildren( newEl );
  390.                 break;
  391.             }
  392.             case XmlNodeType.Attribute:
  393.             {
  394.                 if ( _name == null )   _name = ((XmlAttribute)_matchNode).LocalName;
  395.                 if ( _ns == null )     _ns = ((XmlAttribute)_matchNode).NamespaceURI;
  396.                 if ( _prefix == null ) _prefix = ((XmlAttribute)_matchNode).Prefix;
  397.                 if ( _value == null )  _value = ((XmlAttribute)_matchNode).Value;
  398.                 XmlAttribute newAttr = parent.OwnerDocument.CreateAttribute( _prefix, _name, _ns );
  399.                 newAttr.Value = _value;
  400.                 parent.Attributes.Remove( (XmlAttribute)_matchNode );
  401.                 parent.Attributes.Append( newAttr );
  402.                 break;
  403.             }
  404.             case XmlNodeType.Text:
  405.             case XmlNodeType.CDATA:
  406.             case XmlNodeType.Comment:
  407.                 Debug.Assert( _value != null );
  408.                 ((XmlCharacterData)_matchNode).Data = _value;
  409.                 currentPosition = _matchNode;
  410.                 break;
  411.             case XmlNodeType.ProcessingInstruction:
  412.             {
  413.                 if ( _name != null ) 
  414.                 {
  415.                     if ( _value == null )  
  416.                         _value = ((XmlProcessingInstruction)_matchNode).Data;
  417.                     XmlProcessingInstruction newPi = parent.OwnerDocument.CreateProcessingInstruction( _name, _value );
  418.                     parent.ReplaceChild( newPi, _matchNode );
  419.                     currentPosition = newPi;
  420.                 }
  421.                 else
  422.                 {
  423.                     ((XmlProcessingInstruction)_matchNode).Data = _value;
  424.                     currentPosition = _matchNode;
  425.                 }
  426.                 break;
  427.             }
  428.             case XmlNodeType.EntityReference:
  429.             {
  430.                 Debug.Assert( _name != null );
  431.                 
  432.                 XmlEntityReference newEr = parent.OwnerDocument.CreateEntityReference( _name );
  433.                 
  434.                 parent.ReplaceChild( newEr, _matchNode );
  435.                 currentPosition = newEr;
  436.                 break;
  437.             }
  438.             case XmlNodeType.XmlDeclaration:
  439.             {
  440.                 Debug.Assert( _value != null && _value != string.Empty );
  441.                 XmlDeclaration xmlDecl = (XmlDeclaration)_matchNode;
  442.                 xmlDecl.Encoding = null;
  443.                 xmlDecl.Standalone = null;
  444.                 xmlDecl.InnerText = _value;
  445.                 break;
  446.             }
  447.             case XmlNodeType.DocumentType:
  448.             {
  449.                 if ( _name == null )
  450.                     _name = ((XmlDocumentType)_matchNode).LocalName;
  451.                 if ( _ns == null )
  452.                     _ns = ((XmlDocumentType)_matchNode).SystemId;
  453.                 else if ( _ns == string.Empty )
  454.                     _ns = null;
  455.                 if ( _prefix == null ) 
  456.                     _prefix = ((XmlDocumentType)_matchNode).PublicId;
  457.                 else if ( _prefix == string.Empty ) 
  458.                     _prefix = null;
  459.                 if ( _value == null )  
  460.                     _value = ((XmlDocumentType)_matchNode).InternalSubset;
  461.                 XmlDocumentType docType = _matchNode.OwnerDocument.CreateDocumentType( _name, _prefix, _ns, _value );
  462.                 _matchNode.ParentNode.ReplaceChild( docType, _matchNode );
  463.                 break;
  464.             }
  465.             default:
  466.                 Debug.Assert( false ); 
  467.                 break;
  468.         }
  469.     }
  470. }
  471. //////////////////////////////////////////////////////////////////
  472. // Patch
  473. //
  474. internal class Patch : XmlPatchParentOperation
  475. {
  476. // Fields
  477.     internal XmlNode _sourceRootNode;
  478. // Constructor
  479.     internal Patch( XmlNode sourceRootNode )
  480.     {
  481.         Debug.Assert( sourceRootNode != null );
  482.         _sourceRootNode = sourceRootNode;
  483.     }
  484. // Methods
  485.     internal override void Apply( XmlNode parent, ref XmlNode currentPosition )
  486.     {
  487.         XmlDocument doc = parent.OwnerDocument;
  488.         ApplyChildren( parent );
  489.     }
  490. }