Python Forum
[nested dics] Easy way to find if a key exists?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[nested dics] Easy way to find if a key exists?
#1
Hello,

I'm using xmltodict to work with XML files. It turns data into nested dictionaries.

In nested dictionaries that don't contain the same keys, I can't find an easy way to simply check if any given key exists somewhere.

The following functions don't work as expected:
def f(d, keys):
    if not keys:
        return True
    return keys[0] in d and f(d[keys[0]], keys[1:])
	
def keys_exists(element, *keys):
    '''
    Check if *keys (nested) exists in `element` (dict).
    '''
    if not isinstance(element, dict):
        raise AttributeError('keys_exists() expects dict as first argument.')
    if len(keys) == 0:
        raise AttributeError('keys_exists() expects at least two arguments, one given.')

    _element = element
    for key in keys:
        try:
            _element = _element[key]
        except KeyError:
            return False
    return True
Is there a way besides looping?

Thank you.

   
Reply
#2
You can use recursion perhaps
def get_deep(element, *path):
    if not path:
        return element
    if not isinstance(element, dict):
        raise KeyError(path)
    return get_deep(element[path[0]], *path[1:])

def main():
    D = {
        'foo': 1,
        'bar': {
            'baz': 'ham',
            'qux': {1: 2}},
        'spam': 'eggs'}
        
    print(get_deep(D, 'bar', 'qux', 1)) # prints 2
    
if __name__ == '__main__':
    main()
Reply
#3
Thanks, but I had in mind something like

if key_exists(myarray,"mykey"):
	print("Found key")
else:
	print("Key not in array")
ie. just giving the array and the key, regardless of where it's located.

Impossible?
Reply
#4
It's still a good fit for recursion though, due to the nesting.
Reply
#5
Yes, I'll use it if nothing else comes up. Thank you.
Reply
#6
Here is a recursive single key search
def key_exists(element, key):
    if isinstance(element, dict):
        if key in element:
            return True
        else:
            return any(key_exists(e, key) for e in element.values())
    else:
        return False
Reply
#7
For some reason, it finds 'Placemark', but not 'LineString', altough both are nested dictionaries:

print(key_exists2(doc, 'Placemark'))
#True
print(key_exists2(doc, 'LineString'))
#False
input.kml:
<?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>Document.kml</name>
    <open>1</open>
    <Style id="exampleStyleDocument">
      <LabelStyle>
        <color>ff0000cc</color>
      </LabelStyle>
    </Style>
    <Placemark>
      <name>Document Feature 1</name>
      <styleUrl>#exampleStyleDocument</styleUrl>
      <Point>
        <coordinates>-122.371,37.816,0</coordinates>
      </Point>
    </Placemark>
    <Placemark>
      <name>Document Feature 2</name>
      <styleUrl>#exampleStyleDocument</styleUrl>
      <Point>
        <coordinates>-122.370,37.817,0</coordinates>
      </Point>
    </Placemark>
    <Placemark>
      <name>My track</name>
      <LineString>
        <coordinates>-0.376291,43.296237,199.75
        -0.377381,43.29405</coordinates>
      </LineString>
    </Placemark>
  </Document>
</kml>
Reply
#8
But not everything is a dictionary. Because there are multiple Placemark sections, when you request that key, you get back a list of all sections. Then the code checks, finds it's not a dictionary, and stops. It would need to also iterate through lists to find elements inside sections with repeated names.

>>> type(x['kml']['Document']['Placemark'])
<class 'list'>
>>> print(*x['kml']['Document']['Placemark'], sep='\n')
OrderedDict([('name', 'Document Feature 1'), ('styleUrl', '#exampleStyleDocument'), ('Point', OrderedDict([('coordinates', '-122.371,37.816,0')]))])
OrderedDict([('name', 'Document Feature 2'), ('styleUrl', '#exampleStyleDocument'), ('Point', OrderedDict([('coordinates', '-122.370,37.817,0')]))])
OrderedDict([('name', 'My track'), ('LineString', OrderedDict([('coordinates', '-0.376291,43.296237,199.75\n        -0.377381,43.29405')]))])
Reply
#9
Thanks for the infos.

As a work-around, I'll just search in the source file before it's parsed:
with open(item) as f: xml = f.read()
if 'LineString' in xml:
	print("Found LS")
else:
	print("No LS")
Reply
#10
Maybe your approach is wrong. Instead of having the code look for keys I would write the code so the keys dictate what the code does.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [SOLVED] [Beautifulsoup] Find if element exists, and edit/append? Winfried 2 4,317 Sep-03-2022, 10:14 PM
Last Post: Winfried
  Python Program to Find the Total Sum of a Nested List vlearner 8 4,942 Jan-23-2022, 07:20 PM
Last Post: menator01
  p]Why os.path.exists("abc/d") and os.path.exists("abc/D") treat same rajeev1729 1 2,175 May-27-2020, 08:34 AM
Last Post: DeaD_EyE
  Easy way to sort a nested dict Alfalfa 3 5,663 Dec-07-2018, 04:12 PM
Last Post: Alfalfa

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020