如何编写自定义markdig扩展来自定义图像的路径

问题描述 投票:0回答:1

我想编写一个自定义的 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);
markdown
1个回答
0
投票

您读到的文章中的扩展太复杂了。

您想要的扩展要简单得多:

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);
© www.soinside.com 2019 - 2024. All rights reserved.