ReverseMarkdown (.NET HTML to Markdown converter)
repository·master·Indexed 18 days ago
https://github.com/mysticmind/reversemarkdown-netA high-performance HTML to Markdown converter library for C# using AngleSharp for HTML5 parsing. It supports multiple Markdown flavors including GitHub, CommonMark, Slack, Telegram, MultiMarkdown, and Pandoc. Version 6 introduces a Markdown DOM architecture that decouples parsing from rendering, allowing for structured document manipulation. The library targets netstandard2.0, net8.0, net9.0, and net10.0, and is compatible with .NET Framework 4.6.1+, .NET Core 2.0+, Mono, and Unity.
What's inside ReverseMarkdown
- ReverseMarkdown is an HTML to Markdown converter library for C#/.NET. Version 6 uses an HTML5-compliant parser (AngleSharp) to convert HTML into an intermediate Markdown DOM, which is then rendered into specific Markdown flavors. This architecture allows for high-fidelity conversion, extensibility, and high performance.
Overview of ReverseMarkdown features
masterReverseMarkdown is a high-performance HTML to Markdown converter for C# that uses AngleSharp for HTML5 parsing. Key capabilities include:
- Multiple Output Flavors: Supports
Default,GitHub,CommonMark,Slack,Telegram,MultiMarkdown, andPandocvia theMarkdownFlavorenum. - Spec-compliant Round-trips: High fidelity for CommonMark/GitHub and MultiMarkdown/Pandoc.
- Extensibility: Supports custom readers via
IMdReaderand the[MarkdownReader]attribute, as well as aParse/RenderMarkdown DOM for transformations. - Advanced Element Handling: Supports nested tables, captions, smart hrefs, URI-scheme whitelisting, and configurable base64 image handling (include, skip, or save to disk).
- Modern Runtime Support: Targets
netstandard2.0,net8.0,net9.0, andnet10.0. It is compatible with .NET Framework 4.6.1+, .NET Core 2.0+, Mono, and Unity. - AOT/Trimming Ready: The default path avoids reflection. For Native AOT or trimming, use
RegisterReaderto add custom readers.
- Multiple Output Flavors: Supports
Overview of ReverseMarkdown
masterReverseMarkdown is a fast, spec-compliant HTML to Markdown converter for .NET. Version 6 is built using the AngleSharp HTML5 parser and a Markdown DOM pipeline. It supports seven different output flavors and is designed to be extensible and compatible with modern .NET deployment requirements like Trimming and Native AOT.Check supported .NET frameworks and runtimes
masterReverseMarkdown targets
netstandard2.0,net8.0,net9.0, andnet10.0.Because it targets
netstandard2.0, it is compatible with the following runtimes:- .NET Framework 4.6.1+
- .NET Core 2.0+
- Mono / Xamarin
- Unity
It also supports modern .NET (8, 9, and 10).
How the v6 Markdown DOM architecture works
masterStarting with v6, ReverseMarkdown uses an intermediate Markdown DOM (an
mdast-equivalent typed document tree) to decouple HTML parsing from Markdown rendering. This architecture splits the conversion process into two distinct phases:- Parsing (
Parse): Readers convertHtmlNodeobjects into a rich, flavor-agnostic Markdown DOM. This phase builds a superset tree containing all possible structural information. - Rendering (
Render): Writers take the Markdown DOM and convert it into a specific Markdown flavor string. Writers own all flavor-specific logic and decisions regarding how to represent (or degrade) nodes that a specific flavor cannot support.
This design allows you to perform structured operations on the document—such as querying, pruning, or reshaping the tree—before finally rendering it to a string. This is particularly useful if you need to filter specific parts of the document based on its Markdown structure rather than just its HTML attributes.
- Parsing (
Update Markdown flavor selection in v6
masterThe
MarkdownFlavorenum is now the single, canonical way to select a flavor. Several previous flavor types are now obsolete aliases ofFlavor.Obsolete Flavor Aliases
SlackFlavored(nowFlavor)TelegramMarkdownV2(nowFlavor)CommonMark(nowFlavor)
Important Note on GitHub Flavored Markdown
GithubFlavoredremains distinct. It produces clean GFM markdown using the default writer. Do not confuse it withFlavor = MarkdownFlavor.GitHub, which is a CommonMark-based writer that preserves raw HTML.Migrate from SlackFlavored to MarkdownFlavor.Slack
masterTheSlackFlavored = trueswitch is a legacy option and is now considered an obsolete alias. For future compatibility, replace it with the explicitFlavor = MarkdownFlavor.Slacksetting in yourConversionOptions.Supported Markdown flavors in ReverseMarkdown
masterReverseMarkdown allows you to select the output format using a single
Flavorenum. The supported flavors are:- Default
- GitHub (Verified for 100% round-trip compliance against canonical
cmark-gfm) - CommonMark (Verified for 100% round-trip compliance against canonical
cmark-gfm) - Slack
- Telegram
- MultiMarkdown (Verified against canonical
pandoc) - Pandoc (Verified against canonical
pandoc)
Use the CommonMark flavor for round-trip fidelity
masterThe CommonMark flavor is designed for round-trip-faithful conversion. It preserves soft line breaks, escapes markup-significant characters, and escapes line-start markers to ensure literal text is not reinterpreted during conversion.
Note: The legacy
CommonMark = trueswitch is an obsolete alias forFlavor = MarkdownFlavor.CommonMarkand should be avoided in favor of the explicit flavor setting.// Use the explicit flavor instead of the obsolete CommonMark = true switch var converter = new ReverseMarkdownConverter(new ConversionOptions { Flavor = MarkdownFlavor.CommonMark });Understanding the v6 Reader API change: IElement vs HtmlNode
masterIn version 6 of ReverseMarkdown, the HTML parsing engine has transitioned from
HtmlAgilityPacktoAngleSharp. This change introduces a breaking change to the public API surface for readers:- v5 and earlier: The
IConverterinterface exposedHtmlNode(fromHtmlAgilityPack). - v6 and later: The
IMdReader.Readmethod now exposesIElement(fromAngleSharp).
When implementing or using custom readers in v6, you must work with
AngleSharp.IElementinstead ofHtmlAgilityPack.HtmlNode. This transition provides spec-compliant tree construction, native CSS selector support viaQuerySelector, and automatic entity decoding throughIText.DataandGetAttribute.- v5 and earlier: The
Alias a tag for conversion
masterYou can reuse the conversion logic of an existing tag for a different tag using
Tags.Aliases. The key in the dictionary is the tag you want to remap, and the value is the tag it should be converted as.// Example mapping: treat 'span' as 'em' (italics) var converter = new ReverseMarkdown.Converter(new ConversionOptions { Tags = new Tags { Aliases = new Dictionary<string, string> { { "span", "em" } } } });Telegram flavor formatting and escaping behavior
masterWhen using
MarkdownFlavor.Telegram, the following conversion behaviors are applied to ensure compatibility with Telegram's strict escaping rules:- Escaping: Text and link labels automatically escape Telegram-reserved characters. List markers for ordered (
1\.) and unordered (\-) lists are also escaped. - Images:
<img>tags are converted to link labels using the format[Image: alt](url). - Tables:
<table>tags fall back to a preformatted code block representation. - Superscript:
<sup>tags fall back to caret notation (e.g.,x^2).
- Escaping: Text and link labels automatically escape Telegram-reserved characters. List markers for ordered (