commonmark-java 是一个用于解析和渲染 Markdown 文本的 Java 库;本文主要介绍其基本使用,文中所使用到的软件版本:Java 17.0.5、commonmark-java 0.25.1。
1、简介
commonmark-java 可以用来解析抽象语法树(AST),访问和操作其节点,以及生成 HTML 或 Markdown。它最初是 commonmark.js 的移植版,但后来发展成为一个可扩展的库,具备以下特点:
- 小巧(核心没有依赖,扩展以独立的组件形式提供)
- 快速(比曾经流行的 Markdown 库
pegdown快 10 到 20 倍) - 灵活(解析后可操作 AST,定制 HTML 渲染)
- 可扩展(支持表格、删除线、自动链接等)
commonmark-java 需要使用 Java 11 及以上版本。
2、commonmark-java 使用
2.1、样例文件
解析 Markdown 时使用该样例文件。
## 1 Markdown语法教程### 1.1 标题不同数量的`#`可以完成不同的标题,如下:# 一级标题## 二级标题### 三级标题### 1.2 字体粗体、斜体、粗体和斜体,删除线,需要在文字前后加不同的标记符号。如下:**这个是粗体***这个是斜体****这个是粗体加斜体***~~这里是删除线~~注:如果想给字体换颜色、字体或者居中显示,需要使用内嵌HTML来实现。### 1.3 无序列表无序列表的使用,在符号`-`后加空格使用。如下:- 无序列表 1 - 无序列表 2 - 无序列表 3如果要控制列表的层级,则需要在符号`-`前使用空格。如下:- 无序列表 1 - 无序列表 2- 无序列表 2.1- 无序列表 2.2### 1.4 有序列表有序列表的使用,在数字及符号`.`后加空格后输入内容,如下:1. 有序列表 1 2. 有序列表 2 3. 有序列表 3### 1.5 引用引用的格式是在符号`>`后面书写文字。如下:> 读一本好书,就是在和高尚的人谈话。 ——歌德> 雇用制度对工人不利,但工人根本无力摆脱这个制度。 ——阮一峰### 1.7 链接微信公众号仅支持公众号文章链接,即域名为`https://mp.weixin.qq.com/`的合法链接。使用方法如下所示:对于该论述,欢迎读者查阅之前发过的文章,[你是《未来世界的幸存者》么?](https://mp.weixin.qq.com/s/s5IhxV2ooX3JN_X416nidA)### 1.8 图片插入图片,格式如下:支持 jpg、png、gif、svg 等图片格式,**其中 svg 文件仅可在微信公众平台中使用**,svg 文件示例如下:支持图片**拖拽和截图粘贴**到编辑器中。注:支持图片 ***拖拽和截图粘贴*** 到编辑器中,仅支持 https 的图片,图片粘贴到微信时会自动上传微信服务器。### 1.9 分割线可以在一行中用三个以上的减号来建立一个分隔线,同时需要在分隔线的上面空一行。如下:---### 1.10 表格可以使用冒号来定义表格的对齐方式,如下:| 姓名 | 年龄 | 工作 | | :----- | :--: | -------: | | 小可爱 | 18 | 吃可爱多 | | 小小勇敢 | 20 | 爬棵勇敢树 | | 小小小机智 | 22 | 看一本机智书 |
2.2、引入依赖
<dependency><groupId>org.commonmark</groupId><artifactId>commonmark</artifactId><version>0.26.0</version> </dependency><dependency><groupId>org.commonmark</groupId><artifactId>commonmark-ext-gfm-tables</artifactId><version>0.26.0</version> </dependency>
2.3、API 方式生成 HTML 或 Markdown 文档
@Test public void serialize() {Document document = new Document();Heading heading = new Heading();heading.setLevel(2);heading.appendChild(new Text("1 Markdown语法教程"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.1 标题"));document.appendChild(heading);Paragraph paragraph = new Paragraph();paragraph.appendChild(new Text("不同数量的"));paragraph.appendChild(new Code("#"));paragraph.appendChild(new Text("可以完成不同的标题,如下:"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(1);heading.appendChild(new Text("一级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(2);heading.appendChild(new Text("二级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("三级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.2 字体"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("粗体、斜体、粗体和斜体,删除线,需要在文字前后加不同的标记符号。如下:"));document.appendChild(paragraph);paragraph = new Paragraph();StrongEmphasis strongEmphasis = new StrongEmphasis();strongEmphasis.appendChild(new Text("这个是粗体"));paragraph.appendChild(strongEmphasis);document.appendChild(paragraph);paragraph = new Paragraph();Emphasis emphasis = new Emphasis("*");emphasis.appendChild(new Text("这个是斜体"));paragraph.appendChild(emphasis);document.appendChild(paragraph);paragraph = new Paragraph();strongEmphasis = new StrongEmphasis();emphasis = new Emphasis("*");emphasis.appendChild(new Text("这个是粗体加斜体"));strongEmphasis.appendChild(emphasis);paragraph.appendChild(strongEmphasis);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("~~这里是删除线~~"));document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("注:如果想给字体换颜色、字体或者居中显示,需要使用内嵌HTML来实现。"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.3 无序列表"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("无序列表的使用,在符号"));paragraph.appendChild(new Code("-"));paragraph.appendChild(new Text("后加空格使用。如下:"));document.appendChild(paragraph);BulletList bulletList = new BulletList();ListItem listItem = new ListItem();listItem.appendChild(new Text("无序列表 1"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 2"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 3"));bulletList.appendChild(listItem);document.appendChild(bulletList);paragraph = new Paragraph();paragraph.appendChild(new Text("如果要控制列表的层级,则需要在符号"));paragraph.appendChild(new Code("-"));paragraph.appendChild(new Text("前使用空格。如下:"));document.appendChild(paragraph);bulletList = new BulletList();listItem = new ListItem();listItem.appendChild(new Text("无序列表 1"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 2"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());BulletList bulletList2 = new BulletList();listItem = new ListItem();listItem.setMarkerIndent(2);listItem.appendChild(new Text("无序列表 2.1"));bulletList2.appendChild(listItem);bulletList2.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.setMarkerIndent(2);listItem.appendChild(new Text("无序列表 2.2"));bulletList2.appendChild(listItem);bulletList.appendChild(bulletList2);document.appendChild(bulletList);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.4 有序列表"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("有序列表的使用,在数字及符号"));paragraph.appendChild(new Code("."));paragraph.appendChild(new Text("后加空格后输入内容,如下:"));document.appendChild(paragraph);OrderedList orderedList = new OrderedList();listItem = new ListItem();listItem.appendChild(new Text("有序列表 1"));orderedList.appendChild(listItem);orderedList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("有序列表 2"));orderedList.appendChild(listItem);orderedList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("有序列表 3"));orderedList.appendChild(listItem);document.appendChild(orderedList);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.5 引用"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("引用的格式是在符号"));paragraph.appendChild(new Code(">"));paragraph.appendChild(new Text("后面书写文字。如下:"));document.appendChild(paragraph);BlockQuote blockQuote = new BlockQuote();blockQuote.appendChild(new Text("读一本好书,就是在和高尚的人谈话。 ——歌德"));document.appendChild(blockQuote);blockQuote = new BlockQuote();blockQuote.appendChild(new Text("雇用制度对工人不利,但工人根本无力摆脱这个制度。 ——阮一峰"));document.appendChild(blockQuote);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.7 链接"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("微信公众号仅支持公众号文章链接,即域名为"));paragraph.appendChild(new Code("https://mp.weixin.qq.com/"));paragraph.appendChild(new Text("的合法链接。使用方法如下所示:"));document.appendChild(paragraph);paragraph = new Paragraph();Link link = new Link("https://mp.weixin.qq.com/s/s5IhxV2ooX3JN_X416nidA", null);link.appendChild(new Text("你是《未来世界的幸存者》么?"));paragraph.appendChild(new Text("对于该论述,欢迎读者查阅之前发过的文章,"));paragraph.appendChild(link);document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.8 图片"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("插入图片,格式如下:"));document.appendChild(paragraph);paragraph = new Paragraph();Image image = new Image("https://markdown.com.cn/images/qrcode_for_gh_82cf87d482f0_258.jpg", null);image.appendChild(new Text("这里写图片描述"));paragraph.appendChild(image);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("支持 jpg、png、gif、svg 等图片格式,"));emphasis = new Emphasis("**");emphasis.appendChild(new Text("其中 svg 文件仅可在微信公众平台中使用"));paragraph.appendChild(emphasis);paragraph.appendChild(new Text(",svg 文件示例如下:"));document.appendChild(paragraph);paragraph = new Paragraph();image = new Image("https://markdown.com.cn/images/i-am-svg.svg", null);paragraph.appendChild(image);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("支持图片"));strongEmphasis = new StrongEmphasis();strongEmphasis.appendChild(new Text("拖拽和截图粘贴"));paragraph.appendChild(strongEmphasis);paragraph.appendChild(new Text("到编辑器中。"));document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("注:支持图片 "));strongEmphasis = new StrongEmphasis();emphasis = new Emphasis("*");emphasis.appendChild(new Text("拖拽和截图粘贴"));strongEmphasis.appendChild(emphasis);paragraph.appendChild(strongEmphasis);paragraph.appendChild(new Text(" 到编辑器中,仅支持 https 的图片,图片粘贴到微信时会自动上传微信服务器。"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.9 分割线"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("可以在一行中用三个以上的减号来建立一个分隔线,同时需要在分隔线的上面空一行。如下:"));document.appendChild(paragraph);ThematicBreak thematicBreak = new ThematicBreak();thematicBreak.setLiteral("---");document.appendChild(thematicBreak);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.10 表格"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("可以使用冒号来定义表格的对齐方式,如下:"));document.appendChild(paragraph);TableBlock tableBlock = new TableBlock();TableHead tableHead = new TableHead();TableRow tableRow = new TableRow();TableCell tableCell = new TableCell();tableCell.appendChild(new Text("姓名"));tableCell.setAlignment(TableCell.Alignment.LEFT);tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("年龄"));tableCell.setAlignment(TableCell.Alignment.CENTER);tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("工作"));tableCell.setAlignment(TableCell.Alignment.RIGHT);tableRow.appendChild(tableCell);tableHead.appendChild(tableRow);TableBody tableBody = new TableBody();tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小可爱"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("18"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("吃可爱多"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小小勇敢"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("20"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("爬棵勇敢树"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小小小机智"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("22"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("看一本机智书"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableBlock.appendChild(tableHead);tableBlock.appendChild(tableBody);document.appendChild(tableBlock);List<Extension> extensions = List.of(TablesExtension.create());MarkdownRenderer markdownRenderer = MarkdownRenderer.builder().extensions(extensions).build();//转成markdown格式String md = markdownRenderer.render(document);System.out.println(md);HtmlRenderer htmlRenderer = HtmlRenderer.builder().extensions(extensions).build();//转成htmlString html = htmlRenderer.render(document);System.out.println(html); }
2.4、解析 Markdown 文档
@Test public void deserialize() throws IOException {List<Extension> extensions = List.of(TablesExtension.create());Parser parser = Parser.builder().extensions(extensions).build();InputStreamReader reader = new InputStreamReader(CommonmarkCase.class.getClassLoader().getResourceAsStream("test.md"));Node document = parser.parseReader(reader);Node node = document.getFirstChild();while (node != null) {System.out.println(node.getClass());if (node.getClass().equals(Heading.class)) {//处理标题Heading heading = (Heading) node;Text text = (Text)heading.getFirstChild();System.out.println(text.getLiteral());} else if (node.getClass().equals(BulletList.class)) {//处理无序列表BulletList bulletList = (BulletList) node;Node node2 = bulletList.getFirstChild();while (node2 != null) {if (node2.getClass().equals(ListItem.class)) {Node node3 = node2.getFirstChild();if (node3.getClass().equals(Paragraph.class)) {Text text = (Text)node3.getFirstChild();System.out.println(text.getLiteral());}if (node3.getNext() != null && node3.getNext().getClass().equals(BulletList.class)) {System.out.println("二级无序列表");//TODO: 继续解析 }}node2 = node2.getNext();}}//else if ...node = node.getNext();} }
2.5、完整代码
package com.abc.md;import lombok.extern.slf4j.Slf4j; import org.commonmark.Extension; import org.commonmark.ext.gfm.tables.*; import org.commonmark.node.*; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.markdown.MarkdownRenderer; import org.junit.Test;import java.io.IOException; import java.io.InputStreamReader; import java.util.List;@Slf4j public class CommonmarkCase {@Testpublic void serialize() {Document document = new Document();Heading heading = new Heading();heading.setLevel(2);heading.appendChild(new Text("1 Markdown语法教程"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.1 标题"));document.appendChild(heading);Paragraph paragraph = new Paragraph();paragraph.appendChild(new Text("不同数量的"));paragraph.appendChild(new Code("#"));paragraph.appendChild(new Text("可以完成不同的标题,如下:"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(1);heading.appendChild(new Text("一级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(2);heading.appendChild(new Text("二级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("三级标题"));document.appendChild(heading);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.2 字体"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("粗体、斜体、粗体和斜体,删除线,需要在文字前后加不同的标记符号。如下:"));document.appendChild(paragraph);paragraph = new Paragraph();StrongEmphasis strongEmphasis = new StrongEmphasis();strongEmphasis.appendChild(new Text("这个是粗体"));paragraph.appendChild(strongEmphasis);document.appendChild(paragraph);paragraph = new Paragraph();Emphasis emphasis = new Emphasis("*");emphasis.appendChild(new Text("这个是斜体"));paragraph.appendChild(emphasis);document.appendChild(paragraph);paragraph = new Paragraph();strongEmphasis = new StrongEmphasis();emphasis = new Emphasis("*");emphasis.appendChild(new Text("这个是粗体加斜体"));strongEmphasis.appendChild(emphasis);paragraph.appendChild(strongEmphasis);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("~~这里是删除线~~"));document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("注:如果想给字体换颜色、字体或者居中显示,需要使用内嵌HTML来实现。"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.3 无序列表"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("无序列表的使用,在符号"));paragraph.appendChild(new Code("-"));paragraph.appendChild(new Text("后加空格使用。如下:"));document.appendChild(paragraph);BulletList bulletList = new BulletList();ListItem listItem = new ListItem();listItem.appendChild(new Text("无序列表 1"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 2"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 3"));bulletList.appendChild(listItem);document.appendChild(bulletList);paragraph = new Paragraph();paragraph.appendChild(new Text("如果要控制列表的层级,则需要在符号"));paragraph.appendChild(new Code("-"));paragraph.appendChild(new Text("前使用空格。如下:"));document.appendChild(paragraph);bulletList = new BulletList();listItem = new ListItem();listItem.appendChild(new Text("无序列表 1"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("无序列表 2"));bulletList.appendChild(listItem);bulletList.appendChild(new SoftLineBreak());BulletList bulletList2 = new BulletList();listItem = new ListItem();listItem.setMarkerIndent(2);listItem.appendChild(new Text("无序列表 2.1"));bulletList2.appendChild(listItem);bulletList2.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.setMarkerIndent(2);listItem.appendChild(new Text("无序列表 2.2"));bulletList2.appendChild(listItem);bulletList.appendChild(bulletList2);document.appendChild(bulletList);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.4 有序列表"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("有序列表的使用,在数字及符号"));paragraph.appendChild(new Code("."));paragraph.appendChild(new Text("后加空格后输入内容,如下:"));document.appendChild(paragraph);OrderedList orderedList = new OrderedList();listItem = new ListItem();listItem.appendChild(new Text("有序列表 1"));orderedList.appendChild(listItem);orderedList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("有序列表 2"));orderedList.appendChild(listItem);orderedList.appendChild(new SoftLineBreak());listItem = new ListItem();listItem.appendChild(new Text("有序列表 3"));orderedList.appendChild(listItem);document.appendChild(orderedList);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.5 引用"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("引用的格式是在符号"));paragraph.appendChild(new Code(">"));paragraph.appendChild(new Text("后面书写文字。如下:"));document.appendChild(paragraph);BlockQuote blockQuote = new BlockQuote();blockQuote.appendChild(new Text("读一本好书,就是在和高尚的人谈话。 ——歌德"));document.appendChild(blockQuote);blockQuote = new BlockQuote();blockQuote.appendChild(new Text("雇用制度对工人不利,但工人根本无力摆脱这个制度。 ——阮一峰"));document.appendChild(blockQuote);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.7 链接"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("微信公众号仅支持公众号文章链接,即域名为"));paragraph.appendChild(new Code("https://mp.weixin.qq.com/"));paragraph.appendChild(new Text("的合法链接。使用方法如下所示:"));document.appendChild(paragraph);paragraph = new Paragraph();Link link = new Link("https://mp.weixin.qq.com/s/s5IhxV2ooX3JN_X416nidA", null);link.appendChild(new Text("你是《未来世界的幸存者》么?"));paragraph.appendChild(new Text("对于该论述,欢迎读者查阅之前发过的文章,"));paragraph.appendChild(link);document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.8 图片"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("插入图片,格式如下:"));document.appendChild(paragraph);paragraph = new Paragraph();Image image = new Image("https://markdown.com.cn/images/qrcode_for_gh_82cf87d482f0_258.jpg", null);image.appendChild(new Text("这里写图片描述"));paragraph.appendChild(image);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("支持 jpg、png、gif、svg 等图片格式,"));emphasis = new Emphasis("**");emphasis.appendChild(new Text("其中 svg 文件仅可在微信公众平台中使用"));paragraph.appendChild(emphasis);paragraph.appendChild(new Text(",svg 文件示例如下:"));document.appendChild(paragraph);paragraph = new Paragraph();image = new Image("https://markdown.com.cn/images/i-am-svg.svg", null);paragraph.appendChild(image);document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("支持图片"));strongEmphasis = new StrongEmphasis();strongEmphasis.appendChild(new Text("拖拽和截图粘贴"));paragraph.appendChild(strongEmphasis);paragraph.appendChild(new Text("到编辑器中。"));document.appendChild(paragraph);paragraph = new Paragraph();paragraph.appendChild(new Text("注:支持图片 "));strongEmphasis = new StrongEmphasis();emphasis = new Emphasis("*");emphasis.appendChild(new Text("拖拽和截图粘贴"));strongEmphasis.appendChild(emphasis);paragraph.appendChild(strongEmphasis);paragraph.appendChild(new Text(" 到编辑器中,仅支持 https 的图片,图片粘贴到微信时会自动上传微信服务器。"));document.appendChild(paragraph);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.9 分割线"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("可以在一行中用三个以上的减号来建立一个分隔线,同时需要在分隔线的上面空一行。如下:"));document.appendChild(paragraph);ThematicBreak thematicBreak = new ThematicBreak();thematicBreak.setLiteral("---");document.appendChild(thematicBreak);heading = new Heading();heading.setLevel(3);heading.appendChild(new Text("1.10 表格"));document.appendChild(heading);paragraph = new Paragraph();paragraph.appendChild(new Text("可以使用冒号来定义表格的对齐方式,如下:"));document.appendChild(paragraph);TableBlock tableBlock = new TableBlock();TableHead tableHead = new TableHead();TableRow tableRow = new TableRow();TableCell tableCell = new TableCell();tableCell.appendChild(new Text("姓名"));tableCell.setAlignment(TableCell.Alignment.LEFT);tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("年龄"));tableCell.setAlignment(TableCell.Alignment.CENTER);tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("工作"));tableCell.setAlignment(TableCell.Alignment.RIGHT);tableRow.appendChild(tableCell);tableHead.appendChild(tableRow);TableBody tableBody = new TableBody();tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小可爱"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("18"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("吃可爱多"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小小勇敢"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("20"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("爬棵勇敢树"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableRow = new TableRow();tableCell = new TableCell();tableCell.appendChild(new Text("小小小机智"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("22"));tableRow.appendChild(tableCell);tableCell = new TableCell();tableCell.appendChild(new Text("看一本机智书"));tableRow.appendChild(tableCell);tableBody.appendChild(tableRow);tableBlock.appendChild(tableHead);tableBlock.appendChild(tableBody);document.appendChild(tableBlock);List<Extension> extensions = List.of(TablesExtension.create());MarkdownRenderer markdownRenderer = MarkdownRenderer.builder().extensions(extensions).build();//转成markdown格式String md = markdownRenderer.render(document);System.out.println(md);HtmlRenderer htmlRenderer = HtmlRenderer.builder().extensions(extensions).build();//转成htmlString html = htmlRenderer.render(document);System.out.println(html);}@Testpublic void deserialize() throws IOException {List<Extension> extensions = List.of(TablesExtension.create());Parser parser = Parser.builder().extensions(extensions).build();InputStreamReader reader = new InputStreamReader(CommonmarkCase.class.getClassLoader().getResourceAsStream("test.md"));Node document = parser.parseReader(reader);Node node = document.getFirstChild();while (node != null) {System.out.println(node.getClass());if (node.getClass().equals(Heading.class)) {//处理标题Heading heading = (Heading) node;Text text = (Text)heading.getFirstChild();System.out.println(text.getLiteral());} else if (node.getClass().equals(BulletList.class)) {//处理无序列表BulletList bulletList = (BulletList) node;Node node2 = bulletList.getFirstChild();while (node2 != null) {if (node2.getClass().equals(ListItem.class)) {Node node3 = node2.getFirstChild();if (node3.getClass().equals(Paragraph.class)) {Text text = (Text)node3.getFirstChild();System.out.println(text.getLiteral());}if (node3.getNext() != null && node3.getNext().getClass().equals(BulletList.class)) {System.out.println("二级无序列表");//TODO: 继续解析 }}node2 = node2.getNext();}}//else if ...node = node.getNext();}} }
参考:https://github.com/commonmark/commonmark-java。