|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在ASP.NET开发中,处理HTML输出并将其转换为纯文本输出是一个常见且重要的需求。这种转换在多种场景下都非常有用,例如生成邮件内容、创建RSS订阅、导出数据为文本格式、搜索引擎优化等。本文将全面探讨C# ASPX开发中HTML输出转文本输出的核心技术,从基础实现原理到高级应用场景,以及安全处理、性能优化和最佳实践,为开发人员提供全方位的指南。
基础实现原理
ASPX页面的生命周期
ASPX页面有一个复杂的生命周期,包括初始化、加载视图状态、处理回发事件、呈现等阶段。在呈现阶段,ASPX将服务器控件转换为HTML,然后发送到客户端浏览器。理解这一生命周期对于掌握HTML到文本的转换至关重要。
- // ASPX页面生命周期示例
- public partial class ExamplePage : System.Web.UI.Page
- {
- protected void Page_Init(object sender, EventArgs e)
- {
- // 初始化阶段
- }
-
- protected void Page_Load(object sender, EventArgs e)
- {
- // 加载阶段
- }
-
- protected void Page_PreRender(object sender, EventArgs e)
- {
- // 预呈现阶段
- }
-
- protected void Page_Render(object sender, EventArgs e)
- {
- // 呈现阶段 - HTML在此阶段生成
- }
-
- protected void Page_Unload(object sender, EventArgs e)
- {
- // 卸载阶段
- }
- }
复制代码
HTML和文本输出的区别
HTML输出包含标签、属性和其他HTML特定元素,而文本输出则是纯文本内容,不包含任何HTML标记。将HTML转换为文本需要去除所有HTML标记,只保留标签之间的文本内容。
例如:
• HTML输出:<p>这是一个<strong>重要</strong>的段落。</p>
• 文本输出:这是一个重要的段落。
基本转换原理
HTML到文本的转换基本原理是解析HTML内容,识别并移除HTML标签,同时保留标签之间的文本内容。这可以通过正则表达式、HTML解析器或专门的库来实现。
核心技术详解
使用正则表达式
正则表达式是一种简单但功能强大的方法,用于从HTML中提取文本内容。
- using System.Text.RegularExpressions;
- public static string HtmlToTextUsingRegex(string html)
- {
- // 移除HTML标签
- string text = Regex.Replace(html, "<[^>]*(>|$)", string.Empty);
-
- // 解码HTML实体
- text = HttpUtility.HtmlDecode(text);
-
- // 规范化空白字符
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
复制代码
这种方法的优点是简单直接,不需要额外的库。但是,正则表达式可能无法正确处理复杂的HTML结构,尤其是嵌套标签或包含特殊字符的HTML。
使用HtmlAgilityPack
HtmlAgilityPack是一个流行的.NET HTML解析器,它提供了更可靠的方式来处理HTML内容。
首先,需要安装NuGet包:
- Install-Package HtmlAgilityPack
复制代码
然后使用以下代码:
- using HtmlAgilityPack;
- public static string HtmlToTextUsingHtmlAgilityPack(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- // 使用XPath选择所有文本节点
- var textNodes = htmlDoc.DocumentNode.SelectNodes("//text()");
-
- if (textNodes == null)
- {
- return string.Empty;
- }
-
- // 连接所有文本节点
- var text = string.Join(" ", textNodes.Select(node => node.InnerText.Trim()));
-
- // 规范化空白字符
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
复制代码
HtmlAgilityPack能够更好地处理复杂的HTML结构,包括格式不正确的HTML。它还提供了XPath查询功能,可以更精确地选择需要的文本内容。
使用AngleSharp
AngleSharp是另一个强大的HTML解析库,它提供了符合现代标准的HTML解析能力。
首先,安装NuGet包:
- Install-Package AngleSharp
复制代码
然后使用以下代码:
- using AngleSharp;
- using AngleSharp.Dom;
- using AngleSharp.Html.Parser;
- public static string HtmlToTextUsingAngleSharp(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 创建HTML解析器
- var parser = new HtmlParser();
- var document = parser.ParseDocument(html);
-
- // 获取文档的文本内容
- var text = document.TextContent;
-
- // 规范化空白字符
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
复制代码
AngleSharp提供了更现代的HTML解析能力,支持HTML5标准,并且可以更好地处理复杂的HTML文档。
使用WebBrowser控件
在某些情况下,可以使用WebBrowser控件来渲染HTML,然后提取文本内容。
- using System.Windows.Forms;
- using System.Threading;
- public static string HtmlToTextUsingWebBrowser(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- string text = string.Empty;
-
- // 创建WebBrowser控件
- var webBrowser = new WebBrowser();
-
- // 设置文档文本
- webBrowser.DocumentText = html;
-
- // 等待文档加载完成
- while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
- {
- Application.DoEvents();
- Thread.Sleep(100);
- }
-
- // 获取文档的文本内容
- text = webBrowser.Document.Body.InnerText;
-
- // 规范化空白字符
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- // 释放资源
- webBrowser.Dispose();
-
- return text;
- }
复制代码
这种方法可以很好地处理复杂的HTML,包括JavaScript生成的内容,但它的性能较差,并且需要STA线程,不适合在服务器端应用程序中使用。
使用.NET内置的HttpUtility类
.NET框架提供了HttpUtility类,其中包含一些处理HTML的方法。
- using System.Web;
- public static string HtmlToTextUsingHttpUtility(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 使用正则表达式移除HTML标签
- string text = Regex.Replace(html, "<[^>]*(>|$)", string.Empty);
-
- // 解码HTML实体
- text = HttpUtility.HtmlDecode(text);
-
- // 规范化空白字符
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
复制代码
这种方法简单直接,但与使用正则表达式的方法类似,可能无法正确处理复杂的HTML结构。
高级应用场景
从网页提取内容用于搜索引擎优化
在SEO中,有时需要从网页中提取纯文本内容,以便搜索引擎更好地理解和索引页面内容。
- using HtmlAgilityPack;
- public static string ExtractContentForSEO(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- // 移除不需要的元素,如脚本、样式、导航等
- var nodesToRemove = htmlDoc.DocumentNode.SelectNodes("//script|//style|//nav|//header|//footer");
- if (nodesToRemove != null)
- {
- foreach (var node in nodesToRemove)
- {
- node.Remove();
- }
- }
-
- // 获取主要内容区域的文本
- var contentNode = htmlDoc.DocumentNode.SelectSingleNode("//main|//article|//*[@id='content']|//*[@class='content']");
- if (contentNode != null)
- {
- return contentNode.InnerText.Trim();
- }
-
- // 如果找不到主要内容区域,则返回body的文本
- var bodyNode = htmlDoc.DocumentNode.SelectSingleNode("//body");
- return bodyNode?.InnerText.Trim() ?? string.Empty;
- }
复制代码
生成邮件纯文本版本
发送HTML邮件时,通常还需要提供一个纯文本版本作为备选。
- using HtmlAgilityPack;
- using System.Text;
- public static string GeneratePlainTextEmail(string htmlEmail)
- {
- if (string.IsNullOrEmpty(htmlEmail))
- {
- return string.Empty;
- }
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(htmlEmail);
-
- // 创建一个StringBuilder来存储纯文本内容
- var sb = new StringBuilder();
-
- // 处理标题
- var titleNode = htmlDoc.DocumentNode.SelectSingleNode("//title");
- if (titleNode != null)
- {
- sb.AppendLine(titleNode.InnerText);
- sb.AppendLine(new string('-', titleNode.InnerText.Length));
- sb.AppendLine();
- }
-
- // 处理链接
- var linkNodes = htmlDoc.DocumentNode.SelectNodes("//a[@href]");
- if (linkNodes != null)
- {
- foreach (var linkNode in linkNodes)
- {
- string linkText = linkNode.InnerText.Trim();
- string linkUrl = linkNode.GetAttributeValue("href", "");
-
- if (!string.IsNullOrEmpty(linkText) && !string.IsNullOrEmpty(linkUrl))
- {
- sb.AppendLine($"{linkText}: {linkUrl}");
- }
- }
- sb.AppendLine();
- }
-
- // 处理段落
- var paragraphNodes = htmlDoc.DocumentNode.SelectNodes("//p");
- if (paragraphNodes != null)
- {
- foreach (var pNode in paragraphNodes)
- {
- string paragraphText = pNode.InnerText.Trim();
- if (!string.IsNullOrEmpty(paragraphText))
- {
- sb.AppendLine(paragraphText);
- sb.AppendLine();
- }
- }
- }
-
- // 处理列表
- var listNodes = htmlDoc.DocumentNode.SelectNodes("//ul|//ol");
- if (listNodes != null)
- {
- foreach (var listNode in listNodes)
- {
- bool isOrdered = listNode.Name == "ol";
- int counter = 1;
-
- var listItemNodes = listNode.SelectNodes("./li");
- if (listItemNodes != null)
- {
- foreach (var liNode in listItemNodes)
- {
- string itemText = liNode.InnerText.Trim();
- if (!string.IsNullOrEmpty(itemText))
- {
- if (isOrdered)
- {
- sb.AppendLine($"{counter++}. {itemText}");
- }
- else
- {
- sb.AppendLine($"• {itemText}");
- }
- }
- }
- sb.AppendLine();
- }
- }
- }
-
- return sb.ToString().Trim();
- }
复制代码
从HTML生成RSS订阅内容
RSS订阅通常需要纯文本内容,而不是HTML。
- using HtmlAgilityPack;
- using System.Xml;
- using System.Text;
- public static string GenerateRssContentFromHtml(string html, string title, string link, string description)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 提取纯文本内容
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- // 移除不需要的元素
- var nodesToRemove = htmlDoc.DocumentNode.SelectNodes("//script|//style|//nav|//header|//footer");
- if (nodesToRemove != null)
- {
- foreach (var node in nodesToRemove)
- {
- node.Remove();
- }
- }
-
- // 获取主要内容
- string content = htmlDoc.DocumentNode.InnerText.Trim();
-
- // 限制内容长度
- if (content.Length > 500)
- {
- content = content.Substring(0, 500) + "...";
- }
-
- // 创建RSS XML
- var sb = new StringBuilder();
- using (var writer = XmlWriter.Create(sb, new XmlWriterSettings { Indent = true }))
- {
- writer.WriteStartElement("rss");
- writer.WriteAttributeString("version", "2.0");
-
- writer.WriteStartElement("channel");
-
- writer.WriteElementString("title", title);
- writer.WriteElementString("link", link);
- writer.WriteElementString("description", description);
- writer.WriteElementString("pubDate", DateTime.Now.ToString("r"));
-
- writer.WriteStartElement("item");
- writer.WriteElementString("title", title);
- writer.WriteElementString("link", link);
- writer.WriteElementString("description", content);
- writer.WriteElementString("pubDate", DateTime.Now.ToString("r"));
- writer.WriteEndElement(); // item
-
- writer.WriteEndElement(); // channel
- writer.WriteEndElement(); // rss
- }
-
- return sb.ToString();
- }
复制代码
生成PDF文档的文本内容
在生成PDF文档时,通常需要从HTML中提取纯文本内容。
- using HtmlAgilityPack;
- using iTextSharp.text;
- using iTextSharp.text.pdf;
- using System.IO;
- public static byte[] GeneratePdfFromHtml(string html, string title)
- {
- if (string.IsNullOrEmpty(html))
- {
- return null;
- }
- // 提取纯文本内容
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- string text = htmlDoc.DocumentNode.InnerText.Trim();
-
- // 创建PDF文档
- using (var memoryStream = new MemoryStream())
- {
- var document = new Document(PageSize.A4);
- PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
- document.Open();
-
- // 添加标题
- var titleFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 16);
- document.Add(new Paragraph(title, titleFont));
- document.Add(new Paragraph(" "));
-
- // 添加内容
- var contentFont = FontFactory.GetFont(FontFactory.HELVETICA, 12);
- document.Add(new Paragraph(text, contentFont));
-
- document.Close();
- writer.Close();
-
- return memoryStream.ToArray();
- }
- }
复制代码
安全处理
防止XSS攻击
在处理HTML内容时,需要防止XSS(跨站脚本)攻击。即使我们只是提取文本内容,也应该确保输入是安全的。
- using System.Web;
- public static string SanitizeHtmlInput(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 使用AntiXSS库来清理HTML输入
- // 需要安装NuGet包: Install-Package AntiXSS
- var sanitizedHtml = Microsoft.Security.Application.Sanitizer.GetSafeHtmlFragment(html);
-
- return sanitizedHtml;
- }
- public static string SafeHtmlToText(string html)
- {
- // 首先清理HTML输入
- string sanitizedHtml = SanitizeHtmlInput(html);
-
- // 然后转换为文本
- return HtmlToTextUsingHtmlAgilityPack(sanitizedHtml);
- }
复制代码
处理HTML实体
在转换HTML为文本时,需要正确处理HTML实体,如、<、>等。
- using System.Web;
- public static string DecodeHtmlEntities(string text)
- {
- if (string.IsNullOrEmpty(text))
- {
- return string.Empty;
- }
- // 使用HttpUtility.HtmlDecode来解码HTML实体
- return HttpUtility.HtmlDecode(text);
- }
- public static string HtmlToTextWithEntityDecoding(string html)
- {
- // 首先转换为文本
- string text = HtmlToTextUsingHtmlAgilityPack(html);
-
- // 然后解码HTML实体
- return DecodeHtmlEntities(text);
- }
复制代码
防止信息泄露
在处理用户提供的HTML内容时,需要防止敏感信息泄露。
- using System.Text.RegularExpressions;
- public static string RemoveSensitiveInformation(string text)
- {
- if (string.IsNullOrEmpty(text))
- {
- return string.Empty;
- }
- // 移除电子邮件地址
- text = Regex.Replace(text, @"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", "[EMAIL REMOVED]", RegexOptions.IgnoreCase);
-
- // 移除电话号码
- text = Regex.Replace(text, @"\b\d{3}[-.\s]?\d{3}[-.\s]?\d{4}\b", "[PHONE REMOVED]");
-
- // 移除信用卡号
- text = Regex.Replace(text, @"\b\d{4}[-.\s]?\d{4}[-.\s]?\d{4}[-.\s]?\d{4}\b", "[CREDIT CARD REMOVED]");
-
- // 移除社会安全号码
- text = Regex.Replace(text, @"\b\d{3}[-.\s]?\d{2}[-.\s]?\d{4}\b", "[SSN REMOVED]");
-
- return text;
- }
- public static string SafeHtmlToTextWithPrivacyProtection(string html)
- {
- // 首先转换为文本
- string text = HtmlToTextUsingHtmlAgilityPack(html);
-
- // 然后解码HTML实体
- text = DecodeHtmlEntities(text);
-
- // 最后移除敏感信息
- return RemoveSensitiveInformation(text);
- }
复制代码
性能优化
使用缓存
对于频繁转换的HTML内容,可以使用缓存来提高性能。
- using System.Runtime.Caching;
- public static string CachedHtmlToText(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 创建缓存键
- string cacheKey = $"HtmlToText_{html.GetHashCode()}";
-
- // 尝试从缓存中获取结果
- var cache = MemoryCache.Default;
- if (cache.Contains(cacheKey))
- {
- return (string)cache.Get(cacheKey);
- }
-
- // 如果不在缓存中,则进行转换
- string text = HtmlToTextUsingHtmlAgilityPack(html);
-
- // 将结果添加到缓存,设置过期时间为1小时
- var policy = new CacheItemPolicy
- {
- AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
- };
- cache.Set(cacheKey, text, policy);
-
- return text;
- }
复制代码
异步处理
对于大量HTML内容的转换,可以使用异步处理来提高性能。
- using System.Threading.Tasks;
- public static async Task<string> HtmlToTextAsync(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return await Task.FromResult(string.Empty);
- }
- return await Task.Run(() =>
- {
- return HtmlToTextUsingHtmlAgilityPack(html);
- });
- }
- public static async Task<string[]> BatchHtmlToTextAsync(string[] htmlArray)
- {
- if (htmlArray == null || htmlArray.Length == 0)
- {
- return new string[0];
- }
- var tasks = new Task<string>[htmlArray.Length];
-
- for (int i = 0; i < htmlArray.Length; i++)
- {
- tasks[i] = HtmlToTextAsync(htmlArray[i]);
- }
-
- return await Task.WhenAll(tasks);
- }
复制代码
优化正则表达式
正则表达式可能会成为性能瓶颈,特别是在处理大量HTML内容时。
- using System.Text.RegularExpressions;
- public static class HtmlRegexPatterns
- {
- public static readonly Regex HtmlTagRegex = new Regex("<[^>]*(>|$)", RegexOptions.Compiled);
- public static readonly Regex WhitespaceRegex = new Regex("\\s+", RegexOptions.Compiled);
- }
- public static string OptimizedHtmlToTextUsingRegex(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- // 使用预编译的正则表达式
- string text = HtmlRegexPatterns.HtmlTagRegex.Replace(html, string.Empty);
- text = HttpUtility.HtmlDecode(text);
- text = HtmlRegexPatterns.WhitespaceRegex.Replace(text, " ").Trim();
-
- return text;
- }
复制代码
使用StringBuilder处理大文本
对于大型HTML文档,使用StringBuilder可以提高性能。
- using System.Text;
- using HtmlAgilityPack;
- public static string HtmlToTextUsingStringBuilder(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- var sb = new StringBuilder();
-
- // 使用递归处理节点
- ProcessNode(htmlDoc.DocumentNode, sb);
-
- // 规范化空白字符
- string text = sb.ToString();
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
- private static void ProcessNode(HtmlNode node, StringBuilder sb)
- {
- if (node.NodeType == HtmlNodeType.Text)
- {
- sb.Append(node.InnerText);
- }
- else
- {
- foreach (var child in node.ChildNodes)
- {
- ProcessNode(child, sb);
- }
- }
- }
复制代码
最佳实践
选择合适的方法
根据具体需求选择合适的HTML到文本转换方法:
• 对于简单的HTML和性能要求不高的场景,可以使用正则表达式方法。
• 对于复杂的HTML和需要更精确控制的场景,应使用HtmlAgilityPack或AngleSharp。
• 对于需要处理JavaScript生成内容的场景,可以考虑使用WebBrowser控件(但要注意性能限制)。
处理边缘情况
考虑各种边缘情况,如空输入、格式不正确的HTML、包含脚本或样式的HTML等。
- public static string RobustHtmlToText(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- try
- {
- // 清理HTML输入
- string sanitizedHtml = SanitizeHtmlInput(html);
-
- // 转换为文本
- string text = HtmlToTextUsingHtmlAgilityPack(sanitizedHtml);
-
- // 解码HTML实体
- text = DecodeHtmlEntities(text);
-
- // 移除敏感信息
- text = RemoveSensitiveInformation(text);
-
- return text;
- }
- catch (Exception ex)
- {
- // 记录错误
- // Logger.Error("Error converting HTML to text", ex);
-
- // 返回空字符串或原始HTML的简化版本
- return "Error processing content.";
- }
- }
复制代码
遵循单一职责原则
将HTML到文本的转换逻辑封装在单独的类或方法中,遵循单一职责原则。
- public interface IHtmlToTextConverter
- {
- string Convert(string html);
- }
- public class HtmlAgilityPackConverter : IHtmlToTextConverter
- {
- public string Convert(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- var htmlDoc = new HtmlDocument();
- htmlDoc.LoadHtml(html);
-
- var textNodes = htmlDoc.DocumentNode.SelectNodes("//text()");
- if (textNodes == null)
- {
- return string.Empty;
- }
-
- var text = string.Join(" ", textNodes.Select(node => node.InnerText.Trim()));
- text = Regex.Replace(text, "\\s+", " ").Trim();
-
- return text;
- }
- }
- public class HtmlToTextService
- {
- private readonly IHtmlToTextConverter _converter;
-
- public HtmlToTextService(IHtmlToTextConverter converter)
- {
- _converter = converter ?? throw new ArgumentNullException(nameof(converter));
- }
-
- public string ConvertHtmlToText(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
- try
- {
- // 清理HTML输入
- string sanitizedHtml = SanitizeHtmlInput(html);
-
- // 转换为文本
- string text = _converter.Convert(sanitizedHtml);
-
- // 解码HTML实体
- text = DecodeHtmlEntities(text);
-
- // 移除敏感信息
- text = RemoveSensitiveInformation(text);
-
- return text;
- }
- catch (Exception ex)
- {
- // 记录错误
- // Logger.Error("Error converting HTML to text", ex);
-
- // 返回空字符串或原始HTML的简化版本
- return "Error processing content.";
- }
- }
-
- private string SanitizeHtmlInput(string html)
- {
- // 实现清理逻辑
- return Microsoft.Security.Application.Sanitizer.GetSafeHtmlFragment(html);
- }
-
- private string DecodeHtmlEntities(string text)
- {
- // 实现解码逻辑
- return HttpUtility.HtmlDecode(text);
- }
-
- private string RemoveSensitiveInformation(string text)
- {
- // 实现敏感信息移除逻辑
- return text; // 简化示例
- }
- }
复制代码
编写单元测试
为HTML到文本的转换功能编写单元测试,确保其正确性和可靠性。
- using NUnit.Framework;
- using System;
- [TestFixture]
- public class HtmlToTextConverterTests
- {
- private IHtmlToTextConverter _converter;
-
- [SetUp]
- public void Setup()
- {
- _converter = new HtmlAgilityPackConverter();
- }
-
- [Test]
- public void Convert_NullInput_ReturnsEmptyString()
- {
- string result = _converter.Convert(null);
- Assert.AreEqual(string.Empty, result);
- }
-
- [Test]
- public void Convert_EmptyInput_ReturnsEmptyString()
- {
- string result = _converter.Convert(string.Empty);
- Assert.AreEqual(string.Empty, result);
- }
-
- [Test]
- public void Convert_SimpleHtml_ReturnsText()
- {
- string html = "<p>Hello, world!</p>";
- string result = _converter.Convert(html);
- Assert.AreEqual("Hello, world!", result);
- }
-
- [Test]
- public void Convert_ComplexHtml_ReturnsText()
- {
- string html = "<html><head><title>Test</title></head><body><h1>Heading</h1><p>This is a <strong>test</strong> paragraph.</p></body></html>";
- string result = _converter.Convert(html);
- Assert.AreEqual("Test Heading This is a test paragraph.", result);
- }
-
- [Test]
- public void Convert_HtmlWithEntities_DecodesEntities()
- {
- string html = "<p>This is a <test> paragraph.</p>";
- string result = _converter.Convert(html);
- Assert.AreEqual("This is a <test> paragraph.", result);
- }
- }
- [TestFixture]
- public class HtmlToTextServiceTests
- {
- private IHtmlToTextConverter _converterMock;
- private HtmlToTextService _service;
-
- [SetUp]
- public void Setup()
- {
- _converterMock = new MockHtmlToTextConverter();
- _service = new HtmlToTextService(_converterMock);
- }
-
- [Test]
- public void ConvertHtmlToText_NullInput_ReturnsEmptyString()
- {
- string result = _service.ConvertHtmlToText(null);
- Assert.AreEqual(string.Empty, result);
- }
-
- [Test]
- public void ConvertHtmlToText_EmptyInput_ReturnsEmptyString()
- {
- string result = _service.ConvertHtmlToText(string.Empty);
- Assert.AreEqual(string.Empty, result);
- }
-
- [Test]
- public void ConvertHtmlToText_ValidInput_ReturnsConvertedText()
- {
- string html = "<p>Hello, world!</p>";
- string result = _service.ConvertHtmlToText(html);
- Assert.AreEqual("Hello, world!", result);
- }
-
- private class MockHtmlToTextConverter : IHtmlToTextConverter
- {
- public string Convert(string html)
- {
- if (string.IsNullOrEmpty(html))
- {
- return string.Empty;
- }
-
- // 简单的模拟实现
- return html.Replace("<p>", "").Replace("</p>", "").Trim();
- }
- }
- }
复制代码
结论
在C# ASPX开发中,将HTML输出转换为文本输出是一个常见的需求,涉及多种技术和方法。本文从基础实现原理到高级应用场景,以及安全处理、性能优化和最佳实践,全面介绍了HTML到文本转换的核心技术。
通过选择合适的转换方法(如正则表达式、HtmlAgilityPack、AngleSharp等),处理各种边缘情况,遵循最佳实践,并确保安全性和性能,开发人员可以有效地实现HTML到文本的转换功能,满足不同场景的需求。
在实际开发中,应根据具体需求选择合适的方法,并考虑安全性、性能和可维护性等因素。通过封装转换逻辑、编写单元测试和遵循单一职责原则,可以构建可靠、高效的HTML到文本转换解决方案。
希望本文能为ASP.NET开发人员提供有价值的参考,帮助他们更好地理解和应用HTML到文本转换的技术。 |
|