iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
自我挑戰組

30天FUME TO FHIR轉換實戰 - 從入門到燃燒殆盡系列 第 19

[FUME TO FHIR] 19 FUME Mapping Language(FLASH)

  • 分享至 

  • xImage
  •  

VI.FUME

19 FUME Mapping Language(FLASH)

今天要來正式介紹FUME Mapping的撰寫,前面有簡單帶過,FUME是由JSONata與FLASH(modified from FSH)所組成,

FLASH負責結構描述的部分、JSONata則負責運算、數據操作等程式部分。

還是不免俗的先將兩個Documentation附上:
https://www.fume.health/docs/release-notes/community
https://docs.jsonata.org/overview.html

https://www.fume.health/docs/flash/

FLASH在最開始的開頭,有一個很重要的概念要提及,

FLASH本身是使用 * 作為開頭,並且是依照層級區分的,因此空格會影響到輸出的正確性,請特別注意

FLASH由幾個宣告做開頭:

InstanceOf: <type>

  用來宣告這個Resource的型別是什麼,如

  InstanceOf: Patient
  InstanceOf: bp
  InstanceOf: http://hl7.org/fhir/StructureDefinition/bp

  支援單純型態、profile的引入

 Instance: <expression>

  用來指派這個Resource的logical ID,但目前筆者不太會使用到

 * <context element> (Context Rule)

  描述FHIR Resource的核心語法,像是:

  #FUME:
  * identifier
    * value = mrn

  ↑ identifier下有value的屬性項,而value的值被指派為輸入端的mrn

  FUME的特性1:如果這個輸入端的mrn能夠從輸入中被找到,

#INPUT:
  {
   "mrn" : "12345"
  }

  
  FHIR輸出端就會建立

  #FHIR:
  "identifier": [
       {
        "value": "12345"
       }
  ]

 * (context).<element> (Input Context)

  這個比較複雜一點,用表達的方式會比較像是:
  今天IG欄位有一個項稱作deviceName,他的Cardinality是0..*,也就是非必填無上限
  前者的context是輸入的來源物件,後者的element是FHIR格式內的屬性

  #FUME:
  * (device_deviceName).deviceName
          * name = device_deviceName_name
          * type = device_deviceName_type

  ↑ 有一個輸入項長成這樣,其中包含了兩個屬性項 device_deviceName_name與device_deviceName_type:
  

  #INPUT:
  "device_deviceName" : [
       {
         "device_deviceName_name" : "deviceName",
         "device_deviceName_type" : "deviceType"
       }
  ]

  之所以這樣撰寫的原因是因為,遇到複數或複合的輸入欄位時,輸入也會需要進行調整,
  所以上面那行FLASH的意思是,找稱作device_deviceName的物件,讓下面的屬性項與device_deviceName的兩個項相映射
  
  結合剛剛講的特性1,如果device_deviceName不存在於輸入端,deviceName的FHIR欄位將不會被建立
  並且,假設device_deviceName只填入device_deviceName_name,FHIR輸出端只會建立:
  

  #FHIR:
  "deviceName": [
              {
                "name": "deviceName"
              }
        ]

  還有一個可以講的東西是,這裡的(context)是可以接運算式的,如:

  * (k_dat_leom != null ? k_dat_leom).extension[religion]
    * valueCodeableConcept

  這個範例代表了若k_dat_leom非空,則該extension[religion]的部分由k_dat_leom的分項內容填入

 * <element>[sliceName] (Slices)

  這個也比較少用一點,這個是另一種呈現複合型態的方式,前面的element表示FHIR的屬性欄位,sliceName則是這個element的子分項,
  可以用這個方法來表達複合屬性內的屬性對應

* extension[birthPlace]
    * valueAddress
      * country = "USA"

  ↑ 上面的例子代表在birthPlace這個extension內,他的valueAddress.country是"USA"
  
 
 假設某個Patient Profile規定必須要有2個identifier屬性項,其中一個對應身分證號,另一個對應病歷號,該怎麼做
 
 這時候有兩個實作思路可以選擇:
 
 1. 把複合欄位交給輸入端,FUME Mapping只用* (context). 處理
 
 EX:

#INPUT:
  "patient_identifier" : [
{
"use" : "official",
"code" : "NNxxx",
"system" : "http://terminology.hl7.org/CodeSystem/v2-0203",
"value" : "A123456789"
},
{
"use" : "official",
"code" : "MR",
"system" : "http://example.com/",
"value" : "123456789"
}
  ]

#FUME:
  * (patient_identifier).identifier
    * use = use
    * code = code
    * system = system
    * value = value

 這個例子中,輸入端把資料都包含在patient_identifier中,FUME只需要用複合元素映射去對應就好
 
 2. 在FUME Mapping中把兩個identifier都先定義好,輸入端只需要少少的輸入即可
 
 EX:

#INPUT:
  "patient_identifier_id" : "A123456789",
  "patient_identifier_mr" : "123456789",
  "patient_identifier_mr_system" : "http://example.com/"

#FUME
  * identifier
    * use = "official"
    * code = "NNxxx"
    * system = "http://terminology.hl7.org/CodeSystem/v2-0203"
    * value = patient_identifier_id
  * identifier
    * use = "official"
    * code = "MR"
    * system = patient_identifier_mr_system
    * value = patient_identifier_mr

 
 兩個方法都是通的,只是實作上重心會偏向哪一方,以實作FUME提供服務的角度來說,
 我們應該盡可能讓使用者(提供源資料)的必填以外的輸入保持完整性的情形下,越少越好
 所以實務上筆者會更推薦使用第二種方法,不過這個實際上還是要跟提供資料的使用者溝通,
 畢竟很多時候欄位是很難省下來的,特別是關於Terminology的場合。這點後面會有case能夠討論。
 
 
 從這裡開始討論FUME的東西知識點會變得很發散,因為是根據筆者實作與理解的經驗彙整而成,
 要如何把這些東西語言組織化並不容易,有想到會盡量寫。
 
 根據範例內提供的Patient,其實目前所講的東西還不足以完整包含到撰寫整個Resource,
 
 明天我會針對這個範例來詳細講解,希望讓讀者更快的進入狀況


上一篇
[FUME TO FHIR] 18 FUME Community 安裝, 環境設定
下一篇
[FUME TO FHIR] 20 實際建立一筆Patient的FUME Mapping
系列文
30天FUME TO FHIR轉換實戰 - 從入門到燃燒殆盡30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言