Я пытаюсь извлечь информацию об определенных конкретных зависимостях из выходных данных конечной точки /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 Я не могу опубликовать реальный пример JSON, потому что даже самый короткий из них не вписывается в ограничение на количество символов вопроса. Для вопроса важно то, что directDependencies — это строка, которая начинается с бесполезного мусора, после чего появляется com.example.commons/[email protected], который меня интересует, после чего снова начинается еще куча бесполезного мусора. Если вместо этого я просто напишу "directDependencies": "xxxcom.example.commons/[email protected]", это поможет?
Важно то, что все четыре dep1, dep2, dep3 и dep4 могут появляться в строке для некоторых элементов входного массива, для других могут присутствовать только один или два, а для некоторых элементов входного массива directDependencies может не содержать ни одного из четверка





Вы можете использовать подход, представленный на примере:
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 только потому, что оно обеспечивает большую гибкость.
Насколько я понимаю вопрос, вы хотите добавлять в объект результата только успешные совпадения. Я бы предпочел использовать 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 Вы можете использовать что-то вроде values // {warning: "no dependencies"}, чтобы отметить «голые» элементы.
Попробую это. Кстати, если бы я хотел "dep1": "0.1.0" вместо "dep1": { "version": "0.1.0" } (то есть без дополнительного вложенного объекта), есть ли простой способ сделать это?
@crizzis Конечно, поменяй .[$dep] = {$version} на просто .[$dep] = $version
Да, я только что понял, что это будет просто ссылка на значение переменной. Думаю, мне нужен еще кофе. Еще раз большое спасибо!
@0stone0 в последнем абзаце моего вопроса буквально говорится: «Я ожидаю, что в выводе будут такие элементы», за которым следует пример. Что еще вы хотите, чтобы я включил?