Wp2ghost/CSharpGhostImporter/HtmlToMarkdownConverter.cs

143 lines
11 KiB
C#
Raw Normal View History

2026-09-20 08:31:23 +02:00
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 => "![](" + m.Groups[1].Value + ")", 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("&amp;", "&").Replace("&lt;", "<").Replace("&gt;", ">").Replace("&quot;", "\"").Replace("&#8217;", "'").Replace("&nbsp;", " ").Replace("&mdash;", "—").Replace("&ndash;", "–");
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);
}
}
}