Как конвертировать HTML в текст на C#?
Я ищу код C# для преобразования HTML-документа в обычный текст.
Я не ищу простой тег удаления , но что-то, что будет выводить обычный текст с помощью разумный сохранение оригинального макета.
вывод должен выглядеть так:
Я посмотрел на HTML Agility Pack, но я не думаю, что это то, что мне нужно. У кого-нибудь есть другие предложения?
EDIT: Я просто загружаю HTML Agility Pack из CodePlex, и запустил проект Html2Txt. Какое разочарование (по крайней мере модуль, который делает HTML для преобразования текста)! Все, что он делал, это снимал теги, сглаживал таблицы и т. д. Выходные данные не выглядели как Html2Txt @ W3C производства. Жаль, что источник не доступен.
Я искал, есть ли более "консервированное" решение доступный.
EDIT 2: спасибо всем за ваши предложения. FlySwat наклонил меня в том направлении, куда я хотел пойти. Я могу использовать System.Diagnostics.Process класс для запуска lynx.exe с переключателем "- dump " для отправки текста на стандартный вывод и захвата stdout с помощью ProcessStartInfo.UseShellExecute = false и ProcessStartInfo.RedirectStandardOutput = true. Я оберну все это в класс C#. Этот код будет вызываться только иногда, поэтому я не слишком беспокоюсь о создании нового процесса против выполнения его в коде. Плюс, рысь это Быстро!!
18 ответов:
то, что вы ищете,-это текстовый режим DOM renderer, который выводит текст, так же как Lynx или другие текстовые браузеры...Это гораздо труднее сделать, чем можно было бы ожидать.
просто заметка о HtmlAgilityPack для потомков. Проект содержит пример разбора текста в html, который, как отмечает OP, вообще не обрабатывает пробелы, как любой, кто пишет HTML. Там есть полнотекстовые решения для рендеринга, отмеченные другими на этот вопрос, чего нет (он даже не может обрабатывать таблицы в своей текущей форме), но он легкий и быстрый, что все, что я хотел для создания простой текстовой версии HTML-писем.
using System.IO; using System.Text.RegularExpressions; using HtmlAgilityPack; //small but important modification to class https://github.com/zzzprojects/html-agility-pack/blob/master/src/Samples/Html2Txt/HtmlConvert.cs public static class HtmlToText { public static string Convert(string path) { HtmlDocument doc = new HtmlDocument(); doc.Load(path); return ConvertDoc(doc); } public static string ConvertHtml(string html) { HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); return ConvertDoc(doc); } public static string ConvertDoc (HtmlDocument doc) { using (StringWriter sw = new StringWriter()) { ConvertTo(doc.DocumentNode, sw); sw.Flush(); return sw.ToString(); } } internal static void ConvertContentTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) { foreach (HtmlNode subnode in node.ChildNodes) { ConvertTo(subnode, outText, textInfo); } } public static void ConvertTo(HtmlNode node, TextWriter outText) { ConvertTo(node, outText, new PreceedingDomTextInfo(false)); } internal static void ConvertTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) { string html; switch (node.NodeType) { case HtmlNodeType.Comment: // don't output comments break; case HtmlNodeType.Document: ConvertContentTo(node, outText, textInfo); break; case HtmlNodeType.Text: // script and style must not be output string parentName = node.ParentNode.Name; if ((parentName == "script") || (parentName == "style")) { break; } // get text html = ((HtmlTextNode)node).Text; // is it in fact a special closing node output as text? if (HtmlNode.IsOverlappedClosingElement(html)) { break; } // check the text is meaningful and not a bunch of whitespaces if (html.Length == 0) { break; } if (!textInfo.WritePrecedingWhiteSpace || textInfo.LastCharWasSpace) { html= html.TrimStart(); if (html.Length == 0) { break; } textInfo.IsFirstTextOfDocWritten.Value = textInfo.WritePrecedingWhiteSpace = true; } outText.Write(HtmlEntity.DeEntitize(Regex.Replace(html.TrimEnd(), @"\s{2,}", " "))); if (textInfo.LastCharWasSpace = char.IsWhiteSpace(html[html.Length - 1])) { outText.Write(' '); } break; case HtmlNodeType.Element: string endElementString = null; bool isInline; bool skip = false; int listIndex = 0; switch (node.Name) { case "nav": skip = true; isInline = false; break; case "body": case "section": case "article": case "aside": case "h1": case "h2": case "header": case "footer": case "address": case "main": case "div": case "p": // stylistic - adjust as you tend to use if (textInfo.IsFirstTextOfDocWritten) { outText.Write("\r\n"); } endElementString = "\r\n"; isInline = false; break; case "br": outText.Write("\r\n"); skip = true; textInfo.WritePrecedingWhiteSpace = false; isInline = true; break; case "a": if (node.Attributes.Contains("href")) { string href = node.Attributes["href"].Value.Trim(); if (node.InnerText.IndexOf(href, StringComparison.InvariantCultureIgnoreCase)==-1) { endElementString = "<" + href + ">"; } } isInline = true; break; case "li": if(textInfo.ListIndex>0) { outText.Write("\r\n{0}.\t", textInfo.ListIndex++); } else { outText.Write("\r\n*\t"); //using '*' as bullet char, with tab after, but whatever you want eg "\t->", if utf-8 0x2022 } isInline = false; break; case "ol": listIndex = 1; goto case "ul"; case "ul": //not handling nested lists any differently at this stage - that is getting close to rendering problems endElementString = "\r\n"; isInline = false; break; case "img": //inline-block in reality if (node.Attributes.Contains("alt")) { outText.Write('[' + node.Attributes["alt"].Value); endElementString = "]"; } if (node.Attributes.Contains("src")) { outText.Write('<' + node.Attributes["src"].Value + '>'); } isInline = true; break; default: isInline = true; break; } if (!skip && node.HasChildNodes) { ConvertContentTo(node, outText, isInline ? textInfo : new PreceedingDomTextInfo(textInfo.IsFirstTextOfDocWritten){ ListIndex = listIndex }); } if (endElementString != null) { outText.Write(endElementString); } break; } } } internal class PreceedingDomTextInfo { public PreceedingDomTextInfo(BoolWrapper isFirstTextOfDocWritten) { IsFirstTextOfDocWritten = isFirstTextOfDocWritten; } public bool WritePrecedingWhiteSpace {get;set;} public bool LastCharWasSpace { get; set; } public readonly BoolWrapper IsFirstTextOfDocWritten; public int ListIndex { get; set; } } internal class BoolWrapper { public BoolWrapper() { } public bool Value { get; set; } public static implicit operator bool(BoolWrapper boolWrapper) { return boolWrapper.Value; } public static implicit operator BoolWrapper(bool boolWrapper) { return new BoolWrapper{ Value = boolWrapper }; } }в качестве примера приведен следующий HTML-код...
<!DOCTYPE HTML> <html> <head> </head> <body> <header> Whatever Inc. </header> <main> <p> Thanks for your enquiry. As this is the 1<sup>st</sup> time you have contacted us, we would like to clarify a few things: </p> <ol> <li> Please confirm this is your email by replying. </li> <li> Then perform this step. </li> </ol> <p> Please solve this <img alt="complex equation" src="http://upload.wikimedia.org/wikipedia/commons/8/8d/First_Equation_Ever.png"/>. Then, in any order, could you please: </p> <ul> <li> a point. </li> <li> another point, with a <a href="http://en.wikipedia.org/wiki/Hyperlink">hyperlink</a>. </li> </ul> <p> Sincerely, </p> <p> The whatever.com team </p> </main> <footer> Ph: 000 000 000<br/> mail: whatever st </footer> </body> </html>...будет преобразован в:
Whatever Inc. Thanks for your enquiry. As this is the 1st time you have contacted us, we would like to clarify a few things: 1. Please confirm this is your email by replying. 2. Then perform this step. Please solve this [complex equation<http://upload.wikimedia.org/wikipedia/commons/8/8d/First_Equation_Ever.png>]. Then, in any order, could you please: * a point. * another point, with a hyperlink<http://en.wikipedia.org/wiki/Hyperlink>. Sincerely, The whatever.com team Ph: 000 000 000 mail: whatever st...в отличие от:
Whatever Inc. Thanks for your enquiry. As this is the 1st time you have contacted us, we would like to clarify a few things: Please confirm this is your email by replying. Then perform this step. Please solve this . Then, in any order, could you please: a point. another point, with a hyperlink. Sincerely, The whatever.com team Ph: 000 000 000 mail: whatever st
вы могли бы использовать это:
public static string StripHTML(string HTMLText, bool decode = true) { Regex reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); var stripped = reg.Replace(HTMLText, ""); return decode ? HttpUtility.HtmlDecode(stripped) : stripped; }Обновлено
Спасибо за комментарии, я обновил, чтобы улучшить эту функцию
Я слышал из надежного источника, что, если вы делаете анализ HTML в .Net, вы должны снова посмотреть на пакет HTML agility pack..
http://www.codeplex.com/htmlagilitypack
некоторые образцы на так..
потому что я хотел преобразования в обычный текст с LF и пули, я нашел это довольно решение на codeproject, который охватывает многие преобразования usecases:
преобразование HTML в обычный текст
Да, выглядит так большой, но работает нормально.
вы пробовали http://www.aaronsw.com/2002/html2text/ это Python, но с открытым исходным кодом.
предполагая, что у вас хорошо сформирован html, вы также можете попробовать преобразование XSL.
вот пример:
using System; using System.IO; using System.Xml.Linq; using System.Xml.XPath; using System.Xml.Xsl; class Html2TextExample { public static string Html2Text(XDocument source) { var writer = new StringWriter(); Html2Text(source, writer); return writer.ToString(); } public static void Html2Text(XDocument source, TextWriter output) { Transformer.Transform(source.CreateReader(), null, output); } public static XslCompiledTransform _transformer; public static XslCompiledTransform Transformer { get { if (_transformer == null) { _transformer = new XslCompiledTransform(); var xsl = XDocument.Parse(@"<?xml version='1.0'?><xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" exclude-result-prefixes=""xsl""><xsl:output method=""html"" indent=""yes"" version=""4.0"" omit-xml-declaration=""yes"" encoding=""UTF-8"" /><xsl:template match=""/""><xsl:value-of select=""."" /></xsl:template></xsl:stylesheet>"); _transformer.Load(xsl.CreateNavigator()); } return _transformer; } } static void Main(string[] args) { var html = XDocument.Parse("<html><body><div>Hello world!</div></body></html>"); var text = Html2Text(html); Console.WriteLine(text); } }
самым простым, вероятно, будет удаление тегов в сочетании с заменой некоторых тегов элементами макета текста, такими как тире для элементов списка (li) и разрывы строк для br и p. Это не должно быть слишком сложно, чтобы распространить это на таблицы.
У меня были некоторые проблемы декодирования с HtmlAgility, и я не хотел тратить время на его изучение.
вместо этого я использовал утилиты из API Microsoft Team Foundation:
var text = HtmlFilter.ConvertToPlainText(htmlContent);
следующий пост предполагает HTML agility pack:
Это гибкий HTML-парсер, который создает DOM для чтения / записи и поддерживает обычный XPATH или XSLT (вы на самом деле не нужно понимать выражение XPath, ни XSLT, чтобы использовать его, не волнуйтесь...). Это библиотека кода .NET, которая позволяет разбор" из интернета " HTML файлов. Этот парсер очень терпим с "Реалом мир" искаженной HTML. Объект модель очень похожа на то, что предлагает Система.Xml, но для документов HTML (или потоки.)
Я использовал Detagger в прошлом. Он делает довольно хорошую работу по форматированию HTML в виде текста и больше, чем просто удаление тегов.
Я не знаю C#, но здесь есть довольно маленький и простой для чтения скрипт python html2txt:http://www.aaronsw.com/2002/html2text/
У меня есть недавно написал в блоге о решении это сработало для меня, используя файл Markdown XSLT для преобразования источника HTML. Источник HTML, конечно, должен быть действительным XML first
попробуйте простой и удобный способ: просто позвони
StripHTML(WebBrowserControl_name);public string StripHTML(WebBrowser webp) { try { doc.execCommand("SelectAll", true, null); IHTMLSelectionObject currentSelection = doc.selection; if (currentSelection != null) { IHTMLTxtRange range = currentSelection.createRange() as IHTMLTxtRange; if (range != null) { currentSelection.empty(); return range.text; } } } catch (Exception ep) { //MessageBox.Show(ep.Message); } return ""; }
в Genexus вы можете сделать с регулярным выражением
&шаблон = ']+>'
&TSTRPNOT=&TSTRPNOT.ReplaceRegEx (&pattern,"")
in Genexus possiamo gestirlo con Regex,
можно использовать WebBrowser управление для отображения в памяти вашего html-контента. После LoadCompleted событие уволен...
IHTMLDocument2 htmlDoc = (IHTMLDocument2)webBrowser.Document; string innerHTML = htmlDoc.body.innerHTML; string innerText = htmlDoc.body.innerText;
Если вы используете .NET framework 4.5, вы можете использовать System.Net.WebUtility.HtmlDecode (), который принимает кодированную строку HTML и возвращает декодированную строку.
документировано на MSDN по адресу: http://msdn.microsoft.com/en-us/library/system.net.webutility.htmldecode(v=vs.110).aspx
вы можете использовать это в приложении магазина Windows, а также.
Это еще одно решение для преобразования HTML в текст или RTF в C#:
SautinSoft.HtmlToRtf h = new SautinSoft.HtmlToRtf(); h.OutputFormat = HtmlToRtf.eOutputFormat.TextUnicode; string text = h.ConvertString(htmlString);эта библиотека не является бесплатным, это коммерческий продукт, и это мой собственный продукт.
Comments