hyperion.ng/include/utils/jsonschema/QJsonUtils.h

305 lines
7.7 KiB
C
Raw Normal View History

JSON Auto correction + hyperion schema split for better readability (#452) * revoke schema split * add "getAutoCorrectedConfig" function * revoke schema split * revoke schema split * revoke schema split * Prevent compiler error if none grabber is available * revoke schema split * add "getAutoCorrectedConfig" function * revoke schema split * remove "configMigrator" * remove "configMigrator" * Change TestConfigFile to show how the autocorrection works * revoke schema split * revoke schema split * remove "ConfigMigrator" * remove "ConfigMigrator" * remove "ConfigMigratorBase" * remove "ConfigMigratorBase" * Add QJsonUtils.h * added ability "ignore-required" It has been added the ability to correct the configuration without having to pay attention to the keyword "required" in the hyperion schema * Allow Comments in Hyperion Schema * add ability to ignore the "required" keyword in hyperion schema * add ability to ignore the "required" keyword in hyperion schema * add ability to ignore the "required" keyword in hyperion schema * //Allow Comments in Hyperion Schema * Update jsonschema.py to version 0.8.0 to support ... references in json schema * add RefResolver from jsonschema.py to resolve references in hyperion schema * remove dupe code * split the hyperion schema in separatly files For better readability * add function "resolveReferences" to resolve references in hyperion schema. * remove CURRENT_CONFIG_VERSION * remove CURRENT_CONFIG_VERSION * split the hyperion schema in separatly files For better readability * Create schema-backgroundEffect.json * Add the rest of the Hyperion schema via upload * Remove Comments in config file * Add return variable to function writeJson(). fix function resolveReferences(). edit function load() to handle QPair result from schemaChecker. * edit function validate() to return QPair variable * fit function loadEffectDefinition() * fit function checkJson() * Expand error check by dividing "_error" variable in "_error" and "_schemaError". Replace variable "bool" in validate() in QPair * Extend function "cmd_cfg_set" to handle auto correction * Extend function "loadConfig" to handle auto correction * fix function loadConfig()
2017-07-30 13:32:10 +02:00
#pragma once
// QT include
#include <QString>
#include <QStringList>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
class QJsonUtils
{
public:
static void modify(QJsonObject& value, QStringList path, const QJsonValue& newValue = QJsonValue::Null, QString propertyName = "")
{
QJsonObject result;
if (!path.isEmpty())
{
if (path.first() == "[root]")
path.removeFirst();
for (QStringList::iterator it = path.begin(); it != path.end(); ++it)
{
QString current = *it;
if (current.left(1) == ".")
*it = current.mid(1, current.size()-1);
}
if (!value.isEmpty())
modifyValue(value, result, path, newValue, propertyName);
else if (newValue != QJsonValue::Null && !propertyName.isEmpty())
result[propertyName] = newValue;
}
value = result;
}
static QJsonValue create(QJsonValue schema, bool ignoreRequired = false)
{
return createValue(schema, ignoreRequired);
}
static QString getDefaultValue(const QJsonValue & value)
{
QString ret;
switch (value.type())
{
case QJsonValue::Array:
{
for (const QJsonValue &v : value.toArray())
{
ret = getDefaultValue(v);
if (!ret.isEmpty())
break;
}
break;
}
case QJsonValue::Object:
ret = getDefaultValue(value.toObject().find("default").value());
break;
case QJsonValue::Bool:
return value.toBool() ? "True" : "False";
case QJsonValue::Double:
return QString::number(value.toDouble());
case QJsonValue::String:
return value.toString();
case QJsonValue::Null:
case QJsonValue::Undefined:
break;
}
return ret;
}
JSON Auto correction + hyperion schema split for better readability (#452) * revoke schema split * add "getAutoCorrectedConfig" function * revoke schema split * revoke schema split * revoke schema split * Prevent compiler error if none grabber is available * revoke schema split * add "getAutoCorrectedConfig" function * revoke schema split * remove "configMigrator" * remove "configMigrator" * Change TestConfigFile to show how the autocorrection works * revoke schema split * revoke schema split * remove "ConfigMigrator" * remove "ConfigMigrator" * remove "ConfigMigratorBase" * remove "ConfigMigratorBase" * Add QJsonUtils.h * added ability "ignore-required" It has been added the ability to correct the configuration without having to pay attention to the keyword "required" in the hyperion schema * Allow Comments in Hyperion Schema * add ability to ignore the "required" keyword in hyperion schema * add ability to ignore the "required" keyword in hyperion schema * add ability to ignore the "required" keyword in hyperion schema * //Allow Comments in Hyperion Schema * Update jsonschema.py to version 0.8.0 to support ... references in json schema * add RefResolver from jsonschema.py to resolve references in hyperion schema * remove dupe code * split the hyperion schema in separatly files For better readability * add function "resolveReferences" to resolve references in hyperion schema. * remove CURRENT_CONFIG_VERSION * remove CURRENT_CONFIG_VERSION * split the hyperion schema in separatly files For better readability * Create schema-backgroundEffect.json * Add the rest of the Hyperion schema via upload * Remove Comments in config file * Add return variable to function writeJson(). fix function resolveReferences(). edit function load() to handle QPair result from schemaChecker. * edit function validate() to return QPair variable * fit function loadEffectDefinition() * fit function checkJson() * Expand error check by dividing "_error" variable in "_error" and "_schemaError". Replace variable "bool" in validate() in QPair * Extend function "cmd_cfg_set" to handle auto correction * Extend function "loadConfig" to handle auto correction * fix function loadConfig()
2017-07-30 13:32:10 +02:00
private:
static QJsonValue createValue(QJsonValue schema, bool ignoreRequired)
{
QJsonObject result;
QJsonObject obj = schema.toObject();
if (obj.find("type") != obj.end() && obj.find("type").value().isString())
{
QJsonValue ret = QJsonValue::Null;
if (obj.find("type").value().toString() == "object" && ( obj.find("required").value().toBool() || ignoreRequired ) )
ret = createValue(obj["properties"], ignoreRequired);
else if (obj.find("type").value().toString() == "array" && ( obj.find("required").value().toBool() || ignoreRequired ) )
{
QJsonArray array;
if (obj.find("default") != obj.end())
ret = obj.find("default").value();
else
{
ret = createValue(obj["items"], ignoreRequired);
if (!ret.toObject().isEmpty())
array.append(ret);
ret = array;
}
}
else if ( obj.find("required").value().toBool() || ignoreRequired )
if (obj.find("default") != obj.end())
ret = obj.find("default").value();
return ret;
}
else
{
for (QJsonObject::const_iterator i = obj.begin(); i != obj.end(); ++i)
{
QString attribute = i.key();
const QJsonValue & attributeValue = *i;
QJsonValue subValue = obj[attribute];
if (attributeValue.toObject().find("type") != attributeValue.toObject().end())
{
if (attributeValue.toObject().find("type").value().toString() == "object" && ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired ) )
{
if (obj.contains("properties"))
result[attribute] = createValue(obj["properties"], ignoreRequired);
else
result[attribute] = createValue(subValue, ignoreRequired);
}
else if (attributeValue.toObject().find("type").value().toString() == "array" && ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired ) )
{
QJsonArray array;
if (attributeValue.toObject().find("default") != attributeValue.toObject().end())
result[attribute] = attributeValue.toObject().find("default").value();
else
{
QJsonValue retEmpty;
retEmpty = createValue(attributeValue.toObject()["items"], ignoreRequired);
if (!retEmpty.toObject().isEmpty())
array.append(retEmpty);
result[attribute] = array;
}
}
else if ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired )
{
if (attributeValue.toObject().find("default") != attributeValue.toObject().end())
result[attribute] = attributeValue.toObject().find("default").value();
else
result[attribute] = QJsonValue::Null;
}
}
}
}
return result;
}
static void modifyValue(QJsonValue source, QJsonObject& target, QStringList path, const QJsonValue& newValue, QString& property)
{
QJsonObject obj = source.toObject();
if (!obj.isEmpty())
{
for (QJsonObject::iterator i = obj.begin(); i != obj.end(); ++i)
{
QString propertyName = i.key();
QJsonValue subValue = obj[propertyName];
if (subValue.isObject())
{
if (!path.isEmpty())
{
if (propertyName == path.first())
{
path.removeFirst();
if (!path.isEmpty())
{
QJsonObject obj;
modifyValue(subValue, obj, path, newValue, property);
subValue = obj;
}
else if (newValue != QJsonValue::Null)
subValue = newValue;
else
continue;
if (!subValue.toObject().isEmpty())
target[propertyName] = subValue;
}
else
{
if (path.first() == property && newValue != QJsonValue::Null)
{
target[property] = newValue;
property = QString();
}
target[propertyName] = subValue;
}
}
else
if (!subValue.toObject().isEmpty())
target[propertyName] = subValue;
}
else if (subValue.isArray())
{
if (!path.isEmpty())
{
if (propertyName == path.first())
{
path.removeFirst();
int arrayLevel = -1;
if (!path.isEmpty())
{
if ((path.first().left(1) == "[") && (path.first().right(1) == "]"))
{
arrayLevel = path.first().mid(1, path.first().size()-2).toInt();
path.removeFirst();
}
}
QJsonArray array = subValue.toArray();
QJsonArray json_array;
for (QJsonArray::iterator i = array.begin(); i != array.end(); ++i)
{
if (!path.isEmpty())
{
QJsonObject arr;
modifyValue(*i, arr, path, newValue, property);
subValue = arr;
}
else if (newValue != QJsonValue::Null)
subValue = newValue;
else
continue;
if (!subValue.toObject().isEmpty())
json_array.append(subValue);
else if (newValue != QJsonValue::Null && arrayLevel != -1)
json_array.append( (i - array.begin() == arrayLevel) ? subValue : *i );
}
if (!json_array.isEmpty())
target[propertyName] = json_array;
else if (newValue != QJsonValue::Null && arrayLevel == -1)
target[propertyName] = newValue;
}
else
{
if (path.first() == property && newValue != QJsonValue::Null)
{
target[property] = newValue;
property = QString();
}
target[propertyName] = subValue;
}
}
else
if (!subValue.toArray().isEmpty())
target[propertyName] = subValue;
}
else
{
if (!path.isEmpty())
{
if (propertyName == path.first())
{
path.removeFirst();
if (path.isEmpty())
{
if (newValue != QJsonValue::Null && property.isEmpty())
subValue = newValue;
else
continue;
}
target[propertyName] = subValue;
}
else
{
if (path.first() == property && newValue != QJsonValue::Null)
{
target[property] = newValue;
property = QString();
}
target[propertyName] = subValue;
}
}
else
target[propertyName] = subValue;
}
}
}
else if (newValue != QJsonValue::Null && !property.isEmpty())
{
target[property] = newValue;
property = QString();
}
}
};