使用 commonmark-java 进行 Markdown 渲染
1. 概述
处理 Markdown 内容是常见的编程任务。CommonMark 是一个 Java 库,可简化 Markdown 文档的处理。
在本教程中,我们将学习如何使用该库操作 Markdown 内容。我们将了解如何将 Markdown 解析为 HTML,以及如何将 HTML 转换回 Markdown。最后,我们将探索如何自定义节点以实现高级处理。
2. commonmark-java 库
commonmark-java 库提供了基于 CommonMark 规范处理 Markdown 内容的类和接口。它允许我们将 Markdown 解析为 HTML,并将 HTML 转换回 Markdown。此外,它还提供对抽象语法树(AST)的访问,从而实现进一步的自定义和处理。
要使用 commonmark-java 库,我们将 commonmark 依赖添加到 pom.xml 中:
commonmark 依赖提供了用于 Markdown 处理和渲染的类,例如 Parser、HtmlRenderer 和 MarkdownRenderer。
此外,CommonMark 还提供扩展依赖以实现更高级的处理功能,例如用于 GitHub 风格的 Markdown 表格的 commonmark-ext-gfm-tables 和用于警报块的 commonmark-ext-gfm-alerts。
3. 将 Markdown 解析并渲染为 HTML
接下来,我们看一下该库最常见的用途之一:解析 Markdown 并将其渲染为 HTML。
首先,定义一个名为 markDownToHtml() 的方法:
这里,我们创建了一个 Parser 实例来将 Markdown 输入解析为文档节点。接着,创建 HtmlRenderer 实例将解析后的节点渲染为 HTML。
Node 表示解析后的 Markdown 文档树中的一个元素。
然后,编写一个单元测试来验证结果:
在上面的代码中,我们将包含 Markdown 语法的字符串传递给 markDownToHtml() 方法。由于 Baeldung 被星号 (*) 包裹,Markdown 解析器将其解释为强调文本。因此,渲染器将其转换为 HTML 的 <em> 元素。
4. 处理解析后的节点
此外,我们可以使用访问者模式来进一步处理解析后的文档树中的节点。该库允许我们扩展 AbstractVisitor 类来处理节点。
让我们创建一个访问者类,统计句子中的每个单词数量:
接下来,编写一个使用该访问者的方法:
在上面的方法中,我们创建了一个 WordCountVisitor 对象并将其传递给解析后的节点进行处理。
编写一个单元测试来确认该方法:
这里,我们验证预期的单词计数与实际单词计数相等。
5. 将 HTML 渲染为 Markdown
此外,CommonMark 还提供了将类似 HTML 的文档结构渲染为 Markdown 格式的类,使其成为一个同时用于 HTML 和 Markdown 处理的库。
让我们通过编写将 HTML 标题转换为 Markdown 格式的代码来展示这一点:
在上面的代码中,我们创建了一个 Heading 对象,并将其级别设置为 2,表示 H2 标题。接着,我们追加一个包含标题内容的 Text 对象。最后,使用 MarkdownRenderer 构建器将文档渲染为 Markdown。
接下来,编写一个单元测试来确认输出:
在上面的代码中,我们验证了渲染器正确地将文档结构转换为有效的 Markdown 输出。
6. 自定义 HTML 渲染
此外,CommonMark 允许我们使用 AttributeProvider 接口自定义渲染的 HTML 属性。
让我们通过实现一个自定义图片属性提供者类来展示这一点:
在上面的代码中,我们创建了一个名为 ImageAttributeProvider 的类,实现了 AttributeProvider 接口。在 setAttributes() 方法中,我们检查当前节点是否为 Image 的实例。如果是,则添加一个值为 "border" 的 class 属性。
接下来,编写一个方法,在 HTML 渲染期间应用自定义属性提供者:
在上面的代码中,我们使用 attributeProviderFactory() 方法自定义 HtmlRenderer,传入自定义的属性提供者。通过lambda 表达式,我们为每个节点调用我们的提供者,从而可以自定义生成的 HTML 属性。每个渲染的图片元素都会获得一个 class="border" 属性。
最后,编写一个单元测试来验证自定义输出:
在上面的测试中,我们验证了自定义属性提供者成功地将 border CSS 类添加到了渲染的图片元素中。
7. 自定义渲染节点
此外,该库允许我们通过实现 NodeRenderer 接口来自定义特定节点的渲染方式。
让我们为 IndentedCodeBlock 节点创建一个自定义渲染器:
在上面的代码中,我们实现了 NodeRenderer 接口,并通过 getNodeTypes() 方法指定该渲染器处理 IndentedCodeBlock 节点。
然后,在 render() 方法中,我们使用 HtmlWriter 手动生成代码块的 HTML 输出。
接下来,将自定义渲染器注册到 HtmlRenderer:
这里,我们使用 nodeRendererFactory() 方法自定义渲染器。通过方法引用调用自定义节点。这允许渲染器在 HTML 生成期间将匹配的节点委托给我们的自定义实现。
编写一个单元测试来验证 customizingHtmlRendering() 方法:
这里,我们验证了缩进代码块使用了我们的自定义渲染器实现来渲染。
8. 结论
在本文中,我们学习了如何使用 CommonMark 库将 Markdown 解析为 HTML,以及将 HTML 转换回 Markdown。此外,我们还了解了如何自定义 HTML 属性和节点渲染以实现更高级的处理场景。
与往常一样,示例代码的源代码可在 GitHub 上获取。