reST/Sphinx中链接内的替换

23 投票
4 回答
7139 浏览
提问于 2025-04-15 13:22

我正在使用Sphinx来为一个将在不同服务器上部署的网络服务编写文档。文档中有很多用户可以点击的URL示例,这些链接应该能正常工作。我的问题是,主机、端口和部署根目录会有所不同,因此每次部署时都需要重新生成文档。

我尝试像这样定义替换内容:

|base_url|/path
.. |base_url| replace:: http://localhost:8080

但是生成的HTML并不是我想要的(生成的链接中没有包含“/path”):

<a href="http://localhost:8080">http://localhost:8080</a>/path

有没有人知道该怎么解决这个问题?

4 个回答

4

好的,我来告诉你我是怎么做到的。首先,apilinks.py 是一个 Sphinx 的扩展:

from docutils import nodes, utils

def setup(app):
    def api_link_role(role, rawtext, text, lineno, inliner, options={},
                      content=[]):
        ref = app.config.apilinks_base + text
        node = nodes.reference(rawtext, utils.unescape(ref), refuri=ref,
                               **options)
        return [node], []
    app.add_config_value('apilinks_base', 'http://localhost/', False)
    app.add_role('apilink', api_link_role)

接下来,在 conf.py 文件中,把 'apilinks' 加到扩展列表里,并为 'apilinks_base' 设置一个合适的值(否则,它会默认设置为 'http://localhost/')。我的文件看起来是这样的:

extensions = ['sphinx.ext.autodoc', 'apilinks']
# lots of other stuff
apilinks_base = 'http://host:88/base/'

使用方法:

:apilink:`path`

输出结果:

<a href="http://host:88/base/path">http://host:88/base/path</a>
5

我遇到过类似的问题,需要在图片的目标链接中替换网址。extlinks在作为图片的:target:属性值时不会展开。最后,我写了一个自定义的sphinx转换功能,用来重写以特定前缀开头的网址,在我的例子中是http://mybase/。以下是conf.py中的相关代码:

from sphinx.transforms import SphinxTransform

class ReplaceMyBase(SphinxTransform):

    default_priority = 750
    prefix = 'http://mybase/'

    def apply(self):
        from docutils.nodes import reference, Text
        baseref = lambda o: (
            isinstance(o, reference) and
            o.get('refuri', '').startswith(self.prefix))
        basetext = lambda o: (
            isinstance(o, Text) and o.startswith(self.prefix))
        base = self.config.mybase.rstrip('/') + '/'
        for node in self.document.traverse(baseref):
            target = node['refuri'].replace(self.prefix, base, 1)
            node.replace_attr('refuri', target)
            for t in node.traverse(basetext):
                t1 = Text(t.replace(self.prefix, base, 1), t.rawsource)
                t.parent.replace(t, t1)
        return

# end of class

def setup(app):
    app.add_config_value('mybase', 'https://en.wikipedia.org/wiki', 'env')
    app.add_transform(ReplaceMyBase)
    return

这段代码会把以下的rst源文件扩展为指向英文维基百科。当conf.py设置mybase="https://es.wikipedia.org/wiki"时,链接就会指向西班牙语维基百科。

* inline link http://mybase/Helianthus
* `link with text <http://mybase/Helianthus>`_
* `link with separate definition`_
* image link |flowerimage|

.. _link with separate definition: http://mybase/Helianthus

.. |flowerimage| image:: https://upload.wikimedia.org/wikipedia/commons/f/f1/Tournesol.png
   :target: http://mybase/Helianthus
31

Sphinx v1.0的新功能:

sphinx.ext.extlinks – 一种简化外部链接的标记方式

https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html

这个扩展增加了一个新的配置项:

extlinks

这个配置项需要是一个字典,里面包含外部网站的信息,主要是把独特的短名称和一个基础网址、前缀对应起来。比如,如果你想为上面提到的问题创建一个别名,你可以添加:

extlinks = {'issue': 
    ('http://bitbucket.org/birkenfeld/sphinx/issue/%s', 'issue ')}

现在,你可以用这个别名作为新的角色,比如 :issue:`123`。这样就会插入一个链接到 http://bitbucket.org/birkenfeld/sphinx/issue/123。可以看到,在这个角色中给出的目标会替换掉基础网址中的 %s

链接的标题取决于元组中的第二个项目,也就是前缀:

如果前缀是 None,链接的标题就是完整的网址。
如果前缀是空字符串,链接的标题就是角色内容中给出的部分网址(在这个例子中是123)。
如果前缀是非空字符串,链接的标题就是部分网址,前面加上前缀 – 在上面的例子中,链接的标题会是问题 123。
你也可以使用其他生成链接的角色支持的“显式标题”语法,也就是 :issue:`this issue <123>`。在这种情况下,前缀就不重要了。

撰写回答