using System.
IO;
using [Link];
using HtmlAgilityPack;
//small but important modification to class [Link]
agility-pack/blob/master/src/Samples/Html2Txt/[Link]
public static class HtmlToText
{
public static string Convert(string path)
{
HtmlDocument doc = new HtmlDocument();
[Link](path);
return ConvertDoc(doc);
}
public static string ConvertHtml(string html)
{
HtmlDocument doc = new HtmlDocument();
[Link](html);
return ConvertDoc(doc);
}
public static string ConvertDoc (HtmlDocument doc)
{
using (StringWriter sw = new StringWriter())
{
ConvertTo([Link], sw);
[Link]();
return [Link]();
}
}
internal static void ConvertContentTo(HtmlNode node, TextWriter outText,
PreceedingDomTextInfo textInfo)
{
foreach (HtmlNode subnode in [Link])
{
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 ([Link])
{
case [Link]:
// don't output comments
break;
case [Link]:
ConvertContentTo(node, outText, textInfo);
break;
case [Link]:
// script and style must not be output
string parentName = [Link];
if ((parentName == "script") || (parentName == "style"))
{
break;
}
// get text
html = ((HtmlTextNode)node).Text;
// is it in fact a special closing node output as text?
if ([Link](html))
{
break;
}
// check the text is meaningful and not a bunch of whitespaces
if ([Link] == 0)
{
break;
}
if (![Link] ||
[Link])
{
html= [Link]();
if ([Link] == 0) { break; }
[Link] =
[Link] = true;
}
[Link]([Link]([Link]([Link](),
@"\s{2,}", " ")));
if ([Link] = [Link](html[[Link]
- 1]))
{
[Link](' ');
}
break;
case [Link]:
string endElementString = null;
bool isInline;
bool skip = false;
int listIndex = 0;
switch ([Link])
{
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 ([Link])
{
[Link]("\r\n");
}
endElementString = "\r\n";
isInline = false;
break;
case "br":
[Link]("\r\n");
skip = true;
[Link] = false;
isInline = true;
break;
case "a":
if ([Link]("href"))
{
string href = [Link]["href"].[Link]();
if ([Link](href,
[Link])==-1)
{
endElementString = "<" + href + ">";
}
}
isInline = true;
break;
case "li":
if([Link]>0)
{
[Link]("\r\n{0}.\t", [Link]++);
}
else
{
[Link]("\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 ([Link]("alt"))
{
[Link]('[' + [Link]["alt"].Value);
endElementString = "]";
}
if ([Link]("src"))
{
[Link]('<' + [Link]["src"].Value +
'>');
}
isInline = true;
break;
default:
isInline = true;
break;
}
if (!skip && [Link])
{
ConvertContentTo(node, outText, isInline ? textInfo : new
PreceedingDomTextInfo([Link]){ ListIndex = listIndex });
}
if (endElementString != null)
{
[Link](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 [Link];
}
public static implicit operator BoolWrapper(bool boolWrapper)
{
return new BoolWrapper{ Value = boolWrapper };
}
}