Рассмотрим язык специального назначения, XSLT , использующий сторонний модуль Python, lxml
, для непосредственного преобразования XML в выход CSV. В частности, XSLT извлекает из нижнего уровня SetData
и извлекает информацию о верхнем уровне с помощью ancestor
.
XSLT (сохранить как файл .xsl, специальный. xml файл)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="delim">,</xsl:variable>
<xsl:template match="/ProjectData">
<!------------------------------- HEADERS ------------------------------->
<xsl:text>id,service_code,rational,qualify,description_num,description,</xsl:text>
<xsl:text>data_file_dg,data_file_dg_id,data_file_unit,data_file_unit_id,</xsl:text>
<xsl:text>set_data_x,set_data_xin,set_data_xat,set_data_value
</xsl:text>
<!----------------------------------------------------------------------->
<xsl:apply-templates select="descendant::SetData"/>
</xsl:template>
<xsl:template match="SetData">
<xsl:value-of select="concat(ancestor::START/@id, $delim,
ancestor::START/@service_code, $delim,
ancestor::START/*[1]/Rational, $delim,
ancestor::START/*[1]/Qualify, $delim,
ancestor::START/Description/@num, $delim,
ancestor::START/Description, $delim,
ancestor::START/DataFile/@dg, $delim,
ancestor::START/DataFile/@dg_id, $delim,
ancestor::START/DataFile/@unit, $delim,
ancestor::START/DataFile/@unit_id, $delim,
@x, $delim,
@xin, $delim,
@xat, $delim,
@value)"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Python (без for
петель или if
/ else
logi c)
import lxml.etree as et
# LOAD XML AND XSL FILES
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')
# INITIALIZE TRANSFORMER
transform = et.XSLT(xsl)
# TRANSFORM INPUT
result = transform(xml)
print(str(result))
# id,service_code,rational,qualify,description_num,description,data_file_dg,data_file_dg_id,data_file_unit,data_file_unit_id,set_data_x,set_data_xin,set_data_xat,set_data_value
# ID0001,0x5196,225196,6251960000A0DE,1213f2312,The parameter,12,let,,,,,,32
# DG0003,0x517B,23423,342342,3423423f3423,The third,55,big,,,E1,,,21259
# DG0003,0x517B,23423,342342,3423423f3423,The third,55,big,,,E2,,,02
# ID0048,0x5198,225198,343243324234234,434234234,The forth,,,21,FEDS,,5,,323
# ID0048,0x5198,225198,343243324234234,434234234,The forth,,,21,FEDS,,123,,555
# ID0048,0x5198,225198,343243324234234,434234234,The forth,,,21,FEDS,,17,,23
# SAVE XML TO CSV
with open('Output.csv', 'wb') as f:
f.write(str(result))
Онлайн-демонстрация
![CSV Output](https://i.stack.imgur.com/mPSxC.png)
К л oop в папке XML файлов, просто интегрируйте выше в al oop. Здесь все процессы обработки XML объединяются в единый метод для построения списка результатов с помощью понимания списка и, наконец, итеративной записи в CSV. ПРИМЕЧАНИЕ : для одного набора заголовков размещайте заголовки только в CSV и удаляйте из XSLT, как указано выше.
import lxml.etree as et
from pathlib import Path
# LOAD XSL SCRIPT
xsl = et.parse('Script.xsl') # LOAD XML FILE ONCE (REMOVE HEADERS)
def proc_xml(xml_file):
xml = et.parse(xml_file) # LOAD XML FILE
transform = et.XSLT(xsl) # INITIALIZE TRANSFORMER
result = transform(xml) # TRANSFORM INPUT
return str(result)
xml_files_list = list(map(str,Path(directory).glob('**/*.xml')))
results = [proc_xml(x) for x in xml_files_list]
with open('Output.csv', 'w', newline='') as f:
f.write('id,service_code,rational,qualify,description_num,description,'
'data_file_dg,data_file_dg_id,data_file_unit,data_file_unit_id,'
'set_data_x,set_data_xin,set_data_xat,set_data_value\n')
# SAVE XML TO CSV
for r in results:
f.write(r)