7#include "jsonldimportfilter.h"
8#include "json/jsonld.h"
9#include "json/jsonldfilterengine.h"
15#include <QJsonDocument>
27 {
"AutoDealer",
"LocalBusiness" },
28 {
"AutoRepair",
"LocalBusiness" },
29 {
"AutomotiveBusiness",
"LocalBusiness" },
30 {
"Bakery",
"FoodEstablishment" },
31 {
"BarOrPub",
"FoodEstablishment" },
32 {
"BedAndBreakfast",
"LodgingBusiness" },
33 {
"Brewery",
"FoodEstablishment" },
34 {
"BusStop",
"BusStation" },
35 {
"BusinessEvent",
"Event" },
36 {
"CafeOrCoffeeShop",
"FoodEstablishment" },
37 {
"Campground",
"LodgingBusiness" },
38 {
"ChildrensEvent",
"Event" },
39 {
"ComedyEvent",
"Event" },
40 {
"ComputerStore",
"LocalBusiness" },
41 {
"DanceEvent",
"Event" },
42 {
"Distillery",
"FoodEstablishment" },
43 {
"EditAction",
"UpdateAction" },
44 {
"EducationEvent",
"Event" },
45 {
"ElectronicsStore",
"LocalBusiness" },
46 {
"EntertainmentBusiness",
"LocalBusiness" },
47 {
"ExhibitionEvent",
"Event" },
48 {
"FastFoodRestaurant",
"FoodEstablishment" },
49 {
"Festival",
"Event" },
50 {
"HobbyShop",
"LocalBusiness" },
51 {
"HomeAndConstructionBusiness",
"LocalBusiness" },
52 {
"Hostel",
"LodgingBusiness" },
53 {
"Hotel",
"LodgingBusiness" },
54 {
"IceCreamShop",
"FoodEstablishment" },
55 {
"LiteraryEvent",
"Event" },
56 {
"Motel",
"LodgingBusiness" },
57 {
"MovieTheater",
"LocalBusiness" },
58 {
"MusicEvent",
"Event" },
59 {
"Resort",
"LodgingBusiness" },
60 {
"Restaurant",
"FoodEstablishment" },
61 {
"SaleEvent",
"Event" },
62 {
"ScreeningEvent",
"Event" },
63 {
"SocialEvent",
"Event" },
64 {
"SportsEvent",
"Event" },
65 {
"Store",
"LocalBusiness" },
66 {
"TheaterEvent",
"Event" },
67 {
"VisualArtsEvent",
"Event" },
68 {
"Winery",
"FoodEstablishment" },
72 const auto val = obj.
value(key);
80 obj.
insert(key, arr.at(0));
83static void migrateToAction(
QJsonObject &obj,
const char *propName,
const char *typeName,
bool remove)
86 if (value.isNull() || value.isUndefined()) {
90 const auto actionsVal = obj.
value(
"potentialAction"_L1);
92 if (actionsVal.isArray()) {
93 actions = actionsVal.toArray();
94 }
else if (actionsVal.isObject()) {
95 actions = { actionsVal };
98 for (
const auto &act : actions) {
106 action.
insert(QStringLiteral(
"target"), value);
107 actions.push_back(action);
108 obj.
insert(QStringLiteral(
"potentialAction"), actions);
118 if (
const auto addr = obj.
value(
"address"_L1); addr.
isString()) {
120 {
"@type"_L1,
"PostalAddress"_L1},
121 {
"streetAddress"_L1, addr.toString()},
125 const auto lat = obj.
value(
"latitude"_L1);
126 const auto lon = obj.
value(
"longitude"_L1);
127 if (lat.isDouble() && lon.isDouble()) {
129 if (!
geo.contains(
"@type"_L1)) {
130 geo.insert(
"@type"_L1,
"GeoCoordinates"_L1);
132 if (!
geo.contains(
"latitude"_L1)) {
133 geo.insert(
"latitude"_L1, lat);
135 if (!
geo.contains(
"longitude"_L1)) {
136 geo.insert(
"longitude"_L1, lon);
138 obj.
insert(
"geo"_L1, geo);
153 for (
const auto key : {
"ticketToken"_L1,
"ticketNumber"_L1}) {
157 if (ticket.isEmpty()) {
158 ticket.insert(
"@type"_L1, u
"Ticket"_s);
160 if (!ticket.contains(key)) {
161 ticket.insert(key, v);
162 res.
insert(
"reservedTicket"_L1, ticket);
170 if (!resStat.isEmpty()) {
171 if (resStat.startsWith(
"https:"_L1)) {
172 resStat.remove(4, 1);
174 if (!resStat.contains(
"/Reservation"_L1)) {
175 res.
insert(
"reservationStatus"_L1, resStat.replace(
"http://schema.org/"_L1,
"http://schema.org/Reservation"_L1));
187 migrateToAction(res,
"cancelReservationUrl",
"CancelAction",
true);
188 migrateToAction(res,
"checkinUrl",
"CheckInAction",
true);
189 migrateToAction(res,
"modifyReservationUrl",
"UpdateAction",
true);
190 migrateToAction(res,
"ticketDownloadUrl",
"DownloadAction",
true);
191 migrateToAction(res,
"url",
"ViewAction",
false);
200static void filterFoodEstablishment(
QJsonObject &restaurant)
203 auto reservationsValue =
205 if (reservationsValue.isString()) {
206 const QString reservations = reservationsValue.toString();
212 migrateToAction(restaurant,
"acceptsReservations",
"ReserveAction",
217 filterPlace(restaurant);
223 QString filteredTargetUrlString;
232 for (
auto it = targets.
begin(); it != targets.
end(); ++it) {
233 auto target = (*it).toObject();
239 if (actionPlatform.
isArray()) {
240 platforms = actionPlatform.
toArray();
246 if (!filteredTargetUrlString.
isEmpty()) {
247 const bool hasPreferredPlatform = std::any_of(platforms.
begin(), platforms.
end(), [](
const QJsonValue &platformValue) {
248 const QString platform = platformValue.toString();
250 return platform == QLatin1StringView(
251 "http://schema.org/DesktopWebPlatform");
254 if (!hasPreferredPlatform) {
262 if (!url.isValid()) {
266 filteredTargetUrlString = url.toString();
269 if (filteredTargetUrlString.
isEmpty()) {
272 action.
insert(QStringLiteral(
"target"), filteredTargetUrlString);
285 for (
auto it = actions.
begin(); it != actions.
end(); ++it) {
286 auto action = (*it).toObject();
287 filterActionTarget(action);
296 unpackArray(obj,
"location"_L1);
299 if (
const auto endDate = obj.
value(
"endDate"_L1).
toString(); endDate.
size() == 10) {
301 if (date.isValid()) {
320 {
"Event", filterEvent },
321 {
"Flight", filterFlight },
322 {
"FoodEstablishment", filterFoodEstablishment },
323 {
"LocalBusiness", filterPlace },
324 {
"Organization", filterPlace },
325 {
"Place", filterPlace },
326 {
"PostalAddress", filterPostalAddress },
332 {
"BusTrip",
"arrivalStation",
"arrivalBusStop" },
333 {
"BusTrip",
"busCompany",
"provider" },
334 {
"BusTrip",
"departureStation",
"departureBusStop" },
337 {
"Flight",
"provider",
"airline" },
340 {
"LodgingReservation",
"checkinDate",
"checkinTime" },
341 {
"LodgingReservation",
"checkoutDate",
"checkoutTime" },
343 {
"ProgramMembership",
"program",
"programName" },
344 {
"ProgramMembership",
"memberNumber",
"membershipNumber" },
346 {
"Reservation",
"price",
"totalPrice" },
347 {
"Ticket",
"price",
"totalPrice" },
350 {
"TrainTrip",
"trainCompany",
"provider" },
358 for (
const auto &o : graph) {
360 std::copy(a.begin(), a.end(), std::back_inserter(result));
370 if (typeVal.isString()) {
372 }
else if (typeVal.isArray()) {
373 const auto typeNames = typeVal.toArray();
374 for (
const auto &t : typeNames) {
383 return graphExpand(obj);
389 filterEngine.setTypeMappings(type_mapping);
390 filterEngine.setTypeFilters(type_filters);
391 filterEngine.setPropertyMappings(property_mappings);
392 for (
const auto &type : types) {
394 res.
insert(QStringLiteral(
"@type"), type);
398 if (
const auto mainEntityOfPage =
400 !mainEntityOfPage.isEmpty()) {
402 for (
auto it = mainEntityOfPage.begin(); it != mainEntityOfPage.end();
408 res.
insert(it.key(), it.value());
413 filterReservation(res);
417 if (!actions.isUndefined()) {
418 res.
insert(QStringLiteral(
"potentialAction"), filterActions(actions));
423 if (image.isObject()) {
424 const auto imageObject = image.toObject();
427 res.
insert(QStringLiteral(
"image"),
434 if (
const auto a = resFor.toArray(); !a.isEmpty()) {
435 for (
const auto &entry : a) {
JSON-LD filtering for input normalization or type transforms.
void filterRecursive(QJsonObject &obj)
Recursively apply filtering rules to obj.
char * toString(const EngineQuery &query)
QJsonArray filterObject(const QJsonObject &obj)
Filter the top-level object obj for loading with JsonLdDocument.
QString typeName(const QJsonObject &obj)
Normalized type name from object.
void renameProperty(QJsonObject &obj, const char *oldName, const char *newName)
Rename a property, if present and the new name isn't in use already.
GeoCoordinates geo(const QVariant &location)
Returns the geo coordinates of a given location.
Classes for reservation/travel data models, data extraction and data augmentation.
QStringView country(QStringView ifopt)
QDate fromString(QStringView string, QStringView format, QCalendar cal)
void push_back(const QJsonValue &value)
bool contains(QLatin1StringView key) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
void remove(QLatin1StringView key)
QJsonValue value(QLatin1StringView key) const const
bool isArray() const const
bool isObject() const const
bool isString() const const
QJsonArray toArray() const const
QJsonObject toObject() const const
QString toString() const const
bool isEmpty() const const
void push_back(parameter_type value)
bool isEmpty() const const
qsizetype size() const const