Я пытаюсь извлечь информацию об определенных конкретных зависимостях из выходных данных конечной точки /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" }
}
В документации такой опции не нашел. Есть идеи, как это решить?
Вы можете использовать подход, представленный на примере:
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"))
}
Насколько я понимаю вопрос, вы хотите добавлять в объект результата только успешные совпадения. Я бы предпочел использовать 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
(т. е. хотя бы одна) из полученных частей была равна этой строке.