说我有以下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文档中解析字段列表。我该怎么做?
答案 0 :(得分:7)
您可以尝试使用类似以下代码的内容。而不是使用我使用publish_doctree
的publish_parts
方法来获取文档的伪XML表示。然后我转换为XML DOM以提取所有field
元素。然后,我获得每个field_name
元素的第一个field_body
和field
元素。
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
),所以您可能希望使用{ {3}}模块,我发现它更容易使用。如果您使用lxml,您还可以使用XPATH表示法查找所有field
,field_name
和field_body
元素。
答案 1 :(得分:0)
我有一个替代解决方案,我觉得不那么负担,但可能更脆弱。在查看节点类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)
答案 2 :(得分:0)
这是我的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'}