Похоже, что некоторые значения, которые вы хотите, являются прямыми потомками nasl
, а некоторые находятся в attributes/attribute
.
То, что вы могли бы сделать, это иметь два списка (или кортежей));один с точными именами элементов и один с точными именами атрибутов (attribute/name
).
Примечание: это может показаться немного запутанным, потому что в этом случае «имя атрибута» действительно является элементом с именем «атрибут» сдочерний элемент с именем «name», а не истинный атрибут XML с именем «name».
Объединение этих кортежей даст вам все поля в вашем CSV.Вы можете использовать это для создания dict, содержащего все поля со значениями по умолчанию Unknown
.
Затем вы можете выполнить итерации по обоим кортежам для создания двух разных типов XPath.Если элемент существует, текстовое значение обновляется в dict.В противном случае значение остается Unknown
.
Пример ...
Ввод XML (test.xml)
<nasl_plugins>
<nasl>
<filename>fedora_2017-c3149b5fcb.nasl</filename>
<script_id>101028</script_id>
<script_name>Fedora 25 : xen (2017-c3149b5fcb)</script_name>
<script_version>$Revision: 1.5 $</script_version>
<script_copyright>This script is Copyright (C) 2017-2018 Tenable Network Security,
Inc.</script_copyright>
<script_family>Fedora Local Security Checks</script_family>
<cves>
<cve>CVE-2017-10911</cve>
<cve>CVE-2017-10912</cve>
<cve>CVE-2017-10913</cve>
<cve>CVE-2017-10915</cve>
<cve>CVE-2017-10916</cve>
<cve>CVE-2017-10917</cve>
<cve>CVE-2017-10918</cve>
<cve>CVE-2017-10919</cve>
<cve>CVE-2017-10920</cve>
<cve>CVE-2017-10923</cve>
</cves>
<bids> </bids>
<xrefs>
<xref>FEDORA:2017-c3149b5fcb</xref>
<xref>IAVB:2017-B-0074</xref>
</xrefs>
<dependencies>
<dependency>ssh_get_info.nasl</dependency>
</dependencies>
<required_keys>
<key>Host/local_checks_enabled</key>
<key>Host/RedHat/release</key>
<key>Host/RedHat/rpm-list</key>
</required_keys>
<attributes>
<attribute>
<name>plugin_type</name>
<value>local</value>
</attribute>
<attribute>
<name>plugin_modification_date</name>
<value>2018/02/02</value>
</attribute>
<attribute>
<name>stig_severity</name>
<value>I</value>
</attribute>
<attribute>
<name>cvss_base_score</name>
<value>10.0</value>
</attribute>
</attributes>
</nasl>
</nasl_plugins>
Python3.x
import csv
from lxml import etree
elem_names = ('script_id', 'script_name', 'script_family')
attr_names = ('solution', 'description', 'synopsis', 'cvss_base_score', 'plugin_type',
'stig_severity')
field_names = elem_names + attr_names
with open('test.csv', 'w', newline='', encoding='utf8') as xml_data_to_csv:
csv_writer = csv.DictWriter(xml_data_to_csv, fieldnames=field_names,
quoting=csv.QUOTE_ALL)
csv_writer.writeheader()
tree = etree.parse('test.xml')
for nasl in tree.xpath('.//nasl'):
# Build a dict containing all of the "field_names" with default values of "Unknown".
values = {key: 'Unknown' for key in field_names}
# Process the direct children of "nasl".
for elem_name in elem_names:
for child in nasl.xpath(f'*[self::{elem_name}]'):
values[child.tag] = child.text
# Process attribute with matching attribute names.
for attr_name in attr_names:
for val in nasl.xpath(f'attributes/attribute[name="{attr_name}"]/value'):
values[attr_name] = val.text
csv_writer.writerow(values)
Выход (test.csv)
"script_id","script_name","script_family","solution","description","synopsis","cvss_base_score","plugin_type","stig_severity"
"101028","Fedora 25 : xen (2017-c3149b5fcb)","Fedora Local Security Checks","Unknown","Unknown","Unknown","10.0","local","I"