シリアライゼーション・コンバーター
異なるシリアライゼーション・フォーマット間の変換方法
この例では、JSON、CBOR、XML、QDataStream 、いくつかの単純なテキスト形式を変換します。使用されているフォーマットを自動検出することも、どのフォーマットを使用するかを指定することもできます。すべてのフォーマットが入力と出力の両方をサポートしているわけではなく、どのコンテンツ・データ型をサポートしているかはそれぞれ異なる。QDataStream 、XMLが最も豊富で、CBOR、JSON、プレーン・テキストフォーマットの順となる。能力の低いフォーマットで変換すると、データから構造が失われがちだ。
コンバータークラス
Converterクラスは、すべてのフォーマットとのコンバーターの抽象スーパークラスです。これらのクラスはすべて、QVariant クラスから、または クラスに変換します。 クラスは、内部的にすべてのデータ構造を表現するために使用されます。
class Converter { static QList<const Converter *> &converters(); protected: Converter(); static bool isNull(const Converter *converter); // in nullconverter.cpp public: static const QList<const Converter *> &allConverters(); enum class Direction { In = 1, Out = 2, InOut = In | Out }; Q_DECLARE_FLAGS(Directions, Direction) enum Option { SupportsArbitraryMapKeys = 0x01 }; Q_DECLARE_FLAGS(Options, Option) virtual ~Converter() = 0; virtual QString name() const = 0; virtual Directions directions() const = 0; virtual Options outputOptions() const; virtual const char *optionsHelp() const; virtual bool probeFile(QIODevice *f) const; virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const; virtual void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) const = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Directions) Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options)
コンバータのコンストラクタとデストラクタは、メイン・プログラムが使用可能なコンバータのリストを管理する。各コンバーター・タイプは静的インスタンスを定義し、それが構築されていることを保証するため、このリストを通じてメイン・プログラムから利用できるようになる。allConverters()
メソッドはmain()
のコードにリストへのアクセスを提供する。
Converter::Converter() { converters().append(this); } Converter::~Converter() { converters().removeAll(this); } QList<const Converter *> &Converter::converters() { Q_CONSTINIT static QList<const Converter *> store; return store; } const QList<const Converter *> &Converter::allConverters() { return converters(); }
name() 関数はコンバーターの名前を返す。directors()関数は、コンバーターが入力に使えるのか、出力に使えるのか、あるいは両方に使えるのかを判断するために使われる。これらにより、メイン・プログラムは、入力形式と出力形式を選択するコマンドライン・オプションのヘルプ・テキストで、どのコンバーターが使用可能かを報告することができる。
QStringList inputFormats; QStringList outputFormats; for (const Converter *conv : Converter::allConverters()) { auto direction = conv->directions(); QString name = conv->name(); if (direction.testFlag(Converter::Direction::In)) inputFormats << name; if (direction.testFlag(Converter::Direction::Out)) outputFormats << name; }
optionsHelp()関数は、--format-options <format>
コマンドラインオプションを使用して問い合わせたときに、使用可能なフォーマットでサポートされているさまざまなコマンドラインオプションを報告するために使用されます。
for(constConverter*conv: Converter::allConverters()) {if(conv->name()==format) {const char *help = conv->optionsHelp();if(help) { { (ヘルプ) qInfo("The following options are available for format '%s':\n\n%s", qPrintable(format), help); }else{ qInfo("Format '%s' supports no options.", qPrintable(format)); }returnEXIT_SUCCESS; } }
outputOptions() 関数は、コンバータの出力機能を報告します。現在のところ、唯一のオプション機能は、キーから値へのマッピングにおける任意のキーのサポートです。入力コンバーターのloadFile()は、この情報を使って、読み込んだデータを出力コンバーターがその能力が許す限り忠実に表現できるように、表示する形式を調整することができます。
probeFile()関数は、ファイルがコンバータの書式に合っているかどうかを判定するために使われます。メイン・プログラムは、ユーザがコマンドラインで使用する形式を指定していない場合に、ファイルの名前と潜在的な内容に基づいて、ファイルの読み書きの際に使用する形式を決定するためにこれを使用する。
loadFile()関数はデータをデシリアライズする。呼び出し元は、loadFile() に使用するシリアライザを指定します。loadFile() は、outputOptions() に問い合わせて、読み込んだデータを表現する形式を決定します。呼び出し元が出力コンバータの選択を決めていない場合、loadFile() は返そうとしているデータに適したデフォルトの出力コンバータを返します。
saveFile()関数はデータをシリアライズする。loadHelp()で説明したように、コマンドラインからオプションを渡され、ファイルに保存する際のデータの表現方法の詳細を調整することができます。
loadFile() と saveFile() はどちらも、任意のQIODevice で使用できます。つまり、コンバーターは、ネットワーク・ソケットや他のデータ・ソースから読み込んだり、書き込んだりするためにも使用することができる。このプログラムでは、メイン・プログラムは常にQFile を渡し、ディスク上のファイルまたはプロセスの標準ストリームのいずれかにアクセスする。
利用可能なコンバーター
いくつかのコンバーターがサポートされており、コンバーター・プログラムを他のフォーマットに適応させることができることを示している。詳細はそれぞれのソースコードを参照のこと。CBORコンバーターは、コンバーターがどのように機能するかを比較的フル機能で説明するもので、以下でさらに詳しく見ていく。この表は利用可能なコンバータをまとめたものである:
クラス | モード | 形式 |
---|---|---|
CborConverter | イン/アウト | CBOR |
Cbor診断ダンパ | 出力 | CBOR診断 |
データストリームコンバーター | イン/アウト | QDataStream |
デバッグテキストダンパ | アウト | ロスレス、非標準、人間が読める |
Jsonコンバーター | イン/アウト | JSON |
Nullコンバーター | 出力 | 出力なし |
テキスト・コンバーター | イン/アウト | 構造化プレーンテキスト |
Xmlコンバーター | 入出力 | XML |
入力をサポートするものは、それ自身を loadFile() のフォールバック・コンバータとして使用します。ただし、CBOR とQDataStream コンバータは例外で、それぞれの出力専用ダンパーのコンパニオン・クラスを使用します。ヌル・コンバータは、入力コンバータが行う検証や確認のために、プログラムを実行するときに出力コンバータとして使用することができます。
CborConverterクラスとCborDiagnosticDumperクラス
CborConverterクラスはCBORフォーマットとの間のシリアライズをサポートします。浮動小数点値の出力を設定するさまざまなオプションと、ファイルがCBORデータを含んでいることを示すファイルヘッダとして機能するCBORタグで出力を開始するかどうかを決定するsignature
オプションをサポートしている。
CborDiagnosticDumperクラスもあり、CBOR診断表記で出力します。データのロードはサポートしていない。出力の形式は2つのオプションで設定できる。1つは(より冗長な)拡張CBOR診断フォーマットを使用するかどうかを選択します。もう1つは、各CBOR値を別々の行に表示するかどうかを制御します。
プレーンな診断記法はJSONに似ているが、JSONへの変換は非可逆になる可能性がある一方で、CBORストリームの内容を非可逆に表示することをサポートしているため、正確ではない。CborConverterのloadFile()は、呼び出し元が出力フォーマットを決定していない場合、フォールバック出力コンバータとしてCborDiagnosticDumperを使用する。
convertCborValue()、convertCborMap()、convertCborArray()ヘルパー関数は、CborConverter::loadFile()のために、QCborValue をQVariant に変換するために使用されます。
static QVariant convertCborValue(const QCborValue &value); static QVariant convertCborMap(const QCborMap &map) { VariantOrderedMap result; result.reserve(map.size()); for (auto pair : map) result.append({ convertCborValue(pair.first), convertCborValue(pair.second) }); return QVariant::fromValue(result); } static QVariant convertCborArray(const QCborArray &array) { QVariantList result; result.reserve(array.size()); for (auto value : array) result.append(convertCborValue(value)); return result; } static QVariant convertCborValue(const QCborValue &value) { if (value.isArray()) return convertCborArray(value.toArray()); if (value.isMap()) return convertCborMap(value.toMap()); return value.toVariant(); }
convertFromVariant() 関数は、QVariant をQCborValue に変換し、いずれかのクラスのsaveFile()
で出力するために使用します。
enum TrimFloatingPoint { Double, Float, Float16 }; static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrimming) { if (v.userType() == QMetaType::QVariantList) { const QVariantList list = v.toList(); QCborArray array; for (const QVariant &v : list) array.append(convertFromVariant(v, fpTrimming)); return array; } if (v.userType() == qMetaTypeId<VariantOrderedMap>()) { const auto m = qvariant_cast<VariantOrderedMap>(v); QCborMap map; for (const auto &pair : m) map.insert(convertFromVariant(pair.first, fpTrimming), convertFromVariant(pair.second, fpTrimming)); return map; } if (v.userType() == QMetaType::Double && fpTrimming != Double) { float f = float(v.toDouble()); if (fpTrimming == Float16) return float(qfloat16(f)); return f; } return QCborValue::fromVariant(v); }
変換プログラム
main()
関数は、QApplication とQCommandLineParser をセットアップし、ユーザーが指定したオプションを理解し、ユーザーが要求した場合にヘルプを提供します。ユーザーの選択を記述するさまざまなQCommandLineOption インスタンスで得られた値と、ファイル名の位置引数を使用して、使用するコンバーターを準備します。
そして、入力コンバーターを使ってデータを読み込み(まだ出力コンバーターを選択していない場合は、その選択を解決することもある)、出力コンバーターを使って、ユーザーがコマンドラインで指定した出力オプションを考慮してデータをシリアライズする。
QStringList files = parser.positionalArguments(); QFile input(files.value(0)); QFile output(files.value(1)); const Converter *inconv = prepareConverter(parser.value(inputFormatOption), Converter::Direction::In, &input); const Converter *outconv = prepareConverter(parser.value(outputFormatOption), Converter::Direction::Out, &output); // Now finally perform the conversion: QVariant data = inconv->loadFile(&input, outconv); Q_ASSERT_X(outconv, "Serialization Converter", "Internal error: converter format did not provide default"); outconv->saveFile(&output, data, parser.values(optionOption)); return EXIT_SUCCESS;
CBORデータの解析と表示、ゲームの保存と読み込み、QtのCBORサポートも参照してください 。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.