メインコンテンツまでスキップ

マッピングセッティングプロファイル仕様

1.概要

マッピングセッティングプロファイルは、FHIRリソースに関連するデータ変換・生成のための言語です。
変換元のデータはCSVのほか、FHIRリソース、各種メディアなどを想定しています。 変換先のデータはFHIRリソースのほか、CSVを含むテキスト、異なるバージョンのFHIRリソース などを想定しています。

制約:

  • 現バージョンではCSVファイルからm文書n情報を生成するために必要な機能のみを実装しています。

以下は2つのCSVファイルからPatientリソースを生成するプログラム例です。

* $PatientIdentification = files(PatientIdentification.csv)    // 患者情報ファイル
* $PatientAddress = files(PatientAddress*.csv, HIS_PATIENT_ID) // 患者住所ファイル
<<context Identification, $PatientIdentification // 患者レコード毎ループ
* $Patient = createResource(Patient,${HIS_PATIENT_ID}) // リソースを作成
* $Patient.birthDate = YYYYMMDD2date(${BIRTHDATE}) // 誕生日を設定
* $Patient.gender = HIS_SEX2gender(${SEX}) // 性別を設定
<<context Address, $PatientAddress.get(${HIS_PATIENT_ID}) // CSVファイルをネスト
* $Patient.address[+].postalCode = ${POSTAL_CD} // 郵便番号
* $Patient.address[=].period.start = YYYYMMDD2date(${PA_START_DATE}) //開始日
* $Patient.address[=].period.end = YYYYMMDD2date(${PA_END_DATE}) //終了日
>>
>>

変換プログラムは上から順に実行します。

<<, >>で囲まれた部分はループです。

マッピングセッティングプロファイル処理系はCSV変換を簡潔に記述するための機能を内蔵しています。

  • PatientIdentification.csvという名前の患者情報ファイルのレコードごとに外側のループを繰り返します。
  • ${<カラム名>} という形式でCSVレコードが含む文字列を参照できます。
  • CSVファイルを特定のカラムの内容でグループ分けできます。
    「files(PatientAddress*.csv, HIS_PATIENT_ID)」はHIS_PATIENT_IDの値でグループ分けをしています。「$PatientAddress.get(${HIS_PATIENT_ID})」でグループをとりだし、その値でつぎのループを回しています。

マッピングセッティングプロファイルが処理するデータの型には、つぎのものがあります。

  • 文字列型
  • 数値型(整数またはBigDecimalで表現される)
  • boolean型(真偽値。定数は「$$$_true」と「$$$_false」)
  • null型(表記は「」)
  • List型(添え字が0~の整数)
  • Map型(添え字が文字列)
  • Tree(樹状のデータ構造)
  • レコードセット型(CSVファイルから得たレコード群)
  • リソース型(FHIRリソース。HL7が提供するJavaライブラリによる実装)

$で始まる英数字の文字列は変数名です。

