鑒于下面的示例xml:
<_Document>
<_Data1> 'foo'
<_SubData1> 'bar1' </_SubData1>
<_SubData2> 'bar2' </_SubData2>
<_SubData3> 'bar3' </_SubData3>
</_Data1>
</_Document>
我想捕獲每個 SubData 值并使用字典中的 Data1 值更新它,然后將該值附加到串列中。這樣輸出看起來像:
[{Data1: 'foo', SubData1: 'bar1'}, {Data1: 'foo', SubData2: 'bar2'}, {Data1: 'foo', SubData3: 'bar3'}]
我的代碼是:
from lxml import etree
import re
new_records = []
for child in root.iter('_Document'): #finding all children with each 'Document' string
for top_data in child.iter(): #iterating through the entirety of each 'Document' sections tags and text.
if "Data" in top_data.tag:
for data in top_data:
rec = {}
if data.text is not None and data.text.isspace() is False: #avoiding NoneTypes and empty data.
g = data.tag.strip("_") #cleaning up the tag
rec[g] = data.text.replace("\n", " ") #cleaning up the value
for b in re.finditer(r'^_SubData', data.tag): #searching through each 'SubData' contained in a given tag.
for subdata in data:
subdict = {}
if subdata.text is not None: #again preventing NoneTypes
z = subdata.tag.strip("_") #tag cleaning
subdict[z] = subdata.text.replace("\n", " ") #text cleaning
rec.update(subdict) #update the data record dictionary with the subdata
new_records.append(rec) #appending to the list
不幸的是,這輸出:
[{Data1: 'foo', SubData3: 'bar3'}]
因為它只更新并附加字典的最終更新。
我嘗試了不同的變體,包括在第二個 for 回圈中的第一個“if”陳述句之后初始化一個串列,以在每次回圈通過后追加,但這需要在最后進行大量清理才能通過嵌套原因。我還嘗試在回圈之外初始化空字典以進行更新以保留以前的更新并以這種方式追加。
我很好奇是否有我錯過的 lxml 的某些功能,或者是否有更pythonic 的方法來獲得所需的輸出。
uj5u.com熱心網友回復:
我在另一個解決方案中提供了我認為的宣告性方法。如果您更愿意使用回圈明確定義結構,這里有一個命令式方法:
from xml.etree import ElementTree as ET
import pprint
new_records = []
document = ET.parse('input.xml').getroot()
for elem in document:
if elem.tag.startswith('_Data'):
data = elem
data_name = data.tag[1:] # skip leading '_'
data_val = data.text.strip()
for elem in data:
if elem.tag.startswith('_SubData'):
subdata = elem
subdata_name = subdata.tag[1:]
subdata_val = subdata.text.strip()
new_records.append(
{data_name: data_val, subdata_name: subdata_val}
)
pprint.pprint(new_records)
輸入和輸出與我的其他解決方案中的相同。
uj5u.com熱心網友回復:
您可以使用 Python 的內置ElementTree類及其iterparse()
方法來完成此操作,該類遍歷XML 樹并為樹中的每一步生成一對事件和元素。我們監聽它何時開始決議一個元素,以及它_Data...
或_SubData...
我們是否采取了行動。
這是一種宣告性方法,并且依賴于一個事實,即_SubData
它只是 的一個子項_Data
,也就是說,您的非常小而簡單的樣本完全代表了您實際處理的內容。
您需要為_Data
元素管理一些狀態,但僅此而已:
from xml.etree import ElementTree as ET
import pprint
new_records = []
data_name = None
data_val = None
for event, elem in ET.iterparse('input.xml', ['start']):
tag_name = elem.tag[1:] # skip possible leading '_'
if event == 'start' and tag_name.startswith('Data'):
data_name = tag_name
data_val = elem.text.strip()
if event == 'start' and tag_name.startswith('SubData'):
subdata_name = tag_name
subdata_val = elem.text.strip()
record = {
data_name: data_val, subdata_name: subdata_val
}
new_records.append(record)
pprint.pprint(new_records)
我修改了你的示例,我的input.xml:
<_Document>
<_Data1>foo
<_SubData1>bar1</_SubData1>
<_SubData2>bar2</_SubData2>
<_SubData3>bar3</_SubData3>
</_Data1>
<_Data2>FOO
<_SubData1>BAR1</_SubData1>
<_SubData2>BAR2</_SubData2>
<_SubData3>BAR3</_SubData3>
</_Data2>
</_Document>
當我在該輸入上運行我的腳本時,我得到:
[{'Data1': 'foo', 'SubData1': 'bar1'},
{'Data1': 'foo', 'SubData2': 'bar2'},
{'Data1': 'foo', 'SubData3': 'bar3'},
{'Data2': 'FOO', 'SubData1': 'BAR1'},
{'Data2': 'FOO', 'SubData2': 'BAR2'},
{'Data2': 'FOO', 'SubData3': 'BAR3'}]
uj5u.com熱心網友回復:
考慮使用字典合并的字典理解:
new_records = [
{
**{doc.tag.replace('_', ''): doc.text.strip().replace("'", "")},
**{data.tag.replace('_', ''): data.text.strip().replace("'", "")}
}
for doc in root.iterfind('*')
for data in doc.iterfind('*')
]
new_records
[{'Data1': 'foo', 'SubData1': 'bar1'},
{'Data1': 'foo', 'SubData2': 'bar2'},
{'Data1': 'foo', 'SubData3': 'bar3'}]
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/401039.html
上一篇:如果為空,則洗掉特定的空標簽