我想编写一个自定义的 markdig 扩展来更改图像的路径。
例如:
![text](test.gif)
不应转换为
<img src="test.gif" alt="text">
但是
<img src="images/test.gif" alt="text">
我可以通过事后遍历文档来完成,例如:
string markdown = "![text](test.gif)";
MarkdownPipeline pipeline = new MarkdownPipelineBuilder().Build();
MarkdownDocument document = Markdown.Parse(markdown, pipeline);
foreach (LinkInline link in document.Descendants<LinkInline>())
{
if (link.IsImage) {
link.Url = "images/" + link.Url;
}
}
string html = document.ToHtml(pipeline);
但我很好奇如何通过扩展来做到这一点。
我已阅读https://www.codeproject.com/Articles/5348000/Writing-Custom-Markdig-Extensions-2,但似乎无法修改此示例来执行我想要对图像路径执行的操作。 在文章中,作者提到可以使用 LinkInline 元素代替 LeafInline,但我无法让它工作。我不知道如何编写解析器和渲染器。
public class CustomImagePath : LeafInline
{
public string? OriginalPath { get; set; }
}
public class CustomImagePathExtension : IMarkdownExtension
{
private readonly CustomImagePathOptions _options;
public CustomImagePathExtension(CustomImagePathOptions options)
{
_options = options;
}
public void Setup(MarkdownPipelineBuilder pipeline)
{
OrderedList<InlineParser> parsers;
parsers = pipeline.InlineParsers;
if (!parsers.Contains<CustomImagePathInlineParser>())
{
parsers.Add(new CustomImagePathInlineParser());
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
HtmlRenderer? htmlRenderer;
ObjectRendererCollection? renderers;
htmlRenderer = renderer as HtmlRenderer;
renderers = htmlRenderer?.ObjectRenderers;
if (renderers != null && !renderers.Contains<CustomImagePathRenderer>())
{
renderers.Add(new CustomImagePathRenderer(_options));
}
}
}
public static class CustomImagePathExtensionFunctions
{
public static MarkdownPipelineBuilder UseCustomImagePath(this MarkdownPipelineBuilder pipeline, CustomImagePathOptions options)
{
OrderedList<IMarkdownExtension> extensions;
extensions = pipeline.Extensions;
if (!extensions.Contains<CustomImagePathExtension>())
{
extensions.Add(new CustomImagePathExtension(options));
}
return pipeline;
}
}
public class CustomImagePathInlineParser : InlineParser
{
private static readonly char[] _openingCharacters =
{
'!'
};
public CustomImagePathInlineParser()
{
OpeningCharacters = _openingCharacters;
}
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// Check if the current character is the start of an image
if (slice.CurrentChar == '!' && !char.IsLetterOrDigit(slice.PeekCharExtra(-1)))
{
// Move the slice position to skip the '!'
slice.NextChar();
// Delegate the parsing to the base LinkInlineParser
var result = Match(processor, ref slice);
if (result && processor.Inline is LinkInline linkInline)
{
// Check if it's an image link
if (linkInline.IsImage)
{
// Modify the image path
var imagePath = "images/" + linkInline.Url;
// Update the link inline with the modified path
linkInline.Url = imagePath;
}
}
return result;
}
return false;
}
}
public class CustomImagePathRenderer : HtmlObjectRenderer<LinkInline>
{
private readonly CustomImagePathOptions _options;
public CustomImagePathRenderer(CustomImagePathOptions options)
{
_options = options;
}
protected override void Write(HtmlRenderer renderer, LinkInline link)
{
if (link.IsImage)
{
// Check if the image inline is our custom inline
if (link.FirstChild is CustomImagePath customImage)
{
// Modify the image path before rendering
var imagePath = "images/" + customImage.OriginalPath;
// Render the modified image path
renderer.Write("<img src=\"");
renderer.WriteEscapeUrl(imagePath);
renderer.Write("\"");
renderer.WriteAttributes(link);
renderer.Write("/>");
return;
}
}
renderer.Write(link);
}
}
并使用它:
string markdown = "![text](test.gif)";
MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
.UseCustomImagePath(new CustomImagePathOptions())
.Build();
string html = Markdown.ToHtml(markdown, pipeline);
您读到的文章中的扩展太复杂了。
您想要的扩展要简单得多:
using Markdig;
using Markdig.Renderers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
public class ImgExtension : IMarkdownExtension
{
public void Setup(MarkdownPipelineBuilder pipeline)
{
pipeline.DocumentProcessed += ChangeImgPath;
}
public void ChangeImgPath(MarkdownDocument document)
{
foreach (LinkInline link in document.Descendants<LinkInline>())
{
if (link.IsImage)
link.Url = "images/" + link.Url;
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
}
}
并使用它:
string markdown = "![text](test.gif)";
MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
.Use<ImgExtension>()
.Build();
string html = Markdown.ToHtml(markdown, pipeline);