Извлечение нескольких объектов JSON на разных глубинах с помощью JayWay JSONPath

#java #jsonpath

#java #jsonpath

Вопрос:

Ситуация

  • У меня есть JSON
  • Я пытаюсь захватить каждый элемент в массиве, который содержит некоторые конкретные вложенные объекты. Сложность заключается в том, что некоторые из этих объектов вложены на разных глубинах.
  • Я использую JayWay JSONPathhttps://github.com/json-path/JsonPath , и мой код работает точно так же, как https://jsonpath.herokuapp.com

Это предназначено для использования на нашей платформе,https://dashdash.com — электронная таблица с интеграциями для известных веб-сервисов (и ваших частных API тоже).

Частный случай (тестируемый)

Рассмотрим следующий исходный JSON, я хочу возвращать только элементы массива, которые имеют вложенные объекты B, C и G. G находится на другой глубине, чем B и C.

Ниже вы можете увидеть исходный код и 2 варианта возврата.

исходный JSON

 [  
   {  
      "A":"val1",
      "B":"val2",
      "C":"val3",
      "D":{  
         "E":[  
            {  
               "F":"val4"
            }
         ],
         "G":[  
            {  
               "H":"val5",
               "I":"val6",
               "J":"val7"
            }
         ]
      }
   },
   {  
      "A":"val8",
      "B":"val9",
      "C":"val10",
      "D":{  
         "E":[  
            {  
               "F":"val11"
            }
         ],
         "G":[  
            {  
               "H":"val12",
               "I":"val13",
               "J":"val14"
            }
         ]
      }
   },
   {  
      "A":"val15",
      "B":"val16"
   },
   {  
      "A":"val8",
      "B":"val9",
      "C":"val10",
      "D":{  
         "E":[  
            {  
               "F":"val11"
            }
         ]
      }
   }
]
  

Ожидаемый возврат Вариант 1.

 [
   {
      "B":"val2",
      "C":"val3",
      "G":[
         {
            "H":"val5",
            "I":"val6",
            "J":"val7"
         }
      ]
   },
   {
      "B":"val9",
      "C":"val10",
      "G":[
         {
            "H":"val12",
            "I":"val13",
            "J":"val14"
         }
      ]
   }
]
  

Ожидаемый возврат Вариант 2.

 [
   {
      "B":"val2",
      "C":"val3",
      "D":{
         "E":[
            {
               "F":"val4"
            }
         ],
         "G":[
            {
               "H":"val5",
               "I":"val6",
               "J":"val7"
            }
         ]
      }
   },
   {
      "B":"val9",
      "C":"val10",
      "D":{
         "E":[
            {
               "F":"val11"
            }
         ],
         "G":[
            {
               "H":"val12",
               "I":"val13",
               "J":"val14"
            }
         ]
      }
   }
]
  

Где я нахожусь

  • Я могу извлечь все элементы массива, имеющие B, C и D, с помощью запроса $..['B','C','D']

Я пытался извлечь B, C и G, но все следующие запросы завершаются неудачей:

  • $..['B','C','G'] : возвращает значение null.
  • $..['B','C',['D'].['G']] : возвращает только объекты внутри G.

Опять же, я использую JayWay JSONPath https://github.com/json-path/JsonPath , и мой код работает точно так же, как https://jsonpath.herokuapp.com .

Заранее спасибо

Ответ №1:

