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("![text](/url.png)");
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)

添加对图片属性的支持(特别是宽高)

属性元素在图像节点后的花括号内以键值对形式编写,例如

![text](/url.png){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

♥ 赞助 ♥

尽管去做,或许最终的结果不尽人意,但你不付出,他不付出,那怎会进步呢?