ไลบรารี Java สำหรับการแยกวิเคราะห์และแสดงข้อความ Markdown ตามข้อกำหนด CommonMark (และส่วนขยายบางส่วน)
จัดให้มีคลาสสำหรับการแยกวิเคราะห์อินพุตไปยังแผนผังไวยากรณ์เชิงนามธรรม (AST) การเยี่ยมชมและจัดการโหนด และการเรนเดอร์เป็น HTML หรือกลับไปยัง Markdown มันเริ่มต้นจากการเป็นพอร์ตของ commonmark.js แต่ตั้งแต่นั้นมาก็ได้พัฒนาเป็นไลบรารี่ที่ขยายได้พร้อมคุณสมบัติดังต่อไปนี้:
เล็ก (คอร์ไม่มีการพึ่งพา มีส่วนขยายในส่วนแยกกัน)
รวดเร็ว (เร็วกว่า pegdown ซึ่งเคยเป็นไลบรารี Markdown ยอดนิยมถึง 10-20 เท่า ดูการวัดประสิทธิภาพใน repo)
ยืดหยุ่น (จัดการ 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 จะตามมา แพ็คเกจที่มี beta
หมายความว่ายังไม่อยู่ภายใต้การรับประกัน API ที่เสถียร แต่สำหรับการใช้งานปกติก็ไม่จำเป็นที่จะต้องใช้
ดูไฟล์ spec.txt หากคุณสงสัยว่าขณะนี้มีการใช้งานข้อมูลจำเพาะเวอร์ชันใด ตรวจสอบ CommonMark dingus เพื่อทำความคุ้นเคยกับไวยากรณ์หรือลองใช้ Edge Case หากคุณโคลนพื้นที่เก็บข้อมูล คุณสามารถใช้คลาส DingusApp
เพื่อทดลองใช้งานแบบโต้ตอบได้
นำเข้า org.commonmark.node.*;นำเข้า org.commonmark.parser.Parser;นำเข้า org.commonmark.renderer.html.HtmlRenderer;Parser parser = Parser.builder().build();เอกสารโหนด = parser.parse(" นี่คือ *Markdown*");HtmlRenderer renderer = HtmlRenderer.builder().build();renderer.render(เอกสาร); // "<p>นี่คือ <em>มาร์คดาวน์</em></p>n"
สิ่งนี้ใช้ parser และ renderer พร้อมตัวเลือกเริ่มต้น ผู้สร้างทั้งสองมีวิธีในการกำหนดค่าลักษณะการทำงาน:
escapeHtml(true)
บน HtmlRenderer
จะหลีกเลี่ยงแท็กและบล็อก HTML แบบ Raw
sanitizeUrls(true)
บน HtmlRenderer
จะตัด URL ที่อาจไม่ปลอดภัยออกจากแท็ก <a>
และ <img>
สำหรับตัวเลือกที่มีทั้งหมด โปรดดูวิธีการของผู้สร้าง
โปรดทราบว่าไลบรารีนี้ไม่ได้พยายามฆ่าเชื้อ HTML ที่ได้ โดยคำนึงถึงแท็กที่ได้รับอนุญาต ฯลฯ นั่นเป็นความรับผิดชอบของผู้เรียก และหากคุณเปิดเผย HTML ที่เป็นผลลัพธ์ คุณอาจต้องการเรียกใช้ sanitizer หลังจากนี้ .
นำเข้า org.commonmark.node.*;นำเข้า org.commonmark.renderer.markdown.MarkdownRenderer;MarkdownRenderer renderer = MarkdownRenderer.builder().build();เอกสารโหนด = เอกสารใหม่();ส่วนหัว ส่วนหัว = ส่วนหัวใหม่();ส่วนหัว .setLevel(2);heading.appendChild(ข้อความใหม่("My หัวเรื่อง"));document.appendChild(หัวเรื่อง);renderer.render(เอกสาร); // "## ชื่อของฉันn"
สำหรับการแสดงผลเป็นข้อความธรรมดาโดยมีมาร์กอัปน้อยที่สุด ก็ยังมี TextContentRenderer
อีกด้วย
หลังจากแยกวิเคราะห์ข้อความต้นฉบับแล้ว ผลลัพธ์จะเป็นแผนผังของโหนด ต้นไม้นั้นสามารถแก้ไขได้ก่อนการเรนเดอร์ หรือเพียงแค่ตรวจสอบโดยไม่ต้องเรนเดอร์:
โหนดโหนด = parser.parse("ตัวอย่างn=======nnข้อความเพิ่มเติมบางส่วน");ผู้เยี่ยมชม WordCountVisitor = new WordCountVisitor();node.accept(visitor);visitor.wordCount; // 4class WordCountVisitor ขยาย AbstractVisitor { int wordCount = 0; @แทนที่การเข้าชมโมฆะสาธารณะ (ข้อความ) { // สิ่งนี้เรียกว่าสำหรับโหนดข้อความทั้งหมด แทนที่วิธีการเยี่ยมชมอื่นๆ สำหรับโหนดประเภทอื่น // นับคำ (นี่เป็นเพียงตัวอย่างเท่านั้น ไม่ได้ทำด้วยเหตุผลหลายประการ) wordCount += text.getLiteral().split("\W+").ความยาว; // สืบเชื้อสายมาจากลูก (ในกรณีนี้อาจละเว้นได้เนื่องจากโหนดข้อความไม่มีลูก) เยี่ยมชมเด็ก ๆ (ข้อความ); - -
หากคุณต้องการทราบว่า Node
ที่แยกวิเคราะห์ปรากฏที่ใดในข้อความต้นฉบับอินพุต คุณสามารถขอให้ parser ส่งกลับตำแหน่งแหล่งที่มาดังนี้:
var parser = Parser.builder().includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES).build();
จากนั้นแยกวิเคราะห์โหนดและตรวจสอบตำแหน่งแหล่งที่มา:
var source = "foonnbar *baz*";var doc = parser.parse(source);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 หากสิ่งที่คุณต้องการทำคือเพิ่มหรือเปลี่ยนแปลงแอตทริบิวต์ในองค์ประกอบบางอย่าง ก็มีวิธีง่ายๆ ในการดำเนินการดังกล่าว
ในตัวอย่างนี้ เราลงทะเบียนโรงงานสำหรับ AttributeProvider
บนตัวเรนเดอร์เพื่อตั้งค่าแอตทริบิวต์ class="border"
บนองค์ประกอบ img
ตัวแยกวิเคราะห์ parser = Parser.builder().build();HtmlRenderer renderer = HtmlRenderer.builder() .attributeProviderFactory(new AttributeProviderFactory() { สร้าง AttributeProvider สาธารณะ (บริบท AttributeProviderContext) { คืน ImageAttributeProvider ใหม่ (); - - .build();โหนดเอกสาร = parser.parse("");renderer.render(document);// "<p><img src="/url.png " alt="text" class="border" /></p>n"class ImageAttributeProvider ใช้งาน AttributeProvider { @Override public void setAttributes(โหนดโหนด, string tagName, Map<String, String> คุณลักษณะ) { if (อินสแตนซ์ของโหนดของรูปภาพ) { คุณลักษณะ.put("class", "border"); - - -
หากคุณต้องการทำมากกว่าแค่เปลี่ยนแอตทริบิวต์ ยังมีวิธีควบคุมวิธีแสดงผล HTML ได้อย่างสมบูรณ์อีกด้วย
ในตัวอย่างนี้ เรากำลังเปลี่ยนการแสดงผลของบล็อกโค้ดที่เยื้องไว้เพื่อล้อมไว้เฉพาะใน pre
แทนที่จะเป็น pre
และ code
:
ตัวแยกวิเคราะห์ parser = Parser.builder().build();HtmlRenderer renderer = HtmlRenderer.builder() .nodeRendererFactory(new HtmlNodeRendererFactory() { NodeRenderer สาธารณะสร้าง (บริบท HtmlNodeRendererContext) { คืน IndentedCodeBlockNodeRenderer ใหม่ (บริบท); - - .build();Node document = parser.parse("Example:nn code");renderer.render(document);// "<p>ตัวอย่าง:</p>n<pre>coden </pre>n"คลาส IndentedCodeBlockNodeRenderer ใช้งาน NodeRenderer { private สุดท้าย HtmlWriter html; IndentedCodeBlockNodeRenderer (บริบท HtmlNodeRendererContext) { this.html = context.getWriter (); } @แทนที่ชุดสาธารณะ<Class<? ขยายโหนด>> getNodeTypes() { // คืนประเภทโหนดที่เราต้องการใช้ตัวเรนเดอร์นี้ กลับชุดของ (IndentedCodeBlock.class); } @Override public void render(Node node) { // เราจัดการเพียงประเภทเดียวตาม getNodeTypes ดังนั้นเราจึงสามารถส่งมันได้ที่นี่ IndentedCodeBlock codeBlock = (IndentedCodeBlock) โหนด; html.line(); html.tag("ก่อน"); html.text(codeBlock.getLiteral()); html.tag("/pre"); html.line(); - -
ในกรณีที่คุณต้องการจัดเก็บข้อมูลเพิ่มเติมในเอกสารหรือมีองค์ประกอบที่กำหนดเองใน HTML ที่เป็นผลลัพธ์ คุณสามารถสร้างคลาสย่อยของ CustomNode
ของคุณเองและเพิ่มอินสแตนซ์เป็นโหนดลูกให้กับโหนดที่มีอยู่ได้
หากต้องการกำหนดการเรนเดอร์ HTML คุณสามารถใช้ NodeRenderer
ตามที่อธิบายไว้ข้างต้น
มีสองสามวิธีในการขยายการแยกวิเคราะห์หรือแทนที่การแยกวิเคราะห์ในตัว ซึ่งทั้งหมดใช้วิธีการบน Parser.Builder
(ดูบล็อกและอินไลน์ในข้อมูลจำเพาะสำหรับภาพรวมของบล็อก/อินไลน์):
การแยกวิเคราะห์ประเภทบล็อกเฉพาะ (เช่น ส่วนหัว บล็อกโค้ด ฯลฯ) สามารถเปิด/ปิดใช้งานได้ด้วย enabledBlockTypes
การแยกวิเคราะห์บล็อกสามารถขยาย/แทนที่ด้วย customBlockParserFactory
การแยกวิเคราะห์เนื้อหาแบบอินไลน์สามารถขยาย/แทนที่ด้วย customInlineContentParserFactory
การแยกวิเคราะห์ตัวคั่นในเนื้อหาอินไลน์สามารถขยายได้ด้วย customDelimiterProcessor
การประมวลผลลิงก์สามารถปรับแต่งได้ด้วย linkProcessor
และ linkMarker
ทั้ง Parser
และ HtmlRenderer
ได้รับการออกแบบมาเพื่อให้คุณสามารถกำหนดค่าได้เมื่อใช้ตัวสร้างแล้วใช้หลายครั้ง/จากหลายเธรด ซึ่งทำได้โดยการแยกสถานะสำหรับการแยกวิเคราะห์/การแสดงผลออกจากการกำหนดค่า
ต้องบอกว่าอาจมีข้อบกพร่องแน่นอน หากคุณพบกรุณารายงานปัญหา
Javadocs พร้อมใช้งานออนไลน์บน javadoc.io
ส่วนขยายจำเป็นต้องขยาย parser หรือตัวเรนเดอร์ HTML หรือทั้งสองอย่าง หากต้องการใช้ส่วนขยาย ออบเจ็กต์ตัวสร้างสามารถกำหนดค่าด้วยรายการส่วนขยายได้ เนื่องจากส่วนขยายเป็นทางเลือก ส่วนขยายจึงอยู่ในอาร์ติแฟกต์ที่แยกจากกัน ดังนั้นจึงจำเป็นต้องเพิ่มการขึ้นต่อกันเพิ่มเติมด้วย
มาดูวิธีเปิดใช้งานตารางจาก GitHub Flavoured Markdown ขั้นแรก เพิ่มการพึ่งพาเพิ่มเติม (ดู Maven Central สำหรับรายการอื่นๆ):
<การพึ่งพา> <groupId>org.commonmark</groupId> <artifactId>commonmark-ext-gfm-tables</artifactId> <เวอร์ชัน>0.24.0</เวอร์ชัน> </การพึ่งพา>
จากนั้น กำหนดค่าส่วนขยายบนตัวสร้าง:
นำเข้า org.commonmark.ext.gfm.tables.TablesExtension;List<ส่วนขยาย> ส่วนขยาย = List.of(TablesExtension.create());Parser parser = Parser.builder() .ส่วนขยาย(ส่วนขยาย) .build();HtmlRenderer renderer = HtmlRenderer.builder() .ส่วนขยาย(ส่วนขยาย) .สร้าง();
หากต้องการกำหนดค่าส่วนขยายอื่นในตัวอย่างข้างต้น เพียงเพิ่มลงในรายการ
ส่วนขยายต่อไปนี้ได้รับการพัฒนาด้วยไลบรารีนี้ โดยแต่ละส่วนมีสิ่งประดิษฐ์ของตัวเอง
เปลี่ยนลิงก์ธรรมดา เช่น URL และที่อยู่อีเมลให้เป็นลิงก์ (อิงตาม autolink-java)
ใช้คลาส AutolinkExtension
จากสิ่งประดิษฐ์ commonmark-ext-autolink
เปิดใช้งานการขีดฆ่าข้อความโดยใส่ไว้ใน ~~
ตัวอย่างเช่น ใน hey ~~you~~
you
จะแสดงผลเป็นข้อความขีดทับ
ใช้คลาส StrikethroughExtension
ในสิ่งประดิษฐ์ commonmark-ext-gfm-strikethrough
เปิดใช้งานตารางโดยใช้ไปป์เช่นเดียวกับใน GitHub Flavoured Markdown
ใช้คลาส TablesExtension
ในสิ่งประดิษฐ์ commonmark-ext-gfm-tables
เปิดใช้งานเชิงอรรถเช่นใน GitHub หรือ Pandoc:
Main text[^1] [^1]: Additional text in a footnote
เชิงอรรถแบบอินไลน์ เช่น ^[inline footnote]
ยังได้รับการสนับสนุนเมื่อเปิดใช้งานผ่าน FootnotesExtension.Builder#inlineFootnotes
ใช้คลาส FootnotesExtension
ในสิ่งประดิษฐ์ commonmark-ext-footnotes
เปิดใช้งานการเพิ่มแอตทริบิวต์ "id" ที่สร้างขึ้นอัตโนมัติให้กับแท็กส่วนหัว "id" จะขึ้นอยู่กับข้อความของหัวข้อ
# Heading
จะแสดงผลเป็น:
<h1 id="heading">Heading</h1>
ใช้คลาส HeadingAnchorExtension
ในสิ่งประดิษฐ์ commonmark-ext-heading-anchor
ในกรณีที่คุณต้องการเรนเดอร์ส่วนหัวแบบกำหนดเองแทน คุณสามารถใช้คลาส IdGenerator
ร่วมกับ HtmlNodeRendererFactory
ได้โดยตรง (ดูตัวอย่างด้านบน)
เปิดใช้งานการขีดเส้นใต้ข้อความโดยใส่ไว้ใน ++
ตัวอย่างเช่น ใน hey ++you++
you
จะแสดงผลเป็นข้อความที่ขีดเส้นใต้ ใช้แท็ก <ins>
ใช้คลาส InsExtension
ในสิ่งประดิษฐ์ commonmark-ext-ins
เพิ่มการรองรับข้อมูลเมตาผ่านบล็อกส่วนหน้าของ YAML ส่วนขยายนี้รองรับเฉพาะชุดย่อยของไวยากรณ์ YAML นี่คือตัวอย่างสิ่งที่ได้รับการสนับสนุน:
--- key: value list: - value 1 - value 2 literal: | this is literal value. literal values 2 --- document start here
ใช้คลาส YamlFrontMatterExtension
ในสิ่งประดิษฐ์ commonmark-ext-yaml-front-matter
หากต้องการดึงข้อมูลเมตา ให้ใช้ YamlFrontMatterVisitor
เพิ่มการรองรับการระบุแอตทริบิวต์ (โดยเฉพาะความสูงและความกว้าง) สำหรับรูปภาพ
อิลิเมนต์แอ็ตทริบิวต์ถูกกำหนดเป็นคู่ key=value
ภายในเครื่องหมายปีกกา { }
หลังโหนดรูปภาพที่ใช้ ตัวอย่างเช่น:
{width=640 height=480}
จะแสดงผลเป็น:
<img src="/url.png" alt="text" width="640" height="480" />
ใช้คลาส ImageAttributesExtension
ในสิ่งประดิษฐ์ commonmark-ext-image-attributes
หมายเหตุ: เนื่องจากส่วนขยายนี้ใช้เครื่องหมายปีกกา {
}
เป็นตัวคั่น (ใน 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>
ใช้คลาส TaskListItemsExtension
ในสิ่งประดิษฐ์ commonmark-ext-task-list-items
คุณยังสามารถค้นหาส่วนขยายอื่น ๆ ได้อีกด้วย:
commonmark-ext-notifications: ส่วนขยายนี้ช่วยให้สามารถสร้างย่อหน้าการแจ้งเตือน/คำเตือน เช่น INFO
, SUCCESS
, WARNING
หรือ ERROR
ได้อย่างง่ายดาย
ผู้ใช้ห้องสมุดนี้บางราย (อย่าลังเลที่จะเพิ่ม PR หากคุณต้องการเพิ่ม):
Atlassian (ซึ่งห้องสมุดได้รับการพัฒนาในช่วงแรก)
ชวา (OpenJDK) (ลิงก์)
การตรวจสอบโค้ด Gerrit/Gitiles (ลิงก์)
การเขียนโปรแกรมสดแบบหล่อได้ของเสมียนสำหรับ Clojure
ซไน
Markwon: ไลบรารี Android สำหรับเรนเดอร์ markdown เป็น Spannables ของระบบ
flexmark-java: ทางแยกที่เพิ่มการรองรับไวยากรณ์และความยืดหยุ่นที่มากขึ้น
ดูไฟล์ CONTRIBUTING.md
ลิขสิทธิ์ (c) 2015, Robin Stocker
ได้รับอนุญาต BSD (2 ข้อ) ดูไฟล์ LICENSE.txt