第3章:数据格式基础(上)——JSON结构解析、XML解析与生成、CSV文件读写、YAML配置管理
各位同学,欢迎来到数据格式基础的上半部分。说实话,在医疗设备这个行当里,数据格式就是咱们的通用语言。设备之间要对话,系统之间要传数据,全靠这些格式来搭桥。我做了十几年医疗软件,见过太多因为格式问题导致的故障——有的数据丢了,有的解析错了,最严重的一次差点影响病人数据上报。所以这一章,咱们得把基础打扎实。
3.1 JSON结构解析——轻量级的数据交换王者
JSON,全称JavaScript Object Notation。说白了,就是一种轻量级的数据交换格式。为什么医疗设备特别喜欢它?因为够简单、够直观、解析速度还快。
我个人习惯,在医疗设备的数据接口中,JSON用得最多。比如病人基本信息、设备状态上报、检查结果传输,这些场景JSON都能胜任。
核心要点:JSON由两种结构组成——对象(Object)和数组(Array)。对象用花括号{}包裹,数组用方括号[]包裹。
来看一个典型的医疗设备JSON数据示例:
{
"deviceId": "DX-2024-001",
"deviceName": "数字化X光机",
"status": "online",
"patientInfo": {
"patientId": "P20240315001",
"name": "张三",
"age": 45,
"gender": "male",
"examType": "chest"
},
"measurements": [
{
"timestamp": "2024-03-15T10:30:00Z",
"parameter": "kVp",
"value": 120,
"unit": "kV"
},
{
"timestamp": "2024-03-15T10:30:01Z",
"parameter": "mA",
"value": 200,
"unit": "mA"
}
]
}
嗯,这里要注意几个关键点。第一,键名必须用双引号包裹。第二,字符串值也必须用双引号。第三,最后一个元素后面不能有逗号。我在项目中遇到过,有个同事在JSON末尾多写了个逗号,结果解析器直接报错,查了半天才发现。
我的小技巧:写JSON的时候,建议用在线校验工具先验证一遍。或者用代码里的JSON库来序列化,别手写。手写容易出错,尤其是嵌套层级多的时候。
解析JSON,在Python里用json模块就行。我一般这么写:
import json
# 从字符串解析
json_str = '{"deviceId": "DX-2024-001", "status": "online"}'
data = json.loads(json_str)
print(data["deviceId"]) # 输出: DX-2024-001
# 从文件读取
with open("device_data.json", "r", encoding="utf-8") as f:
data = json.load(f)
# 生成JSON字符串
output = json.dumps(data, indent=2, ensure_ascii=False)
print(output)
你想想看,如果不用ensure_ascii=False,中文会被转成Unicode编码,可读性很差。我刚开始做医疗设备项目时就踩过这个坑,病人姓名显示成\u5f20\u4e09,被测试同事吐槽了好久。
3.2 XML解析与生成——老牌工业标准
XML,可扩展标记语言。虽然现在JSON很流行,但在医疗设备领域,XML依然占据重要地位。为什么?因为很多医疗设备标准协议,比如HL7、DICOM,底层都依赖XML。
XML的结构,说白了就是标签套标签。每个标签可以带属性,也可以有子标签。来看一个医疗设备配置的XML示例:
<?xml version="1.0" encoding="UTF-8"?>
<deviceConfiguration>
<device id="DX-2024-001">
<name>数字化X光机</name>
<manufacturer>蓝海医疗</manufacturer>
<parameters>
<parameter name="kVp" unit="kV">
<min>40</min>
<max>150</max>
<default>120</default>
</parameter>
<parameter name="mA" unit="mA">
<min>10</min>
<max>500</max>
<default>200</default>
</parameter>
</parameters>
</device>
</deviceConfiguration>
解析XML,Python里常用的有xml.etree.ElementTree和lxml。我个人更推荐lxml,功能更强大,处理大文件也更快。
from lxml import etree
# 解析XML字符串
xml_str = '''<device><name>X光机</name></device>'''
root = etree.fromstring(xml_str)
print(root.find("name").text) # 输出: X光机
# 从文件解析
tree = etree.parse("device_config.xml")
root = tree.getroot()
# 遍历所有参数
for param in root.findall(".//parameter"):
name = param.get("name")
default = param.find("default").text
print(f"参数: {name}, 默认值: {default}")
# 生成XML
new_device = etree.Element("device")
etree.SubElement(new_device, "name").text = "CT扫描仪"
etree.SubElement(new_device, "status").text = "active"
xml_output = etree.tostring(new_device, pretty_print=True, encoding="UTF-8")
print(xml_output.decode())
避坑指南:我曾经在解析XML时,没注意命名空间(namespace),结果find方法一直返回None。查了半天才发现,标签前面有个ns:前缀。处理带命名空间的XML,要用{namespace}tag这种写法。
XML的优点是自描述性强,缺点是冗余信息多,文件体积大。在医疗设备中,我建议:配置文件和协议报文用XML,实时数据传输用JSON。
3.3 CSV文件读写——最朴素的表格数据
CSV,逗号分隔值。别看它简单,在医疗设备中用处可大了。比如导出检查记录、批量导入病人信息、设备日志分析,CSV都是首选。
CSV的格式,说白了就是一行一条记录,每列用逗号隔开。但要注意,如果字段里包含逗号或换行符,需要用双引号包裹。
来看一个病人检查记录的CSV示例:
病人ID,姓名,检查类型,检查日期,检查结果
P001,张三,胸部X光,2024-03-15,正常
P002,李四,腹部CT,2024-03-16,发现结节
P003,王五,心电图,2024-03-16,窦性心律
Python里读写CSV,用内置的csv模块就行。我一般这么写:
import csv
# 写入CSV文件
with open("exam_records.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["病人ID", "姓名", "检查类型", "检查日期", "检查结果"])
writer.writerow(["P001", "张三", "胸部X光", "2024-03-15", "正常"])
writer.writerow(["P002", "李四", "腹部CT", "2024-03-16", "发现结节"])
# 读取CSV文件
with open("exam_records.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(f"病人{row['姓名']}的检查结果是{row['检查结果']}")
我的经验:用DictReader和DictWriter比普通reader更方便,可以直接用列名访问数据。另外,写入时一定要加newline="",否则Windows系统下会多出空行。这个坑我踩过不止一次。
CSV的优点是简单、通用,任何表格软件都能打开。缺点是缺乏数据类型定义,所有字段都是字符串。所以在读取后,记得做类型转换。
3.4 YAML配置管理——人类友好的配置文件
YAML,YAML Ain't Markup Language。这个名字挺有意思,递归缩写。YAML的设计目标就是——人类可读性第一。
在医疗设备中,YAML特别适合做配置文件。比如设备参数配置、系统设置、环境变量。为什么?因为YAML支持注释,结构清晰,还支持复杂的数据类型。
来看一个医疗设备系统的YAML配置示例:
# 医疗设备系统配置文件
system:
name: "蓝海医疗影像系统"
version: "3.2.1"
log_level: "INFO"
database:
host: "192.168.1.100"
port: 3306
name: "medical_db"
user: "admin"
password: "${DB_PASSWORD}" # 使用环境变量
device:
- id: "DX-001"
type: "X光机"
ip: "192.168.1.10"
port: 8080
enabled: true
- id: "CT-001"
type: "CT扫描仪"
ip: "192.168.1.11"
port: 8081
enabled: false
alerts:
email:
enabled: true
recipients:
- "admin@example.com"
- "tech@example.com"
sms:
enabled: false
解析YAML,Python里用PyYAML库。安装命令:pip install pyyaml。
import yaml
# 读取YAML文件
with open("config.yaml", "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
print(config["system"]["name"]) # 输出: 蓝海医疗影像系统
print(config["device"][0]["type"]) # 输出: X光机
# 写入YAML文件
config["system"]["version"] = "3.3.0"
with open("config.yaml", "w", encoding="utf-8") as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
避坑指南:YAML对缩进非常敏感,必须用空格,不能用Tab。我曾经在项目中,因为编辑器自动把空格转成了Tab,结果YAML解析一直报错。建议在编辑器里设置显示空白字符,一眼就能看出问题。
另外,YAML里布尔值的写法要注意。true、True、TRUE、yes、on都会被解析为布尔值True。如果你想要字符串"true",记得加引号。
3.5 四种格式的对比与选择
好了,四种格式都讲完了。咱们来做个对比,方便你在实际项目中做选择。
| 特性 | JSON | XML | CSV | YAML |
|---|---|---|---|---|
| 可读性 | 高 | 中 | 高 | 非常高 |
| 解析速度 | 快 | 慢 | 非常快 | 中 |
| 文件大小 | 小 | 大 | 最小 | 中 |
| 支持注释 | 否 | 是 | 否 | 是 |
| 数据类型 | 丰富 | 弱 | 无 | 丰富 |
| 适用场景 | API数据交换 | 标准协议、文档 | 表格数据导出 | 配置文件 |
我个人建议:
- 实时数据传输:用JSON,解析快、体积小
- 遵循医疗标准协议:用XML,比如HL7、DICOM
- 批量数据导出导入:用CSV,通用性强
- 系统配置文件:用YAML,可读性好、支持注释
核心总结:没有最好的格式,只有最合适的场景。在医疗设备开发中,往往是多种格式混合使用。关键是理解每种格式的特点,知道什么时候该用哪个。
好了,这一章的内容就到这儿。下一章咱们继续讲数据格式的下半部分,包括二进制数据、Protocol Buffers、MessagePack这些更高级的格式。到时候再聊!