Commit a04f8c89 authored by Volker Krause's avatar Volker Krause
Browse files

First part of adding JSON-LD multi-type support

The JSON-LD import filter now multiplies objects, one per type. This isn't
fully forwarded yet as we first need to propagate the new singular
deserialization API before we can change the default one.

Meanwhile this at least produces some output in the multi-type case,
rather than none previously.
parent aa6305bf
[
{
"@context": "http://schema.org",
"@type": [ "Hotel", "Hostel" ],
"name": "A place to stay",
"description": "Test multi-type expansion in import filtering"
}
]
[
{
"@context": "http://schema.org",
"@type": "LodgingBusiness",
"description": "Test multi-type expansion in import filtering",
"name": "A place to stay"
}
]
......@@ -151,7 +151,7 @@ QVariant File::reservation(const QString &resId) const
}
return array.at(0);
} else if (doc.isObject()) {
return JsonLdDocument::fromJson(doc.object());
return JsonLdDocument::fromJsonSingular(doc.object());
}
return {};
}
......@@ -278,7 +278,7 @@ QVariant File::documentInfo(const QString &id) const
}
return array.at(0);
} else if (doc.isObject()) {
return JsonLdDocument::fromJson(doc.object());
return JsonLdDocument::fromJsonSingular(doc.object());
}
return {};
}
......
......@@ -238,7 +238,7 @@ GenericExtractor::Result GenericPkPassExtractor::extract(KPkPass::Pass *pass, co
// decode the barcode here already, so we have more information available for the following steps
// also, we have additional context time information here
auto res = JsonLdDocument::fromJson(result);
auto res = JsonLdDocument::fromJsonSingular(result);
if (JsonLd::isA<FlightReservation>(res)) {
const auto bcbp = res.value<FlightReservation>().reservedTicket().value<Ticket>().ticketTokenData();
const auto bcbpData = IataBcbpParser::parse(bcbp, iataContextDate(pass, contextDate).date());
......
......@@ -223,7 +223,6 @@ static QVariant createInstance(const QJsonObject &obj)
}
#undef MAKE_FACTORY
QVector<QVariant> JsonLdDocument::fromJson(const QJsonArray &array)
{
QVector<QVariant> l;
......@@ -239,7 +238,21 @@ QVector<QVariant> JsonLdDocument::fromJson(const QJsonArray &array)
QVariant JsonLdDocument::fromJson(const QJsonObject& obj)
{
return createInstance(JsonLdImportFilter::filterObject(obj));
const auto normalized = JsonLdImportFilter::filterObject(obj);
// TODO actually return a vector here
if (normalized.isEmpty()) {
return {};
}
return createInstance(normalized.at(0).toObject());
}
QVariant JsonLdDocument::fromJsonSingular(const QJsonObject &obj)
{
const auto normalized = JsonLdImportFilter::filterObject(obj);
if (normalized.isEmpty()) {
return {};
}
return createInstance(normalized.at(0).toObject());
}
static bool valueIsNull(const QVariant &v)
......
......@@ -40,7 +40,16 @@ public:
/** Convert JSON-LD array into instantiated data types. */
static KITINERARY_EXPORT QVector<QVariant> fromJson(const QJsonArray &array);
/** Convert JSON-LD object into an instantiated data type. */
static KITINERARY_EXPORT QVariant fromJson(const QJsonObject &obj);
static KITINERARY_EXPORT QVariant fromJson(const QJsonObject &obj); // TODO return QVector<QVariant> here
/** Convert a single JSON-LD object into an instantiated data type.
* @note Use this only if you are sure the JSON-LD object does not expand to multiple objects!
* That is usually only the case for objects you have written yourself and that semantically
* are guaranteed to be a single object. Anything received from external sources can expand
* and should not use this method.
* @since 20.04
*/
static KITINERARY_EXPORT QVariant fromJsonSingular(const QJsonObject &obj);
/** Serialize instantiated data types to JSON-LD. */
static KITINERARY_EXPORT QJsonArray toJson(const QVector<QVariant> &data);
......
......@@ -327,33 +327,53 @@ static void filterRecursive(QJsonObject &obj)
}
}
QJsonObject JsonLdImportFilter::filterObject(const QJsonObject& obj)
QJsonArray JsonLdImportFilter::filterObject(const QJsonObject& obj)
{
QJsonObject res(obj);
filterRecursive(res);
const auto type = obj.value(QLatin1String("@type")).toString();
if (type.endsWith(QLatin1String("Reservation"))) {
filterReservation(res);
QStringList types;
const auto typeVal = obj.value(QLatin1String("@type"));
if (typeVal.isString()) {
types.push_back(typeVal.toString());
} else if (typeVal.isArray()) {
const auto typeNames = typeVal.toArray();
for (const auto &t : typeNames) {
if (t.isString()) {
types.push_back(t.toString());
}
}
}
// TODO consider additionalTypes property
auto actions = res.value(QLatin1String("potentialAction"));
if (!actions.isUndefined()) {
res.insert(QStringLiteral("potentialAction"), filterActions(actions));
}
QJsonArray results;
auto image = res.value(QLatin1String("image"));
if (image.isArray()) {
res.insert(QStringLiteral("image"), image.toArray().first());
}
for (const auto &type : types) {
QJsonObject res(obj);
res.insert(QStringLiteral("@type"), type);
filterRecursive(res);
if (type.endsWith(QLatin1String("Reservation"))) {
filterReservation(res);
}
image = res.value(QLatin1String("image"));
if (image.isObject()) {
const auto imageObject = image.toObject();
if (imageObject.value(QLatin1String("@type")).toString() == QLatin1String("ImageObject")) {
res.insert(QStringLiteral("image"), imageObject.value(QLatin1String("url")));
auto actions = res.value(QLatin1String("potentialAction"));
if (!actions.isUndefined()) {
res.insert(QStringLiteral("potentialAction"), filterActions(actions));
}
auto image = res.value(QLatin1String("image"));
if (image.isArray()) {
res.insert(QStringLiteral("image"), image.toArray().first());
}
image = res.value(QLatin1String("image"));
if (image.isObject()) {
const auto imageObject = image.toObject();
if (imageObject.value(QLatin1String("@type")).toString() == QLatin1String("ImageObject")) {
res.insert(QStringLiteral("image"), imageObject.value(QLatin1String("url")));
}
}
results.push_back(res);
}
return res;
return results;
}
......@@ -18,6 +18,7 @@
#ifndef KITINERARY_JSONLDIMPORTFILTER_H
#define KITINERARY_JSONLDIMPORTFILTER_H
class QJsonArray;
class QJsonObject;
namespace KItinerary {
......@@ -27,8 +28,10 @@ namespace KItinerary {
*/
namespace JsonLdImportFilter
{
/** Filter the top-level object @p obj for loading with JsonLdDocument. */
QJsonObject filterObject(const QJsonObject &obj);
/** Filter the top-level object @p obj for loading with JsonLdDocument.
* Due to type and graph expansion, the result can actually contain multiple object.
*/
QJsonArray filterObject(const QJsonObject &obj);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment