先に他のシステムとのデータ交換の形式にXMLが普及していると
紹介したが現在ではさらに進んでJSONというXMLの拡張形式が
一般的である。
実はインターネットの世界でJavaScriptや他のシステムとのデータ交換の
型式はXMLというよりむしろJSONがもはや一般的なのである。
IBMも i5/OS Ver7.4からJSONのパーサーもDATA-INTOで
組み込めるようにしている。
一応、IBMも時代に追いつこうとしているようである。
せっかくXMLを理解しかけているのにさらにまたJSON?と
思われるかも知れないがオープン系の時代の進むスピードは
速い。もう少し我慢してJSONも勉強してみよう。

JSON(=JavaScript Object Notation)はJavaScriptのような
記述のデータ形式というのが発祥であるので
・JavaScript でサーバーとのデータ交換
・IBM WatsonのようなAIとのデータ交換
・LINE が行うサーバーとのメッセージ交換
のような場面で使われている。
JSONの説明は「109.JSON とは」が最もわかりやすい。
物理ファイルとXMLとJSONの比較をもう一度確認してみよう。
・物理ファイル
| SHCODE | HNAME | SHTANK | SHSCOD |
|---|---|---|---|
| NV-CF1 | Cカセット編集ビデオ | 58000 | 0002 |
・XML表現
<RECORD>
<SHCODE>NV-CF1</SHCODE>
<SHNAME>Cカセット編集ビデオ</SHNAME>
<SHTANK>58000</SHTANK>
<SHSCOD>0002</SHSCOD>
</RECORD>
:
・JSON表現
{
{"SHCODE": "NV-CF1",
"SHNAME": "Cカセット編集ビデオ",
"SHTANK": "58000",
"SHSCOD": "0002"
}
:
}
このように見ているとXMLとJSONには1対1の互換性があることがわかる。
IBM iにはXML-INTOでXMLならばデータ構造(DS=Data Structure)に変換できたのだから
JSONもXMLに変換すればやはりXML-INTOを使ってデータ構造に変換できるはずである。
そこで今回紹介するのがJSONからXML-INTOを使ってデータ構造に変換する
サンプルRPGである。
[ JSONをデータ構造に変換するRPG : TESTJSON1 ]
ソースはこちらから
0001.00 H DFTNAME(TESTJSON1) DATEDIT(*YMD/) BNDDIR('QC2LE')
0002.00 H CCSID(*GRAPH:*SRC)
0003.00 F********** JSON パーサーのテスト *************************************
0004.00 F*
0005.00 F**********************************************************************
0006.00
0007.00 * CRTBNDRPG OBJ(OBJLIB/TESTJSON1) SRCFILE(MYSRCLIB/QRPGLESRC)
0008.00 * DFTACTRP(*NO) ACTGRP(*NEW) DBGVIEW(*SOURCE) AUT(*ALL)
0009.00
0010.00 *-------------------------------------------------------------------*
0011.00 * 2021/11/30 : 作成
0012.00 *-------------------------------------------------------------------*
0013.00 ****************************************************
0014.00 * プロシージャーのプロトタイプ宣言 *
0015.00 ****************************************************
0016.00 D*( JSON2XML のプロトタイプ宣言 )
0017.00 D JSON2XML PR 10I 0
0018.00 D JSON_P * Value
0019.00 D XML_P * Value
0020.00
0021.00 *( 作業変数 )
0022.00 D TRUE# S 10I 0 INZ(0)
0023.00 D FALSE# S 10I 0 INZ(-1)
0024.00 D JSON S 512A
0025.00 D XML S 512A
0026.00 D UCS2 S 512C CCSID(1200)
0027.00
0028.00 D RECORD DS QUALIFIED
0029.00 D SHCODE 1 10A
0030.00 D SHNAME 11 34A
0031.00 D SHTANK 35 41S 0
0032.00 D SHSCOD 42 45A
0033.00
0034.00 /FREE
0035.00 JSON = '{+
0036.00 "SHCODE": "NV-CF1",+
0037.00 "SHNAME": " Cカセット編集ビデオ ",+
0038.00 "SHTANK":"58000",+
0039.00 "SHSCOD":"0002"+
0040.00 }';
0041.00 JSON2XML(%ADDR(JSON): %ADDR(XML)); //JSON を XML に変換する
0042.00 UCS2 = %UCS2(XML);
0043.00 XML-INTO RECORD %XML(UCS2:'ccsid=ucs2 case=any');
0044.00 /END-FREE
0045.00 C SETON LR
0046.00 C RETURN
0047.00 ************************************************************
0048.00 * JSON2XML : JSON を XML に変換する
0049.00 ************************************************************
0050.00 *---( JSON2XML ここから )-----------------------*
0051.00 * JSON を XML に変換する
0052.00 P JSON2XML B
0053.00 D PI 10I 0
0054.00 D JSON_P * Value
0055.00 D XML_P * Value
0056.00 *
0057.00 D JSON S 1A BASED(JSON_P)
0058.00 D DIM(512)
0059.00 D XML S 512A BASED(XML_P)
0060.00 D N S 4S 0
0061.00 D LEN S 4S 0
0062.00 D X S 4S 0
0063.00 D FLD S 10A
0064.00 D VALUE S 256A
0065.00 D bFLD S N INZ(*OFF)
0066.00 D bVALUE S N INZ(*OFF)
0067.00 D bOE S N INZ(*OFF)
0068.00 D OE S 1A INZ(X'0E')
0069.00 D OF S 1A INZ(X'0F')
0070.00
0071.00 /FREE
0072.00 X = 0;
0073.00 LEN = %ELEM(JSON);
0074.00 FOR N = 1 TO LEN;
0075.00 SELECT;
0076.00 WHEN JSON(N) = '{';
0077.00 XML = '';
0078.00 WHEN JSON(N) = '"';
0079.00 IF bOE = *ON;
0080.00 VALUE = %TRIM(VALUE) + JSON(N); // 漢字中
0081.00 ITER;
0082.00 ENDIF;
0083.00 IF bFLD = *OFF;
0084.00 IF %LEN(%TRIMR(FLD)) > 0; // フィールドの終わり
0085.00 bFLD = *ON;
0086.00 XML = %TRIMR(XML) + '<' + %TRIMR(FLD) + '>';
0087.00 ENDIF;
0088.00 ELSE;
0089.00 IF bVALUE = *OFF;
0090.00 IF %LEN(%TRIMR(VALUE)) > 0;
0091.00 bVALUE = *ON; // 値の終わり
0092.00 XML = %TRIMR(XML) + %TRIMR(VALUE) +
0093.00 '' + %TRIMR(FLD) + '>';
0094.00 ENDIF;
0095.00 ELSE;
0096.00 ENDIF;
0097.00 ENDIF;
0098.00 WHEN JSON(N) = ':';
0099.00 IF bOE = *ON;
0100.00 VALUE = %TRIM(VALUE) + JSON(N); // 漢字中
0101.00 ITER;
0102.00 ENDIF;
0103.00 WHEN JSON(N) = ',';
0104.00 IF bOE = *ON;
0105.00 VALUE = %TRIM(VALUE) + JSON(N); // 漢字中
0106.00 ITER;
0107.00 ENDIF;
0108.00 bFLD = *OFF;
0109.00 bVALUE = *OFF;
0110.00 FLD = ' ';
0111.00 VALUE = ' ';
0112.00 WHEN JSON(N) = '}';
0113.00 IF bOE = *OFF;
0114.00 XML = %TRIMR(XML) + ' ';
0115.00 ELSE;
0116.00 VALUE = %TRIM(VALUE) + JSON(N); // 漢字中
0117.00 ENDIF;
0118.00 OTHER;
0119.00 IF JSON(N) = OE;
0120.00 bOE = *ON;
0121.00 ELSE;
0122.00 IF JSON(N) = OF;
0123.00 bOE = *OFF;
0124.00 ENDIF;
0125.00 ENDIF;
0126.00 IF bFLD = *OFF;
0127.00 FLD = %TRIMR(FLD) + JSON(N);
0128.00 ELSE;
0129.00 VALUE = %TRIM(VALUE) + JSON(N);
0130.00 ENDIF;
0131.00 ENDSL;
0132.00 ENDFOR;
0133.00 /END-FREE
0134.00 C RETURN TRUE#
0135.00 P E
0136.00 *---( JSON2XML ここまで )----------------------*
[コンパイル]
CRTBNDRPG PGM(TEST.COM/TESTJSON2) SRCFILE(R610SRC/QRPGLESRC) DFTACTGRP(*NO)
ACTGRP(*NEW) DBGVIEW(*SOURCE) AUT(*ALL)
[解説]
この例では最も簡単なJSONとして
0035.00 JSON = '{+
0036.00 "SHCODE": "NV-CF1",+
0037.00 "SHNAME": " Cカセット編集ビデオ ",+
0038.00 "SHTANK":"58000",+
0039.00 "SHSCOD":"0002"+
0040.00 }';
を用意してそれを
0041.00 JSON2XML(%ADDR(JSON): %ADDR(XML)); //JSON を XML に変換する
によってJSONをJSON2XML というプロシージャーでXMLに変換している。
JSON2XMLはC言語で書いたほうがシンプルでわかりやすいのだが
C言語のサービス・プログラムを書くと大規模になってしまうのと
読者はRPGのほうがわかりやすいだろうとの考慮からRPGで
プロシージャーを記述した。
次にXMLの変数: XML に変換して
0042.00 UCS2 = %UCS2(XML);
によって EBCDIC:XMLを UTF-16: UCS2 に変換する。
これは先に説明したようにXML-INTOは日本語環境のCCSID: 5026, 5025および 1399をサポートしていない
ので唯一互換性のあるUnicodeのUTF-16に変換してから
0043.00 XML-INTO RECORD %XML(UCS2:'ccsid=ucs2 case=any');
でデータ構造
0028.00 D RECORD DS QUALIFIED 0029.00 D SHCODE 1 10A 0030.00 D SHNAME 11 34A 0031.00 D SHTANK 35 41S 0 0032.00 D SHSCOD 42 45A
に変換する。
STRDBG で XML-INTOの実行後に停止させて EVAL RECORD でデータ構造の中身を参照すると
評価式
前のデバッグ式
> EVAL record
RECORD.SHCODE = 'NV-CF1 '
RECORD.SHNAME = ' Cカセット編集ビデオ '
RECORD.SHTANK = 0058000.
RECORD.SHSCOD = '0002'
のようにデータ構造: RECORD の中にJSONの値が更新されていることが確認できる。
このようにして私たちはJSONに本質的に同じ意味を持つデータ構造(DS)にデータを
写すことができたのである。
まず最初の第一歩としてJSONを扱うことができるようになった。
このAS400 TIPS & Techniques もXML-INTO の紹介に始まってJSONも解説しているのだから
十分時代に沿っているはずである。
レガシーなテクニックではなく時代の先端を行こうとしている。
米国の記事を書き写しただけの紹介ではない。

RPGフリー・フォーマット
ところで上記のRPGソースの演算はほとんどがフリー・フォーマットで書かれている。
フリー・フォーマットではなく固定形式で記述すると読み手は読むのも嫌になるような
ロジックのなるがご覧のようにフリー・フォーマットであれば
他人のソースであってもわかりやすくなる。
なぜフリー・フォーマットが優れているかについては来年の技術ショート・セミナーで
解説を予定している。お申し込みは12月17日より開始の予定。
