How to get results from pyparsing Forward object?
<p>Let us assume we have the following string</p>

<pre><code>string = """
object obj1{
    attr1 value1;


    object obj2 {
        attr2 value2;
    }
}

object obj3{
    attr3 value3;
    attr4 value4;
}

"""
</code></pre>

<p>There is a nested object, and we use Forward to parse this. </p>

<pre><code>from pyparsing import *
word = Word(alphanums)

attribute = word.setResultsName("name")
value = word.setResultsName("value")

object_grammar = Forward()

attributes = attribute + value + Suppress(";") + LineEnd().suppress()
object_type = Suppress("object ") + word.setResultsName("object_type") + Suppress('{') + LineEnd().suppress()

object_grammar &lt;&lt;= object_type+\
    OneOrMore(attributes|object_grammar) + Suppress("}") | Suppress("};")

for i, (obj, _, _) in enumerate(object_grammar.scanString(string)):
    print('\n')
    print('Enumerating over object {}'.format(i))
    print('\n')
    print('This is the object type {}'.format(obj.object_type))
    print(obj.asXML())
    print(obj.asDict())
    print(obj.asList())
    print(obj)
    print(obj.dump())
</code></pre>

<p>These are the results. The obj.asXML() function contains all the information, however since it has been flattened, the order of the information is essential to parsing the result. Is this the best way to do it? I must be missing something. I would like a solution that works for both nested and not nested objects, i.e. for obj1, obj2 and obj3.</p>

<p>Also, <code>setResultsName('object_type')</code> doesn't return the <code>object_type</code> for the parent object. The output of the program above is shown below. Any suggestions?</p>

<pre><code>Enumerating over object 0

This is the object type obj2

&lt;ITEM&gt;
  &lt;object_type&gt;obj1&lt;/object_type&gt;
  &lt;name&gt;attr1&lt;/name&gt;
  &lt;value&gt;value1&lt;/value&gt;
  &lt;object_type&gt;obj2&lt;/object_type&gt;
  &lt;name&gt;attr2&lt;/name&gt;
  &lt;value&gt;value2&lt;/value&gt;
&lt;/ITEM&gt;
{'object_type': 'obj2', 'name': 'attr2', 'value': 'value2'}
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
- name: attr2
- object_type: obj2
- value: value2


Enumerating over object 1


This is the object type obj3

&lt;ITEM&gt;
  &lt;object_type&gt;obj3&lt;/object_type&gt;
  &lt;name&gt;attr3&lt;/name&gt;
  &lt;value&gt;value3&lt;/value&gt;
  &lt;name&gt;attr4&lt;/name&gt;
  &lt;value&gt;value4&lt;/value&gt;
&lt;/ITEM&gt;
{'object_type': 'obj3', 'name': 'attr4', 'value': 'value4'}
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
- name: attr4
- object_type: obj3
- value: value4
</code></pre>

<p>I was able to work around this by using <code>listAllMatches=True</code> in the setResultsNames function. This gave me as asXML() result that had structure that I could retrieve information from. It still relies on the order of the XML and requires using zip for get the <code>name</code> and <code>value</code> for a <code>attribute</code> together. I'll leave this question open to see if I get a better way of doing this.</p>

python pyparsing