「files(PatientIdentification.csv)」などは関数呼び出しです。マッピングセッティングプロファイル処理系が提供するシステム関数に加え、マッピングプロファイル(.frumap で関数を定義できます。

上記のプログラムで「PatientIdentification.csv」や「Patient」はRaw文字列と呼ぶ文字列定数です。 Raw文字列はつぎの書式を持ち、代入文の右辺と関数の引数に置くことができます。

  • 英字で始まる英数字の文字列

つぎの場所にはRaw文字列が置けます。逆にここへ式を置く場合にはかっこ「」「 」で囲む必要があることに注意してください。

  • 代入文の右辺
  • 関数呼び出しの引数
  • execのパラメータや関数引数の初期化での「=」の右辺

サンプル(3文書6情報の一部):Patient基本情報を生成するマッピングプロファイル

サンプル(Patient)

以下は、患者基本情報からPatientリソースへ変換して永続化するサンプルです。
マッピングセッティングプロファイルの構文(例:files(...)で入力読込、<<context>>のループ、FHIRリソースへの代入、commit()で保存)を理解する際にお役立てください。詳細は本仕様の各章をご参照ください。
実行手順(ZIP・API)はCSV変換手順 > クイックスタート(Patient)を参照してください。

// -*- coding: utf-8 -*-

// 初期化
//readConversionTables()

* $PatientResult = files(_INPUT/patient_sample.csv)
<<context Result, $PatientResult

<if ${IS_CHILD_RESOURCE} = ('TRUE')
* $PatientRoot = createChildResource(Patient)
><else
* $PatientRoot = createResource(Patient, ${PATIENT_ID})
>
print -----, columns()

// 準拠プロファイル
* $PatientRoot.meta.profile[+] = 'http://jpfhir.jp/fhir/eCS/StructureDefinition/JP_Patient_eCS'
<if ${IS_CHILD_RESOURCE} != ('TRUE') or ${HAVE_LAST_UPDATED} = ('TRUE')
* $PatientRoot.meta.lastUpdated = getNow()
>
// 被保険者個人識別子
* $PatientRoot.identifier[+].use = usual
* $PatientRoot.identifier[=].system = 'http://jpfhir.jp/fhir/clins/Idsystem/JP_Insurance_memberID'
* $PatientRoot.identifier[=].value = ${INSURANCE_ID}

// 自施設の患者番号
<if ${PATIENT_ID} != '' and ${INSTITUTION_NUMBER} != ''
* $PatientRoot.identifier[+].use = usual
* $PatientRoot.identifier[=].system = ('urn:oid:1.2.392.100495.20.3.51.1' + ${INSTITUTION_NUMBER})
* $PatientRoot.identifier[=].value = ${PATIENT_ID}
>

// 姓名
* $PatientRoot.name.text = (${FAMILY_NAME} + ' ' + ${GIVEN_NAME})
* $PatientRoot.name.family = ${FAMILY_NAME}
* $PatientRoot.name.given[+] = ${GIVEN_NAME}
* $PatientRoot.name.extension[+].url = 'http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation'
* $PatientRoot.name.extension[=].valueCode = IDE

// カナ姓名
<if ${FAMILY_NAME_KANA} != '' and ${GIVEN_NAME_KANA} != ''
* $PatientRoot.name[+].text = (${FAMILY_NAME_KANA} + ' ' + ${GIVEN_NAME_KANA})
* $PatientRoot.name.family = ${FAMILY_NAME_KANA}
* $PatientRoot.name.given[+] = ${GIVEN_NAME_KANA}
* $PatientRoot.name.extension[+].url = 'http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation'
* $PatientRoot.name.extension[=].valueCode = SYL
>

// 性別
* $PatientRoot.gender = ${GENDER}

// 生年月日
* $PatientRoot.birthDate = toDate(${BIRTH_DATE})

// 住所
* $PatientRoot.address.text = ${ADDRESS_TEXT}
* $PatientRoot.address.state = ${ADDRESS_STATE}
* $PatientRoot.address.city = ${ADDRESS_CITY}
<if ${ADDRESS_POSTALCODE} != ''
* $PatientRoot.address.postalCode = ${ADDRESS_POSTALCODE}
>
<if ${ADDRESS_LINE} != ''
* $PatientRoot.address.line[+] = ${ADDRESS_LINE}
>

$$$patients[${PATIENT_ID}] = $PatientRoot
>>

<<function public getPatient($patientId)
return $$$patients[$patientId]
>>

// ------------------ 以下変換関数
// 初期化
<<function readConversionTables()

// なし

>>

// 変換定義ファイルの読み込み
<<function makeMap($filename)
print $filename
$input = files(_CONVERTER/map/$($filename).csv)
<<context csv, $input
* $$$conv[$filename][${param1}].system = ${system}
* $$$conv[$filename][${param1}].code = ${code}
* $$$conv[$filename][${param1}].display = ${display}
>>
>>

// 変換
<<function conv($fileName,$param1)
$ret = $$$conv[$fileName][$param1]
// 処理が必要な場合はここで定義
return $ret
>>
ヒント

本サンプルのCSV配置・ZIP化・API実行は、CSV変換手順のルールに従ってください。(input/definition/の2階層、ZIPファイルをBase64エンコードした文字列で送るなど )

2.ファイル

マッピングプロファイル(.frumap)と入力データはマッピングパックというデータとしてマッピングセッティングプロファイル処理系に渡されます。
マッピングパックはファイルシステムのフォルダ構造を抽象化したもので、「/」で区切られたパスと対応するファイル本体の並びを保持します。

マッピングパックが保持するファイルはテキストファイルとバイナリファイルの2種類です。 これらはマッピングパックが生成されるときに拡張子で区別します。

テキストファイルはUTF-8エンコーディングされ、LF(\n)で改行します。 マッピングプロファイル(.frumap とCSVファイルはテキストファイルでなければなりません。

マッピングセッティングプロファイル処理系が扱うCSVファイルはつぎの形式です。

  • カンマ「,」でレコードを区切る。
  • カンマなどのエスケープはExcel準拠とする(Apache commons CSVを使用)
  • 先頭行でカラム名を定義する。

制約:

  • ファイルパスには一般のOSのファイル名として使える文字が使えます。しかしマッピングセッティングプロファイル処理系では正規化などの処理を行っていないため、見た目が同じでも異なるコードを使ったファイル名を同一のものとして扱えません。したがって、ファイルパスとファイル名には英数・アンダースコア・ハイフンのみを使うことを推奨します。

実行時にマッピングセッティングプロファイル処理系へつぎの2つのマッピングパックが渡されます。

  • _CONVERTER:変換プログラムと変換データ
  • _INPUT:入力データ(csvファイルなど)

実行プログラム(起動プログラムやexecで指定するプログラム)は_CONVERTERマッピングパックから読み出します。

関数「files」と「listFilenames」では引数にファイルパスのglob表現を指定できます。 いずれもデフォルトでは_INPUTマッピングパックを対象として処理します。

用語変換などに使うCSVファイルを入力データではなく変換定義の方に含める場合にはパスの先頭に「_CONVERTER/」を付加することで変換定義のファイルを扱うことができます。 入力ファイルを明示的に指定する場合には「_INPUT/」を付加します。 「_CONVERTER/」と「_INPUT/」をglob表現のワイルドカードとして含めることはできません。

記述例

$csv = files('csvs/patient.csv')
特定のファイルを読み込む。
ワイルドカード「*」「?」を含まないので、指定したファイルが存在しなければエラー停止する。

$csv = files('**/*.csv')
$csv = files('_INPUT/**/*.csv')
入力データのマッピングパックからすべてのCSVファイルをパスの辞書順で読み込む。
該当するファイルが1個も存在しない場合にはエラーではなく長さゼロのデータを読み込む。

$csv = files('_CONVERTER/**/*.csv')
変換データのマッピングパックからすべてのCSVファイルをパスの辞書順で読み込む。
該当するファイルが1個も存在しない場合にはエラーではなく長さゼロのデータを読み込む。

3.プログラム

関連するプログラムは1個のマッピングパックとしてマッピングセッティングプロファイル処理系に渡されます。

プログラムはどのディレクトリへ置いても拡張子をはずした名前で呼び出せます。 「Group1/Observation.frumap」は「Observation」という名前で呼び出します。

プログラムはメインプログラムとユーザ定義関数で構成します。

先頭行から、最終行あるいは最初のユーザ定義関数が現れるまでがメインプログラムです。 ユーザ定義関数を定義したあとにメインプログラムを書くことはできません。

たとえば、つぎの3種類のプログラムで1群の機能を構成するような使いかたができます。

  • 全体制御
    リソースを生成する順番や、Compositionの構成を記述します。
  • リソース生成
    リソース種ごとに生成方法を記述します。 ただし、プログラミング上の都合で1個のリソース種に複数のプログラムが対応することや、 同一のCSVデータセットから同時に複数のリソースを生成することもあります。
  • 変換関数
    リソース生成などに必要な関数を定義します。

4.変数

変数には通常変数とカラム変数の2種類があります。

4.1.通常変数

一般的なプログラミング言語の変数と同様に、あるスコープの中で値を保持し参照できる変数です。

通常変数の書式はつぎの通りです。

<スコープ種別><変数名>

<スコープ種別> つぎのいずれか
$ : ローカル変数
$$ : 関数ローカル変数
$$$: グローバル変数

<変数名> :先頭が英文字で英・数・アンダースコアから構成する文字列
例:
$a
$$j_12
$$$A

先頭がアンダースコアの変数名はマッピングセッティングプロファイル処理系の予約名です。 現時点では利用可能ですが、将来的に使用不可となる場合があります。

以下にスコープごとの変数の特性・使い方について説明します。

4.1.1.ローカル変数

メインプログラム・関数、ループなどで区切られたプログラム内で有効な変数です。

  • 定義時に1回だけ書き込み可能です。
  • ループ内で定義したローカル変数は、ループの繰り返しごとに消去します。
  • 書き込みされていないローカル変数を読み出すことはできません(エラー終了します)。
  • 他のメインプログラム・関数からローカル変数を読むことはできません。
  • 同じ名前のローカル変数と関数ローカル変数は定義できません。
  • メインプログラム・関数内で同じ名前のローカル変数は複数定義できません。 ただしループ内でシステムが定義する$_lineなどの変数は、多重ループにおいて複数定義されることがあります(後述)

例:

「$x」はループの先頭で毎回定義され、ループの繰り返し時点で毎回消去されます。

<<for $x: range(1, 5)
print $x
>>

関数の引数はローカル変数としなければなりません。

<<function example($arg)
print $arg
>>

4.1.2.関数ローカル変数

メインプログラム・関数内で有効な変数です。

  • 何回でも書き込み可能です。
  • 書き込みされていない関数ローカル変数を読み出すことはできません(エラー終了します)。
  • 関数ローカル変数は、メインプログラム・関数を終了したときに消去します。
  • 他のメインプログラム・関数から関数ローカル変数を読み書きできません。
  • 同じ名前のローカル変数と関数ローカル変数は定義できません。

例:

$$count = 0
<<while $$count < 5
* $$count = ($$count + 1)
print $$count
>>

4.1.3.グローバル変数

すべてのメインプログラム・関数から読み書きできる変数です。

  • 何回でも書き込むことが可能です。
  • 書き込みされていないグローバル変数を読み出すと「」(null)値が得られます。

例:

$$$xが書き込み済であればその値をプリントします。
まだ書き込みがなされていない場合にはエラーにはならず「{}」null値をプリントします。

print $$$x

4.2.カラム変数

CSVファイルのカラム値を格納することからカラム変数と呼びます。 メインプログラム・関数の呼び出しを越えて読み出すことが可能です。 詳細な操作をするプログラムが大局的なプログラムと引数渡しを介さずに情報を共有するための 機能です。 カラム値のほかシェルスクリプトの環境変数のような使い方ができます。

書式はつぎの通りです。

 ${<カラム名>}

<カラム名>;任意の文字列。ただし連続する空白(\u0020)は1文字とし、先頭と後尾の空白は削除する。

例:

${HIS_PATIENT_ID}

プログラマがカラム変数を定義する方法はつぎの通りです。

  • <<contextループによるCSVファイル
  • exec文のパラメータ

exec文によるメインプログラム読み出し、関数呼び出し、多重ループにおいて、呼び出された側や内側のループから、呼び出し元や外側のループで定義されたカラム変数はすべて読み出せます。

同じカラム名でカラム変数を定義しなおすことは可能です(「コンテキスト」の項参照)。

制約:

  • マッピングセッティングプロファイル処理系では正規化などの処理を行っていないため、見た目が同じでも異なる文字コードを使ったカラム名を同一のものとして扱えません。したがって、日本語や\u0020以外の空白文字を使ったカラム名は推奨しません。
  • マッピングセッティングプロファイル処理系_(アンダースコア)で始まるカラム名を予約します。マッピングプロファイル作成者はアンダースコアで始まるカラム名を使うことはできますが、将来システムを提供する機能にアクセスしにくくなる可能性があります。

4.3.システム変数

システムが値を設定する変数をシステム変数と呼びます。 マッピングセッティングプロファイル処理系_(アンダースコア)で始まる変数名をシステム変数用に予約しています。

マッピングセッティングプロファイル処理系は、マッピングプロファイル作成者による_(アンダースコア)で始まる変数名を禁止はしていません。 たとえばカラム変数ではそのようなカラム名がすでに使われている可能性があります。

  • 今後カラム変数以外の変数名での先頭の_(アンダースコア)を禁止する可能性があります。
  • システム変数と同じ名前の変数を定義したときには、システム変数へアクセスできなくなる可能性があります。

現在までに定義しているシステム変数はつぎの通りです。

  • boolean値の定数。
    マッピングセッティングプロファイル構文でboolean定数を定義していないためグローバル変数として提供しています。
    • $$$_true : 真
    • $$$_false: 偽
  • <<contextループの現在の実行状態を示す変数多重ループでは内側のループの値が読めます。内側のループが終了すると外側のループの値が復活します。
    • $_path:処理中のCSVファイルのパス名
    • $_file:処理中のCSVファイルのファイル名
    • $_line;処理中レコードの行番号(カラム名の行のつぎの行が「1」)
    • $_count:ループの実行回数(最初は1から)
  • カラム変数
    • ${_SEQUENTIAL_UUID}:値が設定されている場合にuuid()、getNow()などが規則正しい値を返します。(デバグ・テスト時に生成されるデータで再現性を持たせるためなどに使います)

4.4.コンテキスト

変数はコンテキストと呼ぶマッピングセッティングプロファイル処理系の記憶領域に格納します。

コンテキストはつぎの処理ごとにスタックへ積まれます。

  • メインプログラムの実行開始
  • execによるメインプログラムの実行
  • 関数呼び出し
  • ループの開始

カラム変数の読み出しでは、スタックの上端から下端へ向かって指定されたカラム名を探索し、 最初にみつかった値を返します。 したがって同名のカラム変数を定義したときには、それまでに定義されたカラム変数は読めなくなり、ループの終了などでコンテキストスタックが戻されたときに元のカラム変数が読めるようになります。

制約:

  • 現状では、同名のカラム変数で隠されたカラム変数を読み出す方法は用意していません。

コンテキストにはローカル変数や関数ローカル変数も格納されています。 stackTrace関数で実行位置でのコンテキストスタックの状態を表示できます。 <<contextなどのループにはコンテキスト名を付与できます。コンテキスト名はcontinueなどのループ制御に利用できるほか、stackTraceの可読性を高めます。

stackTraceの表示例です。

プログラム(0020variable.frumap)

// -*- coding: utf-8 -*-
// 変数の有効範囲テスト

print ('-------------'+${_SEQUENTIAL_UUID})
<<for forloop, $$v : range(1, 1)
func1($$v)
print ('---' + toString($$v))
func2($$v)
print ('---' + toString($$v))
func3($$v)
print ('---' + toString($$v))
>>



<<function func1($parm)
$$v=3
print $parm
$csv = readCSV('0018loop.csv')
<<context Inner, $csv
print 1, ${value}
exec '0020call' test1=111, test2=222
<if ${value} = 'D'
return
>
>>
>>

<<function func2($parm)
<<for $$v : range(20, 23)
print 2, $$v
<if $$v = 22
return
>
>>
>>

<<function func3($parm)
$$v = 0
<<while $$v < 5
print 3, $$v
<if $$v = 3
return
>
$$v = ($$v + 1)
>>
>>

<<function func1($parm)
$$v=3
print $parm
$csv = readCSV('0018loop.csv')
<<context Inner, $csv
print 1, ${value}
exec '0020call' test1=111, test2=222
<if ${value} = 'D'
return
>
>>
>>

プログラム(0020call.frumap)

// -*- coding: utf-8 -*-

$x = 123
print stackTrace()
print '====='
print columns()

0020call.frumap:4での「print stackTrace()」出力

  ++ 6 stackTrace	(subdir/0020call.frumap:4):print stackTrace()
++ 5 0020call.frumap (0020variable.frumap:22):exec '0020call' test1=111, test2=222
-- Variables:
$x:123
-- Columns:
${test2}:222
${test1}:111
-- 4 Inner (0020variable.frumap:20): <<context Inner, $csv
-- Variables:
$_file:0018loop.csv
$_count:1
$_path:0018loop.csv
$_line:1
-- Columns:
${value}:A
++ 3 func1 (0020variable.frumap:6): func1($$v)
-- Variables:
$csv:RecordSet(0018loop.csv)
$parm:1
$$v:3
-- 2 forloop (0020variable.frumap:5):<<for forloop, $$v : range(1,1)
-- Variables:
++ 1 0020variable.frumap
-- Variables:
$$v:1
-- Columns:
${_SEQUENTIAL_UUID}:true

  • 左側に「++」と表示されているのはメインプログラム・関数によって生成されるコンテキストです。関数ローカル変数・ローカル変数・カラム変数がこのコンテキストに格納されています。 メインプログラム名や関数名が表示されています。
  • 左側に「--」と表示されているのはループによって生成されるコンテキストです。ローカル変数・カラム変数がこのコンテキストに格納されています ループに名前をつけた場合にはここに表示されます。「forloop」、「Inner」などがループ名です。

5.Raw文字列

Raw文字列はつぎの書式を持ち、代入文の右辺と関数の引数に置けます。

  • 英字で始まる英数字の文字列

数字で始まる文字列や記号を含んだ文字列をRaw文字列のおける場所へ置く場合には、つぎのようにします。

  • 任意の文字列。引用符「'」で囲みます。 * $x = '123-12'
  • 式は「(」と「)」で囲みます。 * $x = ('10-'+$a)
  • Raw文字列を置ける場所には関数を置けます。 * $x = int2str($a,4,' ')

カンマ「,」はRaw文字列ではなくRaw文字列の区切りとして認識します。

つぎの例ではprint文のパラメータが2つあり、実行結果の出力は「Hello World」となります。

print Hello, World

制約:

  • 様々な文字列を扱えるようにRaw文字列の仕様拡張を検討中です。上記以外の文字列を書いても正常に動作することがあります。今後実装の変更で扱えなくなる可能性がありますので、「英字で始まる英数字の文字列」以外の文字列は引用符「'」で囲んだ定数として記述してください。

6. データ型

6.1. Null型

null値は値が無いことを示す値です。未定義の変数を参照したことや値の設定されていないFHIRpathを参照したことをnull値として表します。

定数としての表記はFHIRPathにならって「」です。

  • 代入していないグローバル変数を参照するとnull値が返ります。
  • 左辺がパス式である代入文へ左辺値としてnull値を適用すると何もしません。
    空白文字列を適用したときにはエレメントが削除されたり空白が代入されたりするのとは動作が異なります。
  • null値と他の値との「=」による比較は偽、null値どうしの「=」による比較は真となります。

6.2. 論理型

真、偽の論理値を保持します。

文法に定数を定義していませんが、システム変数「$$$_true」「$$$_false」で真偽値を使えます。

例 :

if文の条件は論理型の値を持ちます。

<if $n < 0
...
>

6.3. 文字列型

Unicode文字列です。

シフトJISなど他の文字コードが元データであってもマッピングセッティングプロファイル処理系にはUnicodeへ変換して渡されます。

カラム変数の値はすべて文字列型です。

ソースコードでの文字列定数の表現はつぎのものがあります。

  • Raw文字列
    代入文の右辺や関数引数などの式が置けるところに置けるが、演算式の中には置けない。
    例:Patient

  • FHIRPath文字列
    「'」で囲まれた文字列。式の中で使うことができる。
    FHIRPathの文法で定義されている文字列。
    例:'This is a pen.'

つぎの表記で「123」はRaw文字列であり数値型ではないことに注意してください。

* $x = 123
* $x = func(123, 123)

数値として扱う場合にはつぎのように記述します。

* $x = (123)
* $x = toNumber(123)
* $x = func((123), toNumber(123))

if文などの条件式は式であるため、数値として扱います。

<if $x = 123
...
>

6.4. 数値型

内部的にはBigDecimalで表現される数です。

何も指定せずに「123」と書くとRaw文字列であることに注意します。 演算式の中に「123」と書くと数として扱われます。

例 :

$a = (123)

制約:

  • 現状ではマッピングセッティングプロファイルインタープリタの演算子は精度を扱いません。 ただし、CSVファイルからの入力を精度を保ったままリソース型のエレメントへ代入できます。CSVファイルのカラムから生成したカラム変数の値は精度を保持した文字列です。これを後述するリソース型のエレメントへ直接代入する場合には精度を保存します。

6.5. List型

List型は要素として任意の型を保持する配列です。

代入文の左辺の添え字にはつぎの記号を置けます。

  • [] (カッコのみ) リストが空であれば1個の要素を追加し、空でなければ最後の要素を指します。
  • [+] リストの最後に1個の要素を追加し、その要素を指します。
  • [=] リストの最後の要素を指します。リストが空ならエラーとします。
* $a[] = 1  // Listに値を追加します。
* $a[+] = 2 // Listに値を追加します。
* $a[=] = 3 // Listの最後の要素を上書きします。
* $a[2] = 4 // Listの(0番目から数えて)3番目の要素として代入します。
* $a[6] = 5 // 要素を飛ばして代入すると、飛ばされた場所には「{}」(null値)が入ります。
* $a[7][+] = 6 // Listの要素をListとすることができます。
print $a

→ print文の出力
[1,3,4,{},{},{},5,[6]]

6.6. Map型

Map型は文字列をキーとし任意の型を保持する連想配列です。

* $m['abc'] = 1
* $m['def'][+] = 2
* $m['def'][+] = 3

print $m

→ print文の出力
['abc':1,def:[2,3]]

6.7. Tree型

Tree型は名前のついた枝をもつ木構造を保持します。

* $t.a = 1
* $t.b.c = abc
* $t.b.d = def
print $t

→ print文の出力
[.a:1,.b:[.c:abc,.d:def]]

Tree型はMap型に似ていますがつぎの点が違います。

  • 枝の名前に使えるのは、英文字で始まる英数アンダースコアの文字列のみ。
  • 枝の定義順を記録している。print文ではその順番で要素を表示する。

6.8. RecordSet型

CSVファイルから得たレコード群です(詳細は「レコードセットとContextループ」の章参照)。

例 :

* $PatientAddress = files(PatientAddress*.csv, HIS_PATIENT_ID)

6.9. リソース型

HL7ライブラリのリソースを保持する型です。

  • commit関数によってリソースをFRUCtoSへ永続化します。 この動作の詳細については「リソース型のライフサイクル」の章を参照してください。
  • FHIRPathのサブセットを使ってエレメント値を書き換えることができます。
    • 同形で型が一致するTree型の値を一括して代入できます。
    • List型のエレメントへスカラ値を代入する場合には、 List要素がなければ追加する演算([])を実行します。
    • 左辺がFHIRパスの代入文では、右辺がnull型のときにはなにもしません。 CSVファイルの値が誤っていたり存在しないときなどに値を代入しない動作を実現するために 使えます。

制約:

  • FHIRPathのつぎの機能のみを使えます。
    • エレメントを名前で直接指定する。
    • Listの添え字([]の内側)ではつぎの表記のみが使えます。
      • [+]
      • [=]
      • [<整数値となる式>]
  • 代入文の右辺や式の中にFHIRPathを置いてエレメント値を参照する機能は未実装です。 コンパイル時にはエラーになりませんが、実行時にエラーとなります。
  • 要素にListを含むTree型の値は代入できません。 FHIRPathのエレメントへTree型を代入するとき、エレメントがListで対応するTree型の要素がスカラの場合には、Listへの追加([+])演算を適用します。

例 :

* $v.coding.code = '123'
* $v.coding.system = 'http://example.com'
* $ObservationRoot.valueCodeableConcept = $v

の結果は以下と同じになります。

* $v.code = '123'
* $v.system = 'http://example.com'
* $ObservationRoot.valueCodeableConcept.coding[+] = $v

7. 式、演算子、演算式

代入文の右辺、関数の引数、配列のインデクス、埋め込み式などで式を指定できます。

式はつぎのいずれかです。

  • 変数あるいはパス式
    • パス式とはList型やTree型変数の要素を指定する式です。
      例:$a[1] $a.b.c $a['label'][2]など。
  • 関数呼び出し 例:func('abc')
  • 演算式 カッコ「(」「)」で囲んだ式。 例:($x+1)

Raw文字列を置ける場所では、Javaなどの他の言語と違い数式を代入したり引数としたりする場合にカッコ「(」「)」で囲んだ演算式として記述する必要があることに注意してください。

$x = 123   // 「123」はRaw文字列。$xに文字列「123」を代入する。
$x = (123-11) // 「(123-11)」は式。$xには数値「112」を代入する。
$x = ('abc'+'def') // 「('abc'+'def')」は式。$xには文字列「abcdef」を代入する。

制約:

実装済の演算子はつぎの通りです。

  • 数値: 四則(+ - * / %)比較(<= >= > < = !=)
  • 論理: and or
  • 文字列: 結合(+)

8. ステートメント

マッピングセッティングプロファイルは改行をステートメントの区切りとして認識します。

8.1. コメント

コメントにはつぎの2つの形式があります。

  • 「//」から改行まで
  • 「/*」から「*/」まで

インデント(行頭の空白)と行末あるいは//コメントまでの空白はすべて無視します。

8.2. 代入文

代入文はつぎの形式です。

* 左辺 = 右辺

例:
* $x = 'abc'
* $y.z = (123)

左辺には、変数あるいはパス式を置きます。

右辺には、文字列、変数、または式を置きます。

行頭の「*」は省略可能です。 fshファイルとの見た目を合わせるために置いています。

8.3. 関数呼び出し

返り値がない、あるいは無視する関数呼び出しです。

関数名([パラメータ[,パラメータ]])

例:
commit()

8.4. print文

パラメータの値を書き出します。

print <式>[,<式>]]

例:
print Hello, world
print stackTrace()

printという名前の関数と区別するために、演算式を書く場合には「print」と「(」の間に空白を入れます。

8.5. 条件文

条件によって処理を切り替えます。 実行ブロックを<>によって区切ります。

複数の条件をつなげるときには><を使います。 ><> <のように分離したり別の行に分けたりはできません。

例:

<if $x=1
print 1
><elseif $x=2
print 2
><else
print other
>

8.6. ループ文

すべてのループはコンテキストを生成します。 ループの中で定義されたローカル変数はそのループの中でのみ有効で、 ループをまわるごとにリセットされます。

以下の例でlabel1~label3はループに付けた任意の名前です(省略可)。

ループの中ではつぎの文を使えます。

  • break文 ループを終了します。
  • continue文 つぎのループを実行します。

以下の例ではlabel1~3はループの名前です。ループの名前はbreak文やcontinue文の対象を指定するのに使えます。また、stackTrace関数ではコンテキストの名前として表示します。

例:

<<context label1, $PatientAddress.get(${HIS_PATIENT_ID})
...

>>

<<for label2, $component: $Observation.component
...
>>

<<while label3, $$x > 0
...
>>

8.7. exec文

他のファイルのメインプログラムを実行します。

  • メインプログラムの実行が終わると戻ってきて処理を継続します。
  • パラメータはカラム変数として呼ばれた側に渡されます。
exec <プログラム名>([<パラメータ>[, <パラメータ]])

例:
exec Patient(INPUT=PatientIdentification.csv)

8.8. 関数定義

関数定義はつぎの形式のいずれかです。

<<function [public] 関数名 ([パラメータ[, パラメータ]] )
...
返り値>>


<<function [public] <関数名 ([パラメータ[, パラメータ]] ) 返り値代入先
...
>>

値を返さない場合には最後の行は「>>」のみとします。

関数は「関数名」で呼び出します。 関数名はつぎの順番で探索します。

  1. 同一プログラムファイル内で定義されている関数
  2. 他のファイル内で定義されておりpublicと宣言されている関数
  3. システム関数

システム関数は、マッピングセッティングプロファイル処理系が用意している関数です。 (表「MappingFunctions.xlsx」を参照してください。)

システム関数と同名の関数を作るとシステム関数の機能を上書きできます。 この場合にシステム関数を呼び出すには関数名の先頭に_(アンダースコア)をつけます。

9.レコードセットとcontextループ

レコードセットはCSVファイルの内容を保持するデータ型です。

  • CSVファイルの1行目からカラム名を取得します。 (それ以外のケースにも今後対応)
  • 1行を1レコードとし、カラム内の文字列値をそのカラム名へ対応させます。

レコードセットは生成する関数filesの引数によって2種類あります。

  • 単純レコードセット
    「files(<ファイル名>)」レコードセットの並びで、contextループではすべてのレコードを 順番に処理します。カラム変数にはすべてのカラム値をマップします。
  • 分類済レコードセット 「files(<ファイル名>, <カラム名>[, <カラム名>])」指定したカラムの値で分類したレコードセットです。
    • contextループでは、存在するすべてのカラム値の組み合わせをカラム変数へマップします。 getメソッドにカラム値の組を指定すると、そのカラム値組み合わせをもつすべてのレコードで構成するレコードセットを得られます。

処理する表。

keycolumn0column1
abc1112222
abc3334444
def5556666

CSVによる記述「csvfile.csv」

key,column0,column1
abc,111,2222
abc,333,4444
def,555,6666

プログラム :

* $csvfile = files(csvfile.csv, key)
<<context CSV_key, $csvfile
print '----', ${key}
* $keys = $csvfile.get(${key})
<<context Key_group, $keys
print '++', columns()
>>
>>

出力 :

---- abc
++ column1:2222 column0:111 INPUT:csvdata key:abc
++ column1:4444 column0:333 INPUT:csvdata key:abc
---- def
++ column1:6666 column0:555 INPUT:csvdata key:def

制約 :

  • 2個以上のカラム名の組で生成する分類済レコードセットは未実装です。

10. リソース型データのライフサイクル

createResourceで生成したリソース型のデータに対しマッピングプロファイル(.frumap で値を設定し、commitを呼ぶとFRUCtoSにリソースとして作成されます。 マッピングセッティングプロファイル処理系は作成時にリソースIDを記録し、その後は作業用データを破棄します。 以降、そのリソースへの参照はreference関数で取得できます。

また、マッピングセッティングプロファイル処理系は2種類の動作モードがあり、setResourceReferenceModeマッピングプロファイル(.frumap 実行の先頭で指定します。実行途中で切り替えは不可で、デフォルトではBackwardモードです。

  • Backwardモード
    生成済みのリソースへのみリファレンス可能です。 このモードでは参照されるリソースは必ず他のリソースから参照される前にcommitによって生成されなければなりません。 commit関数では、1つ1つのリソースをcreateインタラクションによって生成します。

  • Transactionモード
    同時にcommitするリソース間のリファレンスをfullUrlで指定することで、同時にcommitするリソースの間でもリファレンスできます。 commit関数では、commit対象となるすべてのリソースを1個のトランザクションで生成します。

制約:

  • 現在はBackwardモードのみ実装済みです。

10.1. createResourceで生成したリソースのライフサイクル

前述のようにcreateResourceで生成したリソースデータはcommit関数の実行でFRUCtoS内のリソースとしてcreateされます。

しかしつぎの場合には、他リソース内へ保持されることになるため独立したリソースとしてはcreateされず、そのリソースを保持するリソースの一部としてcreateされます。

  • addContained関数によって他のリソースのcontainedリソースとしたとき。
  • 他のリソースのリソース型Elementへ代入されたとき。

制約:

  • 現在代入をサポートしているリソース型Elementはつぎの2種のみです。
    • Bundle.entry.resource
    • Bundle.response.outcome

10.2. createChildResourceで生成したリソースのライフサイクル

createChildResourceは、他のリソースのcontainedリソースやリソース型エレメントへ 代入するためにリソースを生成する関数です。

この関数で生成したリソースデータは、他のリソースへ代入されなかった場合にはつぎのcommit関数実行時に破棄します。

11. エラー処理

マッピングセッティングプロファイルではつぎのようなエラー処理を想定しています。

  • マッピングセッティングプロファイル処理系による実行中断
    マッピングセッティングプロファイルの構文エラーやマッピングパックの不在などを検出したときには、検出したプログラム位置などの情報を出力して停止します。 この処理はマッピングプロファイル(.frumap が記述する必要はなく、記述もできません。

  • マッピングプロファイル(.frumap)による制御
    マッピングプロファイル(.frumap)が入力データを判定してエラー処理を実現できます。 このためにマッピングセッティングプロファイル処理系にはいくつかの制御手段を用意しています。

    • エラー情報の出力
      • print文を使ってエラー情報をクライアントへ伝える。
      • print文に位置情報を加えるために$_file$_lineなどのシステム変数を提供する。
    • データ生成処理のスキップ
      リソースエレメントへの代入文で右辺の値として{}(null)を指定することで、その代入文の実行をスキップできます。不正なデータを無視するためにこの機能を使えます。
    • 処理の中断
      abort()関数を実行することで、処理系による実行中断と同様のことをマッピングプロファイル(.frumap)から実行できます。
  • print文によるメッセージの出力

    • メッセージの出力先をレスポンス内のOperationOutcomeとしています。
    • OperationOutcomeへはprint文のほか、処理中断メッセージが自動的に出力されます。

制約:

  • メッセージのフォーマット機能は未実装です。メッセージは文字列の連結で作成します。