使用flexmark将Markdown转为HTML

最近将网站后台文章编辑器改为Markdown。
直接写Markdown感觉比使用富文本编辑器更好,主要是富文本编辑会多出非常多的标签,编辑不受控制。
使用Markdown转换HTML就比较令人满意了。

但是这里又有一个问题了,就是外链没有加上rel="nofollow",我们需要自己实现这个功能,代码如下:

package com.acgist.utils;

import com.vladsch.flexmark.ast.AutoLink;
import com.vladsch.flexmark.ast.Link;
import com.vladsch.flexmark.html.AttributeProvider;
import com.vladsch.flexmark.html.AttributeProviderFactory;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
import com.vladsch.flexmark.html.renderer.AttributablePart;
import com.vladsch.flexmark.html.renderer.LinkResolverContext;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.profiles.pegdown.Extensions;
import com.vladsch.flexmark.profiles.pegdown.PegdownOptionsAdapter;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.DataHolder;
import com.vladsch.flexmark.util.data.MutableDataHolder;
import com.vladsch.flexmark.util.html.Attributes;

/**
 * Markdown工具
 * 
 * @author acgist
 */
public class MarkdownUtils {
	
	/**
	 * 本站域名
	 */
	private static final String SITE_HOST = "acgist.com";
	
	static class LinkRefExtension implements HtmlRenderer.HtmlRendererExtension {
		
		@Override
		public void rendererOptions(MutableDataHolder holder) {
		}

		@Override
		public void extend(HtmlRenderer.Builder rendererBuilder, String rendererType) {
			rendererBuilder.attributeProviderFactory(LinkRefAttributeProvider.Factory());
		}

		static LinkRefExtension create() {
			return new LinkRefExtension();
		}
		
	}

	static class LinkRefAttributeProvider implements AttributeProvider {
		
		@Override
		public void setAttributes(Node node, AttributablePart part, Attributes attributes) {
			if ((node instanceof Link || node instanceof AutoLink) && part == AttributablePart.LINK) {
				// 如果非本站地址添加:ref="nofollow"
				final var href = attributes.get("href");
				if(href != null && href.getValue() != null && !href.getValue().contains(SITE_HOST)) {
					attributes.replaceValue("rel", "nofollow");
				}
			}
		}

		static AttributeProviderFactory Factory() {
			return new IndependentAttributeProviderFactory() {
				@Override
				public AttributeProvider apply(LinkResolverContext context) {
					return new LinkRefAttributeProvider();
				}
			};
		}
		
	}

	/**
	 * <p>Markdown转HTML</p>
	 * <p>去掉链接自动转换</p>
	 */
	public static final String toHTML(String markdown) {
		final DataHolder holder = PegdownOptionsAdapter.flexmarkOptions(true, Extensions.ALL ^ Extensions.AUTOLINKS, LinkRefExtension.create());
		final Parser parser = Parser.builder(holder).build();
		final Node document = parser.parse(markdown);
		final HtmlRenderer renderer = HtmlRenderer.builder(holder).build();
		return renderer.render(document);
	}
	
}

两个静态类实现了扩展,向a标签里面添加了ref属性。

Extensions.ALL ^ Extensions.AUTOLINKS这段代码是去掉自动转换链接的扩展。