LIBNAMEのJSONエンジンの欠点は、32KBを超える長さのデータを抽出できない点です。できないものは仕方ないので、32KBを超えてもSASプログラムを抽出するコードを書きました。
字句解析の状態遷移を考えて "code": の値を抽出してバックスラッシュのエンコードを解いてファイルの保存します。入力のJSONファイルは整形されていないコンパクトや書式の前提です。昔、Lex, Yaccを使っていた記憶を掘り起こした。
- /* Code extraction from JSON file of job definition */
- %macro extractJobCode(infile=, outfile=, debug=0);
- %local/readonly DQ='22'x;
- %local/readonly BSL='5c'x;
- %local/readonly BS='08'x;
- %local/readonly FF='0c'x;
- %local/readonly NL='0a'x;
- %local/readonly CR='0d'x;
- %local/readonly TB='09'x;
- %local/readonly SP='20'x;
- data _NULL_;
- attrib filein length=8 label='input file id';
- attrib fileid length=8 label='output file id';
- attrib stat length=8 label='State of lexical analysis';
- attrib token length=$256 label='Token';
- attrib ucode length=$4 label='Unicode';
- attrib count length=8;
- /* Open input/output files */
- filein=fopen("&infile" , 'I', 1, 'B');
- fileid=fopen("&outfile", 'O', 1, 'B');
- count=0;
- stat=0;
- rec=&SP;
- do while(fread(filein)=0);
- rc=fget(filein, rec, 1);
- %if &debug=1 %then
- %do;
- if count < 512 then
- put stat=rec=token=;
- count=count + 1;
- %end;
- if stat eq 0 and rec eq &DQ then
- stat=1;
- else if stat eq 1 then
- do;
- if rec eq &DQ then
- do;
- /* Double quotes */
- if token eq 'code' then
- stat=2;
- else
- stat=0;
- token='';
- end;
- else
- do;
- token=catt(token, rec);
- stat=1;
- end;
- end;
- else if stat eq 2 then
- do;
- if rec in (&SP, &TB, &NL) then
- stat=2;
- else if rec eq ':' then
- stat=3;
- else
- stat=0;
- end;
- else if stat eq 3 then
- do;
- if rec in (&SP, &TB, &NL) then
- stat=3;
- else if rec eq &DQ then
- stat=4;
- else
- stat=0;
- end;
- else if stat eq 4 then
- do;
- if rec eq &DQ then
- stat=0;
- else if rec eq &BSL then
- stat=5;
- else
- do;
- rc=fput(fileid, rec);
- rc=fwrite(fileid);
- end;
- end;
- else if stat eq 5 then
- do;
- /* Handling of backslash-escaped characters */
- if rec eq 'b' then
- do;
- rc=fput(fileid, &BS);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq &DQ then
- do;
- rc=fput(fileid, &DQ);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq &BSL then
- do;
- rc=fput(fileid, &BSL);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq 'f' then
- do;
- rc=fput(fileid, &FF);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq 'n' then
- do;
- rc=fput(fileid, &NL);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq 'r' then
- do;
- rc=fput(fileid, &CR);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq 't' then
- do;
- rc=fput(fileid, &TB);
- rc=fwrite(fileid);
- stat=4;
- end;
- else if rec eq 'u' then
- do;
- ucode='';
- do i=1 to 4;
- rc=fread(filein);
- rc=fget(filein, rec, 1);
- ucode=catt(ucode, rec);
- end;
- if ucode eq '0026' then
- do;
- rc=fput(fileid, '&');
- rc=fwrite(fileid);
- end;
- else if ucode eq '003c' then
- do;
- rc=fput(fileid, '<');
- rc=fwrite(fileid);
- end;
- else if ucode eq '003e' then
- do;
- rc=fput(fileid, '>');
- rc=fwrite(fileid);
- end;
- else
- do;
- rc=fput(fileid, &BSL);
- rc=fput(fileid, 'u');
- rc=fput(fileid, ucode);
- rc=fwrite(fileid);
- end;
- stat=4;
- end;
- end;
- end;
- /* Close input/output files */
- rc=fclose(filein);
- rc=fclose(fileid);
- run;
- %mend;
&、>、< がエンコードされていることがあったので、コードを直しました。
返信削除