![](/img/trans.png)
[英]How can I extract all content from all elements of an XML file with Python and ElementTree?
[英]how can I extract related attributes from different child level elements from XML file with Python ElementTree
我是 Python 的新手,對 XML 解析有些陌生,我正在努力尋找正確的代碼算法來提取我需要的數據,同時保持子元素\屬性之間的關系。
XML 來自音頻錄制軟件應用程序。 它為產品的多個方面定義了配置(所以很大)。 我想從文件的一小部分中提取一些配置項以供外部使用。
以下示例的父路徑是:./Presets/rootObjects/root/list/item[]
<item>
<string name="ID" value="InBusConfig" wide="true"/>
<string name="Name" value="InBusConfig" wide="true"/>
<list name="Items" type="obj">
<obj class="FPreset" ID="1511747008">
<string name="Name" value="Drum & Bass Beds" wide="true"/>
<member name="Object">
<list name="Busses" type="list">
<item>
<string ***name="BusName" value="Kick In"*** wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string ***name="PortId" value="I|Focusrite USB ASIO|Input 3"*** wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
...
<item>
<string name="BusName" value="Live Room" wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string name="PortId" value="I|Focusrite USB ASIO|Digital 10" wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
</list>
<int name="Default Bus Index" value="0"/>
</member>
<int name="Unrenamed" value="1"/>
</obj>
</list>
</item>
我需要提取(並保持相關)的項目是“BusName”屬性和相應的“PortId”屬性,它是名為“connections”的“list”元素的子元素。
對於我的測試配置中存在的 13 個項目,我想將 output 此數據作為 csv(或 JSON)文件用於另一個工具。
我想要這個 output 的格式在理想情況下類似於:(我已經用“-”替換了 pipe 字符,因為它弄亂了表格格式)
總線名稱 | 端口號 |
---|---|
起作用 | I - Focusrite USB ASIO - 輸入 3 |
直播間 | I - Focusrite USB ASIO - 數字 10 |
我沒有提供任何 py 代碼,因為到目前為止我嘗試過的任何東西都不足以提出一個特定的問題。 因此,我請求有關如何解決此問題的更一般性的幫助。
我會對算法、偽代碼甚至一些 python 特定代碼/功能等感到滿意。
任何方向真的會比我現在擁有的更多。
提前致謝。
我建議不要使用內置的 ElementTree,而是使用像lxml
或BeautifulSoup4
這樣的 package 。
編輯:這純粹是一個偏好問題。 正如@barny 正確指出的那樣,使用xml.etree.ElementTree
可以實現完全相同的事情。
這是lxml
的嘗試:
from lxml import etree
data = """
<item>
<string name="ID" value="InBusConfig" wide="true"/>
<string name="Name" value="InBusConfig" wide="true"/>
<list name="Items" type="obj">
<obj class="FPreset" ID="1511747008">
<string name="Name" value="Drum & Bass Beds" wide="true"/>
<member name="Object">
<list name="Busses" type="list">
<item>
<string name="BusName" value="Kick In" wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string name="PortId" value="I|Focusrite USB ASIO|Input 3" wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
<item>
<string name="BusName" value="Live Room" wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string name="PortId" value="I|Focusrite USB ASIO|Digital 10" wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
</list>
<int name="Default Bus Index" value="0"/>
</member>
<int name="Unrenamed" value="1"/>
</obj>
</list>
</item>
"""
root = etree.fromstring(data)
buses = root.xpath('//item[string/@name="BusName"]')
for bus in buses:
bus_name = bus.find('string').get('value')
port_id = bus.xpath('list/item/string/@value')[0]
pair = (bus_name, port_id,)
print(pair)
這里的總體思路是,它使用 xpath 來查找<item>
,其中有一個<string name="BusName">
。
從該項目需要:
<string>
元素的value
屬性。list/item/string
子項的value
屬性的第一個匹配項(因為 xpath 返回一個列表)。 Note: I'm just creating a tuple called pair
, but obviously you can also store these variables in a dataframe ( pandas
), or wirte it directly to json or csv (see eg here: https://realpython.com/python- .csv/ )。
不知道為什么@balduin 推薦 lxml/avoids ElementTree - 它工作得很好。
與 lxml 相比,ElementTree 對 xpath 的支持有限,但它對於許多任務來說已經足夠了,並且避免需要外部 package 通常很有幫助。 文檔在這里: https://docs.python.org/3/library/xml.etree.elementtree.html?highlight=findall#xml
該頁面上方有一些 xpath 示例
import lxml.etree as ETL
import xml.etree.ElementTree as ET
data = """
<item>
<string name="ID" value="InBusConfig" wide="true"/>
<string name="Name" value="InBusConfig" wide="true"/>
<list name="Items" type="obj">
<obj class="FPreset" ID="1511747008">
<string name="Name" value="Drum & Bass Beds" wide="true"/>
<member name="Object">
<list name="Busses" type="list">
<item>
<string name="BusName" value="Kick In" wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string name="PortId" value="I|Focusrite USB ASIO|Input 3" wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
<item>
<string name="BusName" value="Live Room" wide="true"/>
<int name="SpeakerArr" value="0"/>
<list name="Connections" type="list">
<item>
<string name="PortId" value="I|Focusrite USB ASIO|Digital 10" wide="true"/>
<int name="Speaker" value="0"/>
</item>
</list>
</item>
</list>
<int name="Default Bus Index" value="0"/>
</member>
<int name="Unrenamed" value="1"/>
</obj>
</list>
</item>
"""
# lxml
root = ETL.fromstring(data)
buses = root.xpath('//item[string/@name="BusName"]')
for bus in buses:
bus_name = bus.find('string').get('value')
port_id = bus.xpath('list/item/string/@value')[0]
pair = (bus_name, port_id,)
print(pair)
# ElementTree
root1 = ET.fromstring(data)
for el in root1.findall('.//item/string[@name="BusName"]/..'):
bus_name = el.find('./string').get('value')
port_id=el.find("./list/item/string").get('value')
pair=(bus_name,port_id)
print(pair)
Output lxml:
('Kick In', 'I|Focusrite USB ASIO|Input 3')
('Live Room', 'I|Focusrite USB ASIO|Digital 10')
Output 元素樹:
('Kick In', 'I|Focusrite USB ASIO|Input 3')
('Live Room', 'I|Focusrite USB ASIO|Digital 10')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.