[英]Python - XML - LXML- How to use same XML tree structure from a sample XML file to create another XML file
我有一個 XML 文件,其中包含一些樹結構、元素、屬性、文本。 我需要使用這個 XML 作為模板(樹結構和標簽)並創建另一個 XML,它可能具有不同數量的元素(即在模板下面有兩個“列”元素,但我想創建的一個有三個元素“列”)。
下面是我想用作模板的 XML
<custom-data>
<schema>SCHEMA</schema>
<columns>
<column>
<name>ORGANIZATION</name>
<datatype>NUMBER</datatype>
<length/>
<precision>18</precision>
<not-null>Yes</not-null>
</column>
<column>
<name>LOCATION</name>
<datatype>NUMBER</datatype>
<length/>
<precision>18</precision>
<not-null>Yes</not-null>
</column>
</columns>
</custom-data>
而不是使用 lxml 通過如下定義每個元素來定義類似的樹。 例如,如果 'df' 是我的帶有數據的 Pandas 數據框。 其中列為(目標列,數據類型,長度,比例,可空。_
Target Column Data Type Length Scale Nullable
COLUMN1 NUMBER 38 0 N
COLUMN2 NUMBER 38 0 N
COLUMN3 NUMBER 38 0 N
下面是我正在使用的示例 python 代碼
from lxml import etree as et
root = et.Element('custom-data')
schema= et.SubElement(root, 'schema')
schema.text='SCHEMA'
columns= et.SubElement(root, 'columns')
for row in df.iterrows():
column = et.SubElement(columns, 'columns')
name = et.SubElement(column , 'name')
datatype = et.SubElement(column , 'datatype')
length = et.SubElement(column , 'length')
precision = et.SubElement(column , 'precision')
notnull = et.SubElement(column , 'not-null')
name.text = str(row[1]['Target Column'])
datatype.text = str(row[1]['Data Type'])
length.text = str(row[1]['Length'])
precision.text = str(row[1]['Scale'])
notnull.text = str(row[1]['Nullable'])
xml_test=et.tostring(root, pretty_print=True).decode('utf-8')
f=open("xml_test.xml", "w")
f.write(xml_test)
預期輸出是
<custom-data>
<schema>SCHEMA</schema>
<columns>
<column>
<name>COLUMN1</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
<column>
<name>COLUMN2</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
<column>
<name>COLUMN3</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
</columns>
</custom-data>
我如何利用示例 XML 中給出的結構,以便我不需要在我的代碼中再次定義它。 有沒有更簡單的方法?
您應該能夠解析 XML 模板並使用“column”元素的副本來制作新副本,並填充來自 DataFrame 的數據。
應清理和簡化模板,使其僅包含靜態值和用作模板的單個“列”元素。
這是一個例子...
XML 模板(template.xml)
<custom-data>
<schema>SCHEMA</schema>
<columns>
<column>
<name/>
<datatype/>
<length/>
<precision/>
<not-null/>
</column>
</columns>
</custom-data>
Python
import pandas as pd
from copy import deepcopy
from lxml import etree as et
# Mock up DataFrame for testing.
data = {"Target Column": ["COLUMN1", "COLUMN2", "COLUMN3"],
"Data Type": ["NUMBER", "NUMBER", "NUMBER"],
"Length": [38, 38, 38],
"Scale": [0, 0, 0],
"Nullable": ["N", "N", "N"]}
df = pd.DataFrame(data=data)
# Create ElementTree from template XML.
tree = et.parse("template.xml")
# Map column names to element names.
name_map = {"Target Column": "name",
"Data Type": "datatype",
"Length": "length",
"Scale": "precision",
"Nullable": "not-null"}
# Select "columns" element so we can append/remove children.
columns_elem = tree.xpath("/custom-data/columns")[0]
# Select "column" element to use as a template for new column elements.
column_template = columns_elem.xpath("column")[0]
for row in df.iterrows():
# Create a new copy of the column template.
new_column = deepcopy(column_template)
# Populate elements in column template based on name map.
for col_name, elem_name in name_map.items():
new_column.xpath(elem_name)[0].text = str(row[1][col_name])
# Append the new column element to "columns" element.
columns_elem.append(new_column)
# Remove original empty column template.
columns_elem.remove(column_template)
# Write tree to file.
# Note: I could've just done tree.write("output.xml"), but I used
# XMLParser(), tostring(), and fromstring() to get the indents
# all the same.
parser = et.XMLParser(remove_blank_text=True)
et.ElementTree(et.fromstring(et.tostring(tree),
parser=parser)).write("output.xml",
pretty_print=True)
XML 輸出(“output.xml”)
<custom-data>
<schema>SCHEMA</schema>
<columns>
<column>
<name>COLUMN1</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
<column>
<name>COLUMN2</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
<column>
<name>COLUMN3</name>
<datatype>NUMBER</datatype>
<length>38</length>
<precision>0</precision>
<not-null>N</not-null>
</column>
</columns>
</custom-data>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.