C# FHIR资源文件 C#如何序列化和反序列化HL7 FHIR的JSON或XML文件

2次阅读

最稳妥方式是直接用fhirjsonserializer序列化fhir资源为json,需设置Resourceformat.json、确保resourcetype已初始化,并注册自定义extension;xml反序列化须严格校验命名空间;json反序列化失败主因是版本不匹配或字段格式异常,应启用ignoreunknownelements等设置。

C# FHIR资源文件 C#如何序列化和反序列化HL7 FHIR的JSON或XML文件

FhirJsonSerializer 序列化 FHIR 资源为 JSON

直接调用 FhirJsonSerializer 是最稳妥的方式,它内置了 FHIR 版本感知、类型映射和扩展处理逻辑。别自己用 JsonConvert.SerializeObject 硬转——FHIR 资源里大量使用 ElementBackboneElement 和动态 Extension,手动序列化会丢字段或格式错乱。

  • 必须先设置 FhirJsonSerializerSettingsResourceFormatResourceFormat.Json(默认就是,但显式写上更安全)
  • 确保资源实例的 ResourceType 已正确初始化(比如 new Patient() 会自动设,但空构造后手动赋值 Id 不会触发)
  • 如果资源含自定义 Extension,需提前注册:调用 FhirSerializationUtil.RegisterCustomElement<myextensiontype>()</myextensiontype>
  • 示例:
    FhirJsonSerializer serializer = new FhirJsonSerializer(); string json = serializer.SerializeToString(patient);

FhirXmlSerializer 反序列化 XML 到 C# 对象

XML 反序列化比 JSON 更容易出错,主因是命名空间和元素顺序敏感。FHIR XML 必须带 xmlns="http://hl7.org/fhir",缺这个命名空间会导致 FhirXmlSerializer.Deserialize<patient>(xml)</patient> 返回 NULL 或抛 InvalidOperationException

  • 传入的 XML 字符串开头必须包含完整的根命名空间声明,不能只靠 <patient></patient> 简写
  • 不要用 XDocument.Load + 手动提取再反序列化——FhirXmlSerializer 内部依赖完整文档上下文
  • 若 XML 来自外部系统且命名空间不规范(比如用了前缀 fhir:),先做预处理替换:把 fhir:PatientPatient,并补全默认命名空间
  • 示例:
    string xml = @"<Patient xmlns=""http://hl7.org/fhir""><id value=""123""/></Patient>"; FhirXmlSerializer xmlSer = new FhirXmlSerializer(); Patient p = xmlSer.Deserialize<Patient>(xml);

JSON 反序列化失败常见原因和绕过方法

最常见的报错是 Newtonsoft.Json.JsonSerializationException: Cannot create and populate list type Hl7.Fhir.Model.List`1,本质是 JSON 中某个数组字段类型不匹配(比如服务器返回了 "identifier": [],但 SDK 期望 "identifier": [{}])。

  • 优先检查 FHIR 版本是否对齐:.NET SDK 的 Hl7.Fhir.R4 包只能处理 R4 JSON,拿 STU3 的 JSON 去反序列化必崩
  • 遇到未知字段(如服务端加了非标准扩展字段),在 FhirJsonSerializerSettings 中启用 IgnoreUnknownElements = true
  • 若 JSON 含时间字段格式不标准(如 "2023-10-05T14:30" 缺少秒或时区),设置 DateTimeStyle = DateTimeStyle.RoundTrip
  • catch JsonSerializationException 后吞掉——它通常意味着数据结构损坏,应记录原始 JSON 用于排查

性能与线程安全注意事项

FhirJsonSerializerFhirXmlSerializer 实例本身不是线程安全的,但可以复用。反复 new 它们不会显著拖慢,但没必要;而共享单例时要注意内部缓存状态。

  • 推荐每线程一个实例,或用 Static readonly 声明(只要不修改其 Settings 属性)
  • 序列化大资源(如含数百个 ObservationBundle)时,避免在 Web API action 中同步调用 SerializeToString——改用 SerializeToStreamAsync 配合 HttpResponse.Body
  • XML 序列化比 JSON 慢约 3–5 倍,仅在必须兼容旧系统时用;日常接口尽量走 JSON
  • 如果频繁转换同一类资源(比如总在处理 Condition),可预先调用 FhirSerializer.PrepareForType<condition>()</condition> 加速首次序列化

实际用的时候,最容易被忽略的是 FHIR 版本绑定和命名空间校验——两个看似“应该能通”的文件,往往卡在这两处。多打一行日志输出 resource.ResourceTypexml.Contains("xmlns="),省掉半天排查。

text=ZqhQzanResources