Вы можете решить эту проблему, установив для JayWay конфигурацию DEFAULT_PATH_LEAF_TO_NULL (как описано в официальной документации:https://github.com/json-path/JsonPath ) и после этого примените оценку сравнения с нулевым значением:

вот так:

 $.[?(@.A != null amp;amp; @.B != null amp;amp; @.D != null amp;amp;  @.D.G != null)]
  

или это:

 $.[?((@.A != null amp;amp; @.B != null) amp;amp; ((@.D != null amp;amp;  @.D.G != null) || (@.G != null)))]
  

Для установки DEFAULT_PATH_LEAF_TO_NULL вам следует изменить конфигурацию по умолчанию:

 Configuration conf = Configuration.defaultConfiguration();
Configuration conf2 = conf.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
  

Примечание: Если вы используете устаревшую версию jayway, оператор сравнения может работать некорректно, для получения дополнительной информации см.https://code.google.com/archive/p/json-path/issues/27

Я протестировал это решение, и оно отлично работало для меня:

Тест выполнен на https://jsonpath.herokuapp.com / со следующим вводом:

 [  
   {  
      "A":"val1",
      "B":"val2",
      "C":"val3",
      "D":{  
         "E":[  
            {  
               "F":"val4"
            }
         ],
         "G":[  
            {  
               "H":"val5",
               "I":"val6",
               "J":"val7"
            }
         ]
      }
   },
   {  
      "A":"val8",
      "B":"val9",
      "C":"val10",
      "D":{  
         "E":[  
            {  
               "F":"val11"
            }
         ],
         "G":[  
            {  
               "H":"val12",
               "I":"val13",
               "J":"val14"
            }
         ]
      }
   },
   {  
      "A":"val15",
      "B":"val16"
   },
   {  
      "A":"val8",
      "B":"val9",
      "C":"val10",
      "D":{  
         "E":[  
            {  
               "F":"val11"
            }
         ]
      }
   }
]
  

и результатом было:

 [
   {
      "A" : "val1",
      "B" : "val2",
      "C" : "val3",
      "D" : {
         "E" : [
            {
               "F" : "val4"
            }
         ],
         "G" : [
            {
               "H" : "val5",
               "I" : "val6",
               "J" : "val7"
            }
         ]
      }
   },
   {
      "A" : "val8",
      "B" : "val9",
      "C" : "val10",
      "D" : {
         "E" : [
            {
               "F" : "val11"
            }
         ],
         "G" : [
            {
               "H" : "val12",
               "I" : "val13",
               "J" : "val14"
            }
         ]
      }
   }
]
  

Посмотрите доказательства и обратите внимание, что для параметра returning null установлено значение true

Дайте мне знать, если вам понадобится дополнительная помощь в этом.

Комментарии:

1. Я обнаружил незначительную проблему: — Проблема активации DEFAULT_PATH_LEAF_TO_NULL заключается в том, что другие функции будут возвращать нули, даже если пути не существуют. Пример: В Json « [ { «foo»: «foo1», «bar»: «bar1» }, { «foo»: «foo2» } ] « запросы «$ [*].bar» и «$ ..bar» вернут « [ «bar1», null ] ` ` там, где я хотел « [ «bar1» ] « Есть запрос конфигурация, которая решила бы обе проблемы? — выполнить сопоставление для существующих путей в [B, C, D.G] (или [B, C, ..G]); и — не возвращать нули для anything и seek запросов?

2. на самом деле, @dromualdo, ваш запрос почти готов, но он не проверяет существование свойства, скорее, свойство НЕ равно null. Это другое. Например, в приведенном выше JSON, если вы создадите [0].D.B = null, JSONPath, который я ищу, вернет 2 объекта, [0] и [1] — оба имеют B, C и ..G, и он возвращает только [1], потому что [0].B.G существует, но [0].B.G =null.

Ответ №2:

Я пробовал несколько разных подходов, и я думаю, что более простое выражение делает свое дело:

 $.*[?(@.B amp;amp; @.C amp;amp; @.D.G)]
  

Для этого не требуется никакой специальной конфигурации, отличной от конфигурации по умолчанию (согласно эксперименту, проведенному на https://jsonpath.herokuapp.com и выдает следующий результат:

 [
   {
      "A" : "val1",
      "B" : "val2",
      "C" : "val3",
      "D" : {
         "E" : [
            {
               "F" : "val4"
            }
         ],
         "G" : [
            {
               "H" : "val5",
               "I" : "val6",
               "J" : "val7"
            }
         ]
      }
   },
   {
      "A" : "val8",
      "B" : "val9",
      "C" : "val10",
      "D" : {
         "E" : [
            {
               "F" : "val11"
            }
         ],
         "G" : [
            {
               "H" : "val12",
               "I" : "val13",
               "J" : "val14"
            }
         ]
      }
   }
]
  

Что вы думаете?

Комментарии:

1. идеально! это то, что я искал!