1. ホーム
  2. C++

C++ JSON ライブラリ jsoncpp 新 API の使用法 (CharReaderBuilder / StreamWriterBuilder)

2022-02-09 17:21:44
<パス <ブロッククオート

あなたはこの記事を見ているので、Jsonが何であるかを知っている必要があります、Jsonを解析するための多くのオープンソースライブラリがあり、最近の仕事は、Jsonのパースを使用する必要があります、研究はjsoncppは非常に便利に使用することがわかった、インターネットを使用する多くの方法もあります、これまでの基本APIを見つけることができます使用の比較的古い方法、コンパイラはいくつかのAPIの使用が放棄されて思い出される いくつかのAPIが非推奨されていると、いくつかのコンパイラが直接エラー報告することだろう。

新しくシンプルなjsonライブラリを見つけたので、星をたくさんつけて、こちらをお勧めします nlohmann/json .



JSONCPPは、人間が理解しやすく、機械が解析しやすい軽量なデータ交換フォーマットであるJSON文字列の生成とパース用のC++実装です。jsoncppは、Githubからダウンロードすることができます。 https://github.com/open-source-parsers/jsoncpp .

使用方法

スタティック/ダイナミックライブラリの使用

公式には、プロジェクトの説明にあるように、コンパイルにはNinjaを使うことが推奨されています。もちろん、より一般的なcmakeを使用してコンパイルすることも可能です。

mkdir -p build/debug
cd build/debug
cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ... /...
make


生成されたスタティック/ダイナミックライブラリファイルのディレクトリは build/debug/src/lib_json/ 使用するには、プロジェクトにincludeヘッダファイルを追加してリンクします -ljsoncpp パラメータでリンクライブラリーを指定します。

ソースファイルの使用

静的なライブラリを使うより、ソースファイルを直接使う方が便利な気がします。
プロジェクトディレクトリで直接実行する python amalgamate.py コマンドを追加します。 dist ディレクトリに、2つのヘッダーファイルと1つのソースファイルが生成されます。 json-forwards.h は、その json.h jsoncpp.cpp . jsoncppのソースコードは4、5千行しかないので、プロジェクト内の他のコードと一緒にjsconcpp.cppで直接コンパイルした方が簡単です。

新しいAPI

ここにデモ用のランダムなJsonデータがあります。以下のJson文字列は配列とインラインのJson文字列を含んでいますが、これは一般的によくあることですよね?

{
  "Name": "Liming",
  "Age": 26,
  "Language": ["C++", "Java"],
  "E-mail": {
    "Netease": "[email protected]",
    "Hotmail": "[email protected]"
  }
}

#include 

#include "json/json.h"

std::string createJson()
{
    std::string jsonStr;
    Json::Value root, lang, mail;
    Json::StreamWriterBuilder writerBuilder;
    std::ostringstream os;

    root["Name"] = "Liming";
    root["Age"] = 26;

    lang[0] = "C++";
    lang[1] = "Java";
    root["Language"] = lang;

    mail["Netease"] = "[email protected]";
    mail["Hotmail"] = "[email protected]";
    root["E-mail"] = mail;

    std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
    jsonWriter->write(root, &os);
    jsonStr = os.str();

    std::cout << "Json:\n" << jsonStr << std::endl;
    return jsonStr;
}


Json文字列を生成する

Json:
{
	"Age" : 26,
	"E-mail" : 
	{
		"Hotmail" : "[email protected]",
		"Netease" : "[email protected]"
	},
	"Language" : 
	[
		"C++",
		"Java"
	],
	"Name" : "Liming"
}


この関数を呼び出すと、次のように出力されます。

