HTMLUtils.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using HtmlAgilityPack;
  6. namespace InABox.Core
  7. {
  8. public static class HTMLUtils
  9. {
  10. /// <summary>
  11. /// Takes a HTML Snippet and converts it to full HTML.
  12. /// This is used to convert Fast-Reports "html-enabled" text to Syncfusion RichTextEditor html.
  13. /// </summary>
  14. /// <param name="text">The html snippet (no <head> or <body> tags, paragraphs represented by line breaks</param>
  15. /// <returns>Properly formed HTM suitable for editing</returns>
  16. public static string TextToHtml(string text)
  17. {
  18. var result = text;
  19. if (!result.Contains("<html>"))
  20. {
  21. var lines = result.Split("\n").Select(l => $"<p>{(string.IsNullOrWhiteSpace(l) ? "&nbsp;" : l)}</p>").ToList();
  22. while (string.Equals(lines.LastOrDefault(),$"<p>&nbsp;</p>"))
  23. lines.RemoveAt(lines.Count-1);
  24. result = $"<html><body>{string.Join("\n",lines)}</body></html>";
  25. }
  26. var doc = new HtmlDocument();
  27. doc.LoadHtml(result);
  28. HtmlNode? head = null;
  29. var htmlnode = doc.DocumentNode.SelectSingleNode("//html");
  30. if (!htmlnode.ChildNodes.Any(x => string.Equals(x.Name, "head", StringComparison.CurrentCultureIgnoreCase)))
  31. {
  32. head = doc.CreateElement("head");
  33. htmlnode.PrependChild(head);
  34. }
  35. head = doc.DocumentNode.SelectSingleNode("//head");
  36. if (head != null)
  37. {
  38. HtmlNode? style = null;
  39. if (!head.ChildNodes.Any(x =>
  40. string.Equals(x.Name, "style", StringComparison.CurrentCultureIgnoreCase)))
  41. {
  42. style = doc.CreateElement("style");
  43. head.PrependChild(style);
  44. }
  45. else
  46. style = head.ChildNodes["style"];
  47. style.InnerHtml = "p { margin: 0px 0px 0px 0px; }";
  48. }
  49. return doc.DocumentNode.OuterHtml;
  50. }
  51. /// <summary>
  52. /// Converts HTML data to Fast-Reports compatible "html-enabled" text
  53. /// Will dump tags that Fast-Reports cannot display
  54. /// </summary>
  55. /// <param name="html">The HTML data to be processed</param>
  56. /// <returns>Text Suitable for printing using Fast-Reports</returns>
  57. public static string HtmlToText(string html)
  58. {
  59. Dictionary<string, string> _replacements = new Dictionary<string, string>()
  60. {
  61. { "\n", "" },
  62. { "\r", "" },
  63. { "<p[^>]*>", "" },
  64. { "</p[^>]*>", "\r\n" },
  65. };
  66. var doc = new HtmlDocument();
  67. doc.LoadHtml(html);
  68. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-style","italic", "i"));
  69. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "text-decoration","underline", "u"));
  70. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-weight","bold", "b"));
  71. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-size","(.*?)", ""));
  72. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "font-family","(.*?)", ""));
  73. ProcessNode(doc.DocumentNode, (n) => ReplaceAttribute(n, "background","(.*?)", ""));
  74. string result = doc.DocumentNode.SelectSingleNode("//body").InnerHtml;
  75. foreach (var _key in _replacements.Keys)
  76. result = Regex.Replace(result, _key, _replacements[_key]);
  77. var lines = result.Split("\r\n").ToList();
  78. while (string.IsNullOrWhiteSpace(lines.LastOrDefault()))
  79. lines.RemoveAt(lines.Count-1);
  80. return string.Join("\r\n", lines);
  81. }
  82. private static void ProcessNode(HtmlNode node, Action<HtmlNode> action)
  83. {
  84. if (node.Name.ToLower() == "span")
  85. action(node);
  86. foreach (var _child in node.ChildNodes)
  87. ProcessNode(_child,action);
  88. }
  89. private static void ReplaceAttribute(HtmlNode node, string attribute, string value, string tag)
  90. {
  91. var _value = $"{attribute}:{value};";
  92. var _style = node.Attributes.Contains("style") ? node.Attributes["style"] : null;
  93. if (_style != null)
  94. {
  95. var _oldvalue = _style.Value;
  96. _style.Value = Regex.Replace(_style.Value, _value, "");
  97. if (!string.Equals(_style.Value, _oldvalue))
  98. {
  99. if (string.IsNullOrWhiteSpace(_style.Value))
  100. node.Attributes.Remove("style");
  101. if (!string.IsNullOrWhiteSpace(tag))
  102. {
  103. var text = node.OuterHtml;
  104. node.Name = tag;
  105. node.Attributes.RemoveAll();
  106. node.InnerHtml = text;
  107. }
  108. }
  109. }
  110. }
  111. }
  112. }