Распечатать элемент ввода, даже если capture() не соответствует выражению

Я пытаюсь извлечь информацию об определенных конкретных зависимостях из выходных данных конечной точки /v1/project DTrack.

API возвращает данные в формате:

[{
    "name": "project name",
    "classifier": "LIBRARY | APPLICATION",
    "directDependencies": <escaped JSON string in which I need to search for "com.example.commons/[email protected]" and similar strings>
}, ...]

Вот что я получил на данный момент:

jq '.[] | select(.classifier= = "APPLICATION") | {
      id: .name,
      dep1: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep1@(?<version>[0-9.]+)"])),
      dep2: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep2@(?<version>[0-9.]+)"])),
      dep3: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep3@(?<version>[0-9.]+)"])),
      dep4: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep4@(?<version>[0-9.]+)"]))
    }'

Сгенерированный вывод выглядит нормально:

{
  "id": "project1",
  "dep1": {
    "version": "0.102.0"
  },
  "dep2": {
    "version": "0.102.0"
  },
  "dep3": {
    "version": "0.102.0"
  },
  "dep4": {
    "version": "0.102.0"
  }
}
... // more elements

Проблема в том, что выходные данные содержат только те входные элементы, для которых все четыре capture чему-то соответствуют.

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

{
    "id": "project1",
    "dep1": { "version": "0.1.0" },
    // dep2 didn't match
    // dep3 didn't match
    "dep4": { "version": "0.3.0" }
}

В документации такой опции не нашел. Есть идеи, как это решить?

@0stone0 в последнем абзаце моего вопроса буквально говорится: «Я ожидаю, что в выводе будут такие элементы», за которым следует пример. Что еще вы хотите, чтобы я включил?

crizzis 05.08.2024 18:07

@ 0stone0 Я не могу опубликовать реальный пример JSON, потому что даже самый короткий из них не вписывается в ограничение на количество символов вопроса. Для вопроса важно то, что directDependencies — это строка, которая начинается с бесполезного мусора, после чего появляется com.example.commons/[email protected], который меня интересует, после чего снова начинается еще куча бесполезного мусора. Если вместо этого я просто напишу "directDependencies": "xxxcom.example.commons/[email protected]", это поможет?

crizzis 05.08.2024 18:28

Важно то, что все четыре dep1, dep2, dep3 и dep4 могут появляться в строке для некоторых элементов входного массива, для других могут присутствовать только один или два, а для некоторых элементов входного массива directDependencies может не содержать ни одного из четверка

crizzis 05.08.2024 18:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать подход, представленный на примере:

def capture($s; $default): capture($s) // $default;

.[]
| select(.classifier | test("APPLICATION"))
| {
      id: .name,
      dep1: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep1@(?<version>[0-9.]+)"]; "dep1 did not match")),
      dep3: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep3@(?<version>[0-9.]+)"]; "dep2 did not match")),
      dep4: ((.directDependencies // "") | capture(["com\\.example\\.commons/dep4@(?<version>[0-9.]+)"]; "dep1 did not match"))
  }

Спасибо! Это самое элегантное решение, я принимаю ответ @pmf только потому, что оно обеспечивает большую гибкость.

crizzis 06.08.2024 12:09
Ответ принят как подходящий

Насколько я понимаю вопрос, вы хотите добавлять в объект результата только успешные совпадения. Я бы предпочел использовать scan, чтобы найти все совпадения, а затем reduce поверх них, чтобы последовательно создавать объект результата, включая имя зависимости в регулярное выражение (например, как dep1|dep2|dep3|dep4, или короче dep[1-4], или в более общем смысле [^@]+, которое я использовал ниже).

.[] | select(.classifier/" | " | any(. == "APPLICATION")) | reduce (
  .directDependencies | scan("com\\.example\\.commons/(?<dep>[^@]+)@(?<version>[0-9.]+)")
) as [$dep, $version] ({id: .name}; .[$dep] = {$version})

Примечание № 1. Это всегда будет генерировать часть {id: .name}, даже если никакие зависимости не добавлены. Чтобы вместо этого проглотить эти «голые» объекты, начните сокращение с null и в конечном итоге отфильтруйте ненулевое значение values:

.[] | select(.classifier/" | " | any(. == "APPLICATION")) | {id: .name} + (reduce (
  .directDependencies | scan("com\\.example\\.commons/(?<dep>[^@]+)@(?<version>[0-9.]+)")
) as [$dep, $version] (null; .[$dep] = {$version}) | values)

Примечание № 2: Ваш фильтр select(.classifier= = "APPLICATION") соответствует только объектам, у которых значение под .classifier полностью равно строке "APPLICATION", и, таким образом, вообще не будет улавливать вводимый образец, поскольку он содержит {"classifier": "LIBRARY | APPLICATION"}. Поэтому вместо этого я использовал /, чтобы разделить это значение на подстроку " | ", и оно совпадало, если any (т. е. хотя бы одна) из полученных частей была равна этой строке.

Большое спасибо, это работает! Что касается classifier, это либо APPLICATION, либо LIBRARY, думаю, я недостаточно ясно выразился. Что касается «голых» объектов, то, наоборот, лучшим решением для меня было бы каким-то образом помечать запись с отсутствующими значениями, даже если ни одна из четырех зависимостей не совпадала. В любом случае, ваше предложение позволит мне уточнить решение.

crizzis 06.08.2024 12:08

@crizzis Вы можете использовать что-то вроде values // {warning: "no dependencies"}, чтобы отметить «голые» элементы.

pmf 06.08.2024 12:11

Попробую это. Кстати, если бы я хотел "dep1": "0.1.0" вместо "dep1": { "version": "0.1.0" } (то есть без дополнительного вложенного объекта), есть ли простой способ сделать это?

crizzis 06.08.2024 12:13

@crizzis Конечно, поменяй .[$dep] = {$version} на просто .[$dep] = $version

pmf 06.08.2024 12:14

Да, я только что понял, что это будет просто ссылка на значение переменной. Думаю, мне нужен еще кофе. Еще раз большое спасибо!

crizzis 06.08.2024 12:16

Другие вопросы по теме