using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Aspose.App.Models; using Aspose.Html; using Tools.Foundation.Models; namespace Aspose.App.Controllers { internal class AsposeHtmlComparisonController : ApiControllerBase { public async Task Compare(string fileName1, string fileName2, string folderName) { Aspose.App.Models.License.SetAsposeHtmlLicense(); var comparedDocument = string.Format("{0}_compare_to_{1}.html", Path.GetFileNameWithoutExtension(fileName1), Path.GetFileNameWithoutExtension(fileName2)); return await Process(this.GetType().Name, comparedDocument, folderName, ".html", false, false, AsposeHTML + ComparisonApp, ProductFamilyNameKeysEnum.html, "Compare", (inFilePath, outPath, zipOutFolder) => { var tc1 = GetTextContent(AppSettings.WorkingDirectory + folderName + "/" + fileName1); var tc2 = GetTextContent(AppSettings.WorkingDirectory + folderName + "/" + fileName2); var count = Math.Min(tc1.Count, tc2.Count); var result = new Aspose.Html.HTMLDocument(); for (int i = 0; i < count; i++) { var originalStr = tc1[i].Trim(); var modifiedStr = tc2[i].Trim(); var changes = Levenshtein3(originalStr, modifiedStr); var modifications = new System.Collections.Generic.List(); int pos1 = 0, pos2 = 0; var current = new Modification { Status = changes.route[0] }; for (int ii = 0; ii < changes.route.Length; ii++) { var status = changes.route[ii]; char symbol = ' '; if (changes.route[ii] == '=') { symbol = originalStr[pos1++]; pos2++; } if (changes.route[ii] == 'I') { symbol = modifiedStr[pos2++]; } if (changes.route[ii] == 'D') { symbol = originalStr[pos1++]; pos2++; } if (changes.route[ii] == 'R') { symbol = modifiedStr[pos2++]; pos1++; } if (current.Status == status) { current.Value += symbol; } else { modifications.Add(current); current = new Modification { Status = status, Value = symbol.ToString() }; } } modifications.Add(current); var sb = new System.Text.StringBuilder(); foreach (var item in modifications) { switch (item.Status) { case '=': sb.AppendFormat("{0}", item.Value); break; case 'I': sb.AppendFormat("{0}", item.Value); break; case 'R': sb.AppendFormat("{0}", item.Value); break; case 'D': sb.AppendFormat("{0}", item.Value); break; default: break; } } result.Body.InnerHTML += sb.ToString(); } result.Save(outPath); }); } private static List GetTextContent(string fileName) { var document = new HTMLDocument(System.IO.File.ReadAllText(fileName), string.Empty); var scriptsElements = document.GetElementsByTagName("script"); foreach (var element in scriptsElements) { element.TextContent = string.Empty; } var styleElements = document.GetElementsByTagName("style"); foreach (var element in styleElements) { element.TextContent = string.Empty; } var textFragments = new List(); foreach (var element in document.Children) { textFragments.Add(element.TextContent); } return textFragments; } private static Prescription Levenshtein3(string S1, string S2) { int m = S1.Length, n = S2.Length; int h = (int)Math.Sqrt(m + 1); int[,] D = new int[h + 1, n + 1]; char[,] P = new char[h + 1, n + 1]; int d = 0; var route = new System.Text.StringBuilder(); int iPos = m, jPos = n; do { for (int i = 0; i <= jPos; i++) { D[0, i] = i; P[0, i] = 'I'; } int index = 1; for (int i = 1; i <= iPos; i++) { for (int j = 0; j <= jPos; j++) { if (j == 0) D[index, j] = i; else { int cost = (S1[i - 1] != S2[j - 1]) ? 1 : 0; if (D[index, j - 1] < D[index - 1, j] && D[index, j - 1] < D[index - 1, j - 1] + cost) { //Insert D[index, j] = D[index, j - 1] + 1; P[index, j] = 'I'; } else if (D[index - 1, j] < D[index - 1, j - 1] + cost) { //Remove D[index, j] = D[index - 1, j] + 1; P[index, j] = 'D'; } else { //Replace or no ops D[index, j] = D[index - 1, j - 1] + cost; P[index, j] = (cost == 1) ? 'R' : '='; } } } if (i % h == 0) { //Allocate of memory for new lines and copying the last from the previous band to the first line of the new int[] vRow = new int[n + 1]; char[] cRow = new char[n + 1]; for (int j = 0; j <= n; j++) { vRow[j] = D[index, j]; cRow[j] = P[index, j]; } D = new int[h + 1, n + 1]; P = new char[h + 1, n + 1]; for (int j = 0; j <= n; j++) { D[0, j] = vRow[j]; P[0, j] = cRow[j]; } index = 0; } index++; } if (iPos == m && jPos == n) d = D[index - 1, n]; //Restore prescriptions in the last _i - 1 lines while (index > 0 && iPos != 0 && jPos != 0) { char c = P[index - 1, jPos]; route.Append(c); if (c == 'R' || c == '=') { iPos--; jPos--; index--; } else if (c == 'D') { iPos--; index--; } else { jPos--; } } } while ((iPos != 0) && (jPos != 0)); return new Prescription(d, string.Join(string.Empty, route.ToString().ToCharArray().Reverse())); } } internal class Prescription { public string route; public int distance; public Prescription(int distance, string route) { this.distance = distance; this.route = route; } } internal class Modification { public char Status; public string Value; } }