reStructuredText

过去,本专栏讨论过XML的替代方法-满足您可能会使用XML的许多相同目的的文档格式。 reStructuredText延续了这一传统。 与YAML(适用于数据格式)相反,reStructuredText专为文档而设计; 与智能ASCII相比,reStructuredText更重,更强大且更正式地指定。 与XML相比,所有这些格式都可以使用标准文本编辑器轻松自然地读取和编辑。 使用XML或多或少都需要专门的XML编辑器,例如我之前查看过的那些编辑器(请参阅参考资料 )。

reStructuredText(通常缩写为reST)是Python Docutils项目的一部分。 该项目的目标是创建一套用于处理纯文本文档的工具,包括将其导出为HTML,XML和TeX等结构化格式。 尽管该项目来自Python社区,但它所满足的需求超出了Python。 各种类型的程序员和作家经常创建诸如README,HOWTO,FAQ,应用程序手册之类的文档,而对于Python而言,则创建PEP(Python增强建议)。 对于这些类型的文档,要求用户处理冗长而困难的格式(例如XML或LaTeX)通常是不合理的,即使这些用户是程序员。 但是,仍然经常希望将这些类型的文档用于简单查看之外的目的(例如索引,编译,漂亮打印,过滤等)。

Docutils工具可以满足Python程序员的需求,就像JavaDoc帮助Java程序员或POD帮助Perl程序员一样。 可以将Python模块中的文档转换为Docutils文档树,然后转换为各种输出格式(通常在单个脚本中)。 但是对于本文而言,更有趣的用途是用于常规文档。 对于像这样的文章,甚至对于我即将出版的书,我都是使用智能ASCII编写的。 但是我开始觉得reStructuredText的形式会更好(而且我可能会开发工具来转换现有文档)。

在撰写本文时,Docutils项目正在开发中,尚未发布稳定版本。 现有的工具是好的,但是整个项目是诺言,良好意图,部分文档和一些实际工作工具的结合。 但是,进度是稳定的,此时您可以执行的操作非常有用。

reStructuredText的示例

通过一个简短的示例,您可以更好地了解reStructuredText的含义。 以下文本是PEP 287(假设的PEP的一部分)中的一个示例:

清单1. PEP的纯文本版本
Abstract

    This PEP proposes adding frungible doodads [1] to the
    core. It extends PEP 9876 [2] via the BCA [3] mechanism.

...

References and Footnotes

    [1] http://www.example.org/

    [2] PEP 9876, Let's Hope We Never Get Here
        http://www.python.org/peps/pep-9876.html

    [3] "Bogus Complexity Addition"

清单1中的格式正是PEP在287之前的格式。如果使用reStructuredText标记相同的PEP,则它看起来可能像这样:

清单2. PST的reST版本
Abstract
========

