c++ builder XE4, 10.2 Tokyo > JSON > 複数行JSONファイル読取り

```txt:動作環境
C++ Builder XE4
   
RAD Studio 10.2 Tokyo Update 2 (追記: 2017/12/27)
   - v0.2の動作を確認
```

関連 http://qiita.com/7of9/items/af34daf6c79ca8e004a7


http://qiita.com/7of9/items/5f7b93bcab19217bdd11
において複数行のJSONファイルが例示されていた。

C++ Builderで読込み処理を実装してみた。

## v0.1 > 失敗編

### JSONファイル (original)

```info.json
{
 "modify_head": [

  "<script type='text/javascript'>",
  "<!--",
  "  function drawSomeText(id) {",
  "  var pjs = Processing.getInstanceById(id);",
  "  var text = document.getElementById('inputtext').value;",
  "  pjs.drawText(text);}",
  "-->",
  "</script>"

 ],

 "modify_body": [

  "<input type='text' id='inputtext'></input>",
  "<button onclick=drawSomeText('ExampleCanvas')></button>"

 ],
}
```

### JSONファイル (modified)

```info.json
{
 "modify_head": [

  "<script type='text/javascript'>",
  "<!--",
  "  function drawSomeText(id) {",
  "  var pjs = Processing.getInstanceById(id);",
  "  var text = document.getElementById('inputtext').value;",
  "  pjs.drawText(text);}",
  "-->",
  "</script>"

 ],

 "modify_body": [

  "<input type='text' id='inputtext'></input>",
  "<button onclick=drawSomeText('ExampleCanvas')></button>"

 ]
}
```

originalとの違いは最後の`,`を削除したこと。
`,`があると
`TJSONObject *jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));`
がNULLを返す。

### code v0.1

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <memory>
#include <DBXJSON.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	const String kJsonFile = L"info.json";
	const String kJsonKey = L"modify_head";

	if (FileExists(kJsonFile) == false) {
		return;
	}

	String jsonText = L"";

	// 1. file read
	std::unique_ptr<TStringList> fileSL(new TStringList);
	fileSL->LoadFromFile(kJsonFile);
	for(int idx=0; idx < fileSL->Count; idx++) {
		jsonText = jsonText + fileSL->Strings[idx];
	}

	// 2. JSON parser
	TJSONObject *jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));
	String item, value;
	TJSONPair *pair;

	for(int idx=0; idx < jsonObj->Size(); idx++) {
		pair = jsonObj->Get(idx);
		if (pair != NULL) {
			String key = pair->JsonString->Value();
			String txt = pair->JsonValue->Value();
			RichEdit1->Text = txt;
		}
	}
	jsonObj->Free();
}
//---------------------------------------------------------------------------
```

上記のコードでkeyは取得できるが、txtはmodify_head、modify_body両方に対してNULLとなった。


## v0.2 > 成功編

### 参考情報

- http://stackoverflow.com/questions/14864170/how-to-parse-a-json-array-in-rad-studio
- http://www.gesource.jp/weblog/?p=4567

TJSONArrayを使うのはstackoverflowで分かり実装を試みたが、使い方が分からなかった。
山本隆さんのページを参考に解決した。
( `TJSONArray* arr = dynamic_cast<TJSONArray*>(pair->JsonValue);` )。
情報感謝。


### info.json

JSONファイル (modified)と同じ。

```info.json
{
 "modify_head": [

  "<script type='text/javascript'>",
  "<!--",
  "  function drawSomeText(id) {",
  "  var pjs = Processing.getInstanceById(id);",
  "  var text = document.getElementById('inputtext').value;",
  "  pjs.drawText(text);}",
  "-->",
  "</script>"

 ],

 "modify_body": [

  "<input type='text' id='inputtext'></input>",
  "<button onclick=drawSomeText('ExampleCanvas')></button>"

 ]
}
```

### code v0.2

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <memory>
#include <DBXJSON.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	const String kJsonFile = L"info.json";
	const String kJsonKey = L"modify_head";

	if (FileExists(kJsonFile) == false) {
		return;
	}

	String jsonText = L"";

	// 1. file read
	std::unique_ptr<TStringList> fileSL(new TStringList);
	fileSL->LoadFromFile(kJsonFile);
	for(int idx=0; idx < fileSL->Count; idx++) {
		jsonText = jsonText + fileSL->Strings[idx];
	}

	// 2. JSON parser
	TJSONObject *jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));

	for(int oi=0; oi < jsonObj->Size(); oi++) { // oi: outer index
		TJSONPair *pair = jsonObj->Get(oi);
		if (pair == NULL) {
			continue;
		}
		if (pair->JsonString->Value() != kJsonKey) {
			continue;
		}

		TJSONArray* arr = dynamic_cast<TJSONArray*>(pair->JsonValue);

		String txt = L"";
		for(int ii=0; ii < arr->Size(); ii++) { // ii: inner index
			TJSONValue *lobj = arr->Get(ii);
			txt = txt + lobj->Value();
		}
		RichEdit1->Text = txt;
	}
	jsonObj->Free();
}
//---------------------------------------------------------------------------
```

### 結果

成功。
modify_headの値を読み取った。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/bf6d343d-e26e-4ecb-afae-5f3efa6b1328.png)