bool parseJson(const std::string &info)
{
    if (info.empty())
        return false;

    bool res;
    JSONCPP_STRING errs;
    Json::Value root, lang, mail;
    Json::CharReaderBuilder readerBuilder;

    std::unique_ptr<Json::CharReader> const jsonReader(readerBuilder.newCharReader());
    res = jsonReader->parse(info.c_str(), info.c_str()+info.length(), &root, &errs);
    if (!res || !errs.empty()) {
        std::cout << "parseJson err. " << errs << std::endl;
    }

    std::cout << "Name: " << root["Name"].asString() << std::endl;
    std::cout << "Age: " << root["Age"].asInt() << std::endl;

    lang = root["Language"];
    std::cout << "Language: ";
    for (int i = 0; i < lang.size(); ++i) {
        std::cout << lang[i] << " ";
    }
    std::cout << std::endl;

    mail = root["E-mail"];
    std::cout << "Netease: " << mail["Netease"].asString() << std::endl;
    std::cout << "Hotmail: " << mail["Hotmail"].asString() << std::endl;

    return true;
}


Json文字列のパース

Jsonを解析するための前提条件は、Jsonの文字列にどのようなデータが含まれているかが分かっていることです。上記の関数で生成されたJson文字列に対して、以下の関数を使ってデータをパースします。

Name: Liming
Age: 26
Language: "C++" "Java" 
Netease: [email protected]
Hotmail: [email protected]


前の関数の戻り値を入力パラメータとして、main関数内からこの関数を呼び出すと、次のような出力が得られます。

	Json::Value root, ex;
	Json::FastWriter writer;

	root["Name"] = "Lucy";
	root["age"] = 20;
	ex[0] = "ABC";
	ex[1] = "DEF";
	root["exinfo"] = ex;

	string json = writer.write(root);

	Json::Reader reader;
	Json::Value root;
	const char *jsonStr = "{\"Name\":\"Lucy\",\"Age\":20}";
	
	if (!reader.parse(jsonStr, jsonStr + strlen(jsonStr), root)) {
        std::cout << "json parse failed\n";
        return 1;
    }

    std::string name = root["Name"].asString();
    int age = root["Age"].asInt();
    


旧API

Webでの検索はほとんどが古いAPIなので、テストを整理するのが面倒なのですが、おそらくこちら側のような感じだと思います。上の新しいAPIと同じようにネストしています。

Jsonを生成する

warning: 'Reader' is deprecated: Use CharReader and CharReaderBuilder instead [-Wdeprecated-declarations]

warning: 'FastWriter' is deprecated: Use StreamWriterBuilder instead [-Wdeprecated-declarations]


Jsonのパース

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif


旧APIを使用するコンパイラには、以下のようなアラートが表示され、あるコンパイラは警告を、あるコンパイラはエラーを報告し、そして

Json::Value

古いAPIにこだわるなら、このコードをファイルのヘッダーに追加すればいい。

root["Name"]

概要

を配置することが可能です。 .asString() を Json 構造体として使用し、ネストしたり配列のように使用したりすることができ、必要なときに適切な型に変換することができます。
例えば
私たちはすでに、以下のことを知っています。 string を使用して文字列に置き換えることができる文字列を格納します。 root["Language"] から Json::Value タイプになります。
を知っていること root["E-mail"] これは Json::Value は配列なので、配列と同じように添え字を使って取得することができます。
を知っていること root これは Json::Value は内部でネストしたjsonなので // Convert types Int asInt() const; UInt asUInt() const; Int64 asInt64() const; UInt64 asUInt64() const; LargestInt asLargestInt() const; LargestUInt asLargestUInt() const; float asFloat() const; double asDouble() const; bool asBool() const; // Detect the type bool isNull() const; bool isBool() const; bool isInt() const; bool isInt64() const; bool isUInt() const; bool isUInt64() const; bool isIntegral() const; bool isDouble() const; bool isNumeric() const; bool isString() const; bool isArray() const; bool isObject() const; の構造を持つ。
Json::Value その他のメンバー関数は

// Convert types
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
// Detect the type
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;


残りは自分でソースコードを確認してください。

間違いがあればご指摘ください、ありがとうございます〜。