【问题标题】:Extract field list from reStructuredText从 reStructuredText 中提取字段列表
【发布时间】:2012-06-01 18:08:34
【问题描述】:

假设我有以下 reST 输入:

Some text ...

:foo: bar

Some text ...

我想最终得到的是这样的字典:

{"foo": "bar"}

我试过用这个:

tree = docutils.core.publish_parts(text)

它确实解析了字段列表,但我最终在tree["whole"]? 中得到了一些伪 XML:

<document source="<string>">
    <docinfo>
        <field>
            <field_name>
                foo
            <field_body>
                <paragraph>
                    bar

由于tree dict 不包含任何其他有用信息并且只是一个字符串,因此我不确定如何从 reST 文档中解析字段列表。我该怎么做?

【问题讨论】:

    标签: python restructuredtext docutils


    【解决方案1】:

    您可以尝试使用类似以下代码的内容。我没有使用publish_parts 方法,而是使用publish_doctree 来获取文档的伪XML 表示。然后我已转换为 XML DOM 以提取所有 field 元素。然后我得到每个field 元素的第一个field_namefield_body 元素。

    from docutils.core import publish_doctree
    
    source = """Some text ...
    
    :foo: bar
    
    Some text ...
    """
    
    # Parse reStructuredText input, returning the Docutils doctree as
    # an `xml.dom.minidom.Document` instance.
    doctree = publish_doctree(source).asdom()
    
    # Get all field lists in the document.
    fields = doctree.getElementsByTagName('field')
    
    d = {}
    
    for field in fields:
        # I am assuming that `getElementsByTagName` only returns one element.
        field_name = field.getElementsByTagName('field_name')[0]
        field_body = field.getElementsByTagName('field_body')[0]
    
        d[field_name.firstChild.nodeValue] = \
            " ".join(c.firstChild.nodeValue for c in field_body.childNodes)
    
    print d # Prints {u'foo': u'bar'}
    

    xml.dom 模块不是最容易使用的(例如,为什么我需要使用 .firstChild.nodeValue 而不仅仅是 .nodeValue),所以您可能希望使用 xml.etree.ElementTree 模块,我发现更容易使用。如果您使用 lxml,您还可以使用 XPATH 表示法来查找所有 fieldfield_namefield_body 元素。

    【讨论】:

    • 谢谢,这看起来像我要找的东西!
    【解决方案2】:

    我有一个替代解决方案,我发现它的负担更小,但可能更脆弱。在查看节点类https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/nodes.py 的实现之后,您将看到它支持一种walk 方法,该方法可用于提取所需数据,而无需创建数据的两种不同的xml 表示形式。这是我现在在原型代码中使用的内容:

    https://github.com/h4ck3rm1k3/gcc-introspector/blob/master/peewee_adaptor.py#L33

    from docutils.core import publish_doctree
    import docutils.nodes
    

    然后

    def walk_docstring(prop):
        doc = prop.__doc__
        doctree = publish_doctree(doc)
        class Walker:
            def __init__(self, doc):
                self.document = doc
                self.fields = {}
            def dispatch_visit(self,x):
                if isinstance(x, docutils.nodes.field):
                    field_name = x.children[0].rawsource
                    field_value = x.children[1].rawsource
                    self.fields[field_name]=field_value
        w = Walker(doctree)
        doctree.walk(w)
        # the collected fields I wanted
        pprint.pprint(w.fields)
    

    【讨论】:

      【解决方案3】:

      这是我的ElementTree 实现:

      from docutils.core import publish_doctree
      from xml.etree.ElementTree import fromstring
      
      source = """Some text ...
      
      :foo: bar
      
      Some text ...
      """
      
      
      def gen_fields(source):
          dom = publish_doctree(source).asdom()
          tree = fromstring(dom.toxml())
      
          for field in tree.iter(tag='field'):
              name = next(field.iter(tag='field_name'))
              body = next(field.iter(tag='field_body'))
              yield {name.text: ''.join(body.itertext())}
      

      用法

      >>> next(gen_fields(source))
      {'foo': 'bar'}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-10
        • 1970-01-01
        • 2019-11-20
        • 2019-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        相关资源
        最近更新 更多