Извлечь cna.descriptions.value, только если соответствующий cna.descriptions.lang находится в ['en', 'eng', ' english'].
Извлекайте cna.problemTypes.descriptions.description, только если соответствующий cna.problemTypes.descriptions.lang находится в ['en', 'eng', 'english'].
Верните True для ключа is_kev, только если metrics.other.type равен 'kev'.
Пример структуры JSON:
Код: Выделить всё
{
"containers": {
"cna": {
"descriptions": [
{"lang": "en", "value": "English description"},
{"lang": "fr", "value": "Description en français"}
],
"problemTypes": [
{
"descriptions": [
{"lang": "en", "description": "Cross-site Scripting (XSS)"},
{"lang": "de", "description": "Deutscher Text"}
]
}
]
}
},
"metrics": {
"other": {"type": "kev"}
}
}
Я использую следующую структуру, чтобы определить, что нужно извлечь:
Код: Выделить всё
EXTRACTIONS = {
'cve_id': ['cveMetadata.cveId'],
... # There's a bunch more keys I'm trying to extract
'cve_desc': ['cna.descriptions'],
'cwe_desc': ['cna.problemTypes.descriptions'],
'is_kev': ['metrics.other.type']
}
CONDITIONAL_EXTRACTIONS = {
'cve_desc': {
'paths': ['cna.descriptions'],
'condition': lambda _, full_data: [
desc.get('value').strip() for desc in full_data
.get('cna', {}).get('descriptions', [])
if desc.get('lang').strip().lower() in ['en', 'eng', 'english']
]
},
'cwe_desc': {
'paths': ['cna.problemTypes.descriptions'],
'condition': lambda _, full_data: [
desc.get('description').strip() for cwe in full_data
.get('cna', {}).get('problemTypes', [])
for desc in cwe.get('descriptions', [])
if desc.get('lang').strip().lower() in ['en', 'eng', 'english']
]
},
'is_kev': {
'paths': ['metrics.other.type'],
'condition': lambda value, _: value == 'kev'
}
}
Код: Выделить всё
def deep_search(data, target_keys, condition=None):
results = []
def recursive_search(current_data, keys, full_data):
if not keys or not isinstance(current_data, (dict, list)):
return None
current_key = keys[0]
if isinstance(current_data, dict):
if current_key in current_data:
value = current_data[current_key]
if len(keys) == 1:
if isinstance(value, list) and condition:
results.extend(condition(None, full_data))
elif condition is None or condition(value, full_data):
results.append(value)
else:
recursive_search(current_data[current_key], keys[1:], full_data)
for value in current_data.values():
recursive_search(value, keys, full_data)
elif isinstance(current_data, list):
for item in current_data:
recursive_search(item, keys, full_data)
for key_path in target_keys:
keys = key_path.split('.')
recursive_search(data, keys, data)
return results[0] if len(results) == 1 else results or pd.NA
def extract_file_data(
file_path: str,
extraction_mapping: Dict[str, List[str]]
) -> Dict[str, Any]:
""" Extract relevant data from a single JSON file. """
try:
with open(file_path, 'r', encoding='utf-8') as file:
data = json.load(file)
# Extract data using deep search
extracted_data = {}
for key, paths in extraction_mapping.items():
# Handle conditional extractions
if key in CONDITIONAL_EXTRACTIONS:
condition_info = CONDITIONAL_EXTRACTIONS[key]
condition = condition_info.get('condition')
result = deep_search(data, condition_info['paths'], condition)
else:
# Perform unconditional search for each key
result = deep_search(data, paths)
extracted_data[key] = result
print(f"Key: {key}, Paths: {paths}, Result: {result}")
# Return the extracted data
return extracted_data
except Exception as e:
print(f'Error processing {file_path}: {e}')
return {}
Для cve_desc и cwe_desc функция ничего не возвращает, и для меня это не имеет смысла.
Для is_kev, условие возвращает фактическое значение «kev» и None вместо True или False.
Операторы печати в deep_search показывают «Значения» для этих условий. клавиши, расположенные на один уровень выше значение, которое я ищу, которое соответствует тому, что я ожидаю, поскольку лямбда-функция использует методы get с этого уровня для поиска нужных ключей, однако операторы печати extract_file_data подтверждают, что результаты Нет.
Подробнее здесь: https://stackoverflow.com/questions/793 ... ils-to-ret