Как получить имя родительского элемента дочернего элемента в JSON? - PullRequest
0 голосов
/ 29 января 2019

У меня есть динамический JSON, в котором я не буду знать полную структуру перед обработкой.

Однако я знаю, что JSON может содержать некоторые интересующие вложенные элементы.

e.для этого образца полезной нагрузки


{
  "id": "3334343",
  "contractor": {
    "ppsNo": "123334"
  },
  "fullTimeStaff":{
    "ppsNo": "343434"
  }
}

Я хотел бы найти имя всех внешних элементов, которые содержат элемент с именем ppsNo .

Я пытался использовать root.findParents ("ppsNo") но это дает мне элементы ppsNo, а не внешние (родительские) элементы подрядчика и fullTimeStaff , которые мне интересны.

    ObjectMapper objectMapper = new ObjectMapper();
    String payload = "{\n" +
            "  \"id\": \"3334343\",\n" +
            "  \"contractor\": {\n" +
            "    \"ppsNo\": \"123334\"\n" +
            "  },\n" +
            "  \"fullTimeStaff\":{\n" +
            "    \"ppsNo\": \"123334\"\n" +
            "  }\n" +
            "}";

    JsonNode root = objectMapper.readTree(payload);

    List<JsonNode> nodes = root.findParents("ppsNo");

Возвращенные JsonNodes - это элементы {"ppsNo":"123334"}, а не внешние содержащие узлы ("contractor" и "fullTimeStaff").

Есть ли способ сделать это?Я смотрел на использование пути JSON, но я не мог найти очевидный способ получить реальный родительский (содержащий / внешний) элемент с помощью этого.

В этом примере я использую Джексона, но я открыт дляальтернативы

Ответы [ 3 ]

0 голосов
/ 29 января 2019

В библиотеке JsonPath есть опция, которая возвращает все совпавшие пути вместо значений.Таким образом, вы можете сделать что-то вроде:

Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build();
List<String> pathList = JsonPath.using(conf).parse(payload).read("$..ppsNo");

/* Returns :
 * [
 *   "$['contractor']['ppsNo']",
 *   "$['fullTimeStaff']['ppsNo']"
 * ]
 */

Вам просто нужно проанализировать результат с правильным типом и удалить последний элемент, чтобы получить прямого родителя.

Pattern pattern = Pattern.compile("(?<!\\$\\[)(\\w+)(?!\\])");
pathList = pathList.stream().map(path -> {
    Matcher m = pattern.matcher(path.toString());
    return m.find() ? m.group(0) : null;
}).collect(Collectors.toList());
System.out.println(pathList); // [contractor, fullTimeStaff]

Вотссылка на официальный Jayway JsonPath репозиторий Maven.

0 голосов
/ 29 января 2019

Мы можем использовать рекурсию для поиска целевых родительских узлов с помощью метода JsonNode.fields , как в следующем примере.

public class GetParentByChildName {
    public static void main(String[] args) throws IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        String payload = "{                                      \n"
                + "  \"id\": \"3334343\",                        \n"
                + "  \"contractor\": {                           \n"
                + "    \"ppsNo\": \"123334\"                     \n"
                + "  },                                          \n"
                + " \"arr\": [                                   \n"
                + "    {                                         \n"
                + "      \"contractor2\": {                      \n"
                + "        \"ppsNo\": \"123334\"                 \n"
                + "      }                                       \n"
                + "    },                                        \n"
                + "    [                                         \n"
                + "      {                                       \n"
                + "        \"contractor3\": {                    \n"
                + "          \"ppsNo\": \"123334\"               \n"
                + "        }                                     \n"
                + "      }                                       \n"
                + "    ]                                         \n"
                + "  ],                                          \n"
                + "  \"fullTimeStaff\":{                         \n"
                + "    \"ppsNo\": \"123334\"                     \n"
                + "  }                                           \n"
                + "}                                               ";

        JsonNode root = objectMapper.readTree(payload);
        List<String> fieldNames = new ArrayList<String>();
        getParentName(root, "ppsNo", fieldNames);
        System.out.println(fieldNames);
    }

    private static void getParentName(JsonNode node, String targetChildName, List<String> fieldNames) {
        if (node.getNodeType() == JsonNodeType.ARRAY) {
            node.elements().forEachRemaining(x -> getParentName(x, targetChildName, fieldNames));
            return;
        }
        if (node.getNodeType() != JsonNodeType.OBJECT) {
            return;
        }
        node.fields().forEachRemaining(x -> {
            Iterator<String> iter = x.getValue().fieldNames();
            while (iter.hasNext()) {
                String fieldName = iter.next();
                if (fieldName.equals(targetChildName)) {
                    fieldNames.add(x.getKey());
                }
            }
            getParentName(x.getValue(), targetChildName, fieldNames);
        });
    }
}
0 голосов
/ 29 января 2019

я не уделил много времени написанию кода.

выражение, которое вы ищете в Regex, равно \{\n "ppsNo": "\w+"\n } (вы проверяете его по ссылке https://regex101.com).то, что вы должны сделать, это когда вы столкнетесь с этим выражением, начнете возвращаться назад и прочитать первое слово в "".я надеюсь, что это помогло вам

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...