JSON LD vs RDF/JSON (Alternative serialization)
I’d like to say that I am rarely opinionated about technology but that would be a barefaced lie. It is true, however, that I am rarely so opinionated that I motivate myself to write about it. This, unfortunately, is one of those occasions.
On January the 16th the JSON-LD specification became a W3C recommendation. There was an “Alternative Serialization” of RDF into JSON, referred to as RDF/JSON. This format is not to become a recommendation:
The RDF Working Group has decided not to push this document through the W3C Recommendation Track. [from http://www.w3.org/TR/rdf-json/]
I think that decision was a mistake; particularly from the perspective of an RDF user. I have no real right to complain as I was not involved with the working group or a member of the mailing list; I can whine now, though.
Differences
In a nutshell:
RDF/JSON (the Alternative Syntax) is very simple. It maps obviously to Notation 3 and the RDF core concept.
JSON-LD is not specific to RDF and it has lots of features to make it more readable to a human, which makes it more verbose.
Using the syntaxes
I am making an assumption that, in choosing JSON as a format, the user of one of the two syntaxes would likely be a JavaScript developer. So, I put together a minimal example of processing RDF written in both syntaxes. In both cases I have mapped the following Turtle into JSON in the tersest way I could – specifically, I did not use the JSON-LD “@context” attribute, in order to give JSON-LD the fairest chance. Then, for each JSON object I wrote a simple JavaScript program to convert the RDF back into Turtle. Here are the two programs for comparison:
Using the “Alternative Syntax”:
function printLiteralTriple(subject, predicate, value, language) {
document.write("<" + subject + "> <" + predicate + "> "" + value + ""@" + language + " .");
document.write("<br/>");
}
var jsonAlt = {
"http://example.org/about" : {
"http://purl.org/dc/terms/title" : [ { "value" : "Anna's Homepage",
"type" : "literal",
"lang" : "en" } ]
}
}
for (var subject in jsonAlt) {
for (var predicate in jsonAlt[subject]) {
for (var objectIndex in jsonAlt[subject][predicate]) {
var object = jsonAlt[subject][predicate][objectIndex];
printLiteralTriple(subject, predicate, object.value, object.lang);
}
}
}
See the Pen zoFHC by chrismichaelscott (@chrismichaelscott) on CodePen.
Note that the iteration is east to understand as the keys hold useful content – a common construct in JavaScript – and are homogeneous (i.e. the top level keys are always subjects).
Using JSON-LD:
function printLiteralTriple(subject, predicate, value, language) {
document.write("<" + subject + "> <" + predicate + "> "" + value + ""@" + language + " .");
document.write("<br/>");
}
var jsonLD = {
"@id": "http://example.org/about",
"http://purl.org/dc/terms/title": {
"@value": "Anna's Homepage",
"@type": "literal",
"@language" : "en"
}
}
for (var key in jsonLD) {
var subject;
if (key == "@id") {
subject = jsonLD[key];
} else { // NOTE: there are other cases to check for here, such as @context
var predicate = key;
var object = jsonLD[key];
if (object instanceof Array) {
for (var objectIndex in object) {
printLiteralTriple(subject, predicate, object[objectIndex]["@value"], object[objectIndex]["@language"]);
}
} else {
printLiteralTriple(subject, predicate, object["@value"], object["@language"]);
}
}
}
See the Pen JaeIG by chrismichaelscott (@chrismichaelscott) on CodePen.
Because the keys in JSON-LD are not homogeneous (i.e. they may be keywords, like “@id”, or they may be predicates) the developer cannot simply iterate over the object.
Computer readable verses human readable
A fully featured JSON-LD document may be more complex than the example above. One can use the “@context” key to provide typing information and prefixes (as they would be in Turtle). That feature can arguably make the document easier for a human to read but is that really the objective? Look what happens to the JavaScript parser when we include a “@context” – and consider that this is a minimal parser that doesn’t support any case other than a literal valued triple.
var jsonLD = {
"@context": {
"title": {
"@id": "http://purl.org/dc/terms/title",
"@type": "@value",
"@language": "en"
}
},
"@id": "http://example.org/about",
"title": "Anna's Homepage"
}
function printLiteralTriple(subject, predicate, value, language) {
document.write("<" + subject + "> <" + predicate + "> "" + value + ""@" + language + " .");
document.write("<br/>");
}
var contexts = {};
// first resolve contexts
for (var key in jsonLD) {
if (key == "@context") {
if (jsonLD["@context"] instanceof Array) {
for (var contextIndex in jsonLD["@context"]) {
for (var context in jsonLD["@context"][contextIndex]) {
contexts[context] = jsonLD["@context"][contextIndex][context];
}
}
} else {
for (var context in jsonLD["@context"]) {
contexts[context] = jsonLD["@context"][context];
}
}
}
}
for (var key in jsonLD) {
var subject;
if (key == "@id") {
subject = jsonLD[key];
} else if (key != "@context") {
var predicate = key;
var object = jsonLD[key];
var objectLanguage;
if (typeof(contexts[predicate]) !== "undefined") {
if (typeof(contexts[predicate]["@language"]) !== "undefined") {
objectLanguage = contexts[predicate]["@language"];
}
predicate = contexts[predicate]["@id"];
}
if (object instanceof Array) {
for (var objectIndex in object) {
var objectValue;
if (typeof(object[objectIndex]) == "string") {
objectValue = object[objectIndex];
} else {
if (typeof(objectLanguage) == "undefined") {
objectLanguage = object[objectIndex]["@language"];
}
objectValue = object[objectIndex]["@value"];
}
printLiteralTriple(subject, predicate, objectValue, objectLanguage);
}
} else {
var objectValue;
if (typeof(object) == "string") {
objectValue = object;
} else {
if (typeof(objectLanguage) == "undefined") {
objectLanguage = object["@language"];
}
objectValue = object["@value"];
}
printLiteralTriple(subject, predicate, objectValue, objectLanguage);
}
}
}
See the Pen jiarn by chrismichaelscott (@chrismichaelscott) on CodePen.
Not great, is it? I really hope the working group reconsider. For human readable RDF use Turtle: it’s great at that. For RDF to be consumed by object oriented languages, use RDF/JSON, the “Alternative Serialization”. 🙁
Leave a Reply