美文网首页
Sphinx+reStructured: 内容复用设计与实践

Sphinx+reStructured: 内容复用设计与实践

作者: 莉莉邓 | 来源:发表于2023-07-12 10:28 被阅读0次

    缘起:近期有看到提问 “doc-as-code 方案下如何做内容复用?”,想想使用 Sphinx + reStructuredtext 已经有段时间了,也有一些个人认为还是比较实用和提升效率的做法,故趁机重新梳理、复盘一下,希望对有同样需求和问题的小伙伴有些启发和帮助。
    P.S.:其实在之前的两篇文档里,也已经分别介绍过了复用实现方式的变量和条件文本的使用,可分别查看:
    Sphinx+reStructuredText:变量的使用 - 简书 (jianshu.com)
    Sphinx+reStructuredText:条件文本的使用 - 简书 (jianshu.com)

    什么是内容复用

    DITA Best Practice 一书中有这么一句话讲到内容复用,即 In the world of DITA, reuse is about writing content once and reusing that content wherever it is needed. 内容复用,确实具有诸多好处,比如:

    • 提升效率。相同的内容写一次就可以了,省去了重复写的麻烦。如果有翻译的需求,还省去了重复翻译的成本。另外,内容需要维护和审阅时,也省去了重复维护和审阅的成本。

    • 提升准确性和一致性。一次更新可保证全局修改。

    那么,是不是如果没用DITA,是不是就没法实现内容复用呢?doc-as-code 方案中是否内容复用呢?本文想重点讨论这个问题,并分享一些笔者在实际工作过程中的经验。

    根据内容模块的颗粒度,内容复用设计可以包括以下的情况:

    • 词汇和短语类(Phrase level)
    • 段落类(Paragraph level)
    • 主题类(Topic level)
    • 目录/多个主题集合(Map level)

    不同颗粒度内容模块的复用设计与方法

    针对词汇和短语类的信息片段

    对于词汇、短语类的信息片段,可以考虑使用变量的方式处理。例如:

    • 产品名称
    • 模块名称
    • 同一个参数在不同产品/方案上的不同设定值

    步骤:

    Step 1conf.py 文件中定义全局 substitution。

    rst_epilog = """
    
    .. |product name| replace:: Product A 
    
    """
    

    Step 2.rst 文件中使用已定义的 substitution。

    |product name| provides a solution to xxxxxxxxxxxxxxxxxxxxxxxxxx. 
    

    如遇需更新的情况,直接调整 conf.py 的表述即可。当然,如只需达到比如某些 rst (reStructuredText)文件中的统一,可以在 rst 文件中使用局部 substitution 声明变量值,而不在 conf.py 定义(相当于全局变量)。

    当然,substitution 不仅仅能用于文本类变量的应用,也能用于图片或者可执行功能块类的变量应用。以图片为例,reStructuredText Markup Specification (sourceforge.io) 官方提供的用法示例如下:

    West led the |H| 3, covered by dummy's |H| Q, East's |H| K,
    and trumped in hand with the |S| 2.
    
    .. |H| image:: /images/heart.png
       :height: 11
       :width: 11
    .. |S| image:: /images/spade.png
       :height: 11
       :width: 11
    
    * |Red light| means stop.
    * |Green light| means go.
    * |Yellow light| means go really fast.
    
    .. |Red light|    image:: red_light.png
    .. |Green light|  image:: green_light.png
    .. |Yellow light| image:: yellow_light.png
    
    |-><-| is the official symbol of POEE_.
    
    .. |-><-| image:: discord.png
    .. _POEE: http://www.poee.org/
    

    此种用法下,再提供一种升级的用法,即结合 only directive,可以进一步实现相同参数名在不同产品/方案上不同的设定值。具体做法示例如下:

    .. only:: tag_A
       
       .. |parameter_value| replace:: Value_A
     
    
    .. only:: tag_B
       
       .. |parameter_value| replace:: Value_B
    
    
    The Parameter value is  |parameter| 
    
    

    需要注意的一点是,如果使用 only directive,需保证引入的 tag 必须在 conf.py 文件中进行过声明。声明命令如下:

    # In conf.py file
    
    tags.has ('tag_a')
    

    后续结合不同场景需求,可过滤得到已定义 tag 后的内容。

    针对段落类的信息块

    在词汇或短语的基础上,如待重用的是内容较多的内容块,如段落、注意信息等,可以将待重用的内容保存为单独的文件,并使用 include directive 在需要重用的地方直接插入。
    具体操作及代码可参考如下:

    Step 1: 如需重用如下所示的 note 信息,可以将该 note 信息单独存储成一个文件,例如 note_a.txt 文件。

    .. note:: This is a piece of note information, which can be shared for different topics. 
    
    

    Step 2: 在需要重用的位置,使用 include directive 插入。

    Paragraph example xxxxxxxxxxx. 
    
    .. include:: note_a.txt 
    

    针对主题类的模块化文档

    对于内容规模更大些的,即差异较大的内容模块,更建议提供单独的主题文件,及独立的 rst 文件存放。在不同需求场景下,使用 toctree directive 调用不同的主题即可。
    例如假定有如下的文档目录:

    trunk
    |--  product_A/
    |     |-- introduction_product_A.rst
    |--  product_B/
    |     |-- introduction_product_B.rst
    |--  shared/
    |     |-- topic_1.rst
    |     |-- topic_2.rst
    
    

    那么针对产品A、产品B,在文档输出时,可以提供不同主题文件的引用,如:

    # In index_A.rst  file
    
    .. toctree:: 
    
       Introduction <product_A/introduction_product_A.rst>
    
    # In index_B.rst  file
    
    .. toctree:: 
    
       Introduction <product_B/introduction_product_B.rst>
    
    # OR:  In a same toc or subtoc file, use *only* directive to filter 
    
    .. only:: tag_A 
    
       .. toctree:: 
    
          Introduction <product_A/introduction_product_A.rst>
    
    .. only:: tag_B
    
       .. toctree:: 
    
          Introduction <product_B/introduction_product_B.rst>
    
    

    针对目录/多个主题集合

    进一步地,除了单个的 Topic,待复用的是多个主题文件的集合,方法其实与主题文档的复用手段一样,区别在于可以定义整个 Sphinx project 的根目录下的 index.rst 文件,也即 root_doc (version 4.0 以前也叫master_doc )文件。

    此时,可以在项目根目录下准备多个 index.rst 文件,并在不同发布场景的配置文件 conf.py 文件中声明具体使用哪个目录结构文件。

    # In conf.py file
    
    root_doc = index_product_A.rst
    

    条件发布

    在以上的内容复用实现示例中,不难发现已经引入了 conf.py, reStructuredText directives (substitution, only 等),那么在最后文档发布过程如何进行 tag 以及 root_doc 的过滤呢?此时,我们可以考虑灵活应用和扩展下 Makefile 文件。

    在改 Makefile 文件之前,我们先来回顾下 Sphinx build 文档的基本命令。以 HTML 的输出为例,基本的 sphinx-build 命令如下:

    sphinx-build -b html  source  build   -t  tag_option   -c  conf_file_path/
    
    

    在上述命令中:

    • -b 代表要输出的文件格式,此处以 HTML 文件输出为例。如需 PDF输出,则相应为 -M latexpdf
    • source 代表源文件的文件夹。
    • build 代表输出文件的文件夹。此时,文档生成结束后,可以在 build/html 找到所有的输出文件。
    • -t 代表此次文档生成时要去抓取的 tag 标签,即标记为指定 tag_option 下的所有内容。默认为空。
    • -c 代表此次文档生成时要应用的 configuration 文件。默认为 source 目录下的 conf.py 文件。

    一旦引入了不同的 tag_optionconf.py 的组合,以达到不同发布物不同模版配置及内容过滤的需求。进一步地,可在 Makefile 中区分不同的发布命令,以便于其他协作者直接使用简单的 make 命令即可获得相应的发布物。

    In Makefile file
    
    # Set up the target for the HTML output of product A 
    PA-HMTL:
              @$(SPHINXBUILD) -b html   "$(SOURCEDIR)"   "(BUILDDIR)/product_a"  -t  tag_a  -c  ../conf_a/
    

    如是,使用 make PA-HTML 命令即可得到产品 A 的 HMTL 文档。在输出文件中,对于打了 tag 的内容,仅抓取标记为 tag_a 的内容。同时,应用了指定的 conf_a/conf.py 模版文件。在模版文件中,就可以自定义不同的样式设计、全局变量定义等等。

    与 DITA 重用方式的比较

    从上述内容不难发现,可以针对不同的内容颗粒度,灵活使用和组合不同的方式,以达到复用的目的。结合以前使用 DITA 的经验,将不同颗粒度的内容模块复用实现方式比较如下:

    待重用的内容模块 DITA Sphinx + reStructuredText
    词汇或短语 conref / keyref / conkeyref substitution directive
    段落 conref include directive + only directive
    主题 topicref toctree directive + only directive
    目录结构 mapref root_doc + conf.py

    写在最后

    实际工作中,可能也会有小伙伴疑问 “既然已经是 doc-as-code 了,为啥要这么大费周章地考虑复用,最简单的复用方式,不是拉取分支(branch)吗?” 拉取分支固然是简单、直接的方式,但一旦分支(branch)分出后,分支管理、与主 trunk 的关系管理、冲突解决其实会是个比较难处理的问题,特别是对于非技术背景的 TW,一看到稍复杂的冲突可能就得头皮发麻、两手无措了。

    另外,并不是提起内容复用,就一定只能有 DITA 的解决方案,在轻量级的 doc-as-code 模式下,也有相应的复用实现方法。但是,不论何种解决方案下,就内容复用本身,其也不应该是想起来复用就复用的。在决定复用内容之前,要经过全局的内容分析与设计,与团队内约定什么内容应该有限复用,何种场景下选择何种恰当的方式进行复用,以最小化的内容管理代价实现最大化复用效率。无论什么内容都想复用解决、或者一味为了复用而复用,都是不太可取的。

    相关文章

      网友评论

          本文标题:Sphinx+reStructured: 内容复用设计与实践

          本文链接:https://www.haomeiwen.com/subject/vqykudtx.html