2016-09-23 3 views
0

У меня сложная структура, которая вложена, как показано ниже. Я пытаюсь получить доступ к значению вложенного ключа со своей парой ключ: значение sibling.Доступ к дочернему узлу с использованием его пары значений ключа sibling во вложенной карте

Например: Моя сложная структура:

{ 

    key1:value, 

    key2: 

     [ 

     {a:1,c:{d:1}}, 

     {a:2,c:{d:0}}, 

     {a:3,c:{d:1}} 

     ] 

    } 

Я пытаюсь вернуть значение D, где: 3. Очевидно, что d является ребенком родного брата. Если я пройду через key2 и получаю значение c, я могу сделать DFS для детей c, чтобы найти нужное значение.

Это не поможет, если я укажу пару sibling key: value как один уровень вложенности. Для этого нужен обход XPath. Скажем, для вышеприведенного случая, мое выражение было бы:

(a:1>>c)->{d:1} 
(a:2>>c::d)->0 
(key2::a)->[1,2,3] 

Где :: ребенок обозначение и >> является родственными нотациями. Есть ли простой или элегантный способ приблизиться к этому? Существуют ли библиотеки, например, this для Java?

+1

Попробуйте: https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path/2.2.0 (https://github.com/jayway/JsonPath) легко указать путь к объекту JSON , – AlexC

ответ

1

Вы можете решить эти проблемы с помощью библиотеки Java 8 Dynamics. Это позволяет вам перемещать вложенные структуры в прямом, но свободном & нулевым способом.

Map nestedStructure = ... 
// {key1=value, key2=[{a=1, c={d=1}}, {a=2, c={d=0}}, {a=3, c={d=1}}]} 
Dynamic data = Dynamic.from(nestedStructure); 

// "(a:1>>c)": all "c" values that have sibling "a" = 1 
List<Map> aIs1CValues = data.allChildren() 
    // filter to elements that have an 'a=3' child & a "c" map child 
    .filter(el -> el.get("a").maybe().as(Integer.class).orElse(0) == 1) 
    .filter(el -> el.get("c").isMap()) 
    .map(el -> el.get("c").asMap()) 
    .collect(toList()); // [{d=1}] 

// "(a:2>>c::d)": all "d" values, with parent key "c" that has sibling "a" = 2 
List<Integer> aIs2DValues = data.allChildren() 
    .filter(el -> el.get("a").maybe().as(Integer.class).orElse(0) == 2) 
    .filter(el -> el.dget("c.d").is(Integer.class)) 
    .map(el -> el.dget("c.d").as(Integer.class)) 
    .collect(toList()); // [0] 

// "(key2::a)": all "a" values, with some parent key "key2" 
List<Integer> key2As = data.allChildren() 
    .filter(el -> el.key().asObject().equals("key2")) 
    .flatMap(Dynamic::children) 
    .filter(key2Map -> key2Map.get("a").is(Integer.class)) 
    .map(key2Map -> key2Map.get("a").as(Integer.class)) 
    .collect(toList()); // [1, 2, 3] 

я не был полностью уверен, что о вашей реальной проблеме в сравнении с вашим примером, это обращение может быть проще, если мы знаем больше о данных. Например, последняя проблема проще, если мы знаем key2 - это верхний уровень и a всегда присутствует и целое число.

data.get("key2").children() 
    .map(child -> child.get("a").as(Integer.class)) 
    .collect(toList()); // [1, 2, 3] 

См. https://github.com/alexheretic/dynamics для источника, документации и примеров.

Смежные вопросы