電子病歷實作技術
2024年9月28日 星期六
2023年8月25日 星期五
[閒談FHIR] - 是好是壞?
這篇部落格FHIR (in)Consistency? Data, please,雖然這個主要是針對STU3,但整體趨勢是沒有改變的。
注意,曾在某論壇看到訊息說,R5只是中介版本。R6才會長期支援。
但R6仍在CI-Build階段,還要有段時間。
不用急著去看R6 (https://build.fhir.org/),現階段還沒有什麼變動。
從我開始搞HL7到現在,可以這麼說FHIR是最不嚴謹的。
[閒談FHIR] - gRPC
原本猜想FHIR會朝gRPC方向發展嗎?目前官方文件是沒有任何gRPC字眼,但有protobuf。如圖。
雖然如此,其實方向已經很明確了。
Resource中新增了SearchParameter,實做架構已了然於心。
如果對這些資料交換技術架構有疑慮者,建議可以看看這部影片。
2023年7月26日 星期三
從測試角度看FHIR SDK
近期自行開發了一套FHIR SDK。因是自用不對外,也沒有想著要如何寫使用手冊。雖然整個SDK系統內容還算複雜,但從使用角度似乎沒甚麼好說的。
想要深入研究FHIR,真的從無到有開發一次SDK的方式,就能夠知道所有問題所在。
若要直接從SDK設計思維與程式設計的角度切入,那還真的不知要從何說起。經過一番思考後,何不從測試SDK的思維切入,從測試想法來展開FHIR SDK也許是個好主意。
要如何測試Resource
使用者可能會有三種情境:
- 收到某個Resource Type的JSON檔案。不管你是使用甚麼樣的JSON程式庫,最終一定可以變成字串(string)。
- 有個很好的物件定義結構,協助我們產生符合FHIR規範的JSON字串。
- 更新修正JSON內容。
潛在問題
雖然不同Resource的JSON內容不同,但所有測試需求都是一致的。
另外一個就是測試版本問題。FHIR不斷地發展,所以,應該要降低改版時,又得重新設計一次的問題。Resource實在太多了,不可能一改版,就重新寫一次(這邊留個伏筆,相對設計SDK也有同樣問題)。
解決方法
測試系統結構上會有一個抽象父類別讓個別的Resource來繼承,然後把固定的測試函數,寫在這個父類別上。這部分不受FHIR 改版之影響。
程式解說-抽象父類別
行號 |
說明 |
1 |
宣告使用FHIR SDK的基礎套件。 所有Resource都會繼承於DomainResource。 |
2 |
宣告使用System.Text.Json.Nodes套件。 這個是微軟官方提供處理JSON的套件。請參考System.Text.Json.Nodes
Namespace | Microsoft Learn。 |
4 |
命名空間 |
6 |
宣告抽象類別。採用泛型,得知目前所有處理的Resource Type。 所有的Resource Type都會繼承於DomainResource。 |
8 |
宣告 T Resource。_TargetObject是用新增物件方式所產生的。 |
9 |
宣告 T Resource。_TargetString是從字串解析取得的。 |
10 |
宣告 T Resource。_TargetNode是從JsonNode解析取得的。 |
11 |
建構元。輸入Resource Type的JSON字串。 |
13 |
指派_TargetObject。呼叫設定物件之函數。SetupObject函數由個別Resource測試類別去編寫內容。 |
14 |
指派_TargetString。使用泛型技術,呼叫T Resource類別能接受字串的建構元。 |
15 |
指派_TargetNode。使用泛型技術,呼叫T Resource類別能接受JsonNode的建構元。 JsonObject.Parse(jsonString)是將字串解析成JsonNode。 注意,實務上我們收到的一定是JSON Object,不會是JSON Array。多筆的一定是Bundle Resource,他是JSON Object。 |
17 |
宣告一個SetupObject 抽象方法,讓繼承者實做。 這是用來產生一個新的 T Resource。 |
18 |
宣告一個ChangeDataTest抽象方法,讓繼承者實做。 這是一個測試方法,用來測試更新Resource內容時。 |
20 - 27 |
測試方法 ResourceNameTest。 這是確認 T Resource與JSON Resource字串所宣告的Resource Type是否一致。 |
28 - 33 |
測試方法FromJsonNodeTest。 這是確認是否能順利透過JsonNode的方式,來建構T Resource。 並且利用T Resource的ToJsonString,顯示解析後之結果。 |
34 - 39 |
測試方法FromObjectTest。 這是確認是否能順利透過設定物件內容的方式,來建構T Resource。 並且利用T Resource的ToJsonString,顯示解析後之結果。 |
40 - 45 |
測試方法FromStringTest。 這是確認是否能順利透過解析JSON 字串的方式,來建構T Resource。 並且利用T Resource的ToJsonString,顯示解析後之結果。 |
程式解說-Resource測試類別(Account 為例)
行號 |
說明 |
1 |
宣告使用到FHIR SDK Complex的資料型態。 |
2 |
宣告使用到FHIR SDK Primitive的資料型態。 |
3 |
宣告使用到FHIR SDK Account Resource Type。 |
4 |
宣告使用到FHIR SDK 用於Bind的Value Set。 |
6 |
命名空間 |
8 |
宣告這是測試類別。 |
9 |
宣告測試類別,繼承於ResourceTypeTester,用來測試Account Resource Type。 |
11 |
宣告_jsonString其內容為Resource Type的JSON 字串。 可從FHIR官方文件中取得。 |
66 |
建構元。丟Resource Type的JSON字串給父類別處理。 |
67 |
複寫父類別之SetupObject函數。 |
69 |
目標回傳一個新的Account物件。 |
71 |
設定有Id欄位。資料型態是Id,屬Primitive。 FHIR SDK有針對string寫了擴增方法來轉換成FHIR的資料型態。 為了避免與程式語言的資料型態相衝突,FHIR的Primitive資料型態,前面都加上FHIR。 |
72 - 76 |
設定Text欄位。資料型態是Narrative,屬Complex。 因為是Complex所以,是採用新增物件的方式處理。 其中Status的部分,因為有Bind到NarrativeStatus,所以可以取值。 Div雖然資料型態是XHtml,但可透過字串方式轉換。 |
77 - 84 |
設定Identifier欄位,資料型態是Identifier,屬Complex,多筆。 利用C#起始建構元特性來新增物件。 System與Value都是從字串轉成對應之FHIR Data
Type。 |
85 |
設定Status欄位。資料型態是Code。 有Bind到AccountStatus。 |
86 |
設定Name欄位。資料型態是String。 |
90 |
宣告ChangeDataTest是測試方法。 |
91 |
複寫父類別的抽象方法。 |
93 - 105 |
從JSON字串產生Resource。 隨即進行欄位更新。 Name欄位,也可以使用new 物件的方式來建構。 Subject欄位其資料型態是Reference,且為多筆。 |
106 |
測試是否可以正常產生物件。 |
107 |
使用FHIR SDK Resource的ToJsonString方法,倒出資料。 |
測試結果
測試前
測試後
2022年11月5日 星期六
HL7 FHIR 模組說明 - Level 2 Conformance
本系列要討論的是FHIR Level 2 Conformance與標準一致性有關之資源。
這類相關Resource都是用來確保標準制訂過程中的一致與相容性性,也提供了實做層級保持一致性。算是核心類Resource。下圖說明了各Resource關係。
要瞭解這些應用,得先去參考另一份文件:Profiling FHIR 文件中會說明如何製作一份Profile檔。2021年6月1日 星期二
HL7 FHIR 模組說明 - Level 4 Medications - Immunization
官方文件:
簡述:
欄位討論:
- status [0..1]: code
- 事件狀態。
- 限定:Immunization Status Codes (Required)
- {completed | entered-in-error | not-done} --> {完成 | 輸入錯誤 | 未完成}
- statusReason [0..1]: CodeableConcept
- 延續前項,沒有完成的原因。
- 參考:Immunization Status Reason Codes (Example)
- http://terminology.hl7.org/CodeSystem/v3-ActReason
- {IMMUNE | MEDPREC | OSTOCK | OATOBJ} --> {已免疫 | 因病患違反施打要求 | 缺貨 | 病患反對}
- http://snomed.info/sct
- concept is-a 310376006 (Immunization consent not given)
- vaccineCode [1..1]: CodeableConcept
- 疫苗代碼。
- 參考:Vaccine Administered Value Set (Example)
- http://hl7.org/fhir/sid/cvx
- urn:oid:1.2.36.1.2001.1005.17
- patient [1..1]: Reference(Patient)
- 施打之對象。
- encounter [0..1]: Reference(Encounter)
- 就診紀錄。
- occurrence[x] [1..1]: {dateTime | string}
- 施打日期。
- recorded [0..1]: dateTime
- 第一次施打時間。若本次是第一次施打(相同的vaccineCode時),那時間就該與occurrence相同。
- primarySource [0..1]: boolean
- 代表這份Resource的紀錄是來自第一時間施打者所寫。而非由其他系統所產生的紀錄。
- 主要是代表這份文檔的可靠度(reliability)。
- reportOrigin [0..1]: CodeableConcept
- 若不是第一時間施打者之紀錄,那本紀錄來自哪裡。
- 參考:Immunization Origin Codes (Example)
- http://terminology.hl7.org/CodeSystem/immunization-origin
- {provider | record | recall | school} --> {來自其他提供者 | 來是病患書面報告 | 來自病患本身、父母或監護人之回憶 | 來自學校紀錄}
- location [0..1]: Reference(Locatioin)
- 施打地點。
- manufacturer [0..1]: Reference(Organization)
- 疫苗製造商。
- lotNumber [0..1]: string
- 疫苗批量編號。
- expirationDate [0..1]: date
- 疫苗到期日。
- site [0..1]: CodeableConcept
- 疫苗施打在身體的哪個部位。
- 參考:Codes for Immunization Site of Administration (Example)
- http://terminology.hl7.org/CodeSystem/v3-ActSite
- 例如:
- LA --> 左臂
- RA --> 右臂
- route [0..1]: CodeableConcept
- 以什麼途徑方法進入人的身體。
- 參考:Immunization Route Codes (Example)
- http://terminology.hl7.org/CodeSystem/v3-RouteOfAdministration
- 例如:
- IDINJ --> 皮內注射
- IM --> 肌內注射
- NASINHLC --> 鼻吸入
- IVINJ --> 靜脈注射
- PO --> 口服
- SQ --> 皮下注射
- TRNSDERM --> 經皮
- doseQuantity [0..1]: SimpleQuantity
- 疫苗注射量。
- 注意單位代碼。
- performer [0..*]: BackboneElement
- 進行本次施打疫苗事件的執行者。
- 注意一個施打事件可能由很多人共同執行。
- 欄位討論:
- function [0..1]: CodeableConcept
- 這個執行者負責什麼項目。
- 參考可擴充:Immunization Function Codes (Extensible)
- http://terminology.hl7.org/CodeSystem/v2-0443
- 例如:
- OP --> 開立疫苗處方者。
- AP --> 施打疫苗者。
- actor [1..1]: Reference(Practitioner | PractitionerRole | Organization)
- 執行者詳細資料。
- note [0..*]: Annotation
- 註記。
- reasonCode [0..*]: CodeableConcept
- 為什麼要施打此疫苗原因。
- 參考:Immunization Reason Codes (Example)
- reasonReference [0..*]: Reference(Condition | Observation | DiagnosticReport)
- 為何要施打此疫苗詳細原因之參考資訊。
- isSubpotent [0..1]: boolean
- 劑量的效力。應該是指本次施打並無得到完整效能。
- subpotentReason [0..*]: CodeableConcept
- 未達全效的原因。
- 參考:Immunization Subpotent Reason (Example)
- http://terminology.hl7.org/CodeSystem/immunization-subpotent-reason
- 例如:
- partial --> 並沒給予足夠劑量。
- coldchainbreak --> 疫苗有經歷冷鏈損壞。
- recall --> 此疫苗是被製造商招回的。
- education [0..*]: BackboneElement
- 要給施打此疫苗病患之教育訓練教材。
- 欄位討論:
- documentType [0..1]: string
- 教材代碼。
- reference [0..1]: uri
- 教材的參考網址。
- publicationDate [0..1]: dateTime
- 教材出版日期。
- presentationDate [0..1]: dateTime
- 向病患展示教材的日期。
- programEligibility [0..*]: CodeableConcept
- 病患接種此疫苗的資格,或者說他是有資格取得贊助費用。
- 參考:Immunization Program Eligibility (Example)
- http://terminology.hl7.org/CodeSystem/immunization-program-eligibility
- 例如:
- ineligible --> 沒有資格獲取贊助費用。
- uninsured --> 可獲贊助費用,因為病患無保險。
- fundingSource
- 贊助施打疫苗的費用來源。
- 參考:Immunization Funding Source (Example)
- http://terminology.hl7.org/CodeSystem/immunization-funding-source
- 例如:
- private --> 來自私人採購贊助。
- public --> 來自政府採購贊助。
- reaction [0..*]: BackboneElement
- 詳細紀錄施打後的各種副作用反應。
- 欄位討論:
- date [0..1]: dateTime
- 副作用開始時間日期。
- detail [0..1]: Reference(Observation)
- 詳細描述情況。
- reported [0..1]: boolean
- 用來註記是否為自行回報。
- protocalApplied [0..*]: BackboneElement
- 來自提供者的建議(協議)。
- 太過專業,不方便闡述。