Utility class to transform strings depending on json object values.
Utility class to transform strings depending on json object values This is inspired by inja but is much much much more basic.
The template string can contains loops, conditions and variable fields.
Example
Example using templateStr
// code for $name$ (class $upperCamelCase(name)$) or $upperSnakeCase(name)$
// generated on $date()$ $time()$
@for@ $param$ in $parameters$
param = addParameter(new Property("$param.name$", $param.defaultValue$, tr("$param.description$"), "$param.unit$"));
@if@ $param.readOnly$
param->setReadOnly(true);
@else@
// param is not read only
@endif@
@subfor@ $ev$ in $param.enumValues$
// value: $ev$
@endsubfor@
@endfor@
@if@ $name$
// given name: $name$
@else@
// no given name
@endif@
@if@ $option$
// option: $option$
@else@
// no option
@endif@
@if@ $optionList$
// optionList is given
@for@ $o$ in $optionList$
// option: $o$
@endfor@
@else@
// no optionlist
@endif@
and data the given json data:
{
"name": "test data",
"optionList": [
"option1",
"option2",
false,
-5,
0
],
"parameters": [
{
"defaultValue": 100,
"description": "Testing double",
"name": "testDouble",
"readOnly": false,
"type": "double",
"unit": ""
},
{
"defaultValue": "QVector3D(0.0, 0.0, 0.0)",
"description": "test 3D vector",
"name": "testVector3D",
"readOnly": true,
"type": "QVector3D",
"unit": "mm"
},
{
"defaultValue": 1,
"description": "test enum",
"enumValues": [
"V1",
"V2",
"V3"
],
"name": "testenum",
"readOnly": false,
"type": "enum",
"unit": "mm"
}
]
}
then calling:
transformToString(templateStr, data)
will produce:
param = addParameter(new Property("testDouble", 100.0, tr("Testing double"), ""));
param = addParameter(new Property("testVector3D", QVector3D(0.0, 0.0, 0.0), tr("test 3D vector"), "mm"));
param->setReadOnly(true);
param = addParameter(new Property("testenum", 1.0, tr("test enum"), "mm"));
Functions
The following utility functions can be used in the template file (see example table below):
- $date()$ → generation date as YYYY-MM-DD
- $year()$, $month()$, $day()$ → respectively current year (as YYYY), month (1 to 12) and day (1 to 31)
- $time()$ → generation time as HH:MM:SS
- $index(p)$ → index of the current p in a loop (-1 if the template engine is outside a loop)
- $title(var)$ → clean var (remove everything that is not space nor letters) and capitalize the first letter of every words
- $lowerCamelCase(var)$ → same as titleCase but remove non-alphanumeric characters except underscores, first letter is lowercase and all space between words are removed
- $upperCamelCase(var)$ → same as camelCase but first letter is uppercase
- $lowerSnakeCase(var)$ → same as titleCase but remove non-alphanumeric characters except underscores, all space between words are replaced by an underscore and all letters are lowercase
- $upperSnakeCase(var)$ → same as lowerSnakeCase but all letters are uppercase
- $kebabCase(var)$ → same as lowerCamelCase but all letters are lowercase and words are separated by "-"
- $joinKebabCase(var)$ → same as kebabCase but all words are joined (no separator)
| Input | Function | Output |
| "my class name! 123 (test)" | title | "My Class Name! 123 (test)" |
| "my class name! 123 (test)" | lowerCamelCase | "myClassName123Test" |
| "my class name! 123 (test)" | upperCamelCase | "MyClassName123Test" |
| "my class name! 123 (test)" | lowerSnakeCase | "my_class_name_123_test" |
| "my class name! 123 (test)" | upperSnakeCase | "MY_CLASS_NAME_123_TEST" |
| "my class name! 123 (test)" | kebabCase | "my-class-name-123-test" |
| "my class name! 123 (test)" | joinKebabCase | "myclassname123test" |
for statement
Used for array to loop over each value
@for@ $i$ in $array$
... // here $i takes the value of a[i]
... // $i.j$ corresponds to a[i].j
@endfor@
Loop inside loop are supported using @subfor@..@endsubfor@
if statement
In if statement you can use the contains and equals as well (this can also be used in loops):
- @if@ contains($field$) ... @endif@ → check if data contains field
- @if@ contains($object.field$) ... @endif@ → check if data contains object that contains field
- @if@ equals($a$,"yes") yes @else@ no @endif@ → check if the value of data a is equals to "yes"
- @for@ $i$ in $a$ @if@ equals($i.b$,"foo") $index(i)$ has b==foo ($i.b$), @else@ $index(i)$ does not have b==foo, @endif@ @endfor@ → check if each value of i in a are equals to "foo"
- @if@ $parameter$ ...@endif@ → check if parameter can be evaluated to true, i.e.:
- parameter is present in the data
- and it is not null nor of undefined value
- and is either
- a boolean and equals to true
- a string but not empty, nor null nor equals to "false"
- a double but not equals to 0.0
- an int but not equals to 0
- an array, a map or an object but not empty
Algorithm
The main algorithm has three steps
- replace loop 1.1 replace functions inside loop 1.2 replace loop inside loop 1.3 replace conditions inside loop 1.4 replace variables inside loop
- replace conditions
- replace variables
- replace functions
#ifndef __TRANSFORM_ENGINE__
#define __TRANSFORM_ENGINE__
#include <QJsonObject>
public:
bool transformToFile(
const QJsonObject& data,
const QString& filename,
bool overwrite =
true);
private:
QString templateString;
QDate currentDate;
QTime currentTime;
int indexInLoop;
int indexInSubLoop;
QString transformLoop(const QString& textToTransform, const QJsonObject& data);
QString transformCondition(const QString& textToTransform, const QJsonObject& data);
QString transformVariable(const QString& textToTransform, const QJsonObject& data);
QString transformFunctions(const QString& textToTransform, const QJsonObject& data);
QString transformConditionInLoop(const QString& loopContent, const QJsonObject& loopContentData, const QString& variableName);
QString transformVariableInLoop(const QString& loopContent, const QJsonObject& loopContentData, const QString& variableName);
QString transformFunctionsInLoop(const QString& loopContent, const QJsonObject& loopContentData, const QString& variableName);
QString transformLoopInLoop(const QString& loopContent, const QJsonObject& loopContentData, const QString& variableName);
QString genericTransform(const QString& textToTransform, const QString& regularExpression, const std::function<QString(const QStringList&)>& matchFunction, bool withoutTrailingSpace = false);
QString substring(const QString& str, int startIndex, int endIndex = -1);
QString extractLeadingSpaces(const QString& str);
QString removeTrailingSpaces(const QString& str);
QString titleCase(const QString& str, const QString& separator = "");
QString clean(const QString& str);
QString camelCase(const QString& str, const QString& separator = "");
QVariant valueOf(const QJsonObject& data, const QString& key, const QString& subkey = QString());
QString append(QStringList& result, const QString& str, int startIndex = -1, int endIndex = -1, bool removeTrailingSpace = false);
QString appendWithoutTrailingSpace(QStringList& result, const QString& str, int startIndex = -1, int endIndex = -1);
bool saveToFile(const QString& content, const QString& filename, bool overwrite = true);
QString evaluateFunction(const QString& functionName, const QJsonObject& data, const QString& parameter, const QString& parameterField);
};
#endif