Java解析Markdown,commonmark的使用笔记
Hi I'm Shendi
参考github commonmark 官方文档记录的经验笔记 ps:官方是英文版的
commonmark
文档作者: 砷碲
文档编写时间: 2022-12-09
Java 解析 Markdown
Java库,用于根据CommonMark规范(以及一些扩展)解析和呈现Markdown文本。
github: https://github.com/commonmark/commonmark-java
Maven方式引入
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.20.0</version>
</dependency>
或直接下载 jar 引入
在Java 9中使用的模块名是org.commonmark、org.commonmark.ext.autolink等,与包名相对应。
API文档: https://www.javadoc.io/doc/org.commonmark/commonmark
简单的用例
从官网readme拿的用例
import org.commonmark.node.*;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
Parser parser = Parser.builder().build();
Node document = parser.parse("This is *Sparta*");
HtmlRenderer renderer = HtmlRenderer.builder().build();
renderer.render(document); // "<p>This is <em>Sparta</em></p>\n"
其中 HtmlRenderer 有以下选项
- escapeHtml(true)
- 将markdown中的原始html标签转义(html标签作为文本)
- sanitizeUrls(true)
- 将在图片(img),链接(a)中删除潜在的不安全的URL
使用 visitor 处理解析的节点
解析的结果是一个节点树(Node),该树可以在渲染前进行修改或不渲染的情况下进行检查
Node node = parser.parse("Example\n=======\n\nSome more text");
WordCountVisitor visitor = new WordCountVisitor();
node.accept(visitor);
visitor.wordCount; // 4
class WordCountVisitor extends AbstractVisitor {
int wordCount = 0;
@Override
public void visit(Text text) {
// This is called for all Text nodes. Override other visit methods for other node types.
// Count words (this is just an example, don't actually do it this way for various reasons).
wordCount += text.getLiteral().split("\\W+").length;
// Descend into children (could be omitted in this case because Text nodes don't have children).
visitChildren(text);
}
}
添加或修改 HTML 元素的属性
给渲染器(HtmlRenderer)设置 attributeProviderFactory
例如给 img 标签增加 class='border'
Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder()
.attributeProviderFactory(new AttributeProviderFactory() {
public AttributeProvider create(AttributeProviderContext context) {
return new ImageAttributeProvider();
}
})
.build();
Node document = parser.parse("");
renderer.render(document);
// "<p><img src=\"/url.png\" alt=\"text\" class=\"border\" /></p>\n"
class ImageAttributeProvider implements AttributeProvider {
@Override
public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
if (node instanceof Image) {
attributes.put("class", "border");
}
}
}
自定义 HTML 渲染
下面的示例将 tab 键更改为被 pre 标签所包裹
Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder()
.nodeRendererFactory(new HtmlNodeRendererFactory() {
public NodeRenderer create(HtmlNodeRendererContext context) {
return new IndentedCodeBlockNodeRenderer(context);
}
})
.build();
Node document = parser.parse("Example:\n\n code");
renderer.render(document);
// "<p>Example:</p>\n<pre>code\n</pre>\n"
class IndentedCodeBlockNodeRenderer implements NodeRenderer {
private final HtmlWriter html;
IndentedCodeBlockNodeRenderer(HtmlNodeRendererContext context) {
this.html = context.getWriter();
}
@Override
public Set<Class<? extends Node>> getNodeTypes() {
// Return the node types we want to use this renderer for.
return Collections.<Class<? extends Node>>singleton(IndentedCodeBlock.class);
}
@Override
public void render(Node node) {
// We only handle one type as per getNodeTypes, so we can just cast it here.
IndentedCodeBlock codeBlock = (IndentedCodeBlock) node;
html.line();
html.tag("pre");
html.text(codeBlock.getLiteral());
html.tag("/pre");
html.line();
}
}
扩展
一些markdown语法需要被解析需要使用到扩展,例如表格,删除线等
扩展需要扩展解析器(Parse),或者HTML渲染器(HTMLRenderer),或者两者都扩展
例如从 GitHub Flavored Markdown 中启用 Table
添加 Maven 依赖
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark-ext-gfm-tables</artifactId>
<version>0.20.0</version>
</dependency>
配置扩展
import org.commonmark.ext.gfm.tables.TablesExtension;
// 扩展列表
List<Extension> extensions = Arrays.asList(TablesExtension.create());
Parser parser = Parser.builder().extensions(extensions).build();
HtmlRenderer renderer = HtmlRenderer.builder().extensions(extensions).build();
要配置更多扩展,将其加入 list 即可,使用方式与上面描述一致
表格(Tables)
没有使用扩展,表格默认不会被识别渲染
使用 GitHub Flavored Markdown 启用表格
引入maven 的 artifactId 为 commonmark-ext-gfm-tables
使用类 TablesExtension
自动链接(Autolink)
将URL,电子邮箱等转换为链接,基于 autolink-java
引入maven 的 artifactId 为 commonmark-ext-autolink
使用类 AutolinkExtension
删除线(Strikethrough)
将文本包括在 ~~ 中,将加上删除线,例如 ~删除线~
引入maven 的 artifactId 为 commonmark-ext-gfm-strikethrough
使用类 StrikethroughExtension
航向锚定器(Heading anchor)
将自动在标题增加id属性,id为标题的文本
例如,(# 标题)渲染结果如下
<h1 id='标题'>标题</h1>
引入maven 的 artifactId 为 commonmark-ext-heading-anchor
使用类 HeadingAnchorExtension
下划线(Ins)
将文本包括在++中来给文本加入下划线,使用<ins>标签
引入maven 的 artifactId 为 commonmark-ext-ins
使用类 InsExtension
YAML 前言(YAML front matter)
通过 YAML 前端块添加对元数据的支持,此扩展仅支持 YAML 语法的子集,示例如下
---
key: value
list:
- value 1
- value 2
literal: |
this is literal value.
literal values 2
---
document start here
引入maven 的 artifactId 为 commonmark-ext-yaml-front-matter
使用类 YamlFrontMatterExtension
图片属性(Image Attributes)
添加对图片属性的支持(特别是宽高)
属性元素在图像节点后的花括号内以键值对形式编写,例如
{width=640 height=480}
渲染为
<img src="/url.png" alt="text" width="640" height="480" />
引入maven 的 artifactId 为 commonmark-ext-image-attributes
使用类 ImageAttributesExtension
注意:由于此扩展使用花括号{}作为其分隔符(在StylesDimiterProcessor中),这意味着其他分隔符处理器不能使用大括号进行分隔。
任务列表(Task List Items)
添加对列表项任务的支持
语法为,第一个非空字符为左中括号 [ 接下来空白字符或者大小写 x,接下来是右中括号],然后一个空白字符,接下来可以是任何字符,例如
- [ ] task #1
- [x] task #2
渲染如下
<ul>
<li><input type="checkbox" disabled=""> task #1</li>
<li><input type="checkbox" disabled="" checked=""> task #2</li>
</ul>
引入maven 的 artifactId 为 commonmark-ext-task-list-items
使用类 TaskListItemsExtension
本文链接:https://sdpro.top/blog/html/article/1003.html
♥ 赞助 ♥
尽管去做,或许最终的结果不尽人意,但你不付出,他不付出,那怎会进步呢?