129 lines
7.0 KiB
Python
129 lines
7.0 KiB
Python
import xml.etree.ElementTree as ET
|
||
import os
|
||
|
||
class XmlParser:
|
||
def parse_file(self, file_path):
|
||
if not os.path.exists(file_path):
|
||
return None, f"文件未找到: {file_path}"
|
||
|
||
try:
|
||
tree = ET.parse(file_path)
|
||
root = tree.getroot()
|
||
|
||
# Metadata from root
|
||
xml_version = root.get('XMLVersion')
|
||
xml_creation_datetime = root.get('XMLCreationDateTime')
|
||
data_source = os.path.basename(file_path)
|
||
|
||
# SampleResult (assuming single SampleResult for now based on snippet)
|
||
sample_result = root.find('SampleResult')
|
||
if sample_result is None:
|
||
return None, "没有找到 SampleResult 标签"
|
||
|
||
# Common Sample Info
|
||
sample_info = {
|
||
"sample_name": sample_result.get('Name'),
|
||
"operator_name": sample_result.get('OperatorName'),
|
||
"instrument": sample_result.get('Instrument'),
|
||
"method_name": sample_result.get('MethodName'),
|
||
"sample_type": sample_result.get('Type'),
|
||
"xml_version": xml_version,
|
||
"xml_creation_datetime": xml_creation_datetime,
|
||
"data_source": data_source
|
||
}
|
||
|
||
# SampleIDs
|
||
sample_ids_node = sample_result.find('SampleIDs')
|
||
if sample_ids_node:
|
||
for sid in sample_ids_node.findall('SampleID'):
|
||
id_name = sid.find('IDName').text
|
||
id_value = sid.find('IDValue').text
|
||
if id_name == 'Grade ID':
|
||
sample_info['sample_grade_id'] = id_value
|
||
elif id_name == 'Grade Alias':
|
||
sample_info['sample_grade_alias'] = id_value
|
||
|
||
extracted_data = []
|
||
|
||
# MeasurementReplicates
|
||
replicates_node = sample_result.find('MeasurementReplicates')
|
||
if replicates_node:
|
||
for rep in replicates_node.findall('MeasurementReplicate'):
|
||
rep_info = sample_info.copy()
|
||
rep_info['replicate_no'] = rep.get('No')
|
||
rep_info['measure_datetime'] = rep.get('MeasureDateTime')
|
||
rep_info['is_deleted'] = rep.get('IsDeleted')
|
||
|
||
measurement = rep.find('Measurement')
|
||
if measurement:
|
||
rep_info['check_type'] = measurement.get('CheckType')
|
||
rep_info['check_status'] = measurement.get('CheckStatus')
|
||
rep_info['grade_name'] = measurement.get('GradeName')
|
||
rep_info['rsd_check'] = measurement.get('RsdCheck')
|
||
|
||
ext_data_meas = measurement.find('ExtData')
|
||
if ext_data_meas:
|
||
base_el = ext_data_meas.find('Base')
|
||
if base_el is not None:
|
||
rep_info['base_element'] = base_el.text
|
||
duration_el = ext_data_meas.find('MeasDuration')
|
||
if duration_el is not None:
|
||
rep_info['measure_duration'] = duration_el.text
|
||
|
||
# Elements
|
||
elements_node = measurement.find('Elements')
|
||
if elements_node:
|
||
for el in elements_node.findall('Element'):
|
||
el_data = rep_info.copy()
|
||
el_data['element_name'] = el.get('ElementName')
|
||
el_data['element_type'] = el.get('Type')
|
||
el_data['concentration_unit'] = el.get('DefaultConcentrationUnit')
|
||
|
||
# Concentration Result
|
||
conc_res = el.find("./ElementResult[@Kind='Concentration'][@StatType='None']")
|
||
if conc_res:
|
||
el_data['concentration_value'] = conc_res.find('ResultValue').text
|
||
el_data['result_status'] = conc_res.get('Status')
|
||
el_data['calibration_status'] = conc_res.get('CalibrationStatus')
|
||
el_data['acceptance_status'] = conc_res.get('AcceptanceStatus')
|
||
|
||
# Limits
|
||
limits = conc_res.find('ResultValueLimits')
|
||
if limits:
|
||
lower = limits.find("./ResultValueLimit[@Type='LowerAcceptanceLimit']")
|
||
upper = limits.find("./ResultValueLimit[@Type='UpperAcceptanceLimit']")
|
||
el_data['lower_acceptance_limit'] = lower.text if lower is not None else None
|
||
el_data['upper_acceptance_limit'] = upper.text if upper is not None else None
|
||
|
||
# Uncertainty
|
||
ext_res = conc_res.find('ExtData')
|
||
if ext_res:
|
||
unc_abs = ext_res.find("./ResultValue[@SubType='UncertaintyAbs']")
|
||
unc_rel = ext_res.find("./ResultValue[@SubType='UncertaintyRel']")
|
||
el_data['uncertainty_abs'] = unc_abs.text if unc_abs is not None else None
|
||
el_data['uncertainty_rel'] = unc_rel.text if unc_rel is not None else None
|
||
|
||
std_res = el.find("./ElementResult[@StatType='StdDev']")
|
||
if std_res:
|
||
el_data['std_dev_value'] = std_res.find('ResultValue').text
|
||
# 如果为空,就用None填充
|
||
required_keys = [
|
||
'sample_grade_id', 'sample_grade_alias', 'base_element',
|
||
'measure_duration', 'check_type', 'check_status', 'grade_name', 'rsd_check',
|
||
'concentration_value', 'std_dev_value', 'uncertainty_abs',
|
||
'uncertainty_rel', 'lower_acceptance_limit', 'upper_acceptance_limit',
|
||
'result_status', 'calibration_status', 'acceptance_status'
|
||
]
|
||
for key in required_keys:
|
||
if key not in el_data:
|
||
el_data[key] = None
|
||
|
||
extracted_data.append(el_data)
|
||
|
||
return extracted_data, "Success"
|
||
|
||
except Exception as e:
|
||
import traceback
|
||
traceback.print_exc()
|
||
return None, f"Parse error: {str(e)}"
|