En esta página

Conversor de serialización

Cómo convertir entre diferentes formatos de serialización.

Este ejemplo convierte entre JSON, CBOR, XML, QDataStream y algunos formatos de texto simples. Puede auto-detectar el formato que se está utilizando, o que se le diga qué formato utilizar. No todos los formatos admiten tanto entrada como salida, y tienen diferentes conjuntos de qué tipos de datos de contenido admiten. QDataStream y XML son los más ricos, seguidos de CBOR, luego JSON y, por último, los formatos de texto simple. La conversión a través de los formatos menos capaces es propensa a perder la estructura de los datos.

La clase Converter

La clase Converter es la superclase abstracta para todos los convertidores hacia y desde todos los formatos. Todos ellos convierten desde o hacia la clase QVariant, que se utiliza para representar internamente todas las estructuras de datos.

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)

El constructor y el destructor del convertidor gestionan una lista de convertidores disponibles que utiliza el programa principal para saber qué convertidores están disponibles. Cada tipo de convertidor define una instancia estática que asegura que está construido y por lo tanto disponible para el programa principal a través de esta lista. El método allConverters() proporciona al código de main() acceso a la lista.

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();
}

La función name() devuelve el nombre del convertidor. La función directions() se utiliza para determinar si un convertidor puede utilizarse para entrada, salida o ambas. Esto permite al programa principal informar de los conversores disponibles en su texto de ayuda para las opciones de la línea de comandos para seleccionar los formatos de entrada y salida.

    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;
    }

La función optionsHelp() se utiliza para informar de las distintas opciones de línea de comandos compatibles con los formatos disponibles, cuando se consulta utilizando su opción de línea de comandos --format-options <format>.

       for(const Converter *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));
                } return EXIT_SUCCESS; } }

La función outputOptions() informa de las capacidades de salida de un conversor. En la actualidad, la única característica opcional es la compatibilidad con claves arbitrarias en las asignaciones de claves a valores. La función loadFile() de un conversor de entrada puede utilizar esta información para adaptar la forma en la que presenta los datos que ha leído, para que sean representados tan fielmente por el conversor de salida como permitan sus capacidades.

La función probeFile() se utiliza para determinar si un archivo coincide con el formato del conversor. El programa principal la utiliza para determinar qué formato utilizar al leer o escribir un archivo, basándose en su nombre y potencialmente en su contenido, cuando el usuario no ha especificado el formato a utilizar en la línea de comandos.

La función loadFile() deserializa los datos. El llamador indica a loadFile() qué serializador pretende utilizar, de forma que loadFile() pueda consultar su outputOptions() para determinar la forma en la que representar los datos cargados. Si la persona que llama no se ha decidido por un convertidor de salida, loadFile() le proporciona un convertidor de salida por defecto adecuado a los datos que está devolviendo.

La función saveFile() serializa los datos. Se le pasan opciones desde la línea de comandos, como se describe en loadHelp(), que pueden ajustar los detalles de cómo representa los datos al guardarlos en un archivo.

Tanto loadFile() como saveFile() pueden utilizarse con un QIODevice arbitrario. Esto significa que un Convertidor también podría ser utilizado con un socket de red u otra fuente de datos, para leer o escribir. En el presente programa, el programa principal siempre pasa un QFile, accediendo a un archivo en disco o a uno de los flujos estándar del proceso.

Los conversores disponibles

Se admiten varios conversores, lo que ilustra cómo el programa conversor podría adaptarse a otros formatos, si surgiera la necesidad. Consulte el código fuente de cada uno para conocer sus detalles. Los conversores CBOR sirven como ilustración relativamente completa de las formas en que pueden funcionar los conversores, que veremos con más detalle a continuación. Esta tabla resume los conversores disponibles:

Clasemodoformato
CborConverterEntrada/SalidaCBOR
CborDiagnosticDumperSalidaCBOR diagnóstico
DataStreamConverterEntrada/SalidaQDataStream
DebugTextDumperSalidaSin pérdidas, no estándar, legible por humanos
JsonConverterEntrada/SalidaJSON
NullConverterSalidaSin salida
TextConverterEntrada/SalidaTexto plano estructurado
XmlConverterEntrada/SalidaXML

Los convertidores que admiten entrada se utilizan a sí mismos como convertidor alternativo de loadFile(), excepto los convertidores CBOR y QDataStream, que utilizan sus respectivas clases complementarias de volcado sólo de salida. El convertidor nulo puede utilizarse como convertidor de salida al ejecutar el programa para cualquier validación o verificación que pueda realizar un convertidor de entrada.

Las clases CborConverter y CborDiagnosticDumper

La clase CborConverter soporta la serialización desde y hacia el formato CBOR. Soporta varias opciones para configurar la salida de valores de coma flotante y una opción signature para determinar si se debe iniciar su salida con una etiqueta CBOR que sirve como cabecera de archivo, identificando el archivo como que contiene datos CBOR.

También existe una clase CborDiagnosticDumper para la salida en notación de diagnóstico CBOR. No admite la carga de datos. La forma de su salida puede configurarse utilizando dos opciones. Una selecciona si se utiliza el formato de diagnóstico CBOR extendido (más verboso). La otra controla si cada valor CBOR aparece en una línea separada.

La notación de diagnóstico simple es similar a JSON, pero no exactamente, porque permite mostrar el contenido de un flujo CBOR sin pérdidas, mientras que una conversión a JSON puede tener pérdidas. La función loadFile() de CborConverter utiliza CborDiagnosticDumper como convertidor de salida alternativo, si el llamante no ha determinado por sí mismo el formato de salida.

Las funciones de ayuda convertCborValue(), convertCborMap() y convertCborArray() se utilizan para convertir un QCborValue en un QVariant, en beneficio de CborConverter::loadFile().

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();
}

La función convertFromVariant() se utiliza para convertir un QVariant en un QCborValue para su salida por el saveFile() de cualquier clase.

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);
}

El programa convert

La función main() configura un QApplication y un QCommandLineParser para dar sentido a las opciones que el usuario ha especificado y proporcionar ayuda si el usuario la solicita. Utiliza los valores obtenidos para las distintas instancias de QCommandLineOption que describen las opciones del usuario, además de los argumentos posicionales para los nombres de archivo, para preparar los conversores que utilizará.

A continuación, utiliza su convertidor de entrada para cargar los datos (y posiblemente resolver su elección de convertidor de salida, si aún no ha seleccionado uno) y su convertidor de salida para serializar esos datos, teniendo en cuenta cualquier opción de salida que el usuario haya proporcionado en la línea de comandos.

    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;

Proyecto de ejemplo @ code.qt.io

Ver también Análisis y visualización de datos CBOR, Guardar y cargar un juego, y Soporte CBOR en Qt.

© 2026 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.