All formats

commonmark-java

LanguageJava (11+)
LicenseBSD-2-Clause
Repositorygithub.com/commonmark/commonmark-java
DocumentationREADME, javadoc
Depends onnothing (extensions: autolink-java for the autolink extension)
Read / writeparses 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:

XML
<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#

Java
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);
    }
}
Java
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#

Java
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#

Java
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#

Java
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#