Extraer lista de campos de reStructuredText

Digamos que tengo la siguiente entrada reST:

Some text ... :foo: bar Some text ... 

Lo que me gustaría terminar es un dictado como este:

 {"foo": "bar"} 

Intenté usar esto:

 tree = docutils.core.publish_parts(text) 

¿Analiza la lista de campos, pero termino con un pseudo XML en el tree["whole"]? :

 <document source="">    foo   bar 

Como el dict de tree no contiene ninguna otra información útil y eso es solo una cadena, no estoy seguro de cómo analizar la lista de campos del documento reST. ¿Como podría hacerlo?

Puedes intentar usar algo como el siguiente código. En lugar de utilizar el método publish_parts , he utilizado publish_doctree , para obtener la representación pseudo-XML de su documento. Luego me convertí a un DOM XML para extraer todos los elementos del field . Luego obtengo los primeros elementos field_name y field_body de cada elemento de 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'} 

El módulo xml.dom no es el más fácil de trabajar (por qué necesito usar .firstChild.nodeValue lugar de .nodeValue por ejemplo), así que es posible que desee usar el módulo xml.etree.ElementTree , que encuentro mucho más fácil trabajar con Si usa lxml, también puede usar la notación XPATH para encontrar todos los elementos field , field_body y field_body .

Tengo una solución alternativa que me parece menos pesada, pero tal vez más frágil. Después de revisar la implementación de la clase de nodo https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/nodes.py , verá que admite un método de paseo que se puede usar para extraer los datos deseados sin tener que crear dos representaciones XML diferentes de sus datos. Aquí está lo que estoy usando ahora, en mi código de protoype:

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

 from docutils.core import publish_doctree import docutils.nodes 

y entonces

 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) 

Aquí está mi implementación de 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())} 

Uso

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