使用ElementTree与XPath解析XML生成元组列表的问题
问题:基于ElementTree和XPath的XML解析,根据norm值生成不同格式的元组列表
需求说明
- 使用ElementTree结合XPath解析XML文档,生成元组列表输出
- 根据变量
norm(取值True/False)生成两种格式:norm=True:每个国家对应一个元组,包含所有地址信息norm=False:每个地址对应一个元组,重复国家基础信息
预期输出
当norm = True时
[('Liechtenstein', 1, 2008, 'Residence', 'Fern Road', 'NY', 'Office', 'Camac Street', 'DE'), ('Singapore', 4, 2011, 'Residence', 'Lansdown Road', 'CA', 'Office', 'Lord Street', 'WA'), ('Panama', 68, 2011, 'Residence', 'Tobin Road', 'MI', 'Office', 'Broad Street', 'MD') ]
当norm = False时
[('Liechtenstein', 1, 2008, 'Residence', 'Fern Road', 'NY'), ('Liechtenstein', 1, 2008, 'Office', 'Camac Street', 'DE'), ('Singapore', 4, 2011, 'Residence', 'Lansdown Road', 'CA'), ('Singapore', 4, 2011, 'Office', 'Lord Street', 'WA'), ('Panama', 68, 2011, 'Residence', 'Tobin Road', 'MI'), ('Panama', 68, 2011, 'Office', 'Broad Street', 'MD') ]
待解析的XML文档
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank>1</rank> <year>2008</year> <gdppc>141100</gdppc> <rank2><rank>New rank1</rank></rank2> <Addresses> <Address type="Residence"> <Street>Fern Road</Street> <Block>A</Block> <City>NY</City> </Address> <Address type="Office"> <Street>Camac Street</Street> <Block>B2</Block> <City>DE</City> </Address> </Addresses> <Street>Invalid</Street> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank>4</rank> <year>2011</year> <gdppc>59900</gdppc> <rank2><rank>New rank2</rank></rank2> <Addresses> <Address type="Residence"> <Street>Lansdown Road</Street> <Block>K</Block> <City>CA</City> </Address> <Address type="Office"> <Street>Lord Street</Street> <Block>L32</Block> <City>WA</City> </Address> </Addresses> <Street>Invalid</Street> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank>68</rank> <year>2011</year> <gdppc>13600</gdppc> <rank2><rank>New rank3</rank></rank2> <Addresses> <Address type="Residence"> <Street>Tobin Road</Street> <Block>T</Block> <City>MI</City> </Address> <Address type="Office"> <Street>Broad Street</Street> <Block>B7</Block> <City>MD</City> </Address> </Addresses> <Street>Invalid</Street> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data>
注意:仅从Country -> Addresses -> Address -> Street层级提取Street值,排除Country节点下直接存在的、值为Invalid的Street节点。
当前尝试的代码(仅实现norm=True的情况)
import xml.etree.cElementTree as ET lst = [] myTree = ET.parse(r"D:\test.xml") myRoot = myTree.getroot() all_vals = myRoot.findall("./country") norm = "True" super_lst = [] main_lst = [] sub_lst = [] dict = [{"path": "Street"}, {"path": "City"}] final_lst = [] for c in all_vals: val = c.find('./rank').text super_lst.append(val) for sub in c.iterfind("./Addresses/Address"): for path in dict: sub_lst.append(sub.find(path["path"]).text) super_lst = super_lst + sub_lst final_lst.append(tuple(super_lst)) sub_lst.clear() super_lst.clear() print(final_lst)
需要使用XPath(后续计划将XPath作为程序输入参数),解决实现两种输出格式的问题。
解决方案
以下代码通过XPath精准提取所需数据,根据norm的值分支处理,生成对应的元组列表:
import xml.etree.cElementTree as ET def parse_xml(xml_path, norm): tree = ET.parse(xml_path) root = tree.getroot() final_lst = [] # 遍历所有国家节点 for country in root.findall("./country"): # 提取国家基础信息 country_name = country.get("name") rank = int(country.find("./rank").text) year = int(country.find("./year").text) base_info = (country_name, rank, year) # 通过XPath获取Addresses下的所有有效地址节点 addresses = country.findall("./Addresses/Address") if norm: # norm=True:合并当前国家的所有地址到一个元组 combined_data = list(base_info) for addr in addresses: addr_type = addr.get("type") street = addr.find("./Street").text city = addr.find("./City").text combined_data.extend([addr_type, street, city]) final_lst.append(tuple(combined_data)) else: # norm=False:每个地址生成独立元组,复用国家基础信息 for addr in addresses: addr_type = addr.get("type") street = addr.find("./Street").text city = addr.find("./City").text final_lst.append(base_info + (addr_type, street, city)) return final_lst # 调用示例 if __name__ == "__main__": xml_path = r"D:\test.xml" norm = True # 改为False即可切换输出格式 result = parse_xml(xml_path, norm) print(result)
代码说明
- XPath使用细节:
./country:定位所有国家节点./rank、./year:提取国家的排名和年份./Addresses/Address:精准匹配Addresses下的地址节点,避免误取Country节点下的InvalidStreet./Street、./City:提取地址内的街道和城市信息
- 分支逻辑:
norm=True时,将当前国家的所有地址信息追加到基础信息后,形成单个元组norm=False时,为每个地址生成新元组,重复使用国家基础信息
- 类型转换:将rank和year转为整数,与预期输出格式完全匹配
内容的提问来源于stack exchange,提问作者marie20
相关产品推荐
相关产品推荐

