【问题标题】:Using Python markdown Treeprocessor to wrap an etree Element使用 Python markdown Treeprocessor 包装一个 etree 元素
【发布时间】:2020-03-12 13:45:48
【问题描述】:

我正在尝试编写一个 Python markdown Treeprocessor 扩展,它将一个 span 标签包装在一个 div 标签内;所以如果我有(降价)-

before <span>hello world</span> after

然后我想进行后处理 -

before <div><span>hello world</span></div> after

Python markdown 似乎拥有所有这些您可以使用和扩展的不同处理器 -

https://python-markdown.github.io/extensions/api/

我认为 TreeProcessor 可能是最适合的,并想出了以下 -

from markdown.extensions import Extension

from markdown.treeprocessors import Treeprocessor

import markdown

class MyTreeProcessor(Treeprocessor):

    def run(self, doc):
        def iterate(parent):
            print ("%s %s :: %s" % (parent.tag, parent.attrib, parent.text))
            for child in parent.getchildren():
                iterate(child)
        iterate(doc)

class MyTreeExtension(Extension):

    def extendMarkdown(self,
                       md,
                       key="my_extension",
                       index=1e8):
        md.registerExtension(self)
        md.treeprocessors.register(MyTreeProcessor(md.parser),
                                   key, index)

if __name__=="__main__":
    md=markdown.Markdown(extensions=[MyTreeExtension()])
    md.convert("before <span>hello world</span> after")

但如果我使用索引值 1e8 运行它,我会得到以下结果 -

div {} :: None
p {} :: before <span>hello world</span> after

如果我使用索引值 0 运行它,我会得到以下结果 -

div {} :: 

p {} :: before wzxhzdk:0hello worldwzxhzdk:1 after

这些都不是我想要的——在第一种情况下,span 没有被处理,在第二种情况下,它已经以某种奇怪的格式处理了:-/

找到 Markdown 扩展文档对于看似简单的任务非常繁琐 - 有人可以确认我在这里(或不)使用 Treeprocessor 时正在吠叫正确的树,如果是这样,我做错了什么无法将此span 解析为etree.Element

TIA

【问题讨论】:

  • 好奇你为什么使用1e8的优先级?如果我没记错的话,等于100000000.0。然而,只有两个优先级为1020 的内置树处理器。您可以轻松使用任何高于20 的数字。不用一千亿。

标签: python markdown


【解决方案1】:

您可能不想在此处使用 Treeprocessor,因为您正在处理原始 HTML。

Python-Markdown 通过将 Markdown 转换为 etree 对象来解析它。但是,它不解析 HTML(至少不完全解析)并且 etree 对象不能保存原始 HTML 字符串。好吧,它们可以持有它们,但是当etree 对象被呈现为 HTML 字符串时,它们会被转义。因此,原始 HTML 被识别并替换为占位符 (wzxhzdk:0)。在etree 对象呈现为 HTML 字符串后,后处理器会查找所有占位符并将它们替换为使用占位符作为键存储的原始 HTML。

两个索引之间行为不同的原因是其中一个在运行内联模式之前运行(第一个树处理器实际上是所有内联模式的包装器),另一个在之后运行,但在占位符被换回之前当然,由于占位符由后处理器换回,您无法从树预处理器访问该状态。

总结:

  1. 块级原始 HTML 由预处理器处理,永远无法从树处理器中获得。
  2. 内联原始 HTML 由内联模式处理,因此在 inlineProcessor 树处理器运行之前,内联原始 HTML 将不会被处理,但在树处理器运行后将不可用。

一个可能的解决方案是使用内联模式。但是,您需要自己解析 HTML 标签。

此外,您想要的输出不是有效的 HTML。请注意,before &lt;span&gt;hello world&lt;/span&gt; after 将被包装在 &lt;p&gt; 标记中,&lt;p&gt; 标记不能包含任何其他块级元素,包括 &lt;div&gt; 标记。当然,没有什么会迫使您不将 &lt;div&gt; 标签包装在 &lt;p&gt; 标签中,但浏览器永远不会以这种方式解释 HTML。根据 HTML 规范,块级标签会自动关闭 &lt;p&gt; 标签。因此,浏览器(可能)会像这样解释您的输出:

<p>before </p><div><span>hello world</span></div> after<p></p>

请注意,没有 &lt;p&gt; 包装 after。是的,会出现结束标签,但没有开始标签(在结束 &lt;/div&gt; 之后,浏览器不会立即知道它是否开始,你会得到一个空的 &lt;p&gt; 寡妇结束标签。

现在,如果您对这一切都满意,那么为什么不在您的 Markdown 中使用 &lt;div&gt; 开始。还是&lt;span&gt;&lt;div&gt; 只是现实生活中实际标签问题中的占位符?如果是这样,无论它们是内联还是块级都可以改变答案。

【讨论】:

  • 嗯,这是一个了不起的答案,谢谢。我只是使用&lt;span&gt;&lt;div&gt; 作为实际情况的代理。事实上,我正在尝试修复使用 &lt;blockquote class="twitter-tweet&gt; 的 Twitter 嵌入的边距。我似乎无法为 blockquote.twitter-tweet 添加 CSS 样式,因为嵌入在加载时运行了一些 JS,这似乎忽略了任何全局设置的样式。因此,当前的解决方法(如您所建议的)只是将&lt;blockquote&gt; 包装在降价中的&lt;div class="my-twitter"&gt; 中。我只是想知道扩展是否可以插入 &lt;div class="my-twitter"&gt; 但似乎很麻烦
  • 啊,这更有意义。请注意,&lt;blockquote&gt; 是一个块级标记,因此只要它自己在一行上,它的行为就会与 &lt;span&gt; 标记不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多