Search code examples
javanested-mapyamlbeans

iterate, find and update value in nested Map<String, ?>


I have a YML file, which I parse to Map using yamlBeans library. I don't know how deep the nested map goes. for example:

  • key1:
    • key2: value1
    • key3:
      • key4: value2
      • key5: value3

I need to find a specific value in this map, update it, and write the map back to YML file (which I know how to do).

This is my code for updating the value, and it's working. However, this is only iterating twice through the nested map, and I need it to iterate it for as long as needed:

    static void updateYmlContent(Map<String, ?> ymlMap, String value, String... keys) {
    boolean found = false;
    for (Map.Entry entry : ymlMap.entrySet()) {
        if (entry.getKey().equals(keys[0])) {
            found = true;
            for (Map.Entry subEntry : ((Map<?, ?>) entry.getValue()).entrySet()) {
                if (subEntry.getKey().equals(keys[1])) {
                    subEntry.setValue(value);
                    break;
                } else {
                    throwKeyNotFoundException(keys[1]);
                }
            }
            break;
        }
    }
    if (!found) {
        throwKeyNotFoundException(keys[0]);
    }
}

Solution

  • Use recursion and a depth counter to drop through each level of the map. I didn't compile this, so it probably needs a little tweaking, but here's the basic idea:

    static void updateYmlContent(Map<String, ?> ymlMap, String value, String... keys) {
        int depth = 0;
        findAndReplaceContent(ymlMap, value, keys, depth);
    }
    
    static void findAndReplaceContent(Map map, .......) {
      if (map.containsKey(keys[depth]))
      {
        if (depth == keys.length - 1)
        {
          // found it
          map.put(keys[depth], value);
          // done
        }
        else
        {
          findAndReplaceContent(map.get(keys[depth]), value, keys, depth+1);
        }
      }
      else
      {
        // throw key not found
      }
    }