電子版お薬手帳をWebブラウザ表示する

#概要
お薬手帳は、[一般社団法人 保健医療福祉情報システム工業会](https://www.jahis.jp/)（JAHIS）が電子版の標準フォーマットを定め、スマートフォンによる電子お薬手帳が普及しています。電子版お薬手帳はバックアップファイルをテキストで出力することができますが、パソコン版は無いため、パソコンで容易に閲覧できるよう、JavaScriptでWebブラウザ用の表示スクリプトを書いてみました。

#フォーマット
病院や薬局が使用している各種システムと整合性が図られたフォーマットのようです。
これまで数回のヴァージョンアップが図られていますが、今回は最新より1世代前のフォーマットを参考にしました。

- [電子版お薬手帳データフォーマット仕様書Ver.2.1.pdf](https://www.jahis.jp/files/user/04_JAHIS%20standard/15-106_電子版お薬手帳データフォーマット仕様書Ver.2.1.pdf)

今回作成したスクリプトはローカルのブラウザ内で完結するつくりとしました。**仕様書に対しては非準拠**なので、下記のコードについては絶対に自己責任でお願いします。

##文字コード等
- CSVファイル（拡張子は決めが無い様子。私のアプリでは.txt）
- 文字コード：ASCII又はShift-JIS（外字は不可）
- 改行コード：CR + LF
 - 文字列としてのコンマは全角。その他細かい文字制限あり。
- 各レコードの先頭：レコードナンバー
 - フィールドごとに入力可能な文字種、字数の制限あり。
 - 薬関係のフィールドは複数回出現が可能。

##参照コード
- 都道府県コードはJIS X0401を参照している模様。


#スクリプト関係
HTMLがXHTMLなのには深い意味はありません。私が普段、趣味で作成している作業がXHTMLだということ程度です。

下記HTMLのinput要素でファイルを選択すると、スクリプトでTable形式に表示を整理します。なお、空欄のフィールドは非表示にしています。（使われないフィールドはかなり多い印象。）

```HAML:HTML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<script><![CDATA[JavaScript]]></script>
<script type="application/json" id="JSON">
<![CDATA[JSON]]>
</script>
<title>お薬手帳表示スクリプト</title>
</head>
<body>
<form><input type="file"/></form>
<table></table>
</body>
</html>
```

レコードナンバーとフィールドをはJSONで整理しました。

```json:JSON

{
  "バージョン情報":{
    "description":"本データフォーマットのバージョンと、データの出力区分を記録する。"
  },
  "1":{
    "name":"患者情報レコード",
    "item":["患者氏名","患者性別","患者生年月日","患者郵便番号","患者住所","患者電話番号","緊急連絡先","血液型","体重","患者カナ"]
  },
  "2":{
    "name":"患者特記レコード",
    "item":["患者特記種別","患者特記内容","レコード作成者"]
  },
  "3":{
    "name":"一般用医薬品服用レコード",
    "item":["薬品名称","服用開始年月日","服用終了年月日","レコード作成者"]
  },
  "4":{
    "name":"手帳メモレコード",
    "item":["手帳メモ情報","メモ入力年月日","レコード作成者"]
  },
  "5":{
    "name":"調剤等年月日レコード",
    "item":["調剤等年月日","レコード作成者"]
  },
  "11":{
    "name":"調剤-医療機関等レコード",
    "item":["医療機関等名称","医療機関等都道府県","医療機関等点数表","医療機関等コード","医療機関等郵便番号","医療機関等住所","医療機関等電話番号","レコード作成者"]
  },
  "15":{
    "name":"調剤-医師・薬剤師レコード",
    "item":["医師・薬剤師氏名","医師・薬剤師連絡先","レコード作成者"]
  },
  "51":{
    "name":"処方-医療機関レコード",
    "item":["医療機関名称","医療機関都道府県","医療機関点数表","医療機関コード","レコード作成者"]
  },
  "55":{
    "name":"処方-医師レコード",
    "item":["医師氏名","診療科名","レコード作成者"]
  },
  "201":{
    "name":"薬品レコード",
    "item":["RP番号","薬品名称","用量","単位名","薬品レコード種別","薬品コード","レコード作成者"]
  },
  "281":{
    "name":"薬品補足レコード",
    "item":["RP番号","薬品補足情報","レコード作成者"]
  },
  "291":{
    "name":"薬品服用注意レコード",
    "item":["RP番号","内容","レコード作成者"]
  },
  "301":{
    "name":"用法レコード",
    "item":["RP番号","用法名称","調剤数量","調剤単位","剤型コード","用法コード種別","用法コード","レコード作成者"]
  },
  "311":{
    "name":"用法補足レコード",
    "item":["RP番号","用法補足情報","レコード作成者"]
  },
  "391":{
    "name":"処方服用注意レコード",
    "item":["RP番号","内容","レコード作成者"]
  },
  "401":{
    "name":"服用注意レコード",
    "item":["内容","レコード作成者"]
  },
  "411":{
    "name":"医療機関等提供情報レコード",
    "item":["内容","提供情報種別","レコード作成者"]
  },
  "501":{
    "name":"備考レコード",
    "item":["備考情報","レコード作成者"]
  },
  "601":{
    "name":"患者等記入レコード",
    "item":["患者等記入情報","入力年月日"]
  },
  "701":{
    "name":"かかりつけ薬剤師レコード",
    "item":["かかりつけ薬剤師氏名","勤務先薬局名称","連絡先","担当開始日","担当終了日","レコード作成者"]
  },
  "911":{
    "name":"分割制御レコード",
    "item":["データ固有ID","分割数","データ連番"]
  }
}
```

```javascript:JavaScript

const CSV = {};

CSV.ElmMake = function (Data) {
  'use strict';
  const ns = 'http://www.w3.org/1999/xhtml';
  const tbElm = document.createElementNS(ns, 'tbody');
  for (let rec of Data) {
    const trElm = document.createElementNS(ns, 'tr');
    for (let field of rec) {
      const tNode = document.createTextNode(field);
      const Elm = document.createElementNS(ns, 'td');
      Elm.appendChild(tNode);
      trElm.appendChild(Elm);
    }
    tbElm.appendChild(trElm);
  }
  const tElm = document.getElementsByTagNameNS(ns, 'table').item(0);
  if (tElm.hasChildNodes()) {
    tElm.replaceChild(tbElm, tElm.firstChild);
  } else {
    tElm.appendChild(tbElm);
  }
};

CSV.showTable = function (e) {
  'use strict';
  const fileData = e.target.files[0];
  const reader = new FileReader();
  const domText = function () {
    const hData = JSON.parse(document.getElementById('JSON').firstChild.nodeValue);
    const dData = (function () {
      const Rec = [];
      const Table = reader.result.replace(/\r\n/g, '\n').split('\n');
      Table.shift();
      for (let r of Table) {
        Rec.push(r.split(','));
      }
      return Rec;
    }());
    const Data = [];
    for (let rec of dData) {
      const l = rec.length;
      for (let j = 1; j < l; j++) {
        if (rec[j] !== '') {
          Data.push([hData[rec[0]].item[j-1], rec[j]]);
        }
      }
    }
    CSV.ElmMake(Data);
  };
  reader.addEventListener('load', domText, false);
  reader.readAsText(fileData, 'Shift_JIS');
};

CSV.start = function () {
  'use strict';
  const file = document.querySelector('input');
  file.addEventListener('change', CSV.showTable, false);
  window.removeEventListener('DOMContentLoaded', CSV.start, false);
};

(function () {
  'use strict';
  document.addEventListener('DOMContentLoaded', CSV.start, false);
}());
```