This PEP proposes adding `frungible doodads`_ to the core.
It *extends* PEP 9876 [#pep9876]_ via the BCA [#]_ mechanism.

...

References & Footnotes
======================

.. _frungible doodads: http://www.example.org/

.. [#pep9876] PEP 9876, Let's Hope We Never Get Here

.. [#] "Bogus Complexity Addition"

有一些细节与明文不同。 但是,少量字符的散布确实不会损害可读性。 如果您在文本编辑器或打印页面中看到它,则无需翻阅即可。

清单2中的reST格式的文档可以自动转换成XML方言,例如Docutils Generic DTD定义的:

清单3. PEP的Docutils XML版本
<?xml version="1.0" encoding="UTF-8"?>
<document source="test">
  <section id="abstract" name="abstract">
    <title>Abstract</title>
    <paragraph>This PEP proposes adding <reference
      refname="frungible doodads">Frungible doodads</reference>
      to the core. It<emphasis>extends</emphasis><reference
      refuri="http://www.python.org/peps/pep-9876.html">
      PEP 9876</reference><footnote_reference auto="1" id="id1"
      refname="pep9876"/> via the BCA <footnote_reference
      auto="1" id="id2"/> mechanism.</paragraph>
    <paragraph>...</paragraph>
  </section>
  <section id="references-footnotes"
           name="references & footnotes">
    <title>References & Footnotes</title>
    <target id="frungible-doodads" name="frungible doodads"
            refuri="http://www.example.org/"/>
    <footnote auto="1" id="pep9876" name="pep9876">
      <paragraph><reference
        refuri="http://www.python.org/peps/pep-9876.html">PEP
        9876</reference>, Let's Hope We Never Get Here
      </paragraph>
    </footnote>
    <footnote auto="1" id="id3">
      <paragraph>"Bogus Complexity Addition"
      </paragraph>
    </footnote>
  </section>
</document>

您可以对比这三种格式看到几件事。 最显着的区别是浏览XML版本要困难得多。 但是,值得注意的是reStructuredText工具在reST文档中找到了多少信息。 正确匹配了几种类型的引用,标识了文档部分,并添加了字符级印刷标记。 在其他示例中,可以在处理过程中生成链接的TOC以及其他特殊指令。

docutils项目结构

docutils程序包由许多子程序包组成,它们之间的关系相当复杂。 PEP 258(Docutils设计规范)包含一个图表,可用于了解整体模式:

图1. Docutils项目模型
Docutils项目模型

该PEP中包含有关组件子包的更完整的说明,但是在这里需要重复简短的说明。

将reST文本转换为节点树的繁重工作是由docutils.parsers.rst子包完成的。 reStructuredText解析器以面向行的方式处理源,在每行上寻找状态转换; 如果未找到其他过渡模式,则text过渡会抓住这一行。 过渡包括缩进更改,特殊的前导符号等功能。 默认值仅包括下一行作为当前节点内的更多文本。

此结构类似于智能ASCII解析器txt2dwtxt2html中使用的结构 。 其他解析器将位于docutils.parsers层次结构下,但目前未提供任何解析器。 但是,有一个实验性的Python源代码解析器将Python源文件视为文档树。

一旦docutils.transforms子程序包为文档生成了节点树,您就可以通过多种方式来操纵该树。 例如,如果您指定了包含目录的指令,则文档树将遍历以标识列出的项目。 同样,转换在此阶段执行对引用和链接的一些清理。 在初始遍历期间,提示转换的占位符会填充树中未解析元素将要到达的位置。

面向事件的输出

各种docutils.writers模块可能是本文大多数读者感兴趣的主要方面。 一些更有趣的作家在写这篇文章的时候(请在docutils的网站仍处于实验性“沙箱”区域相关信息 ),但原则是在任何情况下是相同的。 writer模块应定义一个继承自docutils.writers.WriterWriter类。 这个Writer类定义了一些设置,但主要定义了.translate()方法,可能类似于:

清单4.典型的自定义Writer.translate()方法
def translate(self):
    visitor = DocBookTranslator(self.document)
    self.document.walkabout(visitor)
    self.output = visitor.astext()

正如您所看到的,作者依赖于一个知道如何处理每种类型节点的访问者 。 访问者通常将从docutils.nodes.NodeVisitor继承。 对访问者进行编程非常类似于对SAXexpatREXML或其他面向事件的XML解析器进行编程。 但是,访问者甚至更接近Python的xmllib模块的编程风格。 也就是说,访问者对于每种类型的节点都将具有.visit_FOO().depart_FOO()方法,而不是在大型.startElement()endElement()方法中打开类型。 OOP的纯粹主义者可能更喜欢这种风格。 Docbook / XML编写器的一个简单示例是:

class DocBookTranslator(nodes.NodeVisitor):
    [...lots of methods...]
    def visit_block_quote(self, node):
      self.body.append(self.starttag(node, 'blockquote'))
    def depart_block_quote(self, node):
      self.body.append('</blockquote>\n')
    [...lots more methods...]

对自定义编写器/访问者进行编程非常简单,并且有用于Docutils / XML,HTML,PEP-HTML,PseudoXML(一种将起始标签与缩进但不包含结束标签的轻型XML),LaTeX,DocBook编写器。 / XML,PDF,OpenOffice / XML和Wiki-HTML。

面向树的处理

您可以将reStructuredText文档转换为可以以类似于DOM的方式进行操作的节点树。 以下是使用清单2中所示的reST PEP的示例。

清单5.创建一个reST节点树
>>> txt = open('pep.txt').read()
>>> def rst2tree(txt):
...     import docutils.parsers.rst
...     parser = docutils.parsers.rst.Parser()
...     document = docutils.utils.new_document("test")
...     document.settings.tab_width = 4
...     document.settings.pep_references = 1
...     document.settings.rfc_references = 1
...     parser.parse(txt, document)
...     return document
...
>>> doc = rst2tree(txt)
>>> doc.children
[<section "abstract": <title...><paragraph...><paragraph...>>,
 <section "references & footnotes": <title...>
   <target "frungible doodads"...><footnote "pep9 ...>]
>>> print doc.autofootnotes
[<footnote "pep9876": <paragraph...>>, <footnote: <paragraph...>>]
>>> print doc.autofootnotes[0].rawsource
PEP 9876, Let's Hope We Never Get Here

与DOM相反,需要注意的一件事是reStructuredText已经是固定的文档方言。 因此,您可以使用以其含义命名的属性来搜索节点,而不是使用通用方法来搜索匹配的节点。 .children属性通常是分层的,但是大多数属性收集给定类型的节点。

reST节点的一种便捷方法是.pformat() ,它生成用于漂亮打印的文档树的伪XML表示,如清单6所示:

清单6. reST节点的伪XML表示形式
>>> print doc.autofootnotes[0].pformat('  ')
<footnote auto="1" id="pep9876" name="pep9876">
  <paragraph>
    <reference refuri="http://www.python.org/peps/pep-9876.html">
      PEP 9876,
    Let's Hope We Never Get Here

节点的方法,如.remove() .copy() .append().insert()是用于修剪和操作树很有用。

对于XML程序员而言,更理想的API可能是DOM本身。 幸运的是,此API仅需一个方法即可调用:

清单7.将reST树转换为DOM树
>>> dom = doc.asdom()
>>> foot0 = dom.getElementsByTagName('footnote')[0]
>>> print foot0.toprettyxml('  ')
<footnote auto="1" id="pep9876" name="pep9876">
  <paragraph>
    <reference refuri="http://www.python.org/peps/pep-9876.html">
      PEP 9876
    </reference>
    , Let's Hope We Never Get Here
  </paragraph>
</footnote>

不幸的是,在撰写本文时,还没有工具或函数将DOM树或XML文档转换回 reStructuredText。 拥有Docutils通用DTD的阅读器会特别好; 这将使您为相应的XML生成一个reST文档树。 您可以使用.astext()节点方法将其写回为reST。 编写这样的阅读器并不难,我相信这会及时发生的(也许是我本人或我的一位读者)。


翻译自: https://www.ibm.com/developerworks/xml/library/x-matters24/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值