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

xml/soap/webservice

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlDiffDocument.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.Diagnostics;
  10. using System.Collections;
  11. namespace Microsoft.XmlDiffPatch
  12. {
  13. //////////////////////////////////////////////////////////////////
  14. // XmlDiffDocument
  15. //
  16. internal class XmlDiffDocument : XmlDiffParentNode
  17. {
  18. // Fields
  19.     protected XmlDiff _XmlDiff;
  20. bool _bLoaded;
  21.     
  22.     // Used at loading only
  23.     XmlDiffNode _curLastChild;
  24.     XmlHash _xmlHash;
  25. // Constructor
  26. internal XmlDiffDocument( XmlDiff xmlDiff ) : base( 0 )
  27. {
  28.         _bLoaded = false;
  29.         _XmlDiff = xmlDiff;
  30.     }
  31. // Properties
  32. internal override XmlDiffNodeType NodeType { get { return XmlDiffNodeType.Document; } }
  33.     internal bool IsFragment {
  34.         get {
  35.             XmlDiffNode node = _firstChildNode;
  36.             while ( node != null && node.NodeType != XmlDiffNodeType.Element ) {
  37.                 node = node._nextSibling;
  38.             }
  39.             if ( node == null  ) {
  40.                 return true;
  41.             }
  42.             node = node._nextSibling;
  43.             while ( node != null && node.NodeType != XmlDiffNodeType.Element ) {
  44.                 node = node._nextSibling;
  45.             }
  46.             return ( node != null );
  47.         }
  48.     }
  49. // Methods
  50.     // computes the hash value of the node and saves it into the _hashValue field
  51.     internal override void ComputeHashValue( XmlHash xmlHash )
  52.     {
  53.         Debug.Assert( _hashValue == 0 );
  54.         _hashValue = xmlHash.ComputeHashXmlDiffDocument( this );
  55.     }
  56.     // compares the node to another one and returns the xmldiff operation for changing this node to the other
  57. internal override XmlDiffOperation GetDiffOperation( XmlDiffNode changedNode, XmlDiff xmlDiff )
  58. {
  59.         if ( changedNode.NodeType != XmlDiffNodeType.Document )
  60.             return XmlDiffOperation.Undefined;
  61.         else 
  62. return XmlDiffOperation.Match;
  63. }
  64.     // Loads the document from XmlReader
  65.     internal virtual void Load( XmlReader reader, XmlHash xmlHash ) 
  66.     {
  67.         if ( _bLoaded ) 
  68.             throw new InvalidOperationException( "The document already contains data and should not be used again." );
  69.         try 
  70.         {
  71.             _curLastChild = null;
  72.             _xmlHash = xmlHash;
  73.             LoadChildNodes( this, reader, false );
  74.             ComputeHashValue( _xmlHash );
  75.             _bLoaded = true;
  76.     #if DEBUG
  77.             if ( XmlDiff.T_LoadedDoc.Enabled )
  78.             {
  79.                 Trace.Write( "nLoaded document " + reader.BaseURI + ": n" );
  80.                 Dump();
  81.             }
  82.     #endif
  83.         }
  84.         finally
  85.         {
  86.             _xmlHash = null;
  87.         }
  88.     }
  89.     // Loads child nodes of the 'parent' node
  90.     internal void LoadChildNodes ( XmlDiffParentNode parent, XmlReader reader, bool bEmptyElement ) 
  91.     {
  92.         XmlDiffNode savedLastChild = _curLastChild;
  93.         _curLastChild = null;
  94.         // load attributes & namespace nodes
  95.         while ( reader.MoveToNextAttribute() )
  96.         {
  97.             if ( reader.Prefix == "xmlns" )
  98.             {
  99.                 if ( !_XmlDiff.IgnoreNamespaces ) 
  100.                 {
  101.                     XmlDiffNamespace nsNode = new XmlDiffNamespace( reader.LocalName, reader.Value );
  102.                     nsNode.ComputeHashValue( _xmlHash );
  103.                     InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode );
  104.                 }
  105.             }
  106.             else if ( reader.Prefix == string.Empty  && reader.LocalName == "xmlns" )
  107.             {
  108.                 if ( !_XmlDiff.IgnoreNamespaces ) 
  109.                 {
  110.                     XmlDiffNamespace nsNode = new XmlDiffNamespace( string.Empty, reader.Value );
  111.                     nsNode.ComputeHashValue( _xmlHash );
  112.                     InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode );
  113.                 }
  114.             }
  115.             else
  116.             {
  117.                 string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText( reader.Value ) : reader.Value;
  118.                 XmlDiffAttribute attr = new XmlDiffAttribute( reader.LocalName, reader.Prefix, reader.NamespaceURI, attrValue );
  119.                 attr.ComputeHashValue( _xmlHash );
  120.                 InsertAttributeOrNamespace( (XmlDiffElement)parent, attr );
  121.             }
  122.         }
  123.         // empty element -> return, do not load chilren
  124.         if ( bEmptyElement ) 
  125.             goto End;
  126.         int childPosition = 0;
  127.         // load children
  128.         if ( !reader.Read()) 
  129.             goto End;
  130.         do {
  131.             // ignore whitespaces between nodes
  132.             if ( reader.NodeType == XmlNodeType.Whitespace )
  133.                 continue;
  134.             switch ( reader.NodeType ) 
  135.             {
  136.                 case XmlNodeType.Element:
  137.                 {
  138.                     bool bEmptyEl = reader.IsEmptyElement;
  139.                     XmlDiffElement elem = new XmlDiffElement( ++childPosition, reader.LocalName, reader.Prefix, reader.NamespaceURI );
  140.                     LoadChildNodes( elem, reader, bEmptyEl );
  141.                     elem.ComputeHashValue( _xmlHash );
  142.                     InsertChild( parent, elem );
  143.                     break;
  144.                 }
  145.                 case XmlNodeType.Attribute:
  146.                 {
  147.                     Debug.Assert( false, "We should never get to this point, attributes should be read at the beginning of thid method." );
  148.                     break;
  149.                 }
  150.                 case XmlNodeType.Text:
  151.                 {
  152.                     string textValue = ( _XmlDiff.IgnoreWhitespace ) ? XmlDiff.NormalizeText( reader.Value ) : reader.Value;
  153.                     XmlDiffCharData charDataNode = new XmlDiffCharData( ++childPosition, textValue, XmlDiffNodeType.Text );
  154.                     charDataNode.ComputeHashValue( _xmlHash );
  155.                     InsertChild( parent, charDataNode );
  156.                     break;
  157.                 }
  158.                 case XmlNodeType.CDATA:
  159.                 {
  160.                     XmlDiffCharData charDataNode = new XmlDiffCharData( ++childPosition, reader.Value, XmlDiffNodeType.CDATA );
  161.                     charDataNode.ComputeHashValue( _xmlHash );
  162.                     InsertChild( parent, charDataNode );
  163.                     break;
  164.                 }
  165.                 case XmlNodeType.EntityReference:
  166.                 {
  167.                     XmlDiffER er = new XmlDiffER( ++childPosition, reader.Name );
  168.                     er.ComputeHashValue( _xmlHash );
  169.                     InsertChild( parent, er );
  170.                     break;
  171.                 }
  172.                 case XmlNodeType.Comment:
  173.                 {
  174.                     ++childPosition;
  175.                     if ( !_XmlDiff.IgnoreComments ) 
  176.                     {
  177.                         XmlDiffCharData charDataNode = new XmlDiffCharData( childPosition, reader.Value, XmlDiffNodeType.Comment );
  178.                         charDataNode.ComputeHashValue( _xmlHash );
  179.                         InsertChild( parent, charDataNode );
  180.                     }
  181.                     break;
  182.                 }
  183.                 case XmlNodeType.ProcessingInstruction:
  184.                 {
  185.                     ++childPosition;
  186.                     if ( !_XmlDiff.IgnorePI )
  187.                     {
  188.                         XmlDiffPI pi = new XmlDiffPI( childPosition, reader.Name, reader.Value );
  189.                         pi.ComputeHashValue( _xmlHash );
  190.                         InsertChild( parent, pi );
  191.                     }
  192.                     break;
  193.                 }
  194.                 case XmlNodeType.SignificantWhitespace:
  195.                 {
  196.                     if( reader.XmlSpace == XmlSpace.Preserve )
  197.                     {
  198.                         ++childPosition;
  199.                         if (!_XmlDiff.IgnoreWhitespace ) 
  200.                         {
  201.                             XmlDiffCharData charDataNode = new XmlDiffCharData( childPosition, reader.Value, XmlDiffNodeType.SignificantWhitespace );
  202.                             charDataNode.ComputeHashValue( _xmlHash );
  203.                             InsertChild( parent, charDataNode );
  204.                         }
  205.                     }
  206.                     break;
  207.                 }
  208.                 case XmlNodeType.XmlDeclaration:
  209.                 {
  210.                     ++childPosition;
  211.                     if ( !_XmlDiff.IgnoreXmlDecl ) 
  212.                     {
  213.                         XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration( childPosition, XmlDiff.NormalizeXmlDeclaration( reader.Value ) );
  214.                         xmlDecl.ComputeHashValue( _xmlHash );
  215. InsertChild( parent, xmlDecl );
  216.                     }
  217.                     break;
  218.                 }
  219.                 case XmlNodeType.EndElement:
  220.                     goto End;
  221.                 case XmlNodeType.DocumentType:
  222.                     childPosition++;
  223.                     if ( !_XmlDiff.IgnoreDtd ) {
  224.                         
  225.                         XmlDiffDocumentType docType = new XmlDiffDocumentType( childPosition, 
  226.                                                                                reader.Name,
  227.                                                                                reader.GetAttribute("PUBLIC"),
  228.                                                                                reader.GetAttribute("SYSTEM"),
  229.                                                                                reader.Value );
  230.                         docType.ComputeHashValue( _xmlHash );
  231.                         InsertChild( parent, docType );
  232.                     }
  233.                     break;
  234.                 default:
  235.                     Debug.Assert( false );
  236.                     break;
  237.             }
  238.         } while ( reader.Read() );
  239.     End:
  240.         _curLastChild = savedLastChild;
  241.     }
  242.     // Loads the document from XmlNode
  243.     internal virtual void Load( XmlNode node, XmlHash xmlHash ) 
  244.     {
  245.         if ( _bLoaded ) 
  246.             throw new InvalidOperationException( "The document already contains data and should not be used again." );
  247.         if ( node.NodeType == XmlNodeType.Attribute ||
  248.              node.NodeType == XmlNodeType.Entity || 
  249.              node.NodeType == XmlNodeType.Notation || 
  250.              node.NodeType == XmlNodeType.Whitespace ) {
  251.             throw new ArgumentException( "Invalid node type." );
  252.         }
  253.         try 
  254.         {
  255.             _curLastChild = null;
  256.             _xmlHash = xmlHash;
  257.             if ( node.NodeType == XmlNodeType.Document || node.NodeType == XmlNodeType.DocumentFragment ) {
  258.                 LoadChildNodes( this, node );
  259.                 ComputeHashValue( _xmlHash );
  260.             }
  261.             else {
  262.                 int childPos = 0;
  263.                 XmlDiffNode rootNode = LoadNode( node, ref childPos );
  264.                 if ( rootNode != null ) {
  265.                     InsertChildNodeAfter( null, rootNode );
  266.                     _hashValue = rootNode.HashValue;
  267.                 }
  268.             }
  269.             _bLoaded = true;
  270.     #if DEBUG
  271.             if ( XmlDiff.T_LoadedDoc.Enabled )
  272.             {
  273.                 Trace.Write( "nLoaded document " + node.BaseURI + ": n" );
  274.                 Dump();
  275.             }
  276.     #endif
  277.         }
  278.         finally
  279.         {
  280.             _xmlHash = null;
  281.         }
  282.     }
  283.     internal XmlDiffNode LoadNode( XmlNode node, ref int childPosition ) {
  284.         switch ( node.NodeType ) 
  285.         {
  286.             case XmlNodeType.Element:
  287.                 XmlDiffElement elem = new XmlDiffElement( ++childPosition, node.LocalName, node.Prefix, node.NamespaceURI );
  288.                 LoadChildNodes( elem, node );
  289.                 elem.ComputeHashValue( _xmlHash );
  290.                 return elem;
  291.             case XmlNodeType.Attribute:
  292.                 Debug.Assert( false, "Attributes cannot be loaded by this method." );
  293.                 return null;
  294.             case XmlNodeType.Text:
  295.                 string textValue = ( _XmlDiff.IgnoreWhitespace ) ? XmlDiff.NormalizeText( node.Value ) : node.Value;
  296.                 XmlDiffCharData text = new XmlDiffCharData( ++childPosition, textValue, XmlDiffNodeType.Text );
  297.                 text.ComputeHashValue( _xmlHash );
  298.                 return text;
  299.             case XmlNodeType.CDATA:
  300.                 XmlDiffCharData cdata = new XmlDiffCharData( ++childPosition, node.Value, XmlDiffNodeType.CDATA );
  301.                 cdata.ComputeHashValue( _xmlHash );
  302.                 return cdata;
  303.             case XmlNodeType.EntityReference:
  304.                 XmlDiffER er = new XmlDiffER( ++childPosition, node.Name );
  305.                 er.ComputeHashValue( _xmlHash );
  306.                 return er;
  307.             case XmlNodeType.Comment:
  308.                 ++childPosition;
  309.                 if ( _XmlDiff.IgnoreComments ) 
  310.                     return null;
  311.                 XmlDiffCharData comment = new XmlDiffCharData( childPosition, node.Value, XmlDiffNodeType.Comment );
  312.                 comment.ComputeHashValue( _xmlHash );
  313.                 return comment;
  314.             case XmlNodeType.ProcessingInstruction:
  315.                 ++childPosition;
  316.                 if ( _XmlDiff.IgnorePI )
  317.                     return null;
  318.                 XmlDiffPI pi = new XmlDiffPI( childPosition, node.Name, node.Value );
  319.                 pi.ComputeHashValue( _xmlHash );
  320.                 return pi;
  321.             case XmlNodeType.SignificantWhitespace:
  322.                 ++childPosition;
  323.                 if ( _XmlDiff.IgnoreWhitespace ) 
  324.                     return null;
  325.                 XmlDiffCharData ws = new XmlDiffCharData( childPosition, node.Value, XmlDiffNodeType.SignificantWhitespace );
  326.                 ws.ComputeHashValue( _xmlHash );
  327.                 return ws;
  328.             case XmlNodeType.XmlDeclaration:
  329.                 ++childPosition;
  330.                 if ( _XmlDiff.IgnoreXmlDecl ) 
  331.                     return null;
  332.                 XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration( childPosition, XmlDiff.NormalizeXmlDeclaration( node.Value ) );
  333.                 xmlDecl.ComputeHashValue( _xmlHash );
  334. return xmlDecl;
  335.             case XmlNodeType.EndElement:
  336.                 return null;
  337.             case XmlNodeType.DocumentType:
  338.                 childPosition++;
  339.                 if ( _XmlDiff.IgnoreDtd )
  340.                     return null;
  341.                 XmlDocumentType docType = (XmlDocumentType)node;
  342.                 XmlDiffDocumentType diffDocType = new XmlDiffDocumentType( childPosition, docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset );
  343.                 diffDocType.ComputeHashValue( _xmlHash );
  344.                 return diffDocType;
  345.             default:
  346.                 Debug.Assert( false );
  347.                 return null;
  348.         }
  349.     }
  350.     // Loads child nodes of the 'parent' node
  351.     internal void LoadChildNodes( XmlDiffParentNode parent, XmlNode parentDomNode ) 
  352.     {
  353.         XmlDiffNode savedLastChild = _curLastChild;
  354.         _curLastChild = null;
  355.         // load attributes & namespace nodes
  356.         XmlNamedNodeMap attribs = parentDomNode.Attributes;
  357.         if ( attribs != null && attribs.Count > 0 ) 
  358.         {
  359.             IEnumerator attrEnum = attribs.GetEnumerator();
  360.             while ( attrEnum.MoveNext() ) 
  361.             {
  362.                 XmlAttribute attr = (XmlAttribute)attrEnum.Current;
  363.                 if ( attr.Prefix == "xmlns" )
  364.                 {
  365.                     if ( !_XmlDiff.IgnoreNamespaces ) 
  366.                     {
  367.                         XmlDiffNamespace nsNode = new XmlDiffNamespace( attr.LocalName, attr.Value );
  368.                         nsNode.ComputeHashValue( _xmlHash );
  369.                         InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode );
  370.                     }
  371.                 }
  372.                 else if ( attr.Prefix == string.Empty && attr.LocalName == "xmlns" )
  373.                 {
  374.                     if ( !_XmlDiff.IgnoreNamespaces ) 
  375.                     {
  376.                         XmlDiffNamespace nsNode = new XmlDiffNamespace( string.Empty, attr.Value );
  377.                         nsNode.ComputeHashValue( _xmlHash );
  378.                         InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode );
  379.                     }
  380.                 }
  381.                 else
  382.                 {
  383.                     string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText( attr.Value ) : attr.Value;
  384.                     XmlDiffAttribute newAttr = new XmlDiffAttribute( attr.LocalName, attr.Prefix, attr.NamespaceURI, attrValue );
  385.                     newAttr.ComputeHashValue( _xmlHash );
  386.                     InsertAttributeOrNamespace( (XmlDiffElement)parent, newAttr );
  387.                 }
  388.             }
  389.         }
  390.         // load children
  391.         XmlNodeList children = parentDomNode.ChildNodes;
  392.         if ( children.Count == 0 )
  393.             goto End;
  394.         int childPosition = 0;
  395.         IEnumerator childEnum = children.GetEnumerator();
  396.         while ( childEnum.MoveNext() )
  397.         {
  398.             XmlNode node = (XmlNode)childEnum.Current;
  399.             // ignore whitespaces between nodes
  400.             if ( node.NodeType == XmlNodeType.Whitespace )
  401.                 continue;
  402.             XmlDiffNode newDiffNode = LoadNode( (XmlNode)childEnum.Current, ref childPosition );
  403.             if ( newDiffNode != null )
  404.                 InsertChild( parent, newDiffNode );
  405.         }
  406.         End:
  407.         _curLastChild = savedLastChild;
  408.     }
  409.     
  410.     // Inserts the 'newChild' node. If child order is significant, the new child is
  411.     // inserted at the end of all child nodes. If the child order is not signoficant,
  412.     // the new node is sorted into the other child nodes.
  413.     private void InsertChild( XmlDiffParentNode parent, XmlDiffNode newChild ) 
  414.     {
  415.         if ( _XmlDiff.IgnoreChildOrder ) 
  416.         {
  417.             XmlDiffNode curChild = parent.FirstChildNode;
  418. XmlDiffNode prevChild = null;
  419.             while ( curChild != null && ( OrderChildren( curChild, newChild ) <= 0 ) ) 
  420.             {
  421.                 prevChild = curChild;
  422.                 curChild = curChild._nextSibling;
  423.             }
  424.             parent.InsertChildNodeAfter( prevChild, newChild );
  425.         }
  426.         else
  427.         {
  428.             parent.InsertChildNodeAfter( _curLastChild, newChild );
  429.             _curLastChild = newChild;
  430.         }
  431.     }
  432.     // Inserts an attribute or namespace node. The new node is sorted into the other attributes/namespace nodes.
  433.     private void InsertAttributeOrNamespace( XmlDiffElement element, XmlDiffAttributeOrNamespace newAttrOrNs ) 
  434.     {
  435.         element.InsertAttributeOrNamespace( newAttrOrNs );
  436.     }
  437.     // Compares the two nodes. Used for sorting of the child nodes when the child order is not significant.
  438.     static internal int OrderChildren( XmlDiffNode node1, XmlDiffNode node2 )
  439.     {
  440.         Debug.Assert( node1 != null && node2 != null );
  441.         int nt1 = (int) node1.NodeType;
  442.         int nt2 = (int) node2.NodeType;
  443.         if ( nt1 < nt2) 
  444.             return -1;
  445.         
  446.         if ( nt2 < nt1 ) 
  447.             return 1;
  448.         // now nt1 == nt2
  449.         switch ( nt1 )
  450.         {
  451.             case (int) XmlDiffNodeType.Element:
  452.                 return OrderElements( node1 as XmlDiffElement, node2 as XmlDiffElement );
  453.             case (int) XmlDiffNodeType.Attribute:
  454.             case (int) XmlDiffNodeType.Namespace:
  455.                 Debug.Assert( false, "We should never get to this point" );
  456.                 return 0;
  457.             case (int) XmlDiffNodeType.EntityReference:
  458.                 return OrderERs( node1 as XmlDiffER, node2 as XmlDiffER );
  459.             case (int) XmlDiffNodeType.ProcessingInstruction:
  460.                 return OrderPIs( node1 as XmlDiffPI, node2 as XmlDiffPI );
  461.             case (int) XmlDiffNodeType.ShrankNode:
  462.                 if ( ((XmlDiffShrankNode)node1).MatchingShrankNode == ((XmlDiffShrankNode)node2).MatchingShrankNode ) {
  463.                     return 0;
  464.                 }
  465.                 else {
  466.                     return ( ((XmlDiffShrankNode)node1).HashValue < ((XmlDiffShrankNode)node2).HashValue ) ? -1 : 1;
  467.                 }
  468.             default:
  469.                 Debug.Assert ( node1 is XmlDiffCharData );
  470.                 return OrderCharacterData( node1 as XmlDiffCharData, node2 as XmlDiffCharData );
  471.         }
  472.     }
  473.     static internal int OrderElements( XmlDiffElement elem1, XmlDiffElement elem2 ) 
  474.     {
  475.         Debug.Assert( elem1 != null && elem2 != null );
  476.         int nCompare;
  477.         if ( ( nCompare = OrderStrings( elem1.LocalName, elem2.LocalName ) ) == 0  &&
  478.              ( nCompare = OrderStrings( elem1.NamespaceURI, elem2.NamespaceURI ) ) == 0 )
  479.         {
  480.             return OrderSubTrees( elem1, elem2 );
  481.         }
  482.         return nCompare;
  483.     }
  484.    static internal int OrderAttributesOrNamespaces( XmlDiffAttributeOrNamespace node1, 
  485.                                                     XmlDiffAttributeOrNamespace node2 ) 
  486.    {
  487.         Debug.Assert( node1 != null && node2 != null );
  488.     if ( node1.NodeType != node2.NodeType )
  489. {
  490. if ( node1.NodeType == XmlDiffNodeType.Namespace )
  491. return -1;
  492. else
  493. return 1;
  494. }
  495.         int nCompare;
  496.         if ( ( nCompare = OrderStrings( node1.LocalName, node2.LocalName ) ) == 0  &&
  497.  ( nCompare = OrderStrings( node1.Prefix, node2.Prefix ) ) == 0  && 
  498.              ( nCompare = OrderStrings( node1.NamespaceURI, node2.NamespaceURI ) ) == 0 &&
  499.              ( nCompare = OrderStrings( node1.Value, node2.Value ) ) == 0 )
  500.         {
  501.             return 0;
  502.         }
  503.         return nCompare;
  504.     }
  505.     static internal int OrderERs( XmlDiffER er1, XmlDiffER er2 ) 
  506.     {
  507.         Debug.Assert( er1 != null && er2 != null );
  508.         return OrderStrings( er1.Name, er2.Name );
  509.     }
  510.     static internal int OrderPIs( XmlDiffPI pi1, XmlDiffPI pi2 ) 
  511.     {
  512.         Debug.Assert( pi1 != null && pi2 != null );
  513.         int nCompare = 0;
  514.         if ( ( nCompare = OrderStrings( pi1.Name, pi2.Name ) ) == 0  && 
  515.              ( nCompare = OrderStrings( pi1.Value, pi2.Value ) ) == 0 ) 
  516.         {
  517.             return 0;
  518.         }
  519.         return nCompare;
  520.     }
  521.     static internal int OrderCharacterData( XmlDiffCharData t1, XmlDiffCharData t2 ) 
  522.     {
  523.         Debug.Assert( t1 != null && t2 != null );
  524.         return OrderStrings( t1.Value, t2.Value );
  525.     }
  526.     // returns 0 if the same string; 1 if s1 > s2 and -1 if s1 < s2
  527.     static internal int OrderStrings( string s1, string s2 ) 
  528.     {
  529.         int len = ( s1.Length < s2.Length ) ? s1.Length : s2.Length;
  530.         int i = 0;
  531.         while ( i < len  &&  s1[i] == s2[i] ) i++;
  532.         if ( i < len ) 
  533.             return ( s1[i] < s2[i]) ? -1 : 1;
  534.         else 
  535.             if ( s1.Length == s2.Length )
  536.                 return 0;
  537.             else
  538.                 return ( s2.Length > s1.Length) ? -1 : 1;
  539.     }
  540.     static internal int OrderSubTrees( XmlDiffElement elem1, XmlDiffElement elem2 ) 
  541.     {
  542.         Debug.Assert( elem1 != null && elem2 != null );
  543.         int nCompare = 0; 
  544.         // attributes - ignore namespace nodes
  545.         XmlDiffAttributeOrNamespace curAttr1 = elem1._attributes;
  546.         XmlDiffAttributeOrNamespace curAttr2 = elem2._attributes;
  547.         while ( curAttr1 != null && curAttr1.NodeType == XmlDiffNodeType.Namespace )
  548.             curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling;
  549.         while ( curAttr2 != null && curAttr2.NodeType == XmlDiffNodeType.Namespace )
  550.             curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling;
  551.         
  552.         while ( curAttr1 != null && curAttr2 != null ) {
  553.             if ( ( nCompare = OrderAttributesOrNamespaces( curAttr1, curAttr2 ) ) != 0 )
  554.                 return nCompare;
  555.             curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling;
  556.             curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling;
  557.         }
  558.         // children
  559.         if ( curAttr1 == curAttr2 ) {
  560.             XmlDiffNode curChild1 = elem1.FirstChildNode;
  561.             XmlDiffNode curChild2 = elem2.FirstChildNode;
  562.             while ( curChild1 != null && curChild2 != null ) 
  563.             {
  564.                 if ( ( nCompare = OrderChildren( curChild1, curChild2 ) ) != 0 )
  565.                     return nCompare;
  566.                 curChild1 = curChild1._nextSibling;
  567.                 curChild2 = curChild2._nextSibling;
  568.             }
  569.             if ( curChild1 == curChild2 ) 
  570.                 return 0;
  571.             else if ( curChild1 ==  null ) 
  572.                 return 1; //elem2 > elem1;
  573.             else 
  574.                 return -1; //elem1 > elem1;
  575.         }
  576.         else if ( curAttr1 == null )
  577.             return 1; //elem2 > elem1;
  578.         else {
  579.             return -1; //elem1 > elem1;
  580.         }
  581.     }
  582.     internal override void WriteTo( XmlWriter w ) 
  583.     {
  584.         WriteContentTo( w );
  585.     }
  586.     internal override void WriteContentTo( XmlWriter w ) 
  587.     {
  588.         XmlDiffNode child = FirstChildNode;
  589.         while ( child != null ) 
  590.         {
  591.             child.WriteTo( w );
  592.             child = child._nextSibling;
  593.         }
  594.     }
  595. #if DEBUG
  596.     private void Dump( )
  597.     {
  598.         Dump( "- " );
  599.     }
  600.     internal override void Dump( string indent )
  601.     {
  602.         DumpChildren( indent );
  603.     }
  604. #endif
  605. }
  606. }