مكتبة Java لتحليل وعرض نص Markdown وفقًا لمواصفات CommonMark (وبعض الامتدادات).
يوفر فئات لتحليل المدخلات إلى شجرة بناء جملة مجردة (AST)، وزيارة العقد ومعالجتها، وتقديمها إلى HTML أو العودة إلى Markdown. لقد بدأ كمنفذ لـ commonmark.js، ولكنه تطور منذ ذلك الحين إلى مكتبة قابلة للتوسيع بالميزات التالية:
صغير (الأساسية لا تحتوي على تبعيات، ملحقات في عناصر منفصلة)
سريعة (10-20 مرة أسرع من pegdown التي كانت مكتبة Markdown شائعة، راجع المعايير في الريبو)
مرن (التعامل مع 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، سيتم اتباع الإصدار الدلالي. الحزمة التي تحتوي على beta
تعني أنها لا تخضع لضمانات واجهة برمجة التطبيقات المستقرة حتى الآن؛ ولكن للاستخدام العادي لا ينبغي أن يكون من الضروري استخدامه.
راجع ملف spec.txt إذا كنت تتساءل عن إصدار المواصفات المطبق حاليًا. تحقق أيضًا من CommonMark dingus للتعرف على بناء الجملة أو تجربة الحالات المتطورة. إذا قمت باستنساخ المستودع، فيمكنك أيضًا استخدام فئة DingusApp
لتجربة الأشياء بشكل تفاعلي.
import org.commonmark.node.*;import org.commonmark.parser.Parser;import org.commonmark.renderer.html.HtmlRenderer;Parser parser = Parser.builder().build();Node document = parser.parse(" هذا هو *Markdown*");HtmlRenderer renderer = HtmlRenderer.builder().build();renderer.render(document); // "<p>هذا <em>تخفيض السعر</em></p>n"
يستخدم هذا المحلل اللغوي والعارض مع الخيارات الافتراضية. لدى كلا المنشئين طرق لتكوين سلوكهما:
سوف يهرب escapeHtml(true)
الموجود على HtmlRenderer
من علامات وكتل HTML الأولية.
سوف يقوم sanitizeUrls(true)
على HtmlRenderer
بإزالة عناوين URL التي قد تكون غير آمنة من علامتي <a>
و <img>
للتعرف على جميع الخيارات المتاحة، راجع الأساليب الموجودة على المنشئين.
لاحظ أن هذه المكتبة لا تحاول تنظيف HTML الناتج فيما يتعلق بالعلامات المسموح بها، وما إلى ذلك. وهذه مسؤولية المتصل، وإذا قمت بالكشف عن HTML الناتج، فمن المحتمل أنك تريد تشغيل المطهر عليه بعد ذلك .
import org.commonmark.node.*;import org.commonmark.renderer.markdown.MarkdownRenderer;MarkdownRenderer renderer = MarkdownRenderer.builder().build();مستند العقدة = مستند جديد();عنوان العنوان = عنوان جديد();العنوان .setLevel(2);heading.appendChild(new Text("My title"));document.appendChild(heading);renderer.render(document); // "## لقبيn"
للتحويل إلى نص عادي بأقل قدر من العلامات، يوجد أيضًا TextContentRenderer
.
بعد تحليل النص المصدر، تكون النتيجة شجرة من العقد. يمكن تعديل هذه الشجرة قبل العرض، أو يمكن فحصها فقط دون العرض:
NodeNode = parser.parse("مثالn=======nnبعض النص الإضافي");WordCountVisitor Visitor = new WordCountVisitor();node.accept(visitor);visitor.wordCount; // 4class WordCountVisitor Extends AbstractVisitor { int wordCount = 0; @Override public void Visit(Text text) { // يتم استدعاء هذا لجميع العقد النصية. تجاوز طرق الزيارة الأخرى لأنواع العقد الأخرى. // عد الكلمات (هذا مجرد مثال، لا تفعل ذلك بهذه الطريقة لأسباب مختلفة). wordCount += text.getLiteral().split("\W+").length; // ينزل إلى الأطفال (يمكن حذفه في هذه الحالة لأن العقد النصية لا تحتوي على أطفال). VisitChildren(text); } }
إذا كنت تريد معرفة مكان ظهور Node
التي تم تحليلها في نص مصدر الإدخال، فيمكنك أن تطلب من المحلل اللغوي إرجاع مواضع المصدر مثل هذا:
var parser = Parser.builder().includeSourceSpans(IncludeSourceSpans.BLOCKS_AND_INLINES).build();
ثم قم بتحليل العقد وفحص مواضع المصدر:
var source = "foonnbar *baz*";var doc = parser.parse(source);var focus = doc.getLastChild().getLastChild();var s = focus.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.builder().build();HtmlRenderer renderer = HtmlRenderer.builder() .attributeProviderFactory(new AttributeProviderFactory() { public AttributeProvider create(AttributeProviderContext context) { return new ImageAttributeProvider(); } }) .build();Node document = parser.parse("![text](/url.png)");renderer.render(document);// "<p><img src="/url.png " alt="text" class="border" /></p>n"class ImageAttributeProvider Implements AttributeProvider { @Override public void setAttributes(Node node, String tagName, Map<String, String> attributes) { if (node exampleof Image) { attributes.put("class", "border"); } } }
إذا كنت تريد القيام بأكثر من مجرد تغيير السمات، فهناك أيضًا طريقة للتحكم الكامل في كيفية عرض HTML.
في هذا المثال، نقوم بتغيير عرض كتل التعليمات البرمجية ذات المسافة البادئة لتغليفها فقط في pre
بدلاً من pre
و code
:
المحلل اللغوي = Parser.builder().build();HtmlRenderer renderer = HtmlRenderer.builder() .nodeRendererFactory(new HtmlNodeRendererFactory() { public NodeRenderer create(HtmlNodeRendererContext context) { return new IndentedCodeBlockNodeRenderer(context); } }) .build();Node document = parser.parse("مثال:nn code");renderer.render(document);// "<p>مثال:</p>n<pre>coden </pre>n"class IndentedCodeBlockNodeRenderer Implements NodeRenderer { Private Final HtmlWriter html; IndentedCodeBlockNodeRenderer(HtmlNodeRendererContext context) { this.html = context.getWriter(); } @Override public Set<Class<? Extends Node>> getNodeTypes() { // قم بإرجاع أنواع العقد التي نريد استخدام هذا العارض لها. return Set.of(IndentedCodeBlock.class); } @Override public void render(NodeNode) { // نحن نتعامل مع نوع واحد فقط وفقًا لـ getNodeTypes، لذلك يمكننا إرساله هنا فقط. IndentedCodeBlock codeBlock = (IndentedCodeBlock) العقدة؛ html.line(); html.tag("قبل"); html.text(codeBlock.getLiteral()); html.tag("/قبل"); html.line(); } }
في حالة رغبتك في تخزين بيانات إضافية في المستند أو الحصول على عناصر مخصصة في HTML الناتج، يمكنك إنشاء فئة فرعية خاصة بك من CustomNode
وإضافة مثيلات كعقد فرعية إلى العقد الموجودة.
لتحديد عرض HTML لهم، يمكنك استخدام NodeRenderer
كما هو موضح أعلاه.
هناك عدة طرق لتوسيع نطاق التحليل أو حتى تجاوز التحليل المضمن، جميعها عبر طرق موجودة في Parser.Builder
(راجع الكتل والسطور في المواصفات للحصول على نظرة عامة على الكتل/السطور):
يمكن تمكين/تعطيل تحليل أنواع كتل محددة (مثل العناوين وكتل التعليمات البرمجية وما إلى ذلك) باستخدام enabledBlockTypes
يمكن تمديد/تجاوز تحليل الكتل باستخدام customBlockParserFactory
يمكن توسيع/تجاوز تحليل المحتوى المضمن باستخدام customInlineContentParserFactory
يمكن توسيع تحليل المحددات في المحتوى المضمن باستخدام customDelimiterProcessor
يمكن تخصيص معالجة الروابط باستخدام linkProcessor
و linkMarker
تم تصميم كل من Parser
و HtmlRenderer
بحيث يمكنك تهيئتهما مرة واحدة باستخدام أدوات الإنشاء ثم استخدامها عدة مرات/من عدة سلاسل رسائل. يتم ذلك عن طريق فصل حالة التحليل/العرض عن التكوين.
ومع ذلك، قد تكون هناك أخطاء بالطبع. إذا وجدت واحدة، يرجى الإبلاغ عن مشكلة.
Javadocs متاحة على الإنترنت على 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.builder() .الامتدادات(الامتدادات) .build();عارض HtmlRenderer = HtmlRenderer.builder() .الامتدادات(الامتدادات) .يبني()؛
لتكوين ملحق آخر في المثال أعلاه، ما عليك سوى إضافته إلى القائمة.
تم تطوير الملحقات التالية باستخدام هذه المكتبة، كل منها في قطعة أثرية خاصة بها.
يحول الروابط العادية مثل عناوين URL وعناوين البريد الإلكتروني إلى روابط (استنادًا إلى الارتباط التلقائي-Java).
استخدم فئة AutolinkExtension
من قطعة أثرية commonmark-ext-autolink
.
تمكين يتوسط النص من خلال تضمينه في ~~
. على سبيل المثال، في hey ~~you~~
، سيتم you
كنص يتوسطه خط.
استخدم فئة StrikethroughExtension
في قطعة أثرية commonmark-ext-gfm-strikethrough
.
تمكين الجداول باستخدام الأنابيب كما هو الحال في GitHub Flavored 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
.
لتمكين إضافة سمات "المعرف" التي يتم إنشاؤها تلقائيًا إلى علامات العناوين. يعتمد "المعرف" على نص العنوان.
# 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
داخل الأقواس المتعرجة { }
بعد عقدة الصورة التي تنطبق عليها، على سبيل المثال:
![text](/url.png){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
بعض مستخدمي هذه المكتبة (لا تتردد في رفع العلاقات العامة إذا كنت تريد إضافتها):
أتلاسيان (حيث تم تطوير المكتبة في البداية)
جافا (OpenJDK) (رابط)
مراجعة كود Gerrit/Gitiles (حلقة الوصل)
كاتب برمجة حية قابلة للتشكيل لـ Clojure
زناي
Markwon: مكتبة Android لعرض تخفيض السعر على أنه Spannables الأصلي للنظام
flexmark-Java: شوكة أضافت دعمًا لمزيد من بناء الجملة والمرونة
راجع ملف CONTRIBUTING.md.
حقوق الطبع والنشر (ج) 2015، روبن ستوكر
ترخيص BSD (بندان)، راجع ملف LICENSE.txt.