【问题标题】:Inserting raw HTML into Markdown将原始 HTML 插入 Markdown
【发布时间】:2019-12-05 17:59:18
【问题描述】:

我需要将原始 HTML 插入到 Markdown 文档中,以便在输出中逐字放置;具体来说,我试图确保文档的某些部分包含在一个容器中(例如<div><aside><section>),而不会破坏其中内容的格式。

但是,如果我采用以下显而易见的方法:

<aside>

## My heading
Some text, some text, some more text.

</aside>

然后 Markdown 处理器生成这个无效的 HTML:

<p><aside></p>
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
<p></aside></p>

但是如果我尝试将添加的标签放在要处理的文本上,例如

<aside>
## My heading
Some text, some text, some more text.
</aside>

然后根据被格式化的实际内容会发生一些不同的事情,但没有一个是正确的——&lt;aside&gt; 仍然被包裹在 &lt;p&gt; 中。

如果我使用&lt;div&gt;,那么所有内容都会呈现为纯文本。

有没有办法指示 Markdown 处理器处理输入文本的运行字面意思,而不进行任何处理?

我目前正在使用 Hoedown(通过 Misaka),它支持许多现代 Markdown 扩展,但如果有更现代的 Markdown 引擎可以更好地处理这个问题,我肯定会考虑切换到它。

【问题讨论】:

  • @JohnHennig 我会更改标题,尽管您建议的标题不是 IMO 的改进。不幸的是,我无法切换 Markdown 实现,但是您有没有这种行为的示例?
  • 一些不完全重复的问题的答案可能会有所帮助:Grouping MarkDown elements in to DIV element or Custom html tagmarkdown=“1” not working inside the p tag
  • 另外,&lt;aside&gt; 是 HTML 5 中的一个新标签,它在旧的 Markdown 实现中不受支持,因为这些实现早于标签的引入。由于 Hoedown 似乎在 4 到 5 年前就被放弃了,我怀疑它从来没有添加对 &lt;aside&gt; 的支持作为“块级”标签。 &lt;div&gt; 的行为如我在上面链接的另外两个问题中所述。
  • @Waylan 我的总体要求更多的是能够将原始 HTML 放入基于 Markdown 的文档中,而无需 Markdown 处理器决定将其包装在无关的 &lt;p&gt; 标记中。如果这导致有充分的理由切换到不同的 Markdown 处理器,那么我会将其视为解决方案的一部分,尽管它不太理想。
  • 在考虑您的反馈后,我想我更了解您的问题并添加了一个全面的答案。希望我做对了。

标签: markdown


【解决方案1】:

安全的答案是使用以下内容:

<div class="aside">
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</div>

但是,它比有许多可能的答案要复杂得多。哪个答案适用于您取决于您​​使用的 Markdown 实现,因为它们之间存在细微差别。让我们从参考实现 (markdown.pl) 和 original rules 开始,因为这是 Hoedown 声称要遵循的(见下文)。

老派降价

许多较旧的解析器是在从 HTML4 过渡到 XHTML1 期间首次开发的,它们的行为和对原始 HTML 的处理反映了这一点。也就是说,最近几年已经更新了一些内容,以添加对较新 HTML 功能的支持。但是,参考实现已经有十多年没有更新了,这是一个很好的起点。一般来说,如果您可以在参考实现中使用某些东西,那么它可以在任何实现中使用,所以让我们专注于这一点。

规则首先描述块级 HTML 标记的处理,然后描述跨度级行为,就好像它是异常一样。但是,在代码中,事情是相反的。跨度级别的行为是默认的,块级别的行为是特殊的例外。

自然,当使用跨度级别标签时,您希望结果包装一个&lt;p&gt; 标签。例如,foo &lt;i&gt;bar&lt;/i&gt; baz 应生成 &lt;p&gt;foo &lt;i&gt;bar&lt;/i&gt; baz&lt;/p&gt;。因此,为了避免将原始 HTML 包装在 &lt;p&gt; 标记中,规则要求有一组非常具体的情况:

唯一的限制是块级 HTML 元素 — 例如 &lt;div&gt;&lt;table&gt;&lt;pre&gt;&lt;p&gt;等 — 必须与 用空行包围内容,以及 块不应使用制表符或空格缩进。 Markdown 很聪明 足够不要在 HTML 块级周围添加额外的(不需要的)&lt;p&gt; 标签 标签。

这里有 3 个要求:

  1. 原始 HTML 块必须以已知的块级标记开头。如前所述,在较旧的实现中,这些标签必须是 HTML4/XHTML1 规范中的有效块级标签。 HTML5 中最近引入的任何内容可能无法在不同的实现中始终如一地工作。
  2. 开始标签前面必须有一个空行或文档的开头,结束标签后面必须有一个空行或文档的结尾。
  3. 开始标签必须以行的第一个字符开头。任何缩进都会导致解析器无法将文本块识别为块级原始 HTML。

最后,规则说明:

请注意,Markdown 格式化语法不会在 块级 HTML 标签。例如,你不能使用 Markdown 风格的 *emphasis* 在 HTML 块内。

请注意,这与跨度级别的 HTML 不同:

与块级 HTML 标签不同,Markdown 语法在 跨度级标签。

