commonmark-java
| Language | Java (11+) |
|---|---|
| License | BSD-2-Clause |
| Repository | github.com/commonmark/commonmark-java |
| Documentation | README, javadoc |
| Depends on | nothing (extensions: autolink-java for the autolink extension) |
| Read / write | parses CommonMark; renders HTML, plain text and Markdown |
commonmark-java implements the CommonMark spec with a parser that builds a node tree (Document, Heading, Paragraph, Link, Text, …) and renderers for HTML (HtmlRenderer), plain text (TextContentRenderer) and Markdown (MarkdownRenderer). It’s fast, has no dependencies, and can record source positions for each node.
GFM and other features are opt-in extension artifacts: commonmark-ext-gfm-tables, commonmark-ext-gfm-strikethrough, commonmark-ext-autolink, commonmark-ext-task-list-items, commonmark-ext-footnotes, commonmark-ext-heading-anchor, commonmark-ext-yaml-front-matter, commonmark-ext-ins and commonmark-ext-image-attributes. Raw HTML passes through by default; escapeHtml(true) and sanitizeUrls(true) on the renderer make output safe for untrusted input.
Installation#
Maven:
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.32.0</version>
</dependency>
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark-ext-gfm-tables</artifactId>
<version>0.32.0</version>
</dependency>
Gradle: implementation("org.commonmark:commonmark:0.32.0")
Basic usage: convert Markdown to HTML#
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import org.commonmark.Extension;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
public class MdToHtml {
public static void main(String[] args) throws Exception {
List<Extension> extensions = List.of(TablesExtension.create());
Parser parser = Parser.builder().extensions(extensions).build();
HtmlRenderer renderer = HtmlRenderer.builder().extensions(extensions).build();
Node document = parser.parse(Files.readString(Path.of("README.md")));
String html = renderer.render(document);
Files.writeString(Path.of("README.html"), html);
}
}
How to list headings and links (visitor)#
import org.commonmark.node.*;
Node doc = Parser.builder().build().parse(markdown);
doc.accept(new AbstractVisitor() {
@Override
public void visit(Heading heading) {
StringBuilder sb = new StringBuilder();
for (Node n = heading.getFirstChild(); n != null; n = n.getNext())
if (n instanceof Text t) sb.append(t.getLiteral());
System.out.println("h" + heading.getLevel() + ": " + sb);
visitChildren(heading);
}
@Override
public void visit(Link link) {
System.out.println("link: " + link.getDestination());
visitChildren(link);
}
});
How to render untrusted Markdown safely#
HtmlRenderer renderer = HtmlRenderer.builder()
.escapeHtml(true) // raw HTML is shown as text
.sanitizeUrls(true) // drops javascript: and similar URLs
.build();
How to read YAML front matter#
import org.commonmark.ext.front.matter.YamlFrontMatterExtension;
import org.commonmark.ext.front.matter.YamlFrontMatterVisitor;
Parser parser = Parser.builder().extensions(List.of(YamlFrontMatterExtension.create())).build();
Node document = parser.parse(markdown);
YamlFrontMatterVisitor visitor = new YamlFrontMatterVisitor();
document.accept(visitor);
Map<String, List<String>> data = visitor.getData(); // e.g. {title=[Release notes]}
The extension’s simple parser handles key: value and lists; parse the raw text with a YAML library for anything more.
How to generate Markdown from a tree#
import org.commonmark.renderer.markdown.MarkdownRenderer;
Heading heading = new Heading();
heading.setLevel(2);
heading.appendChild(new Text("Changelog"));
Document doc = new Document();
doc.appendChild(heading);
String md = MarkdownRenderer.builder().build().render(doc); // "## Changelog\n"
Tips#
ParserandHtmlRendererare immutable and thread-safe; build them once.Parser.builder().includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES)records line and column positions for each node.TextContentRenderer.builder().build().render(doc)strips markup to plain text, for search indexes or previews.