CommonMark 사양(및 일부 확장)에 따라 Markdown 텍스트를 구문 분석하고 렌더링하기 위한 Java 라이브러리입니다.
AST(추상 구문 트리)에 대한 입력을 구문 분석하고, 노드를 방문 및 조작하고, HTML로 렌더링하거나 Markdown으로 다시 렌더링하기 위한 클래스를 제공합니다. commonmark.js의 포트로 시작되었지만 이후 다음 기능을 갖춘 확장 가능한 라이브러리로 발전했습니다.
작음(코어에는 종속성이 없으며 별도의 아티팩트에 확장이 있음)
빠름(인기 있는 Markdown 라이브러리였던 pegdown보다 10~20배 빠릅니다. 저장소의 벤치마크 참조)
유연성(파싱 후 AST 조작, HTML 렌더링 사용자 정의)
확장 가능(테이블, 취소선, 자동 링크 등, 아래 참조)
라이브러리는 Java 11 이상에서 지원됩니다. Android에서도 작동하지만 이는 최선의 노력을 바탕으로 한 것이므로 문제를 보고해 주세요. Android의 경우 최소 API 레벨은 19입니다. commonmark-android-test 디렉토리를 참조하세요.
핵심 라이브러리의 좌표(Maven Central에서 모두 참조):
<의존성> <groupId>org.commonmark</groupId> <artifactId>공통마크</artifactId> <버전>0.24.0</버전> </종속성>
Java 9에서 사용하는 모듈 이름은 패키지 이름에 해당하는 org.commonmark
, org.commonmark.ext.autolink
등입니다.
이 라이브러리의 0.x 릴리스의 경우 API는 아직 안정적인 것으로 간주되지 않으며 마이너 릴리스 사이에 중단될 수 있습니다. 1.0 이후에는 Semantic Versioning이 적용됩니다. beta
포함된 패키지는 아직 안정적인 API 보장이 적용되지 않음을 의미합니다. 그러나 일반적인 사용법에서는 사용할 필요가 없습니다.
현재 구현된 사양 버전이 궁금하다면 spec.txt 파일을 참조하세요. 또한 구문에 익숙해지거나 극단적인 사례를 시험해 보려면 CommonMark dingus를 확인하세요. 저장소를 복제하면 DingusApp
클래스를 사용하여 대화형으로 시험해 볼 수도 있습니다.
import org.commonmark.node.*;import org.commonmark.parser.Parser;import org.commonmark.renderer.html.HtmlRenderer;파서 파서 = Parser.builder().build();노드 문서 = 파서.parse(" 이것은 *Markdown*입니다.");HtmlRenderer 렌더러 = HtmlRenderer.builder().build();renderer.render(document); // "<p>이것은 <em>마크다운</em>입니다.</p>n"
이는 기본 옵션과 함께 파서 및 렌더러를 사용합니다. 두 빌더 모두 동작을 구성하는 방법이 있습니다.
HtmlRenderer
의 escapeHtml(true)
원시 HTML 태그와 블록을 이스케이프합니다.
HtmlRenderer
의 sanitizeUrls(true)
는 <a>
및 <img>
태그에서 잠재적으로 안전하지 않은 URL을 제거합니다.
사용 가능한 모든 옵션을 보려면 빌더의 메서드를 참조하세요.
이 라이브러리는 어떤 태그가 허용되는지 등과 관련하여 결과 HTML을 삭제하려고 시도하지 않습니다. 이는 호출자의 책임이며, 결과 HTML을 노출하는 경우 이 후에 해당 HTML에 대해 삭제 프로그램을 실행하고 싶을 수도 있습니다. .
import org.commonmark.node.*;import org.commonmark.renderer.markdown.MarkdownRenderer;MarkdownRenderer 렌더러 = MarkdownRenderer.builder().build();노드 문서 = 새 Document();제목 제목 = 새 제목();제목 .setLevel(2);heading.appendChild(new Text("내 제목"));document.appendChild(제목);renderer.render(document); // "## 내 제목n"
최소한의 마크업으로 일반 텍스트로 렌더링하기 위한 TextContentRenderer
도 있습니다.
소스 텍스트가 구문 분석된 후 결과는 노드 트리입니다. 해당 트리는 렌더링하기 전에 수정하거나 렌더링하지 않고 검사할 수 있습니다.
노드 노드 = 파서.parse("예n=======nn추가 텍스트");WordCountVisitor Visitor = new WordCountVisitor();node.accept(visitor);visitor.wordCount; // 4클래스 WordCountVisitor는 AbstractVisitor를 확장합니다. { int wordCount = 0; @Override public void Visit(Text text) { // 이는 모든 Text 노드에 대해 호출됩니다. 다른 노드 유형에 대해서는 다른 방문 방법을 재정의합니다. // 단어 수를 셉니다(이것은 단지 예일 뿐이므로 실제로는 여러 가지 이유로 이렇게 하지 마세요). wordCount += text.getLiteral().split("\W+").length; // 하위 항목으로 내려갑니다(이 경우 Text 노드에 하위 항목이 없으므로 생략할 수 있음). VisitChildren(text); } }
구문 분석된 Node
입력 소스 텍스트에 나타난 위치를 알고 싶다면 다음과 같이 소스 위치를 반환하도록 구문 분석기에 요청할 수 있습니다.
var 파서 = Parser.builder().includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES).build();
그런 다음 노드를 구문 분석하고 소스 위치를 검사합니다.
var 소스 = "foonnbar *baz*";var doc = 파서.parse(소스);var 강조 = doc.getLastChild().getLastChild();var s = 강조.getSourceSpans().get(0) ;s.getLineIndex(); // 2 (세번째 줄)s.getColumnIndex(); // 4 (다섯번째 열)s.getInputIndex(); // 9 (문자열 인덱스 9)s.getLength(); // 5source.substring(s.getInputIndex(), s.getInputIndex() + s.getLength()); // "*바즈*"
인라인이 아닌 블록에만 관심이 있는 경우에는 IncludeSourceSpans.BLOCKS
사용하세요.
때로는 HTML이 렌더링되는 방식을 사용자 정의하고 싶을 수도 있습니다. 일부 요소의 속성을 추가하거나 변경하려는 경우 간단한 방법이 있습니다.
이 예에서는 img
요소에 class="border"
속성을 설정하기 위해 렌더러에 AttributeProvider
에 대한 팩토리를 등록합니다.
파서 파서 = Parser.builder().build();HtmlRenderer 렌더러 = HtmlRenderer.builder() .attributeProviderFactory(new AttributeProviderFactory() { public AttributeProvider create(AttributeProviderContext context) { return new ImageAttributeProvider(); } }) .build();노드 문서 = parser.parse("![text](/url.png)");renderer.render(document);// "<p><img src="/url.png " alt="text" class="border" /></p>n"class ImageAttributeProvider는 AttributeProvider를 구현합니다. { @Override public void setAttributes(Node node, String tagName, Map<String, String> 속성) { if (이미지의 노드 인스턴스) { attribute.put("class", "border"); } } }
속성을 변경하는 것 이상의 작업을 수행하려는 경우 HTML이 렌더링되는 방식을 완전히 제어할 수 있는 방법도 있습니다.
이 예에서는 들여쓰기된 코드 블록의 렌더링을 pre
및 code
대신 pre
로만 래핑하도록 변경합니다.
파서 파서 = Parser.builder().build();HtmlRenderer 렌더러 = HtmlRenderer.builder() .nodeRendererFactory(new HtmlNodeRendererFactory() { public NodeRenderer create(HtmlNodeRendererContext context) { return new IndentedCodeBlockNodeRenderer(context); } }) .build();노드 문서 = parser.parse("예:nn 코드");renderer.render(document);// "<p>예:</p>n<pre>코드n </pre>n"class IndentedCodeBlockNodeRenderer는 NodeRenderer를 구현합니다. { private final HtmlWriter html; IndentedCodeBlockNodeRenderer(HtmlNodeRendererContext context) { this.html = context.getWriter(); } @Override 공개 Set<Class<? extends Node>> getNodeTypes() { // 이 렌더러를 사용하려는 노드 유형을 반환합니다. return Set.of(IndentedCodeBlock.class); } @Override public void render(Node node) { // getNodeTypes에 따라 하나의 유형만 처리하므로 여기에서 캐스팅하면 됩니다. IndentedCodeBlock codeBlock = (IndentedCodeBlock) 노드; html.line(); html.tag("pre"); html.text(codeBlock.getLiteral()); html.tag("/pre"); html.line(); } }
문서에 추가 데이터를 저장하거나 결과 HTML에 사용자 정의 요소가 있는 경우 CustomNode
의 자체 하위 클래스를 만들고 인스턴스를 기존 노드에 하위 노드로 추가할 수 있습니다.
HTML 렌더링을 정의하려면 위에서 설명한 대로 NodeRenderer
사용할 수 있습니다.
구문 분석을 확장하거나 내장 구문 분석을 재정의하는 몇 가지 방법이 있습니다. 모두 Parser.Builder
의 메서드를 통해 이루어집니다(블록/인라인 개요는 사양의 블록 및 인라인 참조).
특정 블록 유형(예: 제목, 코드 블록 등)의 구문 분석은 활성화된 enabledBlockTypes
사용하여 활성화/비활성화할 수 있습니다.
customBlockParserFactory
사용하여 블록 구문 분석을 확장/재정의할 수 있습니다.
customInlineContentParserFactory
를 사용하여 인라인 콘텐츠 구문 분석을 확장/재정의할 수 있습니다.
customDelimiterProcessor
사용하여 인라인 콘텐츠의 구분 기호 구문 분석을 확장할 수 있습니다.
linkProcessor
및 linkMarker
사용하여 링크 처리를 사용자 정의할 수 있습니다.
Parser
와 HtmlRenderer
모두 빌더를 사용하여 한 번 구성한 다음 여러 스레드에서 여러 번 사용할 수 있도록 설계되었습니다. 이는 구문 분석/렌더링 상태를 구성에서 분리하여 수행됩니다.
물론 버그가 있을 수도 있다고 합니다. 발견하시면 문제를 신고해주세요.
Javadoc은 javadoc.io에서 온라인으로 사용할 수 있습니다.
확장은 파서나 HTML 렌더러 또는 둘 다를 확장해야 합니다. 확장을 사용하려면 확장 목록을 사용하여 빌더 개체를 구성하면 됩니다. 확장은 선택 사항이므로 별도의 아티팩트에 있으므로 추가 종속성도 추가해야 합니다.
GitHub Flavored Markdown에서 테이블을 활성화하는 방법을 살펴보겠습니다. 먼저 추가 종속성을 추가합니다(다른 내용은 Maven Central 참조).
<의존성> <groupId>org.commonmark</groupId> <artifactId>commonmark-ext-gfm-tables</artifactId> <버전>0.24.0</버전> </의존성>
그런 다음 빌더에서 확장을 구성합니다.
import org.commonmark.ext.gfm.tables.TablesExtension;List<Extension> 확장 = List.of(TablesExtension.create());Parser 파서 = Parser.builder() .extensions(확장자) .build();HtmlRenderer 렌더러 = HtmlRenderer.builder() .extensions(확장자) .짓다();
위 예에서 다른 확장을 구성하려면 해당 확장을 목록에 추가하기만 하면 됩니다.
다음 확장은 각각 자체 아티팩트에서 이 라이브러리를 사용하여 개발되었습니다.
URL 및 이메일 주소와 같은 일반 링크를 링크로 변환합니다(autolink-java 기반).
아티팩트 commonmark-ext-autolink
의 AutolinkExtension
클래스를 사용하세요.
텍스트를 ~~
로 묶어 취소선을 활성화합니다. 예를 들어 hey ~~you~~
에서는 취소선 텍스트로 you
됩니다.
아티팩트 commonmark-ext-gfm-strikethrough
에서 StrikethroughExtension
클래스를 사용하세요.
GitHub Flavored Markdown에서와 같이 파이프를 사용하여 테이블을 활성화합니다.
아티팩트 commonmark-ext-gfm-tables
에서 TablesExtension
클래스를 사용하세요.
GitHub 또는 Pandoc과 같은 각주를 활성화합니다.
Main text[^1] [^1]: Additional text in a footnote
^[inline footnote]
와 같은 인라인 각주는 FootnotesExtension.Builder#inlineFootnotes
통해 활성화되면 지원됩니다.
아티팩트 commonmark-ext-footnotes
에서 FootnotesExtension
클래스를 사용하세요.
제목 태그에 자동 생성된 "id" 속성을 추가할 수 있습니다. "id"는 제목의 텍스트를 기반으로 합니다.
# Heading
다음과 같이 렌더링됩니다:
<h1 id="heading">Heading</h1>
아티팩트 commonmark-ext-heading-anchor
에서 HeadingAnchorExtension
클래스를 사용하세요.
대신 제목의 사용자 정의 렌더링을 원하는 경우 HtmlNodeRendererFactory
와 함께 IdGenerator
클래스를 직접 사용할 수 있습니다(위 예 참조).
++
로 묶어 텍스트에 밑줄을 긋습니다. 예를 들어 hey ++you++
에서는 밑줄 텍스트로 you
됩니다. <ins> 태그를 사용합니다.
아티팩트 commonmark-ext-ins
에서 InsExtension
클래스를 사용하세요.
YAML 머리말 블록을 통해 메타데이터에 대한 지원을 추가합니다. 이 확장은 YAML 구문의 하위 집합만 지원합니다. 지원되는 내용의 예는 다음과 같습니다.
--- key: value list: - value 1 - value 2 literal: | this is literal value. literal values 2 --- document start here
아티팩트 commonmark-ext-yaml-front-matter
에서 YamlFrontMatterExtension
클래스를 사용하세요. 메타데이터를 가져오려면 YamlFrontMatterVisitor
사용하세요.
이미지의 속성(특히 높이 및 너비) 지정에 대한 지원을 추가합니다.
속성 요소는 해당 요소가 적용되는 이미지 노드 뒤의 중괄호 { }
안에 key=value
쌍으로 제공됩니다. 예를 들면 다음과 같습니다.
![text](/url.png){width=640 height=480}
다음과 같이 렌더링됩니다.
<img src="/url.png" alt="text" width="640" height="480" />
아티팩트 commonmark-ext-image-attributes
에서 ImageAttributesExtension
클래스를 사용하세요.
참고: 이 확장은 중괄호 {
}
구분 기호로 사용하므로( StylesDelimiterProcessor
에서) 이는 다른 구분 기호 프로세서가 구분에 중괄호를 사용할 수 없음 을 의미합니다.
작업에 대한 지원을 목록 항목으로 추가합니다.
작업은 공백이 아닌 첫 번째 문자가 왼쪽 대괄호 [
이고 그 다음 단일 공백 문자 또는 소문자 또는 대문자의 문자 x
, 그 다음 오른쪽 대괄호 ]
다음에 다른 공백 앞에 최소한 하나의 공백이 있는 목록 항목으로 표시될 수 있습니다. 콘텐츠.
예를 들어:
- [ ] task #1 - [x] task #2
다음과 같이 렌더링됩니다.
<ul> <li><input type="checkbox" disabled=""> task #1</li> <li><input type="checkbox" disabled="" checked=""> task #2</li> </ul>
아티팩트 commonmark-ext-task-list-items
에서 TaskListItemsExtension
클래스를 사용하세요.
또한 다음과 같은 다른 확장 기능도 찾을 수 있습니다.
commonmark-ext-notifications: 이 확장을 사용하면 INFO
, SUCCESS
, WARNING
또는 ERROR
같은 알림/경고 단락을 쉽게 만들 수 있습니다.
이 라이브러리의 일부 사용자(추가하고 싶다면 자유롭게 PR을 올려주세요):
Atlassian(라이브러리가 처음 개발된 곳)
자바(OpenJDK)(링크)
Gerrit 코드 검토/Gtiles(링크)
Clojure용 사무원 성형 가능 라이브 프로그래밍
즈나이
Markwon: 마크다운을 시스템 네이티브 Spannable로 렌더링하기 위한 Android 라이브러리
flexmark-java: 훨씬 더 많은 구문과 유연성에 대한 지원을 추가한 포크
CONTRIBUTING.md 파일을 참조하세요.
저작권 (c) 2015, 로빈 스토커
BSD(2절) 라이센스가 부여되었습니다. LICENSE.txt 파일을 참조하십시오.