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

xml/soap/webservice

开发平台:

Visual C++

  1. //  ---------------------------------------------------------------------------
  2. // <copyright company="Microsoft Corporation" file="XmlDiffView.cs">
  3. //     Copyright (c) Microsoft Corporation 2005
  4. // </copyright>
  5. // <project>
  6. //     XmlDiffView
  7. // </project>
  8. // <summary>
  9. //     Public entry point for the library.
  10. // </summary>
  11. // <history>
  12. //      [barryw] 01MAR05 Adapted from sample file.
  13. // </history>
  14. //  ---------------------------------------------------------------------------
  15. namespace Microsoft.XmlDiffPatch
  16. {
  17.     #region Using directives
  18.     using System;
  19.     using System.Xml;
  20.     using System.IO;
  21.     using System.Diagnostics;
  22.     using System.Collections;
  23.     using Microsoft.XmlDiffPatch;
  24.     #endregion
  25.     
  26.     #region Library Enums section
  27.        
  28.    
  29.     /// <summary>
  30.     /// Enumerator values for types of differences
  31.     /// (Match indicates no difference) 
  32.     /// </summary>
  33.     internal enum XmlDiffViewOperation
  34.     {
  35.         /// <summary>
  36.         /// Data matches
  37.         /// </summary>
  38.         Match = 0,
  39.         /// <summary>
  40.         /// Data differences will be ignored
  41.         /// </summary>
  42.         Ignore = 1,
  43.         /// <summary>
  44.         /// Data was added
  45.         /// </summary>
  46.         Add = 2,
  47.         /// <summary>
  48.         /// Data was moved to here
  49.         /// </summary>
  50.         MoveTo = 3,
  51.         /// <summary>
  52.         /// Data was removed
  53.         /// </summary>
  54.         Remove = 4,
  55.         /// <summary>
  56.         /// Data was moved from here
  57.         /// </summary>
  58.         MoveFrom = 5,
  59.         /// <summary>
  60.         /// Data was changed
  61.         /// </summary>
  62.         Change = 6,
  63.     }
  64.     #endregion
  65.     /// <summary>
  66.     /// Class which provides the external methods
  67.     /// and properties to use this library.
  68.     /// </summary>
  69.     public sealed class XmlDiffView
  70.     {
  71.         #region Member variables section
  72.         // Static methods and data for drawing
  73.         /// <summary>
  74.         /// Size of the incremental indentation
  75.         /// </summary>
  76.         internal static readonly int DeltaIndent = 15;
  77.         /// <summary>
  78.         /// Operation settings to control writing to 
  79.         /// the baseline and actual "panes" of the html.
  80.         /// </summary>
  81.         internal static readonly bool[,] HtmlWriteToPane = 
  82.         {
  83.             // Match    = 0
  84.             {
  85.                 true,  true
  86.             },
  87.             
  88.             // Ignore   = 1
  89.             {
  90.                 true,  true
  91.             },
  92.             
  93.             // Add      = 2
  94.             {
  95.                 false,  true
  96.             },
  97.             // MoveTo   = 3,
  98.             {
  99.                 false,  true
  100.             },  
  101.             // Remove   = 4,
  102.             {
  103.                 true, false
  104.             },  
  105.             // MoveFrom = 5,
  106.             {
  107.                 true, false
  108.             },  
  109.             // Change   = 6,
  110.             {
  111.                 true,  true
  112.             },  
  113.         };
  114.         /// <summary>
  115.         /// String used to set a required number html space characters.
  116.         /// </summary>
  117.         private static readonly string Nbsp = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
  118.             "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
  119.             "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
  120.         /// <summary>
  121.         /// Declares a view document to hold the merged data.
  122.         /// </summary>
  123.         private XmlDiffViewDocument viewDocument = null;
  124.         
  125.         /// <summary>
  126.         /// Creates a hash table of change short descriptions.
  127.         /// </summary>
  128.         private Hashtable descriptors = new Hashtable();
  129.         
  130.         /// <summary>
  131.         /// Declares a memory stream to hold the diffgram.
  132.         /// </summary>
  133.         private MemoryStream diffgram = null;
  134.         
  135.         /// <summary>
  136.         /// Declares a TextWriter object to hold the output data.
  137.         /// </summary>
  138.         private TextWriter outputData = null;
  139.         /// <summary>
  140.         /// Stores the final output.
  141.         /// </summary>
  142.         private XmlDiffViewResults finalOutput = null;
  143.         // options
  144.         /// <summary>
  145.         /// Initializes the child order option
  146.         /// </summary>
  147.         private bool ignoreChildOrder = false;
  148.         
  149.         /// <summary>
  150.         /// Initializes the comments option
  151.         /// </summary>
  152.         private bool ignoreComments = false;
  153.         
  154.         /// <summary>
  155.         /// Initializes the programming instructions node type option
  156.         /// </summary>
  157.         private bool ignorePI = false;
  158.         
  159.         /// <summary>
  160.         /// Initializes the white space option
  161.         /// </summary>
  162.         private bool ignoreWhitespace = false;
  163.         
  164.         /// <summary>
  165.         /// Initializes the namespaces node type option
  166.         /// </summary>
  167.         private bool ignoreNamespaces = false;
  168.         
  169.         /// <summary>
  170.         /// Initializes the xml prefixes option
  171.         /// </summary>
  172.         private bool ignorePrefixes = false;
  173.         
  174.         /// <summary>
  175.         /// Initializes the declaration node type option
  176.         /// </summary>
  177.         private bool ignoreXmlDecl = false;
  178.         
  179.         /// <summary>
  180.         /// Initializes the DTD node type option
  181.         /// </summary>
  182.         private bool ignoreDtd = false;
  183.         /// <summary>
  184.         /// Declares an object with references to the last
  185.         /// node and attribute.
  186.         /// </summary>
  187.         private LoadState loadState;
  188.         private static int nextOperationId = 1;
  189.         #endregion
  190.         #region  Constructors section
  191.         /// <summary>
  192.         /// Constructor
  193.         /// </summary>
  194.         public XmlDiffView()
  195.         {
  196.         }
  197.         #endregion
  198.         #region Destructors section
  199.         /// <summary>
  200.         /// Destructor
  201.         /// </summary>
  202.         ~XmlDiffView()
  203.         {
  204.         }
  205.         #endregion
  206.         #region Methods section
  207.         #region Public static methods section
  208.         #endregion
  209.         #region Public non-static methods section
  210.         public static int NextOperationId {
  211.             get { return nextOperationId++; }
  212.         }
  213.         public static int LastOperationId {
  214.             get { return nextOperationId; }
  215.         }
  216.         /// <summary>
  217.         /// Loads the diffgram to an XmlDocument object, and drives the 
  218.         /// process of loading the baseline xml file to a 
  219.         /// XmlDiffViewDocument object, tagging the nodes and attributes
  220.         /// according to the options selected, and finally merges the
  221.         /// diffgram data into the XmlDiffViewDocument object. 
  222.         /// </summary>
  223.         /// <param name="sourceXml">baseline data</param>
  224.         /// <param name="diffgram">diffgram data stream</param>
  225.         public void Load(XmlReader sourceXml, XmlReader diffGram)
  226.         {
  227.             nextOperationId = 1;
  228.             if (null == sourceXml)
  229.             {
  230.                 throw new ArgumentNullException("sourceXml");
  231.             }
  232.             if (null == diffGram)
  233.             {
  234.                 throw new ArgumentNullException("diffgram");
  235.             }
  236.             // load diffgram to DOM
  237.             XmlDocument diffgramDoc = new XmlDocument();
  238.             diffgramDoc.Load(diffGram);
  239.             // process operation descriptors
  240.             this.PreprocessDiffgram(diffgramDoc);
  241.             // load document
  242.             this.viewDocument = new XmlDiffViewDocument();
  243.             this.LoadSourceChildNodes(this.viewDocument, sourceXml, false);
  244.             // apply diffgram
  245.             this.ApplyDiffgram(diffgramDoc.DocumentElement, this.viewDocument);
  246.         }
  247.         /// <summary>
  248.         /// Write the differences in the Xml data 
  249.         /// to the output file as formatted xml-like text.
  250.         /// </summary>
  251.         /// <param name="sourceXmlFile">baseline file</param>
  252.         /// <param name="changedXmlFile">actual file</param>
  253.         /// <param name="outputTextPath">Output data file for the data in text form</param>
  254.         /// <param name="appendToOutputFile">Append output to the file</param>
  255.         /// <param name="fragment">This is an xml data frament</param>
  256.         /// <param name="options">Comparison options</param>
  257.         /// <returns>data is identical</returns>
  258.         public bool DifferencesAsFormattedText(
  259.             string sourceXmlFile,
  260.             string changedXmlFile,
  261.             string outputTextPath,
  262.             bool appendToOutputFile,
  263.             bool fragment,
  264.             XmlDiffOptions options)
  265.         {
  266.             // Append to the specified output file.
  267.             FileMode mode;
  268.             if (appendToOutputFile)
  269.             {
  270.                 mode = FileMode.Append;
  271.             }
  272.             else
  273.             {
  274.                 mode = FileMode.Create;
  275.             }
  276.             this.outputData = new StreamWriter(
  277.                 new FileStream(
  278.                 outputTextPath,
  279.                 mode,
  280.                 FileAccess.Write));
  281.             bool identicalData;
  282.             identicalData = this.GetDifferencesAsFormattedText(
  283.                 sourceXmlFile,
  284.                 changedXmlFile,
  285.                 fragment,
  286.                 options);
  287.             // close the output stream to release the file.
  288.             this.outputData.Close();
  289.             return identicalData;
  290.         }
  291.         /// <summary>
  292.         /// Append the differences in the Xml data 
  293.         /// to the output file as formatted xml-like text.
  294.         /// </summary>
  295.         /// <param name="sourceXmlFile">baseline file</param>
  296.         /// <param name="changedXmlFile">actual file</param>
  297.         /// <param name="outputTextPath">output file for the data in text form</param>
  298.         /// <param name="fragment">This is an xml data frament</param>
  299.         /// <param name="options">Comparison options</param>
  300.         /// <returns>Differences were not found.</returns>
  301.         public bool DifferencesAsFormattedText(
  302.             string sourceXmlFile,
  303.             string changedXmlFile,
  304.             string outputTextPath,
  305.             bool fragment,
  306.             XmlDiffOptions options)
  307.         {
  308.             bool identicalData = this.DifferencesAsFormattedText(
  309.                 sourceXmlFile,
  310.                 changedXmlFile,
  311.                 outputTextPath,
  312.                 true,
  313.                 fragment,
  314.                 options);
  315.             return identicalData;
  316.         }
  317.         /// <summary>
  318.         /// Write the differences in the Xml data 
  319.         /// as formatted xml-like text return in
  320.         /// a memory based TextReader object.
  321.         /// </summary>
  322.         /// <param name="sourceXmlFile">baseline file</param>
  323.         /// <param name="changedXmlFile">actual file</param>
  324.         /// <param name="fragment">This is an xml data frament</param>
  325.         /// <param name="options">Comparison options</param>
  326.         /// <param name="reader">A reference to return readable 
  327.         /// formatted xml-like text.</param>
  328.         /// <returns>data is identical</returns>
  329.         public XmlDiffViewResults DifferencesAsFormattedText(
  330.             string sourceXmlFile,
  331.             string changedXmlFile,
  332.             bool fragment,
  333.             XmlDiffOptions options)
  334.         {
  335.             MemoryStream data = new MemoryStream();
  336.             this.outputData = new StreamWriter(
  337.                 data,
  338.                 System.Text.Encoding.Unicode);
  339.             bool identicalData;
  340.             identicalData = this.GetDifferencesAsFormattedText(
  341.                 sourceXmlFile,
  342.                 changedXmlFile,
  343.                 fragment,
  344.                 options);
  345.             // Move the data to the memory stream
  346.             this.outputData.Flush();
  347.             this.finalOutput = new XmlDiffViewResults(data, identicalData);
  348.             // return result of comparison
  349.             return this.finalOutput;
  350.         }
  351.         /// <summary>
  352.         /// Create WinDiff like static comparison in Html.
  353.         /// </summary>
  354.         /// <param name="sourceXmlFile">the baseline file</param>
  355.         /// <param name="changedXmlFile">the actual (or target) file</param>
  356.         /// <param name="resultHtmlViewFile">the html output file</param>
  357.         /// <param name="fragment">the file is only an Xml fragment</param>
  358.         /// <param name="options">comparison filtering options</param>
  359.         /// <returns>Differences were not found after filtering.</returns>
  360.         public bool DifferencesSideBySideAsHtml(
  361.             string sourceXmlFile,
  362.             string changedXmlFile,
  363.             string resultHtmlViewFile,
  364.             bool fragment,
  365.             XmlDiffOptions options)
  366.         {
  367.             bool identicalData = this.DifferencesSideBySideAsHtml(
  368.                 sourceXmlFile,
  369.                 changedXmlFile,
  370.                 resultHtmlViewFile,
  371.                 fragment,
  372.                 true,
  373.                 options);
  374.             return identicalData;
  375.         }
  376.         /// <summary>
  377.         /// Create WinDiff like static comparison in Html.
  378.         /// </summary>
  379.         /// <param name="sourceXmlFile">the baseline file</param>
  380.         /// <param name="changedXmlFile">the actual (or target) file</param>
  381.         /// <param name="resultHtmlViewFile">the html output file</param>
  382.         /// <param name="fragment">the file is only an Xml fragment</param>
  383.         /// <param name="appendToOutputFile">Append to existing output file</param>
  384.         /// <param name="options">comparison filtering options</param>
  385.         /// <returns>Differences were not found after filtering.</returns>
  386.         public bool DifferencesSideBySideAsHtml(
  387.             string sourceXmlFile,
  388.             string changedXmlFile,
  389.             string resultHtmlViewFile,
  390.             bool fragment,
  391.             bool appendToOutputFile,
  392.             XmlDiffOptions options)
  393.         {
  394.             // Append to the specified output file.
  395.             FileMode mode;
  396.             if (appendToOutputFile)
  397.             {
  398.                 mode = FileMode.Append;
  399.             }
  400.             else
  401.             {
  402.                 mode = FileMode.Create;
  403.             }
  404.             this.outputData = new StreamWriter(
  405.                 new FileStream(
  406.                 resultHtmlViewFile,
  407.                 mode,
  408.                 FileAccess.Write));
  409.             bool identicalData;
  410.             try
  411.             {
  412.                 identicalData = this.DifferencesSideBySideAsHtml(
  413.                     sourceXmlFile,
  414.                     changedXmlFile,
  415.                     fragment,
  416.                     options,
  417.                     this.outputData);
  418.             }
  419.             finally
  420.             {
  421.                 this.outputData.Close();
  422.             }
  423.             return identicalData;
  424.         }
  425.         /// <summary>
  426.         /// Create WinDiff like static comparison in Html.
  427.         /// </summary>
  428.         /// <param name="sourceXmlFile">the baseline file</param>
  429.         /// <param name="changedXmlFile">the actual (or target) file</param>
  430.         /// <param name="fragment">the file is only an Xml fragment</param>
  431.         /// <param name="options">comparison filtering options</param>
  432.         /// <param name="reader">Readable output data stream</param>
  433.         /// <returns>Differences were not found after filtering.</returns>
  434.         public XmlDiffViewResults DifferencesSideBySideAsHtml(
  435.             string sourceXmlFile,
  436.             string changedXmlFile,
  437.             bool fragment,
  438.             XmlDiffOptions options)
  439.         {
  440.             MemoryStream data = new MemoryStream();
  441.             try
  442.             {
  443.                 this.outputData = new StreamWriter(
  444.                     data,
  445.                     System.Text.Encoding.Unicode);
  446.                 bool identicalData = this.DifferencesSideBySideAsHtml(
  447.                     sourceXmlFile,
  448.                     changedXmlFile,
  449.                     fragment,
  450.                     options,
  451.                     this.outputData);
  452.                 // Move the data to the memory stream
  453.                 this.outputData.Flush();
  454.                 // Generate the final output using the returned values
  455.                 // from the differences comparison.
  456.                 this.finalOutput = new XmlDiffViewResults(data, identicalData);
  457.             }
  458.             finally
  459.             {
  460.                 if (null != data)
  461.                 {
  462.                     data.Close();
  463.                 }
  464.             }            // return result of comparison
  465.             return this.finalOutput;
  466.         }
  467.         internal static int LastVisitedOpId = 0;
  468.         
  469.         /// <summary>
  470.         /// Converts a copy of the xml data in the 
  471.         /// XmlDiffViewDocument object
  472.         /// to html and writes it out to the 
  473.         /// TextWriter object (which may be a file).
  474.         /// </summary>
  475.         /// <param name="htmlOutput">Data stream for output</param>
  476.         public void GetHtml(TextWriter htmlOutput)
  477.         {
  478.             LastVisitedOpId = 0;
  479.             XmlTextWriter writer = new XmlTextWriter(htmlOutput);
  480.             if (XmlDiffView.LastOperationId > 0) {
  481.                 writer.WriteStartElement("tr");
  482.                     writer.WriteStartElement("td");
  483.                         writer.WriteStartElement("a");
  484.                         writer.WriteAttributeString("href", "#id1");
  485.                         writer.WriteString("first");
  486.                         writer.WriteEndElement();
  487.                     writer.WriteEndElement();
  488.                     writer.WriteStartElement("td");
  489.                     writer.WriteEndElement();
  490.                     writer.WriteStartElement("td");
  491.                     writer.WriteEndElement();
  492.                 writer.WriteEndElement();
  493.             }
  494.             this.viewDocument.DrawHtml(writer, 10);
  495.             if (XmlDiffView.LastOperationId > 0) {
  496.                 writer.WriteStartElement("tr");
  497.                 writer.WriteStartElement("td");
  498.                 writer.WriteStartElement("a");
  499.                 writer.WriteAttributeString("href", "#id" + (XmlDiffView.LastOperationId-1));
  500.                 writer.WriteString("last");
  501.                 writer.WriteEndElement();
  502.                 writer.WriteEndElement();
  503.                 writer.WriteStartElement("td");
  504.                 writer.WriteEndElement();
  505.                 writer.WriteStartElement("td");
  506.                 writer.WriteEndElement();
  507.                 writer.WriteEndElement();
  508.             }
  509.         }
  510.         #endregion
  511.         #region Internal static methods section
  512.         /// <summary>
  513.         /// Writes to the specified section
  514.         /// </summary>
  515.         /// <param name="pane">baseline/actual data presentation sections</param>
  516.         /// <param name="str">Statement to be written</param>
  517.         internal static void HtmlWriteString(
  518.             XmlWriter pane,
  519.             string str)
  520.         {
  521.             pane.WriteString(str);
  522.         }
  523.         /// <summary>
  524.         /// Writes to the specified section using
  525.         /// highlighting based on hte type of data change
  526.         /// </summary>
  527.         /// <param name="pane">baseline/actual data presentation sections</param>
  528.         /// <param name="op">Type of data change</param>
  529.         /// <param name="str">Statement to be written</param>
  530.         internal static void HtmlWriteString(
  531.             XmlWriter pane,
  532.             XmlDiffViewOperation op,
  533.             string str)
  534.         {
  535.             HtmlSetColor(pane, op);
  536.             pane.WriteString(str);
  537.             HtmlResetColor(pane);
  538.         }
  539.         /// <summary>
  540.         /// Writes an 'empty' space character.
  541.         /// </summary>
  542.         /// <param name="pane">baseline/actual data presentation sections</param>
  543.         internal static void HtmlWriteEmptyString(XmlWriter pane)
  544.         {
  545.             pane.WriteRaw("&nbsp;");
  546.         }
  547.         /// <summary>
  548.         /// Writes the start of a table cell
  549.         /// </summary>
  550.         /// <param name="writer">output stream</param>
  551.         /// <param name="indent">Text indentation characters</param>
  552.         internal static void HtmlStartCell(XmlWriter writer, int indent)
  553.         {
  554.             writer.WriteStartElement("td");
  555.             writer.WriteAttributeString("style", "padding-left: " + indent.ToString() + "pt;");
  556.         }
  557.         /// <summary>
  558.         /// Writes the closing tags
  559.         /// </summary>
  560.         /// <param name="writer">output stream</param>
  561.         internal static void HtmlEndCell(XmlWriter writer)
  562.         {
  563.             writer.WriteFullEndElement();
  564.         }
  565.         /// <summary>
  566.         /// Inserts an html break-line and writes the tags to 
  567.         /// close the html element
  568.         /// </summary>
  569.         /// <param name="writer">Output data stream</param>
  570.         internal static void HtmlBr(XmlWriter writer)
  571.         {
  572.             writer.WriteStartElement("br");
  573.             writer.WriteEndElement();
  574.         }
  575.         /// <summary>
  576.         /// Starts a new row in the table
  577.         /// </summary>
  578.         /// <param name="writer">output data stream</param>
  579.         internal static void HtmlStartRow(XmlWriter writer)
  580.         {
  581.             writer.WriteStartElement("tr");
  582.         }
  583.         /// <summary>
  584.         /// Ends a row in the table
  585.         /// </summary>
  586.         /// <param name="writer">output data stream</param>
  587.         internal static void HtmlEndRow(XmlWriter writer)
  588.         {
  589.             writer.WriteFullEndElement();
  590.         }
  591.         /// <summary>
  592.         /// Gets 'empty' string characters to use as an 
  593.         /// indentation for formatting the output.
  594.         /// </summary>
  595.         /// <param name="charCount">Number of indentations</param>
  596.         /// <returns>string to use as an indentation</returns>
  597.         internal static string GetIndent(int charCount)
  598.         {
  599.             int nbspCount = charCount * 6;
  600.             if (nbspCount <= Nbsp.Length)
  601.             {
  602.                 return Nbsp.Substring(0, nbspCount);
  603.             }
  604.             else
  605.             {
  606.                 string indent = string.Empty;
  607.                 while (nbspCount > Nbsp.Length)
  608.                 {
  609.                     indent += Nbsp;
  610.                     nbspCount -= Nbsp.Length;
  611.                 }
  612.                 indent += Nbsp.Substring(0, nbspCount);
  613.                 return indent;
  614.             }
  615.         }
  616.         /// <summary>
  617.         /// This functions allows the size of the indentation to be
  618.         /// set, and returns one indentation.
  619.         /// </summary>
  620.         /// <param name="charCount">Size of the indent (spaces)</param>
  621.         /// <returns>A string of spaces</returns>
  622.         internal static string IndentText(int charCount)
  623.         {
  624.             const string oneSpace = " ";
  625.             string indent = string.Empty;
  626.             while (charCount > 0)
  627.             {
  628.                 // increment the spaces
  629.                 indent += oneSpace;
  630.                 // decrement the count
  631.                 charCount -= 1;
  632.             }
  633.             return indent;
  634.         }
  635.         /// <summary>
  636.         /// Adjusts the format of the data to account for the defined
  637.         /// whitespace characters.
  638.         /// </summary>
  639.         /// <param name="text">data to be formatted</param>
  640.         /// <returns>formatted data</returns>
  641.         internal static string NormalizeText(string text)
  642.         {
  643.             char[] chars = text.ToCharArray();
  644.             int i = 0;
  645.             int j = 0;
  646.             for (;;)
  647.             {
  648.                 while (j < chars.Length && IsWhitespace(text[j]))
  649.                 {
  650.                     j++;
  651.                 }
  652.                 while (j < chars.Length && !IsWhitespace(text[j]))
  653.                 {
  654.                     chars[i++] = chars[j++];
  655.                 }
  656.                 if (j < chars.Length)
  657.                 {
  658.                     chars[i++] = ' ';
  659.                     j++;
  660.                 }
  661.                 else
  662.                 {
  663.                     if (j == 0)
  664.                     {
  665.                         return string.Empty;
  666.                     }
  667.                     if (IsWhitespace(chars[j - 1]))
  668.                     {
  669.                         i--;
  670.                     }
  671.                     return new string(chars, 0, i);
  672.                 }
  673.             }
  674.         }
  675.         /// <summary>
  676.         /// Determines if the specifed character is a 
  677.         /// defined whitespace character.
  678.         /// </summary>
  679.         /// <param name="c">character to test</param>
  680.         /// <returns>specifed character is a 
  681.         /// defined whitespace character</returns>
  682.         internal static bool IsWhitespace(char c)
  683.         {
  684.             return (c == ' ' ||
  685.                 c == 't' ||
  686.                 c == 'n' ||
  687.                 c == 'r');
  688.         }
  689.         #endregion
  690.         #region Private static methods section
  691.         /// <summary>
  692.         /// Sets the output style based on the type of change in the data. 
  693.         /// </summary>
  694.         /// <param name="pane">baseline/actual data presentation sections</param>
  695.         /// <param name="op">Type of data change</param>
  696.         private static void HtmlSetColor(
  697.             XmlWriter pane,
  698.             XmlDiffViewOperation op)
  699.         {
  700.             pane.WriteStartElement("span");
  701.             pane.WriteAttributeString("class", op.ToString().ToLowerInvariant());
  702.         }
  703.         /// <summary>
  704.         /// Closes the tags after setting the color
  705.         /// </summary>
  706.         /// <param name="pane">baseline/actual data presentation sections</param>
  707.         private static void HtmlResetColor(XmlWriter pane)
  708.         {
  709.             pane.WriteFullEndElement();
  710.         }
  711.         /// <include file='docXmlDiff.uex' path='docs/doc[@for="XmlDiff.ParseOptions"]/*' />
  712.         /// <summary>
  713.         ///    Translates string representation of XmlDiff options into XmlDiffOptions enum.
  714.         /// </summary>
  715.         /// <param name="options">Value of the 'options' attribute of the 'xd:xmldiff' element in diffgram.</param>
  716.         /// <returns>An object containing the parsing options.</returns>
  717.         private static XmlDiffOptions ParseOptions(string options)
  718.         {
  719.             if (options == null)
  720.                 throw new ArgumentNullException("options");
  721.             if (options == XmlDiffOptions.None.ToString())
  722.                 return XmlDiffOptions.None;
  723.             else
  724.             {
  725.                 XmlDiffOptions optionsEnum = XmlDiffOptions.None;
  726.                 int j = 0, i = 0;
  727.                 while (i < options.Length)
  728.                 {
  729.                     j = options.IndexOf(' ', i);
  730.                     if (j == -1)
  731.                         j = options.Length;
  732.                     string opt = options.Substring(i, j - i);
  733.                     switch (opt)
  734.                     {
  735.                         case "IgnoreChildOrder": optionsEnum |= XmlDiffOptions.IgnoreChildOrder; 
  736.                             break;
  737.                         case "IgnoreComments": optionsEnum |= XmlDiffOptions.IgnoreComments; 
  738.                             break;
  739.                         case "IgnoreNamespaces": optionsEnum |= XmlDiffOptions.IgnoreNamespaces; 
  740.                             break;
  741.                         case "IgnorePI": optionsEnum |= XmlDiffOptions.IgnorePI; 
  742.                             break;
  743.                         case "IgnorePrefixes": optionsEnum |= XmlDiffOptions.IgnorePrefixes; 
  744.                             break;
  745.                         case "IgnoreWhitespace": optionsEnum |= XmlDiffOptions.IgnoreWhitespace; 
  746.                             break;
  747.                         case "IgnoreXmlDecl": optionsEnum |= XmlDiffOptions.IgnoreXmlDecl; 
  748.                             break;
  749.                         case "IgnoreDtd": optionsEnum |= XmlDiffOptions.IgnoreDtd; 
  750.                             break;
  751.                         default:
  752.                             throw new ArgumentException("options");
  753.                     }
  754.                     i = j + 1;
  755.                 }
  756.                 return optionsEnum;
  757.             }
  758.         }
  759.         #endregion
  760.         #region Private non-static methods section
  761.         /// <summary>
  762.         /// Determines if the data changed
  763.         /// </summary>
  764.         /// <param name="sourceXmlFile">baseline file</param>
  765.         /// <param name="changedXmlFile">actual file</param>
  766.         /// <param name="fragment">xml data fragment</param>
  767.         /// <param name="options">Comparison options</param>
  768.         /// <returns>data is identical</returns>
  769.         private bool GetDifferencesAsFormattedText(
  770.             string sourceXmlFile,
  771.             string changedXmlFile,
  772.             bool fragment,
  773.             XmlDiffOptions options)
  774.         {
  775.             bool identicalData = this.MarkupBaselineWithChanges(
  776.                 sourceXmlFile,
  777.                 changedXmlFile,
  778.                 fragment,
  779.                 options);
  780.             // only generate the output if there are differences. 
  781.             if (!identicalData)
  782.             {
  783.                 // Populate the output
  784.                 this.GetText(sourceXmlFile, changedXmlFile);
  785.             }
  786.             return identicalData;
  787.         }
  788.         /// <summary>
  789.         /// Determines if the data changed
  790.         /// </summary>
  791.         /// <param name="sourceXmlFile">baseline file</param>
  792.         /// <param name="changedXmlFile">actual file</param>
  793.         /// <param name="fragment">xml data fragment</param>
  794.         /// <param name="options">Comparison options</param>
  795.         /// <param name="resultHtml">output data</param>
  796.         /// <returns>data is identical</returns>
  797.         private bool DifferencesSideBySideAsHtml(
  798.             string sourceXmlFile,
  799.             string changedXmlFile,
  800.             bool fragment,
  801.             XmlDiffOptions options,
  802.             TextWriter resultHtml)
  803.         {
  804.             bool identicalData = this.MarkupBaselineWithChanges(
  805.                 sourceXmlFile,
  806.                 changedXmlFile,
  807.                 fragment,
  808.                 options);
  809.             
  810.                 this.SideBySideHtmlHeader(
  811.                     sourceXmlFile,
  812.                     changedXmlFile,
  813.                     identicalData,
  814.                     resultHtml);
  815.             
  816.             this.GetHtml(resultHtml);
  817.             this.SideBySideHtmlFooter(resultHtml);
  818.             return identicalData;
  819.         }
  820.         /// <summary>
  821.         /// Markup the baseline data with changes
  822.         /// </summary>
  823.         /// <param name="sourceXmlFile">baseline xml data</param>
  824.         /// <param name="changedXmlFile">xml data to which to compare</param>
  825.         /// <param name="fragment">xml data fragment</param>
  826.         /// <param name="options">comparison options</param>
  827.         /// <returns>data is identical</returns>
  828.         private bool MarkupBaselineWithChanges(
  829.             string sourceXmlFile,
  830.             string changedXmlFile,
  831.             bool fragment,
  832.             XmlDiffOptions options)
  833.         {
  834.             // generate the diffgram 
  835.             bool identicalData = this.GenerateDiffGram(
  836.                 sourceXmlFile,
  837.                 changedXmlFile,
  838.                 fragment,
  839.                 options);
  840.             this.MergeDiffgramAndBaseline(
  841.                 sourceXmlFile,
  842.                 fragment);
  843.             return identicalData;
  844.         }
  845.         private int ParseOpId(string value) {
  846.             int opid = 0;
  847.             if (string.IsNullOrEmpty(value)) {
  848.                 opid = NextOperationId;
  849.             } else {
  850.                 opid = int.Parse(value);
  851.             }
  852.             if (XmlDiffView.nextOperationId <= opid) {
  853.                 XmlDiffView.nextOperationId = opid + 1;
  854.             }
  855.             return opid;
  856.         }
  857.         /// <summary>
  858.         /// Adjust the diffgram data for the comparison options. 
  859.         /// </summary>
  860.         /// <param name="diffgramDoc">diffgram data</param>
  861.         private void PreprocessDiffgram(XmlDocument diffgramDoc)
  862.         {
  863.             // read xmldiff options
  864.             XmlAttribute attr = (XmlAttribute)
  865.                 diffgramDoc.DocumentElement.Attributes.GetNamedItem("options");
  866.             if (attr == null)
  867.             {
  868.                 throw new NullReferenceException(
  869.                     "Missing 'options' attribute in the diffgram.");
  870.             }
  871.             string optionsAttr = attr.Value;
  872.             XmlDiffOptions options = ParseOptions(optionsAttr);
  873.             this.ignoreChildOrder = (((int)options & (int)
  874.                 (XmlDiffOptions.IgnoreChildOrder)) > 0);
  875.             this.ignoreComments = (((int)options &
  876.                 (int)(XmlDiffOptions.IgnoreComments)) > 0);
  877.             this.ignorePI = (((int)options &
  878.                 (int)(XmlDiffOptions.IgnorePI)) > 0);
  879.             this.ignoreWhitespace = (((int)options &
  880.                 (int)(XmlDiffOptions.IgnoreWhitespace)) > 0);
  881.             this.ignoreNamespaces = (((int)options &
  882.                 (int)(XmlDiffOptions.IgnoreNamespaces)) > 0);
  883.             this.ignorePrefixes = (((int)options &
  884.                 (int)(XmlDiffOptions.IgnorePrefixes)) > 0);
  885.             this.ignoreDtd = (((int)options &
  886.                 (int)(XmlDiffOptions.IgnoreDtd)) > 0);
  887.             if (this.ignoreNamespaces)
  888.             {
  889.                 this.ignorePrefixes = true;
  890.             }
  891.             // read descriptors
  892.             XmlNodeList children =
  893.                 diffgramDoc.DocumentElement.ChildNodes;
  894.             IEnumerator e = children.GetEnumerator();
  895.             while (e.MoveNext())
  896.             {
  897.                 XmlElement desc = e.Current as XmlElement;
  898.                 if (desc != null && desc.LocalName == "descriptor")
  899.                 {
  900.                     int opid = ParseOpId(desc.GetAttribute("opid"));
  901.                     OperationDescriptor.Type type;
  902.                     switch (desc.GetAttribute("type"))
  903.                     {
  904.                         case "move":
  905.                             type =
  906.                                 OperationDescriptor.Type.Move;
  907.                             break;
  908.                         case "prefix change":
  909.                             type = 
  910.                                 OperationDescriptor.Type.PrefixChange;
  911.                             break;
  912.                         case "namespace change":
  913.                             type = OperationDescriptor.Type.NamespaceChange;
  914.                             break;
  915.                         default:
  916.                             throw new ArgumentException(
  917.                                 "Invalid descriptor type.");
  918.                     }
  919.                     OperationDescriptor od = new OperationDescriptor(
  920.                         opid,
  921.                         type);
  922.                     // save this change operation in the hashtable.
  923.                     this.descriptors[opid] = od;
  924.                 }
  925.             }
  926.         }
  927.         /// <summary>
  928.         /// Recurses through the baseline document loading the
  929.         /// contents to the XmlDiffViewDocument object and tagging
  930.         /// the pieces to be ignored later when the data is output.
  931.         /// </summary>
  932.         /// <param name="parent">Parent node</param>
  933.         /// <param name="reader">The xml data</param>
  934.         /// <param name="emptyElement">Node has no children</param>
  935.         private void LoadSourceChildNodes(
  936.             XmlDiffViewParentNode parent,
  937.             XmlReader reader,
  938.             bool emptyElement)
  939.         {
  940.             LoadState savedLoadState = this.loadState;
  941.             this.loadState.Reset();
  942.             // load attributes
  943.             while (reader.MoveToNextAttribute())
  944.             {
  945.                 XmlDiffViewAttribute attr;
  946.                 if (reader.Prefix == "xmlns" ||
  947.                     (reader.Prefix == string.Empty && 
  948.                     reader.LocalName == "xmlns"))
  949.                 {
  950.                     // create new DiffView attribute
  951.                     attr = new XmlDiffViewAttribute(
  952.                         reader.LocalName,
  953.                         reader.Prefix,
  954.                         reader.NamespaceURI,
  955.                         reader.Value);
  956.                     if (this.ignoreNamespaces)
  957.                     {
  958.                         // set the output operation to be performed  
  959.                         attr.Operation = XmlDiffViewOperation.Ignore;
  960.                     }
  961.                 }
  962.                 else
  963.                 {
  964.                     string attrValue = this.ignoreWhitespace ? NormalizeText(reader.Value) : reader.Value;
  965.                     attr = new XmlDiffViewAttribute(
  966.                         reader.LocalName,
  967.                         reader.Prefix,
  968.                         reader.NamespaceURI,
  969.                         attrValue);
  970.                 }
  971.                 ((XmlDiffViewElement)parent).InsertAttributeAfter(
  972.                     attr,
  973.                     this.loadState.LastAttribute);
  974.                 this.loadState.LastAttribute = attr;
  975.             }
  976.             // empty element -> return, do not load chilren
  977.             if (emptyElement)
  978.             {
  979.                 goto End;
  980.             }
  981.             
  982.             // load children
  983.             while (reader.Read())
  984.             {
  985.                 // ignore whitespaces between nodes
  986.                 if (reader.NodeType == XmlNodeType.Whitespace)
  987.                 {
  988.                     continue;
  989.                 }
  990.                 XmlDiffViewNode child = null;
  991.                 switch (reader.NodeType)
  992.                 {
  993.                     case XmlNodeType.Element:
  994.                         bool emptyElementNode = reader.IsEmptyElement;
  995.                         XmlDiffViewElement elem = new XmlDiffViewElement(
  996.                             reader.LocalName,
  997.                             reader.Prefix,
  998.                             reader.NamespaceURI,
  999.                             this.ignorePrefixes);
  1000.                         this.LoadSourceChildNodes(elem, reader, emptyElementNode);
  1001.                         child = elem;
  1002.                         break;
  1003.                     case XmlNodeType.Attribute:
  1004.                         string reason = "We should never get to this point, " +
  1005.                             "attributes should be read at the beginning of this method.";
  1006.                         Debug.Assert(false, reason);
  1007.                         break;
  1008.                     case XmlNodeType.Text:
  1009.                         child = new XmlDiffViewCharData((this.ignoreWhitespace) ? NormalizeText(reader.Value) : reader.Value, XmlNodeType.Text);
  1010.                         break;
  1011.                     case XmlNodeType.CDATA:
  1012.                         child = new XmlDiffViewCharData(reader.Value, XmlNodeType.CDATA);
  1013.                         break;
  1014.                     case XmlNodeType.EntityReference:
  1015.                         Debug.Assert(false, "XmlDiffViewER was thought to be dead code");
  1016.                         
  1017.                         // child = new XmlDiffViewER(reader.Name);
  1018.                         break;
  1019.                     case XmlNodeType.Comment:
  1020.                         child = new XmlDiffViewCharData(reader.Value, XmlNodeType.Comment);
  1021.                         if (this.ignoreComments)
  1022.                         {
  1023.                             child.Operation = XmlDiffViewOperation.Ignore;
  1024.                         }
  1025.                         break;
  1026.                     case XmlNodeType.ProcessingInstruction:
  1027.                         child = new XmlDiffViewPI(reader.Name, reader.Value);
  1028.                         if (this.ignorePI)
  1029.                         {
  1030.                             child.Operation = XmlDiffViewOperation.Ignore;
  1031.                         }
  1032.                         break;
  1033.                     case XmlNodeType.SignificantWhitespace:
  1034.                         if (reader.XmlSpace == XmlSpace.Preserve)
  1035.                         {
  1036.                             child = new XmlDiffViewCharData(reader.Value, XmlNodeType.SignificantWhitespace);
  1037.                             if (this.ignoreWhitespace)
  1038.                             {
  1039.                                 child.Operation = XmlDiffViewOperation.Ignore;
  1040.                             }
  1041.                         }
  1042.                         break;
  1043.                     case XmlNodeType.XmlDeclaration:
  1044.                         child = new XmlDiffViewXmlDeclaration(NormalizeText(reader.Value));
  1045.                         if (this.ignoreXmlDecl)
  1046.                         {
  1047.                             child.Operation = XmlDiffViewOperation.Ignore;
  1048.                         }
  1049.                         break;
  1050.                     case XmlNodeType.EndElement:
  1051.                         goto End;
  1052.                     case XmlNodeType.DocumentType:
  1053.                         child = new XmlDiffViewDocumentType(
  1054.                             reader.Name,
  1055.                             reader.GetAttribute("PUBLIC"),
  1056.                             reader.GetAttribute("SYSTEM"),
  1057.                             reader.Value);
  1058.                         if (this.ignoreDtd)
  1059.                         {
  1060.                             child.Operation = XmlDiffViewOperation.Ignore;
  1061.                         }
  1062.                         break;
  1063.                     default:
  1064.                         Debug.Assert(false, "Invalid node type");
  1065.                         break;
  1066.                 }
  1067.                 parent.InsertChildAfter(child, this.loadState.LastChild, true);
  1068.                 this.loadState.LastChild = child;
  1069.             }
  1070.         End:
  1071.             this.loadState = savedLoadState;
  1072.         }
  1073.         /// <summary>
  1074.         /// Loops through the child nodes of the diffgram and
  1075.         /// annotates the nodes with the type of operation, e.g., 
  1076.         /// add, change, remove, etc.
  1077.         /// </summary>
  1078.         /// <param name="diffgramParent">node in diffgram data</param>
  1079.         /// <param name="sourceParent">node in baseline data</param>
  1080.         private void ApplyDiffgram(
  1081.             XmlNode diffgramParent,
  1082.             XmlDiffViewParentNode sourceParent)
  1083.         {
  1084.             sourceParent.CreateSourceNodesIndex();
  1085.             XmlDiffViewNode currentPosition = null;
  1086.             IEnumerator diffgramChildren = 
  1087.                 diffgramParent.ChildNodes.GetEnumerator();
  1088.             while (diffgramChildren.MoveNext())
  1089.             {
  1090.                 XmlNode diffgramNode = (XmlNode)diffgramChildren.Current;
  1091.                 if (diffgramNode.NodeType == XmlNodeType.Comment)
  1092.                 {
  1093.                     continue;
  1094.                 }
  1095.                 XmlElement diffgramElement = 
  1096.                     diffgramChildren.Current as XmlElement;
  1097.                 if (diffgramElement == null)
  1098.                 {
  1099.                     Trace.WriteLine("Invalid node in diffgram.");
  1100.                     throw new InvalidOperationException(
  1101.                         "Invalid node in diffgram.");
  1102.                 }
  1103.                 if (diffgramElement.NamespaceURI != XmlDiff.NamespaceUri)
  1104.                 {
  1105.                     Trace.WriteLine("Invalid element in diffgram.");
  1106.                     throw new InvalidOperationException(
  1107.                         "Invalid element in diffgram.");
  1108.                 }
  1109.                 string matchAttr = diffgramElement.GetAttribute("match");
  1110.                 XmlDiffPathNodeList matchNodes = null;
  1111.                 if (matchAttr != string.Empty)
  1112.                 {
  1113.                     matchNodes = XmlDiffPath.SelectNodes(
  1114.                     this.viewDocument,
  1115.                     sourceParent,
  1116.                     matchAttr);
  1117.                 }
  1118.                 switch (diffgramElement.LocalName)
  1119.                 {
  1120.                     case "node":
  1121.                         if (matchNodes.Count != 1)
  1122.                         {
  1123.                             string message = "The 'match' attribute of " +
  1124.                                 "'node' element must select a single node.";
  1125.                             throw new InvalidOperationException(message);
  1126.                         }
  1127.                         matchNodes.MoveNext();
  1128.                         if (diffgramElement.ChildNodes.Count > 0)
  1129.                         {
  1130.                             this.ApplyDiffgram(
  1131.                                 diffgramElement,
  1132.                                 (XmlDiffViewParentNode)matchNodes.Current);
  1133.                         }
  1134.                         currentPosition = matchNodes.Current;
  1135.                         break;
  1136.                     case "add":
  1137.                         if (matchAttr != string.Empty)
  1138.                         {
  1139.                             this.OnAddMatch(
  1140.                                 diffgramElement,
  1141.                                 matchNodes,
  1142.                                 sourceParent,
  1143.                                 ref currentPosition);
  1144.                         }
  1145.                         else
  1146.                         {
  1147.                             string typeAttr = diffgramElement.GetAttribute(
  1148.                                 "type");
  1149.                             if (typeAttr != string.Empty)
  1150.                             {
  1151.                                 this.OnAddNode(
  1152.                                     diffgramElement,
  1153.                                     typeAttr,
  1154.                                     sourceParent,
  1155.                                     ref currentPosition);
  1156.                             }
  1157.                             else
  1158.                             {
  1159.                                 this.OnAddFragment(
  1160.                                     diffgramElement,
  1161.                                     sourceParent,
  1162.                                     ref currentPosition);
  1163.                             }
  1164.                         }
  1165.                         break;
  1166.                     case "remove":
  1167.                         this.OnRemove(
  1168.                             diffgramElement,
  1169.                             matchNodes,
  1170.                             sourceParent,
  1171.                             ref currentPosition);
  1172.                         break;
  1173.                     case "change":
  1174.                         this.OnChange(
  1175.                             diffgramElement,
  1176.                             matchNodes,
  1177.                             sourceParent,
  1178.                             ref currentPosition);
  1179.                         break;
  1180.                 }
  1181.             }
  1182.         }
  1183.         /// <summary>
  1184.         /// Tag the relocated data 
  1185.         /// </summary>
  1186.         /// <param name="diffgramElement">node in diffgram</param>
  1187.         /// <param name="matchNodes">the path to the baseline node</param>
  1188.         /// <param name="sourceParent">the baseline parent node</param>
  1189.         /// <param name="currentPosition">the resulting node</param>
  1190.         private void OnRemove(
  1191.             XmlElement diffgramElement,
  1192.             XmlDiffPathNodeList matchNodes,
  1193.             XmlDiffViewParentNode sourceParent,
  1194.             ref XmlDiffViewNode currentPosition)
  1195.         {
  1196.             // opid & descriptor
  1197.             XmlDiffViewOperation operation = XmlDiffViewOperation.Remove;
  1198.             int operationId = 0;
  1199.             OperationDescriptor operationDesc = null;
  1200.             string opidAttr = diffgramElement.GetAttribute("opid");
  1201.             if (opidAttr != string.Empty) {
  1202.                 operationId = int.Parse(opidAttr);
  1203.                 operationDesc = this.GetDescriptor(operationId);
  1204.                 if (operationDesc.OperationType == OperationDescriptor.Type.Move) {
  1205.                     operation = XmlDiffViewOperation.MoveFrom;
  1206.                 }
  1207.             } else {
  1208.                 operationId = NextOperationId;
  1209.             }
  1210.             // subtree
  1211.             string subtreeAttr = diffgramElement.GetAttribute("subtree");
  1212.             bool subtree = (subtreeAttr != "no");
  1213.             if (!subtree)
  1214.             {
  1215.                 if (matchNodes.Count != 1)
  1216.                 {
  1217.                     throw new Exception("The 'match' attribute of 'remove' " +
  1218.                         "element must select a single node when the 'subtree' " +
  1219.                         "attribute is specified.");
  1220.                 }
  1221.                 // annotate node
  1222.                 matchNodes.MoveNext();
  1223.                 XmlDiffViewNode node = matchNodes.Current;
  1224.                 this.AnnotateNode(node, operation, operationId, false);
  1225.                 if (operationId != 0 && operationDesc != null)
  1226.                 {
  1227.                     operationDesc.NodeList.AddNode(node);
  1228.                 }
  1229.                 
  1230.                 // recurse
  1231.                 this.ApplyDiffgram(diffgramElement, (XmlDiffViewParentNode)node);
  1232.             }
  1233.             else
  1234.             {
  1235.                 // annotate nodes
  1236.                 matchNodes.Reset();
  1237.                 while (matchNodes.MoveNext())
  1238.                 {
  1239.                     if (operationId != 0 && operationDesc != null)
  1240.                     {
  1241.                         operationDesc.NodeList.AddNode(matchNodes.Current);
  1242.                     }
  1243.                     this.AnnotateNode(matchNodes.Current, operation, operationId, true);
  1244.                 }
  1245.             }
  1246.         }
  1247.         /// <summary>
  1248.         /// Relocate matched data. 
  1249.         /// </summary>
  1250.         /// <param name="diffgramElement">node in diffgram</param>
  1251.         /// <param name="matchNodes">the path to the baseline node</param>
  1252.         /// <param name="sourceParent">the baseline parent node</param>
  1253.         /// <param name="currentPosition">the resulting node</param>
  1254.         private void OnAddMatch(
  1255.             XmlElement diffgramElement,
  1256.             XmlDiffPathNodeList matchNodes,
  1257.             XmlDiffViewParentNode sourceParent,
  1258.             ref XmlDiffViewNode currentPosition)
  1259.         {
  1260.             string opidAttr = diffgramElement.GetAttribute("opid");
  1261.             if (opidAttr == string.Empty)
  1262.             {
  1263.                 throw new Exception("Missing opid attribute.");
  1264.             }
  1265.             
  1266.             // opid & descriptor
  1267.             int opid = ParseOpId(opidAttr);
  1268.             OperationDescriptor operationDesc = this.GetDescriptor(opid);
  1269.             string subtreeAttr = diffgramElement.GetAttribute("subtree");
  1270.             bool subtree = (subtreeAttr != "no");
  1271.             
  1272.             // move single node without subtree
  1273.             if (!subtree)
  1274.             {
  1275.                 if (matchNodes.Count != 1)
  1276.                 {
  1277.                     throw new Exception("The 'match' attribute of 'add' " +
  1278.                         "element must select a single node when the 'subtree' " +
  1279.                         "attribute is specified.");
  1280.                 }
  1281.                 
  1282.                 // clone node
  1283.                 matchNodes.MoveNext();
  1284.                 XmlDiffViewNode newNode = matchNodes.Current.Clone(false);
  1285.                 this.AnnotateNode(
  1286.                     newNode,
  1287.                     XmlDiffViewOperation.MoveTo,
  1288.                     opid,
  1289.                     true);
  1290.                 operationDesc.NodeList.AddNode(newNode);
  1291.                 // insert in tree
  1292.                 sourceParent.InsertChildAfter(newNode, currentPosition, false);
  1293.                 currentPosition = newNode;
  1294.                 // recurse
  1295.                 this.ApplyDiffgram(
  1296.                     diffgramElement,
  1297.                     (XmlDiffViewParentNode)newNode);
  1298.             }
  1299.             else
  1300.             {
  1301.                 // move subtree
  1302.                 matchNodes.Reset();
  1303.                 while (matchNodes.MoveNext())
  1304.                 {
  1305.                     XmlDiffViewNode newNode = matchNodes.Current.Clone(true);
  1306.                     this.AnnotateNode(
  1307.                         newNode,
  1308.                         XmlDiffViewOperation.MoveTo,
  1309.                         opid,
  1310.                         true);
  1311.                     operationDesc.NodeList.AddNode(newNode);
  1312.                     sourceParent.InsertChildAfter(newNode, currentPosition, false);
  1313.                     currentPosition = newNode;
  1314.                 }
  1315.             }
  1316.         }
  1317.         /// <summary>
  1318.         /// Add the new node or attribute 
  1319.         /// </summary>
  1320.         /// <param name="diffgramElement">node in diffgram</param>
  1321.         /// <param name="nodeTypeAttr">Whether this is an Attribute</param>
  1322.         /// <param name="sourceParent">the baseline parent node</param>
  1323.         /// <param name="currentPosition">the resulting node</param>
  1324.         private void OnAddNode(
  1325.             XmlElement diffgramElement,
  1326.             string nodeTypeAttr,
  1327.             XmlDiffViewParentNode sourceParent,
  1328.             ref XmlDiffViewNode currentPosition)
  1329.         {
  1330.             XmlNodeType nodeType = (XmlNodeType)
  1331.                 int.Parse(nodeTypeAttr);
  1332.             string name = diffgramElement.GetAttribute("name");
  1333.             string prefix = diffgramElement.GetAttribute("prefix");
  1334.             string ns = diffgramElement.GetAttribute("ns");
  1335.             string opidAttr = diffgramElement.GetAttribute("opid");
  1336.             int opid = ParseOpId(opidAttr);
  1337.             if (nodeType == XmlNodeType.Attribute)
  1338.             {
  1339.                 Debug.Assert(name != string.Empty);
  1340.                 XmlDiffViewAttribute newAttr = new XmlDiffViewAttribute(
  1341.                     name,
  1342.                     prefix,
  1343.                     ns,
  1344.                     diffgramElement.InnerText);
  1345.                 newAttr.Operation = XmlDiffViewOperation.Add;
  1346.                 newAttr.OperationId = opid;
  1347.                 ((XmlDiffViewElement)
  1348.                     sourceParent).InsertAttributeAfter(newAttr, null);
  1349.             }
  1350.             else
  1351.             {
  1352.                 XmlDiffViewNode newNode = null;
  1353.                 switch (nodeType)
  1354.                 {
  1355.                     case XmlNodeType.Element:
  1356.                         Debug.Assert(name != string.Empty);
  1357.                         newNode = new XmlDiffViewElement(
  1358.                             name,
  1359.                             prefix,
  1360.                             ns,
  1361.                             this.ignorePrefixes);
  1362.                         this.ApplyDiffgram(
  1363.                             diffgramElement,
  1364.                             (XmlDiffViewParentNode)newNode);
  1365.                         break;
  1366.                     case XmlNodeType.Text:
  1367.                     case XmlNodeType.CDATA:
  1368.                     case XmlNodeType.Comment:
  1369.                         Debug.Assert(diffgramElement.InnerText != string.Empty);
  1370.                         newNode = new XmlDiffViewCharData(
  1371.                             diffgramElement.InnerText,
  1372.                             nodeType);
  1373.                         break;
  1374.                     case XmlNodeType.ProcessingInstruction:
  1375.                         Debug.Assert(diffgramElement.InnerText != string.Empty);
  1376.                         Debug.Assert(name != string.Empty);
  1377.                         newNode = new XmlDiffViewPI(
  1378.                             name,
  1379.                             diffgramElement.InnerText);
  1380.                         break;
  1381.                     case XmlNodeType.EntityReference:
  1382.                         Debug.Assert(name != string.Empty);
  1383.                         Debug.Assert(false, "XmlDiffViewER was thought to be dead code");
  1384.                         //// newNode = new XmlDiffViewER(name);
  1385.                         break;
  1386.                     case XmlNodeType.XmlDeclaration:
  1387.                         Debug.Assert(diffgramElement.InnerText != string.Empty);
  1388.                         newNode = new XmlDiffViewXmlDeclaration(
  1389.                             diffgramElement.InnerText);
  1390.                         break;
  1391.                     case XmlNodeType.DocumentType:
  1392.                         newNode = new XmlDiffViewDocumentType(
  1393.                             diffgramElement.GetAttribute("name"),
  1394.                             diffgramElement.GetAttribute("publicId"),
  1395.                             diffgramElement.GetAttribute("systemId"),
  1396.                             diffgramElement.InnerText);
  1397.                         break;
  1398.                     default:
  1399.                         Debug.Assert(false, "Invalid node type.");
  1400.                         break;
  1401.                 }
  1402.                 Debug.Assert(newNode != null);
  1403.                 newNode.Operation = XmlDiffViewOperation.Add;
  1404.                 newNode.OperationId = opid;
  1405.                 sourceParent.InsertChildAfter(newNode, currentPosition, false);
  1406.                 currentPosition = newNode;
  1407.             }
  1408.         }
  1409.         /// <summary>
  1410.         /// Add the new fragment 
  1411.         /// </summary>
  1412.         /// <param name="diffgramElement">node in diffgram</param>
  1413.         /// <param name="sourceParent">the baseline parent node</param>
  1414.         /// <param name="currentPosition">the resulting node</param>
  1415.         private void OnAddFragment(
  1416.             XmlElement diffgramElement,
  1417.             XmlDiffViewParentNode sourceParent,
  1418.             ref XmlDiffViewNode currentPosition)
  1419.         {
  1420.             int opid = NextOperationId;
  1421.             IEnumerator childNodes = 
  1422.                 diffgramElement.ChildNodes.GetEnumerator();
  1423.             while (childNodes.MoveNext())
  1424.             {
  1425.                 XmlDiffViewNode newChildNode = this.ImportNode(
  1426.                     (XmlNode)childNodes.Current);
  1427.                 sourceParent.InsertChildAfter(
  1428.                     newChildNode,
  1429.                     currentPosition,
  1430.                     false);
  1431.                 currentPosition = newChildNode;
  1432.                 this.AnnotateNode(
  1433.                     newChildNode,
  1434.                     XmlDiffViewOperation.Add,
  1435.                     opid,
  1436.                     true);
  1437.             }
  1438.         }
  1439.         /// <summary>
  1440.         /// Generate a new node
  1441.         /// </summary>
  1442.         /// <param name="node">node to clone</param>
  1443.         /// <returns>the new node</returns>
  1444.         private XmlDiffViewNode ImportNode(XmlNode node)
  1445.         {
  1446.             XmlDiffViewNode newNode = null;
  1447.             switch (node.NodeType)
  1448.             {
  1449.                 case XmlNodeType.Element:
  1450.                     XmlElement el = (XmlElement)node;
  1451.                     XmlDiffViewElement newElement = new XmlDiffViewElement(
  1452.                         el.LocalName,
  1453.                         el.Prefix,
  1454.                         el.NamespaceURI,
  1455.                         this.ignorePrefixes);
  1456.                     
  1457.                     // attributes
  1458.                     IEnumerator attributes = node.Attributes.GetEnumerator();
  1459.                     XmlDiffViewAttribute lastNewAttr = null;
  1460.                     while (attributes.MoveNext())
  1461.                     {
  1462.                         XmlAttribute at = (XmlAttribute)attributes.Current;
  1463.                         XmlDiffViewAttribute newAttr = new XmlDiffViewAttribute(
  1464.                             at.LocalName,
  1465.                             at.Prefix,
  1466.                             at.NamespaceURI,
  1467.                             at.Value);
  1468.                         newElement.InsertAttributeAfter(newAttr, lastNewAttr);
  1469.                         lastNewAttr = newAttr;
  1470.                     }
  1471.                     // children
  1472.                     IEnumerator childNodes = node.ChildNodes.GetEnumerator();
  1473.                     XmlDiffViewNode lastNewChildNode = null;
  1474.                     while (childNodes.MoveNext())
  1475.                     {
  1476.                         XmlDiffViewNode newChildNode = this.ImportNode(
  1477.                             (XmlNode)childNodes.Current);
  1478.                         newElement.InsertChildAfter(
  1479.                             newChildNode,
  1480.                             lastNewChildNode,
  1481.                             false);
  1482.                         lastNewChildNode = newChildNode;
  1483.                     }
  1484.                     newNode = newElement;
  1485.                     break;
  1486.                 case XmlNodeType.Text:
  1487.                 case XmlNodeType.CDATA:
  1488.                 case XmlNodeType.Comment:
  1489.                     newNode = new XmlDiffViewCharData(
  1490.                         node.Value,
  1491.                         node.NodeType);
  1492.                     break;
  1493.                 case XmlNodeType.ProcessingInstruction:
  1494.                     newNode = new XmlDiffViewPI(node.Name, node.Value);
  1495.                     break;
  1496.                 case XmlNodeType.EntityReference:
  1497.                     Debug.Assert(false, "XmlDiffViewER was thought to be dead code");
  1498.                     //// newNode = new XmlDiffViewER(node.Name);
  1499.                     break;
  1500.                 default:
  1501.                     Debug.Assert(false, "Invalid node type.");
  1502.                     break;
  1503.             }
  1504.             Debug.Assert(newNode != null);
  1505.             return newNode;
  1506.         }
  1507.         /// <summary>
  1508.         /// Store changes in the ChangeInfo object of the marked-up-baseline node
  1509.         /// </summary>
  1510.         /// <param name="diffgramElement">current element in the diffgram</param>
  1511.         /// <param name="matchNodes">Object containing the list of baseline nodes
  1512.         ///  which match the position in the diffgram</param>
  1513.         /// <param name="sourceParent">parent node in the baseline data</param>
  1514.         /// <param name="currentPosition">current position</param>
  1515.         private void OnChange(
  1516.             XmlElement diffgramElement,
  1517.             XmlDiffPathNodeList matchNodes,
  1518.             XmlDiffViewParentNode sourceParent,
  1519.             ref XmlDiffViewNode currentPosition)
  1520.         {
  1521.             Debug.Assert(matchNodes.Count == 1);
  1522.             matchNodes.Reset();
  1523.             matchNodes.MoveNext();
  1524.             XmlDiffViewNode node = matchNodes.Current;
  1525.             if (node.NodeType != XmlNodeType.Attribute)
  1526.             {
  1527.                 currentPosition = node;
  1528.             }
  1529.             XmlDiffViewNode.ChangeInfo changeInfo = new XmlDiffViewNode.ChangeInfo();
  1530.             string name = diffgramElement.HasAttribute("name") ? diffgramElement.GetAttribute("name") : null;
  1531.             string prefix = diffgramElement.HasAttribute("prefix") ? diffgramElement.GetAttribute("prefix") : null;
  1532.             string ns = diffgramElement.HasAttribute("ns") ? diffgramElement.GetAttribute("ns") : null;
  1533.             switch (node.NodeType)
  1534.             {
  1535.                 case XmlNodeType.Element:
  1536.                     changeInfo.LocalName = (name == null) ? ((XmlDiffViewElement)node).LocalName : name;
  1537.                     changeInfo.Prefix = (prefix == null) ? ((XmlDiffViewElement)node).Prefix : prefix;
  1538.                     changeInfo.NamespaceUri = (ns == null) ? ((XmlDiffViewElement)node).NamespaceUri : ns;
  1539.                     break;
  1540.                 case XmlNodeType.Attribute:
  1541.                     string value = diffgramElement.InnerText;
  1542.                     if (name == string.Empty && prefix == string.Empty && value == string.Empty)
  1543.                     {
  1544.                         return;
  1545.                     }
  1546.                     changeInfo.LocalName = (name == null) ? ((XmlDiffViewAttribute)node).LocalName : name;
  1547.                     changeInfo.Prefix = (prefix == null) ? ((XmlDiffViewAttribute)node).Prefix : prefix;
  1548.                     changeInfo.NamespaceUri = (ns == null) ? ((XmlDiffViewAttribute)node).NamespaceUri : ns;
  1549.                     changeInfo.Subset = diffgramElement.InnerText;
  1550.                     break;
  1551.                 case XmlNodeType.Text:
  1552.                 case XmlNodeType.CDATA:
  1553.                     Debug.Assert(diffgramElement.FirstChild != null);
  1554.                     changeInfo.Subset = diffgramElement.InnerText;
  1555.                     break;
  1556.                 case XmlNodeType.Comment:
  1557.                     Debug.Assert(diffgramElement.FirstChild != null);
  1558.                     Debug.Assert(diffgramElement.FirstChild.NodeType == XmlNodeType.Comment);
  1559.                     changeInfo.Subset = diffgramElement.FirstChild.Value;
  1560.                     break;
  1561.                 case XmlNodeType.ProcessingInstruction:
  1562.                     if (name == null)
  1563.                     {
  1564.                         Debug.Assert(diffgramElement.FirstChild != null);
  1565.                         Debug.Assert(diffgramElement.FirstChild.NodeType == XmlNodeType.ProcessingInstruction);
  1566.                         changeInfo.LocalName = diffgramElement.FirstChild.Name;
  1567.                         changeInfo.Subset = diffgramElement.FirstChild.Value;
  1568.                     }
  1569.                     else
  1570.                     {
  1571.                         changeInfo.LocalName = name;
  1572.                         changeInfo.Subset = ((XmlDiffViewPI)node).InnerText;
  1573.                     }
  1574.                     break;
  1575.                 case XmlNodeType.EntityReference:
  1576.                     Debug.Assert(name != null);
  1577.                     changeInfo.LocalName = name;
  1578.                     break;
  1579.                 case XmlNodeType.XmlDeclaration:
  1580.                     Debug.Assert(diffgramElement.FirstChild != null);
  1581.                     changeInfo.Subset = diffgramElement.InnerText;
  1582.                     break;
  1583.                 case XmlNodeType.DocumentType:
  1584.                     changeInfo.LocalName = (name == null) ? ((XmlDiffViewDocumentType)node).Name : name;
  1585.                     if (diffgramElement.HasAttribute("publicId"))
  1586.                     {
  1587.                         changeInfo.Prefix = diffgramElement.GetAttribute("publicId");
  1588.                     }
  1589.                     else
  1590.                     {
  1591.                         changeInfo.Prefix = ((XmlDiffViewDocumentType)node).PublicId;
  1592.                     }
  1593.                     if (diffgramElement.HasAttribute("systemId"))
  1594.                     {
  1595.                         changeInfo.NamespaceUri = diffgramElement.GetAttribute("systemId");
  1596.                     }
  1597.                     else
  1598.                     {
  1599.                         changeInfo.NamespaceUri = ((XmlDiffViewDocumentType)node).SystemId;
  1600.                     }
  1601.                     if (diffgramElement.FirstChild != null)
  1602.                     {
  1603.                         changeInfo.Subset = diffgramElement.InnerText;
  1604.                     }
  1605.                     else
  1606.                     {
  1607.                         changeInfo.Subset = ((XmlDiffViewDocumentType)node).Subset;
  1608.                     }
  1609.                     break;
  1610.                 default:
  1611.                     Debug.Assert(false, "Invalid node type.");
  1612.                     break;
  1613.             }
  1614.             node.ChangeInformation = changeInfo;
  1615.             node.Operation = XmlDiffViewOperation.Change;
  1616.             string opidAttr = diffgramElement.GetAttribute("opid");
  1617.             if (opidAttr != string.Empty) {
  1618.                 node.OperationId = int.Parse(opidAttr);
  1619.             } else {
  1620.                 node.OperationId = NextOperationId;
  1621.             }
  1622.             if (node.NodeType == XmlNodeType.Element &&
  1623.                 diffgramElement.FirstChild != null)
  1624.             {
  1625.                 this.ApplyDiffgram(diffgramElement, (XmlDiffViewParentNode)node);
  1626.             }
  1627.         }
  1628.         /// <summary>
  1629.         /// Gets a reference to the operation description object
  1630.         /// for the operation identification number provided.
  1631.         /// </summary>
  1632.         /// <param name="opid">operation identification number</param>
  1633.         /// <returns>A reference to the operation description object</returns>
  1634.         private OperationDescriptor GetDescriptor(int opid)
  1635.         {
  1636.             OperationDescriptor operationDesc = (OperationDescriptor)this.descriptors[opid];
  1637.             if (operationDesc == null)
  1638.             {
  1639.                 throw new Exception("Invalid operation id.");
  1640.             }
  1641.             return operationDesc;
  1642.         }
  1643.         /// <summary>
  1644.         /// Mark the nodes (and attributes) with the type of data change
  1645.         /// </summary>
  1646.         /// <param name="node">the node to annotate</param>
  1647.         /// <param name="op">the type of data change</param>
  1648.         /// <param name="opid">the operation identification number</param>
  1649.         /// <param name="subtree">the node's subtree</param>
  1650.         private void AnnotateNode(
  1651.             XmlDiffViewNode node,
  1652.             XmlDiffViewOperation op,
  1653.             int opid,
  1654.             bool subtree)
  1655.         {
  1656.             node.Operation = op;
  1657.             node.OperationId = opid;
  1658.             if (node.NodeType == XmlNodeType.Element)
  1659.             {
  1660.                 XmlDiffViewAttribute attr = (
  1661.                     (XmlDiffViewElement)node).Attributes;
  1662.                 while (attr != null)
  1663.                 {
  1664.                     attr.Operation = op;
  1665.                     attr.OperationId = opid;
  1666.                     attr = (XmlDiffViewAttribute)attr.NextSibbling;
  1667.                 }
  1668.             }
  1669.             if (subtree)
  1670.             {
  1671.                 XmlDiffViewNode childNode = node.FirstChildNode;
  1672.                 while (childNode != null)
  1673.                 {
  1674.                     this.AnnotateNode(childNode, op, opid, true);
  1675.                     childNode = childNode.NextSibbling;
  1676.                 }
  1677.             }
  1678.         }
  1679.         /// <summary>
  1680.         /// initialise the output with differences node and
  1681.         /// start the process of formatting the output
  1682.         /// </summary>
  1683.         /// <param name="baselineFile">baseline file name</param>
  1684.         /// <param name="actualFile">actual file name</param>
  1685.         private void GetText(
  1686.             string baselineFile,
  1687.             string actualFile)
  1688.         {
  1689.             // initialise output with differences node
  1690.             this.outputData.Write(Tags.XmlOpenBegin +
  1691.                 Difference.Tag + Difference.NodeDifferences +
  1692.                 " fromFile='" + baselineFile + "' toFile='" +
  1693.                 actualFile + "'" + Tags.XmlOpenEnd + this.outputData.NewLine);
  1694.             
  1695.             // flag the output object is open for cleanup later.
  1696.             this.viewDocument.DrawText(this.outputData, Indent.InitialSize);
  1697.             
  1698.             // end differences node
  1699.             this.outputData.Write(Tags.XmlCloseBegin +
  1700.                 Difference.Tag + Difference.NodeDifferences +
  1701.                 Tags.XmlCloseEnd + this.outputData.NewLine);
  1702.         }
  1703.         /// <summary>
  1704.         /// Compare the xml data files
  1705.         /// </summary>
  1706.         /// <param name="sourceXmlFile">baseline file</param>
  1707.         /// <param name="changedXmlFile">actual file</param>
  1708.         /// <param name="fragment">xml data fragment</param>
  1709.         /// <param name="options">comparison options</param>
  1710.         /// <returns>data is identical</returns>
  1711.         private bool GenerateDiffGram(
  1712.             string sourceXmlFile,
  1713.             string changedXmlFile,
  1714.             bool fragment,
  1715.             XmlDiffOptions options)
  1716.         {
  1717.             // set class scope variables
  1718.             // MemoryStream diffgram
  1719.             bool identicalData;
  1720.             this.diffgram = new MemoryStream();
  1721.             XmlTextWriter diffgramWriter = new XmlTextWriter(
  1722.                 new StreamWriter(this.diffgram));
  1723.             Trace.WriteLine("Comparing " + sourceXmlFile +
  1724.                 " & " + changedXmlFile);
  1725.             XmlDiffOptions xmlDiffOptions = (XmlDiffOptions)options;
  1726.             XmlDiff xmlDiff = new XmlDiff(xmlDiffOptions);
  1727.             try
  1728.             {
  1729.                 identicalData = xmlDiff.Compare(
  1730.                     sourceXmlFile,
  1731.                     changedXmlFile,
  1732.                     fragment,
  1733.                     diffgramWriter);
  1734.             }
  1735.             catch (XmlException format)
  1736.             {
  1737.                 Trace.WriteLine(format.Message);
  1738.                 throw;
  1739.             }
  1740.             Trace.WriteLine("Files compared " +
  1741.                 (identicalData ? "identical." : "different."));
  1742.             
  1743.             return identicalData;
  1744.         }
  1745.         /// <summary>
  1746.         /// The generic html header.
  1747.         /// </summary>
  1748.         /// <param name="sourceXmlFile">baseline xml data</param>
  1749.         /// <param name="changedXmlFile">xml data to which to compare</param>
  1750.         /// <param name="identicalData">Data is identical</param>
  1751.         /// <param name="resultHtml">Output file</param>
  1752.         public void SideBySideHtmlHeader(
  1753.             string sourceXmlFile,
  1754.             string changedXmlFile,
  1755.             bool identicalData,
  1756.             TextWriter resultHtml)
  1757.         {
  1758.             // this initializes the html
  1759.             resultHtml.WriteLine("<html><head>");
  1760.             resultHtml.WriteLine(@"<html><head>
  1761.                 <style TYPE='text/css' MEDIA='screen'>
  1762.                 <!-- td { font-family: Courier New; font-size:14; } 
  1763.                 th { font-family: Arial; } 
  1764.                 p { font-family: Arial; } 
  1765.                 .match { }
  1766.                 .ignore { color:#AAAAAA; }
  1767.                 .add { background-color:yellow; }
  1768.                 .moveto { background-color:cyan; color:navy; }
  1769.                 .remove { background-color:red; }
  1770.                 .movefrom {  background-color:cyan; color:navy; }
  1771.                 .change {  background-color:lightgreen;  }
  1772.                 -->
  1773.             </style></head>
  1774.             <body>
  1775.                 <table border='0' style='table-layout:fixed;' width='100%'>
  1776.                     <col width='20'><col width='50%'><col width='50%'>
  1777.                     <tr><td><table border='0' width='100%'>
  1778.                     <tr><td colspan='3' align='center'>
  1779.                     <b>Legend:</b> <span class='add'>added</span>&nbsp;&nbsp;
  1780.                         <span class='remove'>removed</span>&nbsp;&nbsp;
  1781.                         <span class='change'>changed</span>&nbsp;&nbsp;
  1782.                         <span class='movefrom'>moved from</span>&nbsp;&nbsp;
  1783.                         <span class='moveto'>moved to</span>&nbsp;&nbsp;
  1784.                         <span class='ignore'>ignored</span><br/><br/>
  1785.                     </td></tr>");
  1786.             resultHtml.WriteLine("<tr><td><table border='0'>");
  1787.             resultHtml.WriteLine("<tr><th>" + sourceXmlFile + "</th><th>" +
  1788.                 changedXmlFile + "</th></tr>" +
  1789.                 "<tr><td colspan='3'><hr size=1></td></tr>");
  1790.             if (identicalData)
  1791.             {
  1792.                 resultHtml.WriteLine("<tr><td colspan='3' align='middle'>Files are identical.</td></tr>");
  1793.             }
  1794.             else
  1795.             {
  1796.                 resultHtml.WriteLine("<tr><td colspan='3' align='middle'>" +
  1797.                     "Files are different.</td></tr>");
  1798.             }
  1799.         }
  1800.         /// <summary>
  1801.         /// Merge the diffgram and the baseline file 
  1802.         /// into a new XmlDiffViewDocument object.
  1803.         /// </summary>
  1804.         /// <param name="sourceXmlFile">the baseline file</param>
  1805.         /// <param name="fragment">the file is an Xml fragment</param>
  1806.         private void MergeDiffgramAndBaseline(
  1807.             string sourceXmlFile,
  1808.             bool fragment)
  1809.         {
  1810.             Debug.Assert(null != this.diffgram);
  1811.             // Populate an xml reader with the baseline data.
  1812.             this.diffgram.Seek(0, SeekOrigin.Begin);
  1813.             XmlTextReader sourceReader;
  1814.             if (fragment)
  1815.             {
  1816.                 NameTable nt = new NameTable();
  1817.                 ////Todo: break up the following overly
  1818.                 ////      complex statement to avoid StyleCop
  1819.                 ////      complaints.
  1820.                 sourceReader = new XmlTextReader(
  1821.                     new FileStream(
  1822.                         sourceXmlFile,
  1823.                         FileMode.Open,
  1824.                         FileAccess.Read),
  1825.                     XmlNodeType.Element,
  1826.                     new XmlParserContext(
  1827.                         nt,
  1828.                         new XmlNamespaceManager(nt),
  1829.                         string.Empty,
  1830.                         XmlSpace.Default));
  1831.             }
  1832.             else
  1833.             {
  1834.                 sourceReader = new XmlTextReader(sourceXmlFile);
  1835.             }
  1836.             sourceReader.XmlResolver = null;
  1837.             this.Load(
  1838.                 sourceReader,
  1839.                 new XmlTextReader(this.diffgram));
  1840.         }
  1841.         /// <summary>
  1842.         /// html footer
  1843.         /// </summary>
  1844.         /// <param name="resultHtml">output stream</param>
  1845.         private void SideBySideHtmlFooter(TextWriter resultHtml)
  1846.         {
  1847.             resultHtml.WriteLine("</table></table></body></html>");
  1848.         }
  1849.         #endregion
  1850.         #endregion
  1851.         #region Structs section
  1852.         /// <summary>
  1853.         /// An object used when loading to provide 
  1854.         /// references to the last node and attribute.
  1855.         /// </summary>
  1856.         private struct LoadState
  1857.         {
  1858.             #region Member variables section
  1859.             /// <summary>
  1860.             /// Declares a reference to the last child node processed
  1861.             /// </summary>
  1862.             private XmlDiffViewNode lastChild;
  1863.             
  1864.             /// <summary>
  1865.             /// Declares a reference to the last attribute processed
  1866.             /// </summary>
  1867.             private XmlDiffViewAttribute lastAttribute;
  1868.             #endregion
  1869.             #region Properties section
  1870.             /// <summary>
  1871.             /// Gets or sets a reference to the last child node processed
  1872.             /// </summary>
  1873.             public XmlDiffViewNode LastChild
  1874.             {
  1875.                 get
  1876.                 {
  1877.                     return this.lastChild;
  1878.                 }
  1879.                 
  1880.                 set
  1881.                 {
  1882.                     this.lastChild = value;
  1883.                 }
  1884.             }
  1885.             /// <summary>
  1886.             /// Gets or sets a reference to the last attribute processed
  1887.             /// </summary>
  1888.             public XmlDiffViewAttribute LastAttribute
  1889.             {
  1890.                 get
  1891.                 {
  1892.                     return this.lastAttribute;
  1893.                 }
  1894.                 set
  1895.                 {
  1896.                     this.lastAttribute = value;
  1897.                 }
  1898.             }
  1899.             #endregion
  1900.             #region Methods section
  1901.             /// <summary>
  1902.             /// Clear the references the last 
  1903.             /// child node and attribute processed.
  1904.             /// </summary>
  1905.             public void Reset()
  1906.             {
  1907.                 this.lastChild = null;
  1908.                 this.lastAttribute = null;
  1909.             }
  1910.             #endregion
  1911.         }
  1912.         #endregion
  1913.     }
  1914. }