def parse_listdelimited_aws_xml(xml_stream, list_tags=None):
    '''
    Parse a stream of XML and return a nested dict.  The dict represents each
    XML element with a key that matches the element's name and a value of
    another dict if the element contains at least one child element, or the
    element's text if it does not.

    For each element whose name appears in the list_tags list, its dict
    value will instead be a list that aggregates the values of each of that
    element's children.

    This function is designed to parse XML from AWS services that explicitly
    start and end lists with their own elements, such as EC2.

    Examples:
        <a><b>spam</b><c>eggs</c></a> -> {'a': {'b': 'spam', 'c': 'eggs'}}

        <a>
          <b>
            <c>spam</c>
          </b>          + ['a'] -> {'a': [{'c': 'spam'}, {'c': 'eggs'}]}
          <b>
            <c>eggs</c>
          </b>
        </a>
    '''
    # One fundamental assumption we make here is that elements contain text
    # xor other elements.
    if list_tags is None:
        list_tags = ()
    stack = [(None, {})]
    try:
        for event, elem in ElementTree.iterparse(xml_stream,
                                                 events=('start', 'end')):
            tag = _strip_ns(elem.tag)
            if event[0] == 's':  # start
                if tag in list_tags:
                    # Start a new list
                    stack.append((tag, []))
                else:
                    stack.append((tag, {}))
            else:  # end
                assert tag == stack[-1][0]
                if isinstance(stack[-2][1], list):
                    # Add the thing we just finished parsing to the list
                    if stack[-1][1] == {}:
                        # No inner elements; use text instead
                        if elem.text is not None:
                            stack[-2][1].append(elem.text)
                        else:
                            # No text either, so use {} to make code like this
                            # work when presented with an empty element that
                            # does not match a list tag:
                            # response.get('foo', {}).get('bar')
                            stack[-2][1].append({})
                    else:
                        stack[-2][1].append(stack[-1][1])
                else:
                    # Add the thing we just finished parsing to the dict
                    if stack[-1][1] == {}:
                        # No inner elements; use text instead
                        if elem.text is not None:
                            stack[-2][1][tag] = elem.text
                        else:
                            # No text either, so use {} to make code like this
                            # work when presented with an empty element that
                            # does not match a list tag:
                            # response.get('foo', {}).get('bar')
                            stack[-2][1][tag] = {}
                    else:
                        stack[-2][1][tag] = stack[-1][1]
                stack.pop()
                elem.clear()  # free up some memory
    except (ParseError, SyntaxError):
        raise ValueError('XML parse error')
    return stack[0][1]
dataset/ETHPy150Open boto/requestbuilder/requestbuilder/xmlparse.py/parse_listdelimited_aws_xml/original