diff --git a/src/Common/Updates.xsd b/src/Common/Updates.xsd new file mode 100644 index 0000000..0d9ec39 --- /dev/null +++ b/src/Common/Updates.xsd @@ -0,0 +1,70 @@ + + + + + + + + + + + The name of the application being updated. + + + + + The location of the update xml page. + + + + + Location of the download page. + + + + + Location of the installation page. + + + + + Location of the page showing update history. + + + + + The frequency we need to check for updates to the application, any valid TimeSpan. + + + + + + + + This element describes a new version of the application. + + + + + + Description of a new feature added in this version. + + + + + Description of a bug fixed in this version. + + + + + + The version number. + + + + + + + + diff --git a/src/Common/Updates.xslt b/src/Common/Updates.xslt new file mode 100644 index 0000000..6e85818 --- /dev/null +++ b/src/Common/Updates.xslt @@ -0,0 +1,76 @@ + + + + + + + + <xsl:value-of select="updates/application/title"/> + + + + +
+ + + + + + + + + + +
+ + - Change History + +
+
+

+

+
+ + +
+
+
+ + +
+ + + + + + + background:teal;color:white + + + + Version + + + + + + background:MediumTurquoise + + Feature + + + + + + + background:LightPink + + Bug + + + + + +
diff --git a/src/Common/changes.xml b/src/Common/changes.xml index f62d471..8b4bdf3 100644 --- a/src/Common/changes.xml +++ b/src/Common/changes.xml @@ -1,6 +1,17 @@ + + Microsoft XML Diff + https://raw.githubusercontent.com/lovettchris/xmldiff/master/src/Common/changes.xml + https://www.nuget.org/packages/LovettSoftware.XmlDiff + https://www.nuget.org/packages/LovettSoftware.XmlDiff + https://github.com/microsoft/XmlNotepad/blob/master/src/Updates/Updates.xml + 1.00:00:00 + + + Thanks to Mark Roberts for a cool new feature that omits identical output to make the diff HTML output scale better on huge XML files. + Add back strong naming for XmlDiffPatch.dll diff --git a/src/Common/version.props b/src/Common/version.props index 78092b7..cdef499 100644 --- a/src/Common/version.props +++ b/src/Common/version.props @@ -2,8 +2,8 @@ Lovett Software Copyright © Lovett Software - 1.0.8 - 1.0.8 - 1.0.8 + 1.1.0 + 1.1.0 + 1.1.0 \ No newline at end of file diff --git a/src/Common/version.txt b/src/Common/version.txt index 337a6a8..1cc5f65 100644 --- a/src/Common/version.txt +++ b/src/Common/version.txt @@ -1 +1 @@ -1.0.8 \ No newline at end of file +1.1.0 \ No newline at end of file diff --git a/src/UnitTests/UnitTest1.cs b/src/UnitTests/UnitTest1.cs index 507bf47..3261186 100644 --- a/src/UnitTests/UnitTest1.cs +++ b/src/UnitTests/UnitTest1.cs @@ -79,6 +79,27 @@ public void SideBySideDiffView() } } + [Fact] + public void SideBySideDiffViewCompact() + { + using (var col = new TempFileCollection()) + { + var xmlSource = col.CreateTempFile(""); + var xmlChanged = col.CreateTempFile(""); + + var view = new XmlDiffView(); + var options = XmlDiffOptions.IgnoreChildOrder | XmlDiffOptions.IgnoreWhitespace; + var results = view.DifferencesSideBySideAsHtml(xmlSource, xmlChanged, false, options, true); + + var diff = results.ReadToEnd(); + Assert.Contains("root", diff); + Assert.Contains("banana", diff); + Assert.Contains("<temp", diff); + Assert.DoesNotContain("apple", diff); + Assert.DoesNotContain("elephant", diff); + } + } + private string ToComparibleString(XmlDocument doc) { // avoid comparing the hash. diff --git a/src/XmlDiffView/XmlDiff.nuspec b/src/XmlDiffView/XmlDiff.nuspec index 085ca38..1a0a980 100644 --- a/src/XmlDiffView/XmlDiff.nuspec +++ b/src/XmlDiffView/XmlDiff.nuspec @@ -2,7 +2,7 @@ LovettSoftware.XmlDiff - 1.0.9 + 1.1.0 Chris Lovett A library that compares and merges XML files. https://github.com/lovettchris/xmldiff diff --git a/src/XmlDiffView/XmlDiffView.cs b/src/XmlDiffView/XmlDiffView.cs index 66e26bd..e5b7eff 100644 --- a/src/XmlDiffView/XmlDiffView.cs +++ b/src/XmlDiffView/XmlDiffView.cs @@ -425,13 +425,15 @@ public XmlDiffViewResults DifferencesAsFormattedText( /// the html output file /// the file is only an Xml fragment /// comparison filtering options + /// omit html output for identical xml elements /// Differences were not found after filtering. public bool DifferencesSideBySideAsHtml( string sourceXmlFile, string changedXmlFile, string resultHtmlViewFile, bool fragment, - XmlDiffOptions options) + XmlDiffOptions options, + bool omitIdenticalHtmlOutput = false) { bool identicalData = this.DifferencesSideBySideAsHtml( sourceXmlFile, @@ -439,7 +441,8 @@ public bool DifferencesSideBySideAsHtml( resultHtmlViewFile, fragment, true, - options); + options, + omitIdenticalHtmlOutput); return identicalData; } @@ -453,6 +456,7 @@ public bool DifferencesSideBySideAsHtml( /// the file is only an Xml fragment /// Append to existing output file /// comparison filtering options + /// omit html output for identical xml elements /// Differences were not found after filtering. public bool DifferencesSideBySideAsHtml( string sourceXmlFile, @@ -460,7 +464,8 @@ public bool DifferencesSideBySideAsHtml( string resultHtmlViewFile, bool fragment, bool appendToOutputFile, - XmlDiffOptions options) + XmlDiffOptions options, + bool omitIdenticalHtmlOutput = false) { // Append to the specified output file. FileMode mode; @@ -481,11 +486,12 @@ public bool DifferencesSideBySideAsHtml( bool identicalData; try { - identicalData = this.DifferencesSideBySideAsHtml( + identicalData = this.InternalDifferencesSideBySideAsHtml( sourceXmlFile, changedXmlFile, fragment, options, + omitIdenticalHtmlOutput, this.outputData); } finally @@ -503,12 +509,14 @@ public bool DifferencesSideBySideAsHtml( /// the actual (or target) file /// the file is only an Xml fragment /// comparison filtering options + /// omit html output for identical xml elements /// Differences were not found after filtering. public XmlDiffViewResults DifferencesSideBySideAsHtml( string sourceXmlFile, string changedXmlFile, bool fragment, - XmlDiffOptions options) + XmlDiffOptions options, + bool omitIdenticalHtmlOutput = false) { MemoryStream data = new MemoryStream(); @@ -521,11 +529,12 @@ public XmlDiffViewResults DifferencesSideBySideAsHtml( bool identicalData = false; try { - identicalData = this.DifferencesSideBySideAsHtml( + identicalData = this.InternalDifferencesSideBySideAsHtml( sourceXmlFile, changedXmlFile, fragment, options, + omitIdenticalHtmlOutput, this.outputData); } @@ -556,12 +565,18 @@ public XmlDiffViewResults DifferencesSideBySideAsHtml( /// TextWriter object (which may be a file). /// /// Data stream for output - public void GetHtml(TextWriter htmlOutput, bool omitMatches = false) + /// Omit matching lines to compress the size of the HTML output + /// HTML indent to show in points - default is padding-left: 10pt; + public void GetHtml(TextWriter htmlOutput, bool omitMatches = false, int indentPoints = 10) { LastVisitedOpId = 0; XmlDiffViewNode.ResetLineNumbers(); XmlTextWriter writer = new XmlTextWriter(htmlOutput); - this.viewDocument.DrawHtml(writer, 10, new XmlDiffViewRenderState { OmitMatches = omitMatches }); + if (omitMatches) + { + this.viewDocument.PruneMatchingElements(); + } + this.viewDocument.DrawHtml(writer, indentPoints); } #endregion @@ -907,13 +922,15 @@ private bool GetDifferencesAsFormattedText( /// actual file /// xml data fragment /// Comparison options + /// omit html output for identical xml elements /// output data /// data is identical - private bool DifferencesSideBySideAsHtml( + private bool InternalDifferencesSideBySideAsHtml( string sourceXmlFile, string changedXmlFile, bool fragment, XmlDiffOptions options, + bool omitIdenticalHtmlOutput, TextWriter resultHtml) { bool identicalData = this.MarkupBaselineWithChanges( @@ -929,7 +946,7 @@ private bool DifferencesSideBySideAsHtml( identicalData, resultHtml); - this.GetHtml(resultHtml); + this.GetHtml(resultHtml, omitIdenticalHtmlOutput); this.SideBySideHtmlFooter(resultHtml); diff --git a/src/XmlDiffView/XmlDiffViewAttribute.cs b/src/XmlDiffView/XmlDiffViewAttribute.cs index 21d0a52..9a52b32 100644 --- a/src/XmlDiffView/XmlDiffViewAttribute.cs +++ b/src/XmlDiffView/XmlDiffViewAttribute.cs @@ -249,7 +249,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// output stream /// size of indent [Obsolete("This method should never be called", true)] - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { throw new Exception("This method should never be called."); } diff --git a/src/XmlDiffView/XmlDiffViewCharData.cs b/src/XmlDiffView/XmlDiffViewCharData.cs index f5b3531..fa889de 100644 --- a/src/XmlDiffView/XmlDiffViewCharData.cs +++ b/src/XmlDiffView/XmlDiffViewCharData.cs @@ -122,7 +122,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output stream /// number of indentations - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { if (Operation == XmlDiffViewOperation.Change) { diff --git a/src/XmlDiffView/XmlDiffViewDocument.cs b/src/XmlDiffView/XmlDiffViewDocument.cs index 81a6724..bf1b9ba 100644 --- a/src/XmlDiffView/XmlDiffViewDocument.cs +++ b/src/XmlDiffView/XmlDiffViewDocument.cs @@ -78,9 +78,9 @@ internal override XmlDiffViewNode Clone(bool deep) /// output stream /// number of indentations /// - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { - HtmlDrawChildNodes(writer, indent, renderState); + HtmlDrawChildNodes(writer, indent); } /// diff --git a/src/XmlDiffView/XmlDiffViewDocumentType.cs b/src/XmlDiffView/XmlDiffViewDocumentType.cs index 638ae30..fa84f3e 100644 --- a/src/XmlDiffView/XmlDiffViewDocumentType.cs +++ b/src/XmlDiffView/XmlDiffViewDocumentType.cs @@ -183,7 +183,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output stream /// number of indentations - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { if (Operation == XmlDiffViewOperation.Change) { diff --git a/src/XmlDiffView/XmlDiffViewER.cs b/src/XmlDiffView/XmlDiffViewER.cs index c34d7a2..296d2d1 100644 --- a/src/XmlDiffView/XmlDiffViewER.cs +++ b/src/XmlDiffView/XmlDiffViewER.cs @@ -78,7 +78,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output data stream /// size of indentation - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { if (Operation == XmlDiffViewOperation.Change) { diff --git a/src/XmlDiffView/XmlDiffViewElement.cs b/src/XmlDiffView/XmlDiffViewElement.cs index 56a2fb9..e32d248 100644 --- a/src/XmlDiffView/XmlDiffViewElement.cs +++ b/src/XmlDiffView/XmlDiffViewElement.cs @@ -165,10 +165,12 @@ public string Name } } + public bool HideAttributes { get; internal set; } + #endregion - + #region Methods section - + /// /// Gets an attribute object for the specified attribute name. /// @@ -276,23 +278,8 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output stream /// number of indentations - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { - if (renderState.OmitMatches) - { - if (IsDescendentAndSelfMatch(this)) - { - if (!renderState.InOmissionBlock) - { - XmlDiffView.HtmlOmissionBlock(writer); - renderState.InOmissionBlock = true; - } - return; - } - - renderState.InOmissionBlock = false; - } - XmlDiffViewOperation typeOfDifference = Operation; bool closeElement = false; XmlDiffView.HtmlStartRow(writer); @@ -373,7 +360,7 @@ internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderS // child nodes if (ChildNodes != null) { - HtmlDrawChildNodes(writer, indent + XmlDiffView.DeltaIndent, renderState); + HtmlDrawChildNodes(writer, indent + XmlDiffView.DeltaIndent); // end element XmlDiffView.HtmlStartRow(writer); @@ -431,37 +418,6 @@ internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderS } } - /// - /// Return true if node and all descendents are unchanged - /// - private static bool IsDescendentAndSelfMatch(XmlDiffViewNode node, bool rootNode = true) - { - while (true) - { - if (node.Operation != XmlDiffViewOperation.Match) - { - return false; - } - - if (node is XmlDiffViewElement element && element.Attributes != null && !IsDescendentAndSelfMatch(element.Attributes, false)) - { - return false; - } - - if (node.FirstChildNode != null && !IsDescendentAndSelfMatch(node.FirstChildNode, false)) - { - return false; - } - - if (node.NextSibling == null || rootNode) - { - return true; - } - - node = node.NextSibling; - } - } - /// /// Generates output data in text form /// @@ -567,6 +523,12 @@ private void DrawHtmlAttributes( { return; } + if (this.HideAttributes) + { + writer.WriteString(" "); + writer.WriteCharEntity('\u2026'); + return; + } string attrIndent = string.Empty; if (this.Attributes.NextSibling != null) { diff --git a/src/XmlDiffView/XmlDiffViewNode.cs b/src/XmlDiffView/XmlDiffViewNode.cs index e869c33..aa118bb 100644 --- a/src/XmlDiffView/XmlDiffViewNode.cs +++ b/src/XmlDiffView/XmlDiffViewNode.cs @@ -189,6 +189,11 @@ public XmlDiffViewOperation Operation this.operation = value; } } + + /// + /// This change is to be hidden from the rendered output. + /// + public bool Hidden { get; set; } /// /// Gets or sets the difference identifier number @@ -251,8 +256,7 @@ public void DrawTextNoChange( /// /// data stream /// size of indentation - /// options and and additional state management for rendering - internal abstract void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState); + internal abstract void DrawHtml(XmlWriter writer, int indent); /// /// Abstract method to generate text output data diff --git a/src/XmlDiffView/XmlDiffViewPI.cs b/src/XmlDiffView/XmlDiffViewPI.cs index 9616e6a..e2a96bb 100644 --- a/src/XmlDiffView/XmlDiffViewPI.cs +++ b/src/XmlDiffView/XmlDiffViewPI.cs @@ -101,7 +101,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output data stream /// size of indentation - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { if (Operation == XmlDiffViewOperation.Change) { diff --git a/src/XmlDiffView/XmlDiffViewParentNode.cs b/src/XmlDiffView/XmlDiffViewParentNode.cs index 06e0ac1..0658bd2 100644 --- a/src/XmlDiffView/XmlDiffViewParentNode.cs +++ b/src/XmlDiffView/XmlDiffViewParentNode.cs @@ -19,6 +19,7 @@ namespace Microsoft.XmlDiffPatch using System.Xml; using System.IO; using System.Diagnostics; + using System.Runtime.CompilerServices; /// /// Class to access the parent node object and its child node objects. @@ -203,14 +204,99 @@ internal void InsertChildAfter( /// /// output stream /// number of indentations - internal void HtmlDrawChildNodes(XmlWriter writer, int indent, XmlDiffViewRenderState xmlDiffViewRenderState) + internal void HtmlDrawChildNodes(XmlWriter writer, int indent) { XmlDiffViewNode curChild = this.ChildNodes; + bool hasHidden = false; + bool hasVisible = false; while (curChild != null) { - curChild.DrawHtml(writer, indent, xmlDiffViewRenderState); + if (curChild.Hidden) + { + // consolidate adjacent hidden nodes into one elipsis. + hasHidden = true; + } + else + { + if (hasHidden) + { + WriteEllipsisRow(writer, indent); + hasHidden = false; + } + hasVisible = true; + curChild.DrawHtml(writer, indent); + } curChild = curChild.NextSibling; } + if (hasVisible && hasHidden) + { + WriteEllipsisRow(writer, indent); + } + } + + internal void WriteEllipsisRow(XmlWriter writer, int indent) + { + XmlDiffView.HtmlStartRow(writer); + this.DrawLineNumber(writer); + XmlDiffView.HtmlStartCell(writer, indent); + writer.WriteCharEntity('\u2026'); + XmlDiffView.HtmlEndCell(writer); + XmlDiffView.HtmlStartCell(writer, indent); + writer.WriteCharEntity('\u2026'); + XmlDiffView.HtmlEndCell(writer); + XmlDiffView.HtmlEndRow(writer); + } + + public bool PruneMatchingElements() + { + // XmlDiffView.HtmlOmissionBlock(writer); + bool pruned = true; + XmlDiffViewNode node = this.ChildNodes; + while (node != null) + { + var hidden = true; + if (node.Operation != XmlDiffViewOperation.Match) + { + hidden = false; + } + else if (node is XmlDiffViewElement element && element.Attributes != null) + { + bool foundChangedAttribute = false; + XmlDiffViewNode a = element.Attributes; + while (a != null) + { + if (a.Operation != XmlDiffViewOperation.Match) + { + hidden = false; + foundChangedAttribute = true; + break; + } + a = a.NextSibling; + } + + if (!foundChangedAttribute) + { + element.HideAttributes = true; + } + } + + if (node is XmlDiffViewParentNode container) + { + if (!container.PruneMatchingElements()) + { + hidden = false; // have to show this element then + } + } + + node.Hidden = hidden; + node = node.NextSibling; + if (!hidden) + { + // then pass this up the tree. + pruned = false; + } + } + return pruned; } /// diff --git a/src/XmlDiffView/XmlDiffViewRenderState.cs b/src/XmlDiffView/XmlDiffViewRenderState.cs deleted file mode 100644 index 7759f38..0000000 --- a/src/XmlDiffView/XmlDiffViewRenderState.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Microsoft.XmlDiffPatch -{ - internal class XmlDiffViewRenderState - { - public bool OmitMatches { get; set; } - public bool InOmissionBlock { get; set; } - } -} \ No newline at end of file diff --git a/src/XmlDiffView/XmlDiffViewXmlDeclaration.cs b/src/XmlDiffView/XmlDiffViewXmlDeclaration.cs index 072dd52..dc135e7 100644 --- a/src/XmlDiffView/XmlDiffViewXmlDeclaration.cs +++ b/src/XmlDiffView/XmlDiffViewXmlDeclaration.cs @@ -76,7 +76,7 @@ internal override XmlDiffViewNode Clone(bool deep) /// /// output stream /// number of indentations - internal override void DrawHtml(XmlWriter writer, int indent, XmlDiffViewRenderState renderState) + internal override void DrawHtml(XmlWriter writer, int indent) { if (Operation == XmlDiffViewOperation.Change) {