Cozmonaut
Cozmonaut

Reputation: 3

Retrieving a key from HashMap based on part of certain strings in the key?

Task: Read a XML file to create a Template;

I am reading this XML file as mentioned below and putting it in a HashMap. to get a Key-Value pair, where Key is value under Element attribute "name" and Value is Element Value. eg: Key: map.abc.color.PRIMARY and Value: #FFFFFF eg: Key: map.abc.node.TEXT1 and Value: value1

<properties>
    <property name="map.abc.color.PRIMARY">#FFFFFF</property>
    <property name="map.abc.color.SECONDARY">#F0F0F0</property>
    <property name="map.abc.node.TEXT1">value1</property>
    <property name="map.abc.node.TEXT2">value2</property>
    <property name="map.abc.node.lowercase">value3</property>   
    <property name="map.abc.strFile">/path/to/file</property>

    <property name="map.pqr.color.PRIMARY">#000000</property>
    <property name="map.pqr.color.SECONDARY">#ABABAB</property>
    <property name="map.pqr.node.WORD1">value4</property>
    <property name="map.pqr.node.WORD2">value5</property>
    <property name="map.abc.node.lowercase">value6</property>
    <property name="map.pqr.strFile">/path/to/file</property>
</properties>

Following is a Template(using a StringBuffer) Output to be written to a file.

abc = {
    color: {PRIMARY_COLOR:"#FFFFFF",SECONDARY_COLOR:"#F0F0F0"}
    node:{TEXT1:"value1",TEXT2:"value2"}
};

pqr = {
    color: {PRIMARY_COLOR:"#FFFFFF",SECONDARY_COLOR:"#F0F0F0"}
    node:{WORD1:"value4",WORD2:"value5"}
};

Offnote: I am using following pattern which works fine.

key.matches("map.abc.*.*\\p{Lu}$") or key.matches("map.*.*\\p{Lu}$")

I am hence looking to find a way to get all keys ending with Uppercase alphabets after the last period in the Key from the HashMap(Or possibly any other options)

Upvotes: 0

Views: 859

Answers (3)

Tejay Cardon
Tejay Cardon

Reputation: 4223

OK, now that we have more detail, we can address your data structure. It appears to me that you have a hierarchical map here. Your name seems to define the hierarchy. I'd use a map of maps to store it:

Map<String, Map<String, Map<String, String>>> structure = new HashMap<>();

to parse and populate the map (totally just psuedocode):

path = name.split(".")
// ignore path[0] since it's just 'map'
structure.get(path[1]).get(path[2]).put(path[3], value)

And to retrieve values

for (Map<String, Map<String, String>> element : structure){
  for(Map<String, String> group : element) {
    for(String attribute : group.keys){
      if(allUpper(attribute)) {  //DO YOUR THING HERE }
    }
  }
}

Upvotes: 1

clstrfsck
clstrfsck

Reputation: 14839

It looks to me like you are trying to convert from a java properties-style list of values to javascript objects.

Here is one possibility: you could "unflatten" the properties-style Map into a recursive map of maps/values, and then leverage one of the JSON libraries to output the values. Here is some code to unflatten things:

public class Foo {
  private static final String ROOT_NAME = "map";

  private static boolean noLowercase(CharSequence s) {
    return !s.chars().anyMatch(Character::isLowerCase);
  }

  private static Map<String, Object> getNextMap(Map<String, Object> map, String mapName) {
    Object nextObj = map.get(mapName);
    if (nextObj == null) {
      nextObj = new LinkedHashMap<String, Object>();
      map.put(mapName, nextObj);
    }
    @SuppressWarnings("unchecked")
    Map<String, Object> nextMap = (Map<String, Object>)nextObj;
    return nextMap;
  }

  public static Map<String, Object> unflatten(Map<String, String> properties) {
    List<String> sortedKeys = new ArrayList<>(properties.keySet());
    Collections.sort(sortedKeys);
    Map<String, Object> rootObject = new LinkedHashMap<>();
    for (String key : sortedKeys) {
      String[] splitKey = key.split("\\.");
      String lastItem = splitKey[splitKey.length - 1];
      if (noLowercase(lastItem)) {
        Map<String, Object> currentMap = rootObject;
        for (int i = 1; i < splitKey.length - 1; ++i) {
          currentMap = getNextMap(currentMap, splitKey[i]);
        }
        currentMap.put(lastItem, properties.get(key));
      }
    }
    return rootObject;
  }
}

Serialising with, for example, Gson or Jackson should be pretty easy after this. Here is an example using Gson:

  public static void printMap(Map<String, String> map) {
    Gson gson = new GsonBuilder().setPrettyPrinting().create();

    for (Map.Entry<String, Object> entry : unflatten(map).entrySet()) {
      System.out.format("%s = ", entry.getKey());
      System.out.print(gson.toJson(entry.getValue()));
      System.out.println(";");
      System.out.println();
    }
  }

Alternatively it should not be too hard to write your own printing routines for the map of maps data structure.

Upvotes: 0

Peter Pei Guo
Peter Pei Guo

Reputation: 7870

You can match the key with the following regex and see whether it returns true:

key.matches(".*\\.[A-Z]+");

Upvotes: 1

Related Questions