143 lines
11 KiB
C#
143 lines
11 KiB
C#
|
|
namespace wp2ghost
|
|||
|
|
{
|
|||
|
|
// =============================================================================
|
|||
|
|
// HTML zu Markdown Konverter
|
|||
|
|
// =============================================================================
|
|||
|
|
public static class HtmlToMarkdownConverter
|
|||
|
|
{
|
|||
|
|
public static string Convert(string html)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(html))
|
|||
|
|
return "";
|
|||
|
|
|
|||
|
|
string result = html;
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, "<!--.*?-->", "", System.Text.RegularExpressions.RegexOptions.Singleline);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<h([1-6])[^>]*>(.*?)</h\1>", m => new string('#', int.Parse(m.Groups[1].Value)) + " " + StripTags(m.Groups[2].Value) + Environment.NewLine + Environment.NewLine, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<blockquote[^>]*>(.*?)</blockquote>", m => "> " + StripTags(m.Groups[1].Value).Replace(Environment.NewLine, Environment.NewLine + "> ") + Environment.NewLine, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<pre[^>]*><code[^>]*>(.*?)</code></pre>", m => "```\n" + StripTags(m.Groups[1].Value) + "\n```\n\n", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<code[^>]*>(.*?)</code>", m => "`" + StripTags(m.Groups[1].Value) + "`", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<ul[^>]*>(.*?)</ul>", m => ConvertList(m.Groups[1].Value, "-"), System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<ol[^>]*>(.*?)</ol>", m => ConvertOrderedList(m.Groups[1].Value), System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = ConvertTables(result);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<p[^>]*>(.*?)</p>", m => CleanInnerHtml(m.Groups[1].Value) + Environment.NewLine + Environment.NewLine, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<br\s*/?>", Environment.NewLine, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<strong[^>]*>(.*?)</strong>", "**$1**", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<b[^>]*>(.*?)</b>", "**$1**", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<em[^>]*>(.*?)</em>", "*$1*", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<i[^>]*>(.*?)</i>", "*$1*", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<a\s+[^>]*href=[""']([^""']+)[""'][^>]*>(.*?)</a>", "[$2]($1)", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<img\s+[^>]*src=[""']([^""']+)[""'][^>]*alt=[""']([^""']*)[""'][^>]*>", m => "![" + m.Groups[2].Value + "](" + m.Groups[1].Value + ")", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<img\s+[^>]*src=[""']([^""']+)[""'][^>]*>", m => "", System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"<div[^>]*class=[""'][^""']*wp-block-heading[^""']*[""'][^>]*>(.*?)</div>", m => "# " + StripTags(m.Groups[1].Value) + Environment.NewLine + Environment.NewLine, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result,
|
|||
|
|
@"<figure[^>]*>(.*?)</figure>",
|
|||
|
|
m => ConvertFigure(m.Groups[1].Value),
|
|||
|
|
System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
|
|||
|
|
result = StripTagsKeepFigure(result);
|
|||
|
|
|
|||
|
|
result = System.Text.RegularExpressions.Regex.Replace(result, @"\n{3,}", "\n\n");
|
|||
|
|
|
|||
|
|
result = result.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(""", "\"").Replace("’", "'").Replace(" ", " ").Replace("—", "—").Replace("–", "–");
|
|||
|
|
|
|||
|
|
return result.Trim();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string StripTags(string html) =>
|
|||
|
|
System.Text.RegularExpressions.Regex.Replace(html, "<[^>]*>", "");
|
|||
|
|
|
|||
|
|
private static string CleanInnerHtml(string html)
|
|||
|
|
{
|
|||
|
|
string cleaned = StripTags(html);
|
|||
|
|
cleaned = System.Text.RegularExpressions.Regex.Replace(cleaned, @"\*\*(.+?)\*\*", "**$1**");
|
|||
|
|
return cleaned.Trim();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string ConvertFigure(string figureContent)
|
|||
|
|
{
|
|||
|
|
string imgSrc = "", altText = "", caption = "";
|
|||
|
|
|
|||
|
|
var imgMatch = System.Text.RegularExpressions.Regex.Match(figureContent, @"<img\s+[^>]*src=[""']([^""']+)[""']");
|
|||
|
|
if (imgMatch.Success) imgSrc = imgMatch.Groups[1].Value;
|
|||
|
|
|
|||
|
|
var altMatch = System.Text.RegularExpressions.Regex.Match(figureContent, @"alt=[""']([^""']*)[""']");
|
|||
|
|
if (altMatch.Success) altText = altMatch.Groups[1].Value;
|
|||
|
|
|
|||
|
|
var figMatch = System.Text.RegularExpressions.Regex.Match(figureContent, @"<figcaption[^>]*>(.*?)</figcaption>", System.Text.RegularExpressions.RegexOptions.Singleline);
|
|||
|
|
if (figMatch.Success) caption = System.Text.RegularExpressions.Regex.Replace(figMatch.Groups[1].Value, "<[^>]*>", "").Trim();
|
|||
|
|
|
|||
|
|
if (string.IsNullOrEmpty(imgSrc)) return "";
|
|||
|
|
|
|||
|
|
string result = $"<figure class=\"kg-width-wide kg-card-width-wide\"><img src=\"{imgSrc}\" loading=\"lazy\"";
|
|||
|
|
if (!string.IsNullOrEmpty(altText)) result += $" alt=\"{altText}\"";
|
|||
|
|
result += ">";
|
|||
|
|
if (!string.IsNullOrEmpty(caption)) result += $"<figcaption>{caption}</figcaption>";
|
|||
|
|
result += "</figure>";
|
|||
|
|
return result + Environment.NewLine;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string StripTagsKeepFigure(string html)
|
|||
|
|
{
|
|||
|
|
var figureBlocks = new List<string>();
|
|||
|
|
html = System.Text.RegularExpressions.Regex.Replace(html, @"<figure[^>]*>.*?</figure>", m => { figureBlocks.Add(m.Value); return $"__FIGURE_{figureBlocks.Count - 1}__"; }, System.Text.RegularExpressions.RegexOptions.Singleline);
|
|||
|
|
html = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]*>", "");
|
|||
|
|
for (int i = 0; i < figureBlocks.Count; i++)
|
|||
|
|
html = html.Replace($"__FIGURE_{i}__", figureBlocks[i]);
|
|||
|
|
return html;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string ConvertList(string listHtml, string bullet)
|
|||
|
|
{
|
|||
|
|
listHtml = System.Text.RegularExpressions.Regex.Replace(listHtml, @"<li[^>]*>(.*?)</li>", m => bullet + " " + CleanInnerHtml(m.Groups[1].Value) + Environment.NewLine, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
return StripTags(listHtml).Trim() + Environment.NewLine;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string ConvertOrderedList(string listHtml)
|
|||
|
|
{
|
|||
|
|
int counter = 0;
|
|||
|
|
listHtml = System.Text.RegularExpressions.Regex.Replace(listHtml, @"<li[^>]*>(.*?)</li>", m => { counter++; return counter + ". " + CleanInnerHtml(m.Groups[1].Value) + Environment.NewLine; }, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
return StripTags(listHtml).Trim() + Environment.NewLine;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string ConvertTables(string html)
|
|||
|
|
{
|
|||
|
|
return System.Text.RegularExpressions.Regex.Replace(html, @"<table[^>]*>(.*?)</table>", m =>
|
|||
|
|
{
|
|||
|
|
string tableContent = m.Groups[1].Value;
|
|||
|
|
var headerMatch = System.Text.RegularExpressions.Regex.Match(tableContent, @"<tr[^>]*>(.*?)</tr>", System.Text.RegularExpressions.RegexOptions.Singleline);
|
|||
|
|
if (!headerMatch.Success) return StripTags(tableContent) + Environment.NewLine;
|
|||
|
|
|
|||
|
|
string headers = CleanInnerHtml(headerMatch.Groups[1].Value);
|
|||
|
|
headers = headers.Replace("<th", "<td").Replace("</th>", "</td>");
|
|||
|
|
string headerLine = "| " + string.Join(" | ", StripTags(headers).Split(new[] { "</td>", "<td" }, StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim())) + " |";
|
|||
|
|
string separator = "|" + string.Join("|", StripTags(headers).Split(new[] { "</td>", "<td" }, StringSplitOptions.RemoveEmptyEntries).Select(c => "---")) + "|";
|
|||
|
|
|
|||
|
|
var rows = System.Text.RegularExpressions.Regex.Matches(tableContent, @"<tr[^>]*>(.*?)</tr>", System.Text.RegularExpressions.RegexOptions.Singleline);
|
|||
|
|
var dataRows = new List<string>();
|
|||
|
|
for (int i = 1; i < rows.Count; i++)
|
|||
|
|
{
|
|||
|
|
string rowText = CleanInnerHtml(rows[i].Groups[1].Value);
|
|||
|
|
string[] cells = rowText.Split(new[] { "</td>", "<td" }, StringSplitOptions.RemoveEmptyEntries);
|
|||
|
|
dataRows.Add("| " + string.Join(" | ", cells.Select(c => c.Trim().Replace("<b>", "").Replace("</b>", "").Replace("<strong>", "").Replace("</strong>", ""))) + " |");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return headerLine + Environment.NewLine + separator + Environment.NewLine + string.Join(Environment.NewLine, dataRows) + Environment.NewLine + Environment.NewLine;
|
|||
|
|
}, System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|