在这种情况下,&lt;span&gt;foo *bar*&lt;/span&gt; 的结果是 &lt;p&gt;&lt;span&gt;foo &lt;em&gt;bar&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;,而 &lt;div&gt;foo *bar*&lt;div&gt; 的结果是 &lt;div&gt;foo *bar*&lt;/div&gt;。请注意,在第一个示例中,虽然处理了 Markdown 语法 (*bar*),但整个内容都包含在 &lt;p&gt; 标记中。反过来。在第二个示例中,未处理 Markdown 语法 (*bar*),但该块未包装在 &lt;p&gt; 标记中。因此,任何包裹在块级原始 HTML 中的内容都必须是原始 HTML。

所以,让我们将这些规则应用到您的示例中:

<div>
<aside>
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</aside>
</div>

&lt;div&gt; 提供了旧实现可以识别的标签。并且内容都是原始 HTML,因为无论如何它都不会被处理为 Markdown。 Babelmark 表明这适用于所有实现。

当然,同时使用&lt;aside&gt;&lt;div&gt; 标签是多余的,因此您可以简单地使用&lt;div&gt; 标签并为其分配适当的类:

<div class="aside">
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</div>

作为 Babelmark shows,它也适用于任何地方。

如果您使用的实现添加了对 HTML5 块级标签的支持,您可以直接使用&lt;aside&gt; 标签:

<aside>
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</aside>

当然,我们仍然需要使用所有原始 HTML。作为 Babelmark demonstrates,这适用于大多数实现,但不是所有实现。

扩展 Markdown

多年来,许多 Markdown 实现都为语法添加了非标准扩展,从而增加了额外的功能。出于显而易见的原因,许多用户希望能够在原始 HTML 块中处理 Markdown 语法。因此,许多年前,PHP Markdown Extra introduced markdown="1" 解决方法已被许多实现复制。但是,大多数支持扩展的实现都需要显式启用扩展。默认情况下未启用。

如果您正在使用支持扩展的实现,并且启用了扩展,那么您可以使用它(如果支持较新的 HTML5 标签):

<aside markdown="1">
## My heading
Some text, some text, some more text.
</aside>

或者这个(如果不支持 HTML5 标签):

<div markdown="1">
<aside>
## My heading
Some text, some text, some more text.
</aside>
</div>

或者...

<div class="aside" markdown="1">
## My heading
Some text, some text, some more text.
</div>

共同点

有些人对实现之间的不一致感到沮丧,并着手定义一个严格的规范,该规范被称为 Commonmark。但是,Commonmark spec 自己承认,它打破了原始实现中一些非常明确定义的规则。具有讽刺意味的是,这只会增加更多的不一致。最严重的违规者之一是原始 HTML 处理。

只要您的原始 HTML 块不包含任何空行,Commonmark 就会以与老式 Markdown 实现相同的方式处理您的块。但是,一旦您引入了一个空行,该空行之后的任何内容都将被解析为 Markdown。

此外,Commonmark 规范明确定义了哪些标签被视为块级标签的完整列表。碰巧的是,&lt;aside&gt; 在标签列表中。

因此,如果您使用的是符合标准的 Commonmark 实现,则可以使用以下方法:

<aside>

## My heading
Some text, some text, some more text.

</aside>

请注意,&lt;aside&gt; 标记后面紧跟着一个空行,指示解析器将标记后面的任何内容视为 Markdown。作为 Babelmark demonstrates,这适用于 Commonmark 实现,但不适用于老式实现。

霍顿

Hoedown 特别是 claims 与“官方 Markdown v1.0.0 和 v1.0.3 测试套件”“完全符合标准”。请注意,这些是旧式参考实现的测试套件,而不是较新的 Commonmark 规范。在这种情况下,我们可以假设在原始 HTML 块中处理 Markdown 的 Commonmark 技巧将不起作用。当然,你当然可以试一试。

Hoedown 还声称“对多个(非官方)Markdown 扩展的可选支持”。但是,没有可用扩展的完整列表,也没有任何关于如何启用它们的说明。我没有安装该工具,但也许有命令行可用的说明?如果您能找到启用markdown="1" 扩展的方法,那么您可以使用该技巧在原始 HTML 块中进行 Markdown 处理。

但是,如果没有任何明确的文档,我认为 Hoedown 是一个老式的实现。我还注意到 repo 中的 html_block_names.gperf 文件没有将 aside 列为已知的 HTML 块级标记。因此,我们可以假设任何原始 HTML 块都必须包含在该文件中列出的 24 个标签之一中。

鉴于上述情况,我们可以放心地假设以下是从 Hoedown 获得所需结果的唯一可靠方法:

<div>
<aside>
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</aside>
</div>

或者...

<div class="aside">
<h2>My heading</h2>
<p>Some text, some text, some more text.</p>
</div>

【讨论】:

  • 感谢您提供令人难以置信的全面答案。我会看看 Hoedown 是否支持markdown="1",但我不相信它支持。切换 Markdown 实现是可能的,但不在我试图解决的特定问题的时间范围内。
  • 至少在我启用的扩展中,markdown="1" not 不仅使它实际处理&lt;div&gt; 中的降价,而且Hoedown 仍然剥离了@ 987654371@伪属性,所以我自己无法追溯修复!两全其美,天哪。
猜你喜欢
  • 2013-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
相关资源
最近更新 更多