1、加载包
import chardet
import xml.etree.ElementTree as ET
import csv
2、确定xml文件内数据的格式
with open('20250320081954.xml', 'rb') as f:
raw_data = f.read()
result = chardet.detect(raw_data)
encoding = result['encoding']
print(f"文件编码: {encoding}")
tree = ET.parse('yourfile.xml', encoding=encoding)
如果成功读取数据,万事大吉,若失败,显示BOM
报错,是因为Python的 xml.etree.ElementTree 模块期望该文件以BOM(字节顺序标记)开头,用于指示其字节顺序。
我的数据比较奇怪,chardet显示是ascii
格式,但是文件内部显示是utf-16
的格式🤣🤣
3、读取文件
# 读取XML文件
xml_file = '20250320081954.xml' # 请替换为你的XML文件路径
with open(xml_file, 'rb') as file: # 以二进制模式打开文件
xml_content = file.read().decode('ascii') # 解码为ascii字符串,更适合无BOM的情况,上一个代码怎么都无法读取成功,但是这个可以,玄学
# 解析XML内容
root = ET.fromstring(xml_content)
# 获取风速数据
wind_unit_data = root.find('.//Units')
rows = []
for wind_data in wind_unit_data.findall('WindUnitData'):
row = {
'Height': wind_data.find('Height').text,
'Direction': wind_data.find('Direction').text,
'SpeedH': wind_data.find('SpeedH').text,
'SpeedV': wind_data.find('SpeedV').text,
'CNR': wind_data.find('CNR').text,
'MinAvgHWS': wind_data.find('MinAvgHWS').text,
'MinAvgHWD': wind_data.find('MinAvgHWD').text,
'MinAvgVWS': wind_data.find('MinAvgVWS').text,
'VWSH': wind_data.find('VWSH').text,
'VWSE': wind_data.find('VWSE').text,
'TI': wind_data.find('TI').text,
}
rows.append(row)
3.1 数据特殊要求
由于读取数据中有某一结点未能读取成功,由于我只需要部分的数据,对节点进行判断读取
tree = ET.ElementTree(ET.fromstring(xml_content))
root = tree.getroot()
# 获取高度(Height)列表
wind_unit_data = root.find('.//Units')
heights = [int(wind.findtext('Height')) for wind in wind_unit_data.findall('WindUnitData')]
# 初始化字典,用于存储V1和V2数据
radial_velocity_data = {"Height": heights, "V1": [], "V2": []}
# 读取 RadialVelocityDatas 中的数据
radial_velocity_datas = root.find('.//RadialVelocityDatas')
if radial_velocity_datas:
for velocity_data in radial_velocity_datas.findall('RadialVelocityData'):
azimuth = velocity_data.findtext('Azimuth')
moments = velocity_data.find('.//RadialVelocityMoments')
for moment in moments.findall('RadialVelocityMoment'):
moment_type = moment.findtext('MomentType')
# 只处理 MomentType 为 V 的数据
if moment_type == 'V':
data = [float(value.text) for value in moment.find('.//Data').findall('float')]
if azimuth == '1':
radial_velocity_data["V1"] = data
elif azimuth == '2':
radial_velocity_data["V2"] = data
3.2 综合读取
# 读取XML文件
xml_file = '20250320081954.xml' # 请替换为你的XML文件路径
with open(xml_file, 'rb') as file: # 以二进制模式打开文件
xml_content = file.read().decode('ascii') # 解码文件内容
# 解析XML内容
root = ET.fromstring(xml_content)
# 获取风速数据
wind_unit_data = root.find('.//Units')
radial_velocity_data = root.find('.//RadialVelocityDatas')
rows = []
# 获取MomentType为"V"的数据
moment_v_1 = []
moment_v_2 = []
for radial_data in radial_velocity_data.findall('RadialVelocityData'):
moment = radial_data.find('./RadialVelocityMoments/RadialVelocityMoment[MomentType="V"]')
if moment is not None:
azimuth = radial_data.find('Azimuth').text
data_values = [float(float_value.text) for float_value in moment.findall('./Data/float')]
if azimuth == "1": # V1
moment_v_1 = data_values
elif azimuth == "2": # V2
moment_v_2 = data_values
# 将数据和风速数据对应起来
for idx, wind_data in enumerate(wind_unit_data.findall('WindUnitData')):
row = {
'Height': wind_data.find('Height').text,
'Direction': wind_data.find('Direction').text,
'SpeedH': wind_data.find('SpeedH').text,
'SpeedV': wind_data.find('SpeedV').text,
'CNR': wind_data.find('CNR').text,
'MinAvgHWS': wind_data.find('MinAvgHWS').text,
'MinAvgHWD': wind_data.find('MinAvgHWD').text,
'MinAvgVWS': wind_data.find('MinAvgVWS').text,
'VWSH': wind_data.find('VWSH').text,
'VWSE': wind_data.find('VWSE').text,
'TI': wind_data.find('TI').text,
'V1': moment_v_1[idx] if idx < len(moment_v_1) else None, # 填充V1
'V2': moment_v_2[idx] if idx < len(moment_v_2) else None, # 填充V2
}
rows.append(row)
4、保存为csv
# 输出为CSV文件
csv_file = 'wind_data.csv' # 输出文件名
with open(csv_file, mode='w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=rows[0].keys())
writer.writeheader()
for row in rows:
writer.writerow(row)
5、批量读取保存
import os
# XML文件夹路径
xml_folder = '2025032008' # 请替换为你的XML文件夹路径
# CSV输出文件夹路径
csv_folder = 'CSV/' # 请替换为你的CSV文件输出路径
# 获取XML文件列表
xml_files = [f for f in os.listdir(xml_folder) if f.endswith('.xml')]
# 遍历每个XML文件
for xml_file in xml_files:
xml_path = os.path.join(xml_folder, xml_file)
# 读取XML文件
with open(xml_path, 'rb') as file: # 以二进制模式打开文件
xml_content = file.read().decode('ascii') # 解码为utf-16字符串,处理可能的错误
# 解析XML内容
root = ET.fromstring(xml_content)
# 获取风速数据
wind_unit_data = root.find('.//Units')
rows = []
# 读取Units部分
for wind_data in wind_unit_data.findall('WindUnitData'):
row = {
'Height': wind_data.find('Height').text,
'Direction': wind_data.find('Direction').text,
'SpeedH': wind_data.find('SpeedH').text,
'SpeedV': wind_data.find('SpeedV').text,
'CNR': wind_data.find('CNR').text,
'MinAvgHWS': wind_data.find('MinAvgHWS').text,
'MinAvgHWD': wind_data.find('MinAvgHWD').text,
'MinAvgVWS': wind_data.find('MinAvgVWS').text,
'VWSH': wind_data.find('VWSH').text,
'VWSE': wind_data.find('VWSE').text,
'TI': wind_data.find('TI').text,
'V1': '', # 初始为空,后续填充
'V2': '', # 初始为空,后续填充
}
rows.append(row)
# 获取RadialVelocityDatas数据,仅提取MomentType为"V"的部分
radial_velocity_datas = root.find('.//RadialVelocityDatas')
if radial_velocity_datas:
v1_data = [] # 存储V1数据 (Azimuth=1)
v2_data = [] # 存储V2数据 (Azimuth=2)
# 提取数据
for rv_data in radial_velocity_datas.findall('RadialVelocityData'):
azimuth = rv_data.find('Azimuth').text
for moment in rv_data.findall('.//RadialVelocityMoment'):
if moment.find('MomentType').text == 'V': # 过滤MomentType=V
data = [float(elem.text) for elem in moment.find('Data').findall('float')]
if azimuth == '1': # V1
v1_data = data
elif azimuth == '2': # V2
v2_data = data
# 将V1和V2数据对应填入到风速数据表中,仅当数量匹配时
heights = [float(row['Height']) for row in rows] # 获取所有高度值
if len(v1_data) == len(heights):
for i, row in enumerate(rows):
row['V1'] = v1_data[i]
if len(v2_data) == len(heights):
for i, row in enumerate(rows):
row['V2'] = v2_data[i]
# 输出为CSV文件
csv_file_name = os.path.splitext(xml_file)[0] + '.csv' # 替换文件扩展名
csv_file_path = os.path.join(csv_folder, csv_file_name)
with open(csv_file_path, mode='w', newline='', encoding='utf-8') as file:
fieldnames = list(rows[0].keys())
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
for row in rows:
writer.writerow(row)
print(f"数据已存储到 {csv_file_path}")
😁😁😁
End!!!