10#include <QJsonDocument>
15 const auto prefix = it.value().toString();
19 constexpr const char allowdTrailingChars[] =
":/?#[]@";
20 if (std::count(std::begin(allowdTrailingChars), std::end(allowdTrailingChars), prefix.back().toLatin1()) == 0) {
23 curieMap.insert(it.key(), prefix);
27static void resolveCurie(JsonLdProperty &prop,
const JsonLdCurieMap &curieMap);
29static void resolveCurie(
QString &str,
const JsonLdCurieMap &curieMap)
36 const auto fullPrefix = curieMap.value(prefix.toString());
37 if (fullPrefix.isEmpty()) {
43static void resolveCurie(JsonLdMetaType &mt,
const JsonLdCurieMap &curieMap)
45 resolveCurie(mt.qualifiedName, curieMap);
46 for (
auto &prop : mt.properties) {
47 resolveCurie(prop, curieMap);
51static void resolveCurie(JsonLdProperty &prop,
const JsonLdCurieMap &curieMap)
53 resolveCurie(prop.qualifiedName, curieMap);
54 resolveCurie(prop.type, curieMap);
55 resolveCurie(prop.metaType, curieMap);
56 resolveCurie(prop.prefix, curieMap);
59JsonLdProperty JsonLdProperty::fromJson(
const QString &name,
const QJsonValue &value)
67 prop.qualifiedName = value.
toString();
73 prop.prefix = prop.qualifiedName.left(prop.qualifiedName.indexOf(
QLatin1Char(
':')) + 1);
84 JsonLdCurieMap curieMap;
85 for (
auto it = context.begin(); it != context.end(); ++it) {
86 if (it.value().isObject()) {
87 const auto propObj = it.value().toObject();
88 auto prop = JsonLdProperty::fromJson(it.key(), it.value());
90 prop.metaType.load(propObj);
92 addProperty(std::move(prop));
94 else if (it.value().isString()) {
95 if (readCurie(it, curieMap)) {
98 addProperty(JsonLdProperty::fromJson(it.key(), it.value()));
102 resolveCurie(*
this, curieMap);
105void JsonLdMetaType::addProperty(JsonLdProperty &&property)
107 if (property.name.isEmpty()) {
111 auto it = std::lower_bound(
properties.begin(),
properties.end(), property, [](
const auto &lhs,
const auto &rhs) { return lhs.name < rhs.name; });
112 if (it ==
properties.end() || (*it).name != property.name) {
118void JsonLdContext::load(
const QByteArray &contextData,
const JsonLdDocumentLoader &loader)
121 const auto context = doc.object().value(
QLatin1String(
"@context"));
122 if (context.isObject()) {
123 load(context.toObject());
124 }
else if (context.isArray()) {
125 for (
const auto &c : context.toArray()) {
128 }
else if (c.isString()) {
129 load(loader(c.toString()), loader);
135void JsonLdContext::load(
const QJsonObject &context)
137 for (
auto it = context.
begin(); it != context.
end(); ++it) {
138 if (it.value().isObject()) {
139 const auto subObj = it.value().toObject();
140 if (it.key().front().isUpper() || subObj.contains(
QLatin1String(
"@context"))) {
141 JsonLdMetaType metaType;
142 metaType.name = it.key();
143 metaType.load(subObj);
144 metaTypes.push_back(std::move(metaType));
146 globalProperties.push_back(JsonLdProperty::fromJson(it.key(), it.value()));
149 else if (it.value().isString()) {
150 if (readCurie(it, curieMap)) {
153 if (it.key().front().isUpper()) {
154 JsonLdMetaType metaType;
155 metaType.name = it.key();
156 metaType.qualifiedName = it.value().toString();
157 metaTypes.push_back(std::move(metaType));
159 globalProperties.push_back(JsonLdProperty::fromJson(it.key(), it.value()));
165void JsonLdContext::resolve()
167 for (
auto &mt : metaTypes) {
168 for (
auto prop : globalProperties) {
169 mt.addProperty(std::move(prop));
173 for (
auto &mt : metaTypes) {
174 resolveCurie(mt, curieMap);
177 std::sort(metaTypes.begin(), metaTypes.end(), [](
const auto &lhs,
const auto &rhs) {
178 return lhs.name < rhs.name;
182JsonLdMetaType JsonLdContext::metaType(
const QString &type)
const
184 const auto it = std::lower_bound(metaTypes.begin(), metaTypes.end(), type, [](
const auto &lhs,
const auto &rhs) {
185 return lhs.name < rhs;
187 if (it != metaTypes.end() && (*it).name == type) {
193void JsonLd::setDocumentLoader(
const JsonLdDocumentLoader &loader)
195 m_documentLoader = loader;
198std::vector<Rdf::Quad> JsonLd::toRdf(
const QJsonObject &obj)
const
200 std::vector<Rdf::Quad> quads;
204 JsonLdContext context;
205 if (contextVal.isArray()) {
206 for (
const auto &contextV : contextVal.toArray()) {
207 context.load(m_documentLoader(contextV.toString()), m_documentLoader);
209 }
else if (contextVal.isString()) {
210 context.load(m_documentLoader(contextVal.toString()), m_documentLoader);
214 toRdfRecursive(context, obj, quads);
218Rdf::Term JsonLd::toRdfRecursive(
const JsonLdContext &context,
const QJsonObject &obj, std::vector<Rdf::Quad> &quads)
const
220 const auto id = idForObject(obj);
224 if (typeVal.isArray()) {
225 for (
const auto &typeV : typeVal.toArray()) {
226 toRdfRecursive(context, context.metaType(typeV.toString()),
id, obj, quads);
228 }
else if (typeVal.isString()) {
229 toRdfRecursive(context, context.metaType(typeVal.toString()),
id, obj, quads);
235void JsonLd::toRdfRecursive(
const JsonLdContext &context,
const JsonLdMetaType &mt,
const Rdf::Term &
id,
const QJsonObject &obj, std::vector<Rdf::Quad> &quads)
const
237 if (mt.name.isEmpty() && mt.properties.empty()) {
241 for (
const auto &property : mt.properties) {
242 const auto val = obj.
value(property.name);
243 if (val.isUndefined()) {
247 const auto createQuad = [&](
const QJsonValue &value) {
250 quad.predicate.value =
property.qualifiedName;
251 quad.predicate.type = Rdf::Term::IRI;
253 quad.object.value = value.
toString();
255 quad.object.type = Rdf::Term::IRI;
256 }
else if (property.qualifiedName ==
QLatin1String(
"@type")) {
257 quad.predicate.value = QStringLiteral(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
258 quad.object.type = Rdf::Term::IRI;
259 if (!property.metaType.qualifiedName.isEmpty()) {
260 quad.object.value =
property.metaType.qualifiedName;
261 }
else if (!mt.qualifiedName.isEmpty()) {
262 quad.object.value = mt.qualifiedName;
265 quad.object.type = Rdf::Term::IRI;
266 quad.object.value =
property.prefix + quad.object.value;
268 quad.object.type = Rdf::Term::Literal;
269 quad.object.literalType =
property.type;
272 if (property.metaType.properties.empty()) {
273 quad.object = toRdfRecursive(context, value.
toObject(), quads);
275 const auto subId = idForObject(value.
toObject());
276 toRdfRecursive(context, property.metaType, subId, value.
toObject(), quads);
281 quad.object.type = Rdf::Term::Literal;
282 quad.object.literalType = QStringLiteral(
"http://www.w3.org/2001/XMLSchema#integer");
284 quads.push_back(std::move(quad));
291 for (
const auto &i : val.toArray()) {
301Rdf::Term JsonLd::idForObject(
const QJsonObject &obj)
const
305 if (
id.value.isEmpty()) {
306 id.type = Rdf::Term::BlankNode;
309 id.type = Rdf::Term::IRI;
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
QString name(StandardAction id)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonValue value(QLatin1StringView key) const const
bool isDouble() const const
bool isObject() const const
bool isString() const const
int toInt(int defaultValue) const const
QJsonObject toObject() const const
QString toString() const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString number(double n, char format, int precision)
QStringView left(qsizetype length) const const
QStringView mid(qsizetype start, qsizetype length) const const