docutils 遍历节并使用其路径创建子节列表

问题描述 投票:0回答:1

这个问题试图扩展 Jason S 的代码(谢谢,Jason),可以在这里找到:Docutils:遍历部分?.

Jason S 原创

import docutils

def doctree_resolved(app, doctree, docname):
    for section in doctree.traverse(docutils.nodes.section):
        title = section.next_node(docutils.nodes.Titular)
        if title:
            print title.astext()

def setup(app):
    app.connect('doctree-resolved', doctree_resolved)

现在,假设我只想捕获 H2 小节的文本(或者至少捕获所有小节,如果这是唯一的选择)。

理论上,我正在尝试创建一个小节标题的字典,以及它们各自的网址/路径。 最好的方法是什么?

我对上面原始版本的修改并不成功,但希望您可以通过阅读代码来理解我的方法。我相信,使用列表构建的简单 for 循环并不成功,因为

title = section.next_node(docutils.nodes.Titular)
行,特别是
next_node...
。我查看了,但找不到有关
next_node
的文档。

那么,有什么不同的方法可以实现从每个文档中捕获 H2 小节,以便我可以构建一个字典,其中每个小节都有一个路径/url? 注意:我还没有尝试在下面的代码中构建完整的 URL。

import docutils

docname_list = []
section_list = []

def doctree_resolved(app, doctree, docname):
    for section in doctree.traverse(docutils.nodes.section):
        title = section.next_node(docutils.nodes.Titular)
        if title:
            print(title.astext())
            docname_list.append(docname)
            section_list.append(title.astext())


... 

url_dict = dict(zip(docname_list, section_list)
...

python python-sphinx restructuredtext docutils
1个回答
0
投票

获取文档中所有章节标题列表的最简单方法是

from docutils import nodes

def all_section_titles(doctree):
    return [section.next_node(nodes.title).astext()
            for section in doctree.findall(nodes.section)]

有关使用的元素方法的详细信息,请参阅他们的 Python 文档字符串

help(nodes.Element.findall)
help(nodes.Element.next_node)
doctree
及其元素的结构和功能在 Docutils 文档树中进行了描述。

由于 Docutils 文档树中的

<section>
元素和
<title>
元素没有 level 属性(或 HTML 中的依赖于级别的名称,如 H1、H2、...),因此
nodes.Element.findall()
方法不能轻易用于获取特定级别的章节/章节标题。 我们必须“手动”遍历子元素。

根据全局文档标题是否存在,HTML 输出可能会使用“H2”HTML 元素作为顶级节标题或子节标题。 以下是两个函数,用于捕获顶级部分和子部分的标题元素:

from docutils import nodes

def top_section_titles(doctree):
    return [child.next_node(nodes.title).astext()
            for child in doctree
            if isinstance(child, nodes.section)]

def sub_section_titles(doctree):
    titles = []
    for child in doctree:
        if not isinstance(child, nodes.section):
            continue
        for grandchild in child:
            if not isinstance(grandchild, nodes.section):
                continue
            titles.append(grandchild.next_node(nodes.title).astext())
    return titles

HTML 文档具有自动生成的节元素锚点。 章节标题到 URL 的映射可以通过以下方式实现:

def section_urls(titles, base_url):
    return dict((title, f'{base_url}#{nodes.make_id(title)}')
                for title in titles)

请参阅

help(nodes.make_id)
了解将标题文本转换为 ID 的函数。

让我们测试一下这些功能:

from docutils import core
base_url = "file:demo.html"

sample = """\
Document Title
==============

:docinfo: optional

first section heading
---------------------
first section text

subsection 1.1
..............
subsection text

second section heading
----------------------
second section text

subsection 2.1
..............
subsection text
"""

def demo(fun):
    doctree = core.publish_doctree(sample, base_url)
    # print(doctree.pformat())  # show the document structure as "pseudo-XML"
    titles = fun(doctree)
    # print titles
    url_dict = section_urls(titles, base_url)
    for title, url in url_dict.items():
        print(f'{title}: {url}')
        
print('extract all')
demo(all_section_titles)

print('\nextract top')
demo(top_section_titles)

print('\nextract sub')
demo(sub_section_titles)
© www.soinside.com 2019 - 2024. All rights reserved.