Pustaka Java untuk menguraikan dan merender teks Markdown sesuai dengan spesifikasi CommonMark (dan beberapa ekstensi).
Menyediakan kelas untuk mengurai input ke pohon sintaksis abstrak (AST), mengunjungi dan memanipulasi node, dan merender ke HTML atau kembali ke Markdown. Ini dimulai sebagai port commonmark.js, namun kemudian berkembang menjadi perpustakaan yang dapat diperluas dengan fitur berikut:
Kecil (inti tidak memiliki ketergantungan, ekstensi dalam artefak terpisah)
Cepat (10-20 kali lebih cepat dari pegdown yang dulunya merupakan perpustakaan Markdown yang populer, lihat tolok ukur di repo)
Fleksibel (memanipulasi AST setelah parsing, menyesuaikan rendering HTML)
Dapat diperluas (tabel, coretan, penautan otomatis, dan lainnya, lihat di bawah)
Perpustakaan didukung di Java 11 dan yang lebih baru. Ini juga berfungsi di Android, tapi itu atas dasar upaya terbaik, harap laporkan masalahnya. Untuk Android, level API minimum adalah 19, lihat direktori commonmark-android-test.
Koordinat untuk perpustakaan inti (lihat semuanya di Maven Central):
<ketergantungan> <groupId>org.commonmark</groupId> <artifactId>tanda umum</artifactId> <versi>0.24.0</versi> </ketergantungan>
Nama modul yang digunakan di Java 9 adalah org.commonmark
, org.commonmark.ext.autolink
, dll, sesuai dengan nama paket.
Perhatikan bahwa untuk rilis 0.x perpustakaan ini, API belum dianggap stabil dan mungkin terputus di antara rilis kecil. Setelah 1.0, Versi Semantik akan diikuti. Paket yang mengandung beta
berarti paket tersebut belum tunduk pada jaminan API yang stabil; namun untuk pemakaian normal sebaiknya tidak perlu digunakan.
Lihat file spec.txt jika Anda bertanya-tanya versi spesifikasi mana yang saat ini diterapkan. Periksa juga dingus CommonMark untuk mengenal sintaksis atau mencoba kasus edge. Jika Anda mengkloning repositori, Anda juga dapat menggunakan kelas DingusApp
untuk mencoba berbagai hal secara interaktif.
import org.commonmark.node.*;import org.commonmark.parser.Parser;import org.commonmark.renderer.html.HtmlRenderer;Parser parser = Parser.builder().build();Node document = parser.parse(" Ini adalah *Penurunan harga*");penyaji HtmlRenderer = HtmlRenderer.builder().build();renderer.render(dokumen); // "<p>Ini adalah <em>Penurunan harga</em></p>n"
Ini menggunakan parser dan renderer dengan opsi default. Kedua pembuat memiliki metode untuk mengonfigurasi perilakunya:
escapeHtml(true)
di HtmlRenderer
akan lolos dari tag dan blok HTML mentah.
sanitizeUrls(true)
di HtmlRenderer
akan menghapus URL yang berpotensi tidak aman dari tag <a>
dan <img>
Untuk semua opsi yang tersedia, lihat metode di pembuatnya.
Perhatikan bahwa perpustakaan ini tidak mencoba membersihkan HTML yang dihasilkan sehubungan dengan tag mana yang diperbolehkan, dll. Itu adalah tanggung jawab pemanggil, dan jika Anda mengekspos HTML yang dihasilkan, Anda mungkin ingin menjalankan pembersih setelah ini .
import org.commonmark.node.*;import org.commonmark.renderer.markdown.MarkdownRenderer;MarkdownRenderer renderer = MarkdownRenderer.builder().build();Node dokumen = Dokumen baru();Heading heading = new Heading();heading .setLevel(2);heading.appendChild(Teks baru("My title"));document.appendChild(heading);renderer.render(document); // "## Judul sayan"
Untuk merender ke teks biasa dengan markup minimal, ada juga TextContentRenderer
.
Setelah teks sumber diurai, hasilnya adalah pohon node. Pohon itu dapat dimodifikasi sebelum dirender, atau hanya diperiksa tanpa dirender:
Node node = parser.parse("Contohn=======nnBeberapa teks lagi");WordCountVisitor pengunjung = new WordCountVisitor();node.accept(visitor);visitor.wordCount; // 4kelas WordCountVisitor memperluas AbstrakVisitor { int WordCount = 0; @Override public void visit(Text text) {// Ini dipanggil untuk semua node Teks. Ganti metode kunjungan lain untuk jenis simpul lainnya. // Hitung kata (ini hanya contoh, jangan lakukan seperti ini karena berbagai alasan). jumlah kata += teks.getLiteral().split("\W+").panjang; // Turun ke turunan (dapat dihilangkan dalam kasus ini karena node Teks tidak memiliki turunan). kunjungiAnak-anak(teks); } }
Jika Anda ingin mengetahui di mana Node
yang diurai muncul di teks sumber masukan, Anda dapat meminta parser untuk mengembalikan posisi sumber seperti ini:
var parser = Parser.builder().includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES).build();
Kemudian parsing node dan periksa posisi sumber:
var source = "foonnbar *baz*";var doc = parser.parse(source);var penekanan = doc.getLastChild().getLastChild();var s = penekanan.getSourceSpans().get(0) ;s.getLineIndex(); // 2 (baris ketiga)s.getColumnIndex(); // 4 (kolom kelima)s.getInputIndex(); // 9 (indeks string 9)s.getLength(); // 5source.substring(s.getInputIndex(), s.getInputIndex() + s.getLength()); // "*baz*"
Jika Anda hanya tertarik pada blok dan bukan inline, gunakan IncludeSourceSpans.BLOCKS
.
Terkadang Anda mungkin ingin menyesuaikan cara HTML dirender. Jika yang ingin Anda lakukan hanyalah menambah atau mengubah atribut pada beberapa elemen, ada cara sederhana untuk melakukannya.
Dalam contoh ini, kita mendaftarkan pabrik untuk AttributeProvider
pada renderer untuk menyetel atribut class="border"
pada elemen img
.
Pengurai parser = Parser.builder().build();HtmlRenderer penyaji = HtmlRenderer.builder() .attributeProviderFactory(new AttributeProviderFactory() { public AttributeProvider buat(AttributeProviderContext konteks) { kembalikan ImageAttributeProvider(); } }) .build();Node dokumen = parser.parse("![teks](/url.png)");renderer.render(document);// "<p><img src="/url.png " alt="text" class="border" /></p>n"class ImageAttributeProvider mengimplementasikan AttributeProvider { @Override public void setAttributes(Node node, String tagName, Atribut Map<String, String>) { if (node instanceof Image) { atribut.put("class", "border"); } } }
Jika Anda ingin melakukan lebih dari sekadar mengubah atribut, ada juga cara untuk mengambil kendali penuh atas cara HTML dirender.
Dalam contoh ini, kami mengubah rendering blok kode yang menjorok ke dalam untuk hanya membungkusnya dalam pre
bukan pre
dan code
:
Pengurai parser = Parser.builder().build();HtmlRenderer penyaji = HtmlRenderer.builder() .nodeRendererFactory(baru HtmlNodeRendererFactory() { pembuatan NodeRenderer publik(konteks HtmlNodeRendererContext) { kembalikan IndentedCodeBlockNodeRenderer(konteks); } }) .build();Node document = parser.parse("Contoh:nn kode");renderer.render(document);// "<p>Contoh:</p>n<pre>coden </pre>n"class IndentedCodeBlockNodeRenderer mengimplementasikan NodeRenderer { private final HtmlWriter html; IndentedCodeBlockNodeRenderer(HtmlNodeRendererContext konteks) { this.html = konteks.getWriter(); } @Ganti Set<Kelas<? extends Node>> getNodeTypes() { // Mengembalikan tipe node yang ingin kita gunakan untuk renderer ini. return Set.of(IndentedCodeBlock.class); } @Override public void render(Node node) {// Kita hanya menangani satu tipe sesuai getNodeTypes, jadi kita bisa melemparkannya ke sini. IndentedCodeBlock codeBlock = (IndentedCodeBlock) simpul; html.baris(); html.tag("pra"); html.teks(codeBlock.getLiteral()); html.tag("/pra"); html.baris(); } }
Jika Anda ingin menyimpan data tambahan dalam dokumen atau memiliki elemen khusus dalam HTML yang dihasilkan, Anda dapat membuat subkelas CustomNode
Anda sendiri dan menambahkan instance sebagai node anak ke node yang ada.
Untuk menentukan rendering HTML, Anda dapat menggunakan NodeRenderer
seperti yang dijelaskan di atas.
Ada beberapa cara untuk memperluas penguraian atau bahkan mengganti penguraian bawaan, semuanya melalui metode di Parser.Builder
(lihat Blok dan sebaris dalam spesifikasi untuk ikhtisar blok/sebaris):
Penguraian jenis blok tertentu (misalnya judul, blok kode, dll) dapat diaktifkan/dinonaktifkan dengan enabledBlockTypes
Penguraian blok dapat diperluas/ditimpa dengan customBlockParserFactory
Penguraian konten sebaris dapat diperluas/ditimpa dengan customInlineContentParserFactory
Penguraian pembatas dalam konten sebaris dapat diperluas dengan customDelimiterProcessor
Pemrosesan tautan dapat dikustomisasi dengan linkProcessor
dan linkMarker
Parser
dan HtmlRenderer
dirancang sedemikian rupa sehingga Anda dapat mengonfigurasinya sekali menggunakan pembuatnya dan kemudian menggunakannya beberapa kali/dari beberapa thread. Hal ini dilakukan dengan memisahkan status untuk parsing/rendering dari konfigurasi.
Karena itu, tentu saja mungkin ada bug. Jika Anda menemukannya, laporkan masalahnya.
Javadocs tersedia online di javadoc.io.
Ekstensi perlu memperluas parser, atau penyaji HTML, atau keduanya. Untuk menggunakan ekstensi, objek pembuat dapat dikonfigurasi dengan daftar ekstensi. Karena ekstensi bersifat opsional, ekstensi berada dalam artefak terpisah, sehingga dependensi tambahan juga perlu ditambahkan.
Mari kita lihat cara mengaktifkan tabel dari GitHub Flavored Markdown. Pertama, tambahkan ketergantungan tambahan (lihat Maven Central untuk yang lainnya):
<ketergantungan> <groupId>org.commonmark</groupId> <artifactId>tabel-commonmark-ext-gfm</artifactId> <versi>0.24.0</versi> </ketergantungan>
Kemudian, konfigurasikan ekstensi pada pembuatnya:
import org.commonmark.ext.gfm.tables.TablesExtension;Daftar<Ekstensi> extensions = List.of(TablesExtension.create());Parser parser = Parser.builder() .ekstensi(ekstensi) .build();penyaji HtmlRenderer = HtmlRenderer.builder() .ekstensi(ekstensi) .membangun();
Untuk mengonfigurasi ekstensi lain pada contoh di atas, cukup tambahkan ekstensi tersebut ke daftar.
Ekstensi berikut dikembangkan dengan perpustakaan ini, masing-masing memiliki artefaknya sendiri.
Mengubah tautan biasa seperti URL dan alamat email menjadi tautan (berdasarkan autolink-java).
Gunakan kelas AutolinkExtension
dari artefak commonmark-ext-autolink
.
Mengaktifkan coretan teks dengan mengapitnya di ~~
. Misalnya, di hey ~~you~~
, you
akan ditampilkan sebagai teks yang dicoret.
Gunakan kelas StrikethroughExtension
dalam artefak commonmark-ext-gfm-strikethrough
.
Mengaktifkan tabel menggunakan pipa seperti pada GitHub Flavored Markdown.
Gunakan kelas TablesExtension
dalam artefak commonmark-ext-gfm-tables
.
Mengaktifkan catatan kaki seperti di GitHub atau Pandoc:
Main text[^1] [^1]: Additional text in a footnote
Catatan kaki sebaris seperti ^[inline footnote]
juga didukung bila diaktifkan melalui FootnotesExtension.Builder#inlineFootnotes
.
Gunakan kelas FootnotesExtension
dalam artefak commonmark-ext-footnotes
.
Memungkinkan penambahan atribut "id" yang dibuat secara otomatis ke tag judul. "Id" didasarkan pada teks judul.
# Heading
akan ditampilkan sebagai:
<h1 id="heading">Heading</h1>
Gunakan kelas HeadingAnchorExtension
dalam artefak commonmark-ext-heading-anchor
.
Jika Anda menginginkan rendering judul khusus, Anda dapat menggunakan kelas IdGenerator
secara langsung bersama dengan HtmlNodeRendererFactory
(lihat contoh di atas).
Mengaktifkan penggaris bawahan teks dengan mengapitnya dalam ++
. Misalnya, di hey ++you++
, you
akan ditampilkan sebagai teks yang digaris bawahi. Menggunakan tag <ins>.
Gunakan kelas InsExtension
dalam artefak commonmark-ext-ins
.
Menambahkan dukungan untuk metadata melalui blok materi depan YAML. Ekstensi ini hanya mendukung sebagian sintaksis YAML. Berikut ini contoh yang didukung:
--- key: value list: - value 1 - value 2 literal: | this is literal value. literal values 2 --- document start here
Gunakan kelas YamlFrontMatterExtension
dalam artefak commonmark-ext-yaml-front-matter
. Untuk mengambil metadata, gunakan YamlFrontMatterVisitor
.
Menambahkan dukungan untuk menentukan atribut (khususnya tinggi dan lebar) untuk gambar.
Elemen atribut diberikan sebagai pasangan key=value
di dalam kurung kurawal { }
setelah node gambar yang menerapkannya, misalnya:
![text](/url.png){width=640 height=480}
akan ditampilkan sebagai:
<img src="/url.png" alt="text" width="640" height="480" />
Gunakan kelas ImageAttributesExtension
dalam artefak commonmark-ext-image-attributes
.
Catatan: karena ekstensi ini menggunakan kurung kurawal {
}
sebagai pembatasnya (dalam StylesDelimiterProcessor
), ini berarti pemroses pembatas lainnya tidak dapat menggunakan kurung kurawal untuk membatasi.
Menambahkan dukungan untuk tugas sebagai item daftar.
Tugas dapat direpresentasikan sebagai item daftar dengan karakter non-spasi pertama adalah tanda kurung kiri [
, lalu satu karakter spasi putih atau huruf x
dalam huruf kecil atau besar, lalu tanda kurung siku kanan ]
diikuti oleh setidaknya satu spasi sebelum yang lain isi.
Misalnya:
- [ ] task #1 - [x] task #2
akan ditampilkan sebagai:
<ul> <li><input type="checkbox" disabled=""> task #1</li> <li><input type="checkbox" disabled="" checked=""> task #2</li> </ul>
Gunakan kelas TaskListItemsExtension
dalam artefak commonmark-ext-task-list-items
.
Anda juga dapat menemukan ekstensi lain di alam liar:
commonmark-ext-notifications: ekstensi ini memungkinkan untuk dengan mudah membuat paragraf notifikasi/peringatan seperti INFO
, SUCCESS
, WARNING
atau ERROR
Beberapa pengguna perpustakaan ini (silakan ajukan PR jika ingin ditambahkan):
Atlassian (tempat perpustakaan pertama kali dikembangkan)
Java (OpenJDK) (tautan)
Tinjauan kode Gerrit/Gitiles (tautan)
Pemrograman langsung yang dapat dibentuk oleh petugas untuk Clojure
Znai
Markwon: Pustaka Android untuk merender penurunan harga sebagai Spannables asli sistem
flexmark-java: Fork yang menambahkan dukungan untuk lebih banyak sintaks dan fleksibilitas
Lihat file CONTRIBUTING.md.
Hak Cipta (c) 2015, Robin Stocker
Berlisensi BSD (2-klausul), lihat file LICENSE.txt.