Может ли JMESPATH выполнить поиск / фильтр «содержит X или Y»?

#php #amazon-s3 #sdk #jmespath

#php #amazon-s3 #sdk #jmespath

Вопрос:

Возможно ли переместить preg_match приведенный ниже поиск в фильтр поиска JMESPATH с помощью contains ? Я нашел пример contains в руководстве по JMESPATH, но я не уверен, поддерживает ли синтаксис объединение строк фильтра каким-либо образом с помощью OR .

   $s3_results = $s3_client->getPaginator('ListObjects', ['Bucket' => $config['bucket']]);
  // Narrow S3 list down to files containing the strings "css_" or "js_".
  foreach ($s3_results->search('Contents[].Key') as $key) {
    if (preg_match("/(css_|js_)/", $key)) {
      $s3_keys[] = $key;
    }
  }
  

Ответ №1:

Предполагая, что документ имеет формат, подобный этому:

 {
    "Contents": [
        {
            "Key": "some/path/css_example",
             ...
        },
        {
            "Key": "another/path/js_example",
             ...
        },
        {
            "Key": "blah/blah/other_example",
             ...
        }
    ]
}
  

(Я бы проверил, но у меня нет учетных данных AWS, и на удивление сложно найти примеры формата JSON ответа S3 list-objects.)

Попробуйте выполнить запрос:

 Contents[].Key|[?contains(@, 'css_') || contains(@, 'js_')]
  

В этом случае Contents[].Key выбираются только ключи (как в вашем примере). Канал | используется для сброса проекции, чтобы мы работали со всем списком, а не с каждым ключом в отдельности. [?...] фильтрует список, чтобы выбрать только ключи, которые соответствуют логическому условию. contains Функция может использоваться несколькими способами, но мы используем ее здесь, чтобы увидеть, содержит ли первый аргумент в виде строк ( @ текущий элемент в списке) второй аргумент, подстроку, которую мы ищем. Мы объединяем два использования contains функции с оператором или || , чтобы элемент соответствовал, если выполняется любое условие.

Ответ №2:

Конечно, выражение or — это то, что существует в JMESpath.

Но тогда вы могли бы даже пойти дальше и полностью отказаться от цикла for и извлечь ключи, используя выражение функций.

Учитывая данные:

 {
  "Contents": [
    {
      "Key": [
        "css_foo",
        "js_bar",
        "brown_fox"
      ]
    },
    {
      "Key": [
        "js_foo",
        "css_bar",
        "lazy_dog"
      ]
    }
  ]
}
  

Затем

 $keys = $s3_results->search(
  'Contents[].Key[?contains(@, `js_`) == `true` || contains(@, `css_`) == `true`]'
);
  

Даст вам следующий двумерный массив (потому что есть два содержимого):

 array(2) {
  [0] =>
  array(2) {
    [0] =>
    string(7) "css_foo"
    [1] =>
    string(6) "js_bar"
  }
  [1] =>
  array(2) {
    [0] =>
    string(6) "js_foo"
    [1] =>
    string(7) "css_bar"
  }
}
  

Или даже проще, поскольку contains возвращает true или false , уже:

 $keys = $s3_results->search(
  'Contents[].Key[?contains(@, `js_`) || contains(@, `css_`)]'
);