如何通过Sphinx扩展在当前文档下创建新文档页面
开发Sphinx扩展实现调用时生成子目录文档页面
需求:要做一个Sphinx扩展,当在RST文档(比如foo.rst)里调用该扩展时,能在当前文档的目录下生成独立的新文档页面,例如foo/bar.html、foo/baz.html这类。
以下是用户提供的简化扩展代码(已翻译注释):
class NetYnlInclude(Directive): def run(self): file = "my_file.txt" # 将文件添加到依赖记录,确保文件变化时Sphinx会重新构建 self.state.document.settings.record_dependencies.add(file) parsed_str = parse(file) # 将文件解析为字符串 # 将解析后的内容转为行,插入到当前文档的渲染流程中 self.state_machine.insert_input( statemachine.string2lines(parsed_str), filename) # 返回空段落节点,不影响当前文档的输出 paragraph_node = nodes.paragraph() return paragraph_node
现有代码的局限
当前代码只是把解析后的文本嵌入到调用扩展的RST文档里,并没有生成独立的新页面。要实现生成独立子页面的需求,需要修改逻辑,在Sphinx的构建环境中主动添加新的文档条目。
修改后的实现方案
要生成独立页面,需要在扩展中动态创建新的RST文档文件,并将其注册到Sphinx的构建环境中,让Sphinx把这些新文档当成独立页面来处理。以下是调整后的示例代码:
from docutils.parsers.rst import Directive from docutils import nodes import os from sphinx.util import logging from sphinx.util.osutil import relpath logger = logging.getLogger(__name__) class NetYnlInclude(Directive): def run(self): # 获取当前调用扩展的文档路径(比如foo.rst对应docname为foo) current_doc = self.state.document.settings.env.docname current_dir = os.path.dirname(current_doc) # 定义要生成的新文档名称(无需后缀) new_doc_names = ["bar", "baz"] input_file = "my_file.txt" # 记录依赖,确保输入文件变化时触发重新构建 self.state.document.settings.record_dependencies.add(input_file) # 解析输入文件内容,这里假设parse函数返回可复用的内容模板 base_content = parse(input_file) for doc_name in new_doc_names: # 构建新文档的完整标识路径(比如foo/bar) new_docname = os.path.join(current_dir, doc_name) # 避免重复添加相同文档 if new_docname not in self.state.document.settings.env.docnames: # 为新文档生成RST内容,可根据需求拆分或定制 new_rst = f".. _ref-{new_docname}:\n\n# {doc_name}页面\n\n{base_content}\n" # 拼接新文档的物理路径 new_rst_path = os.path.join(self.state.document.settings.env.srcdir, f"{new_docname}.rst") # 创建RST文件 os.makedirs(os.path.dirname(new_rst_path), exist_ok=True) with open(new_rst_path, "w", encoding="utf-8") as f: f.write(new_rst) # 将新文档注册到Sphinx构建环境 self.state.document.settings.env.found_docs.add(new_docname) logger.info(f"已添加新文档: {new_docname}") # 返回空节点,不影响当前文档的渲染结果 return [nodes.paragraph()] def setup(app): app.add_directive("netynl-include", NetYnlInclude) return { 'version': '0.1', 'parallel_read_safe': True, 'parallel_write_safe': True, }
关键实现说明
- 动态创建RST文件:根据当前文档的目录,生成对应子目录下的RST文件,Sphinx会自动识别这些文件并构建成HTML页面。
- 注册新文档:通过
found_docs.add()将新文档添加到Sphinx的待构建列表,确保这些文档会被处理。 - 依赖管理:记录原始输入文件的依赖,当
my_file.txt内容变化时,所有生成的新文档都会重新构建。 - 路径处理:自动创建所需的子目录,避免因目录不存在导致文件写入失败。
内容的提问来源于stack exchange,提问作者Breno Leitão
相关产品推荐
相关产品推荐

