def RecurseKey(recur_item, depth=15, key_path=''):
  """Flattens nested dictionaries and lists by yielding it's values.

  The hierarchy of a plist file is a series of nested dictionaries and lists.
  This is a helper function helps plugins navigate the structure without
  having to reimplement their own recursive methods.

  This method implements an overridable depth limit to prevent processing
  extremely deeply nested plists. If the limit is reached a debug message is
  logged indicating which key processing stopped on.

  Example Input Plist:
    recur_item = { DeviceRoot: { DeviceMAC1: [Value1, Value2, Value3],
                                 DeviceMAC2: [Value1, Value2, Value3]}}

  Example Output:
    ('', DeviceRoot, {DeviceMACs...})
    (DeviceRoot, DeviceMAC1, [Value1, Value2, Value3])
    (DeviceRoot, DeviceMAC2, [Value1, Value2, Value3])

  Args:
    recur_item: An object to be checked for additional nested items.
    depth: Optional integer indication the current recursion depth.
           This value is used to ensure we stop at the maximum recursion depth.
    key_path: Optional path of the current working key.

  Yields:
    A tuple of the key path, key, and value from a plist.
  """
  if depth < 1:
    logger.debug('Recursion limit hit for key: {0:s}'.format(key_path))
    return

  if isinstance(recur_item, (list, tuple)):
    for recur in recur_item:
      for key in RecurseKey(recur, depth=depth, key_path=key_path):
        yield key
    return

  if not hasattr(recur_item, 'items'):
    return

  for subkey, value in iter(recur_item.items()):
    yield key_path, subkey, value

    if isinstance(value, dict):
      value = [value]

    if isinstance(value, list):
      for item in value:
        if not isinstance(item, dict):
          continue

        subkey_path = '{0:s}/{1:s}'.format(key_path, subkey)
        for tuple_value in RecurseKey(
            item, depth=depth - 1, key_path=subkey_path):
          yield tuple_value
Flattens nested dictionaries and lists by yielding it's values.

  The hierarchy of a plist file is a series of nested dictionaries and lists.
  This is a helper function helps plugins navigate the structure without
  having to reimplement their own recursive methods.

  This method implements an overridable depth limit to prevent processing
  extremely deeply nested plists. If the limit is reached a debug message is
  logged indicating which key processing stopped on.

  Example Input Plist:
    recur_item = { DeviceRoot: { DeviceMAC1: [Value1, Value2, Value3],
                                 DeviceMAC2: [Value1, Value2, Value3]}}

  Example Output:
    ('', DeviceRoot, {DeviceMACs...})
    (DeviceRoot, DeviceMAC1, [Value1, Value2, Value3])
    (DeviceRoot, DeviceMAC2, [Value1, Value2, Value3])

  Args:
    recur_item: An object to be checked for additional nested items.
    depth: Optional integer indication the current recursion depth.
           This value is used to ensure we stop at the maximum recursion depth.
    key_path: Optional path of the current working key.

  Yields:
    A tuple of the key path, key, and value from a plist.