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(); //轉成html String 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 { @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(); //轉成html String html = htmlRenderer.render(document); System.out.println(html); } @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(); } } }
參考:https://github.com/commonmark/commonmark-java。