Получить вложенные JSON элементы из ObjectNode, используя Джексона - PullRequest
0 голосов
/ 04 февраля 2020

У меня есть ObjectNode, который выглядит следующим образом

    {
     "Header":{
       "sub-header1":{
          "#field":"value",
          "#field":"value",

       },
       "sub-header2":{
          "field":"",
          "field":"",
          "field":"",
          "panel_field":{
            "value":"",
            "value":""
         }
      }          
   }

Теперь я хочу получить все поля из подзаголовков в списке. Это метод, который я использую

public static List<String> getDocumentFields(ObjectNode jsonDocumentNode) {        
    List<String> documentFields = new ArrayList<>();
    Iterator<JsonNode> fields = jsonDocumentNode.elements();
    while (fields.hasNext()) {
        JsonNode jsonNode = fields.next();
        Iterator<Map.Entry<String, JsonNode>> jsonFields = jsonNode.fields();
        while (jsonFields.hasNext()) {
            Map.Entry<String, JsonNode> jsonNodeEntry = jsonFields.next();
            documentFields.add(jsonNodeEntry.getKey());
        }
    }
    return documentFields;
}

Но я получаю только заголовки в списке, такие как {sub-header1, sub-header2}, вместо полей. Как я могу это исправить? Я бы очень признателен за любую помощь.

РЕДАКТИРОВАТЬ: Хотя ответ @sfiss очень помог, я все же хотел найти способ сделать это без жесткого кодирования l oop -logi c и this Ответ оказался именно тем, что я искал.

1 Ответ

0 голосов
/ 04 февраля 2020

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

public class MyTest {

    @Test
    public void testJson() throws IOException {
        final String json = getJson();
        final JsonNode jsonDocumentNode = new ObjectMapper().readTree(json);
        final List<String> fields = getDocumentFields((ObjectNode) jsonDocumentNode);
        assertThat(fields, Matchers.contains("#field1", "#field2", "field1", "field2", "field3", "panel_field"));
    }

    public static String getJson() {
        return "{\r\n" +
                "     \"Header\":{\r\n" +
                "       \"sub-header1\":{\r\n" +
                "          \"#field1\":\"value\",\r\n" +
                "          \"#field2\":\"value\"\r\n" +
                "       },\r\n" +
                "       \"sub-header2\":{\r\n" +
                "          \"field1\":\"\",\r\n" +
                "          \"field2\":\"\",\r\n" +
                "          \"field3\":\"\",\r\n" +
                "          \"panel_field\":{\r\n" +
                "            \"value1\":\"\",\r\n" +
                "            \"value2\":\"\"\r\n" +
                "         }\r\n" +
                "      }          \r\n" +
                "   }\r\n" +
                "}";
    }

    public static List<String> getDocumentFields(final ObjectNode jsonDocumentNode) {
        final List<String> documentFields = new ArrayList<>();
        for (final JsonNode header : (Iterable<JsonNode>) jsonDocumentNode::elements) {
            for (final JsonNode subheader : (Iterable<JsonNode>) header::elements) {
                for (final Map.Entry<String, JsonNode> field : (Iterable<Map.Entry<String, JsonNode>>) subheader::fields) {
                    documentFields.add(field.getKey());
                }
            }
        }
        return documentFields;
    }
}

Однако я бы сказал, что проще позволить Джексону сериализовать JSON в удобные данные структура, и вы просто используете геттеры POJO для получения ваших значений. Это также сделало бы это более понятным, чем обработка JsonNode.

Просто к вашему сведению, я немного отредактировал ваши JSON и использовал Java 8 преобразований SAM для создания итераций для циклов foreach из итераторов, но вы все равно можете использовать свой код и повторить еще один уровень, используя while и итераторы.

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