RDF lists are not converted to json indexed arrays on compact
I currently try to read data from a triple store (construct query, yields turtle), load this data through a N3.js parser and compact the data with jsonld.js together with a custom context. The turtle data contains an ordered list and the context object contains the correct jsonld specification for an ordered list. My expected result would be:
{
"@context": {
"answers": {
"@id": "http://ex.org/eal/hasAnswerText",
"@container": "@list"
}
},
"@id": "http://ex.org/item/2",
"@type": "http://ex.org/eal/item",
"answers": ["42", "43", "41"]
}
But actually I get:
{
"@context": {
"answers": {
"@id": "http://ex.org/eal/hasAnswerText",
"@container": "@list"
}
},
"@graph": [
{
"@id": "/b5",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "42",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@id": "/b6"
}
},
{
"@id": "/b6",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "43",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@list": [
"41"
]
}
},
{
"@id": "http://ex.org/item/2",
"@type": "http://ex.org/eal/item",
"http://ex.org/eal/hasAnswerText": {
"@id": "/b5"
}
}
]
}
from this text/turtle:
@prefix ns1: <http://ex.org/eal/> .
<http://ex.org/item/2> a ns1:item ;
ns1:hasAnswerText ( "42" "43" "41" ) .
minimal script to proof this behaviour:
const jsonld = require('jsonld');
let itemContext = { answers: {'@id': 'http://ex.org/eal/hasAnswerText', '@container': '@list'} };
async function turtleToJSONLD(doc) {
let parsedTurtle = await turtleParser(doc);
let jsonRep = await jsonld.fromRDF(parsedTurtle);
return await jsonld.compact(jsonRep, itemContext);
}
async function turtleParser(doc) {
const parser = new require('n3').Parser();
let [quads, prefixes] = await new Promise((resolve, reject) => {
let quads = [];
parser.parse(doc, (error, quad, prefixes) => {
if (error)
reject(error);
else if (quad)
quads.push(quad);
else
resolve([quads, prefixes]);
});
});
return quads;
}
(async() => {
let toConvert = `@prefix ns1: <http://ex.org/eal/> . <http://ex.org/item/2> a ns1:item ; ns1:hasAnswerText ( "42" "43" "41" ) .`;
let converted = await turtleToJSONLD(toConvert);
console.log(converted);
})();
When I use the same context vice versa (accept {answers: ["42", "43", "41"]}, add the context from above, execute jsonld.toRDF of this object, load the result via N3.js, issue result to a sparql endpoint, request it again as turtle), the resulting turtle string looks as expected (have a look at the example above).
Workaround: If the format n-triples instead of turtle is used for jsonld.fromRDF() the resulting serialisation is correct and uses an indexed array for a RDF List, instead of producing the json structure mentioned in the initial posting. This should be noted somewhere, as the parser is afaik able to parse turtle too.
This behavior is weird. As far as I understand the API anything that can be compacted to a list representation should be compacted to a list representation. Maybe this fix should be included in JSON-LD 1.1?
Compaction to the list form happens when converting from RDF to JSON-LD. Note that RDF lists that can be serialized with a shorthand (Turtle or JSON-LD) subjects always use a Blank Nodes; your example uses relative IRIs, so wouldn't convert.
Try converting the following, instead:
{
"@context": {
"answers": {
"@id": "http://ex.org/eal/hasAnswerText",
"@container": "@list"
}
},
"@graph": [
{
"@id": "_:b5",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "42",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@id": "_:b6"
}
},
{
"@id": "_:b6",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "43",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@list": [
"41"
]
}
},
{
"@id": "http://ex.org/item/2",
"@type": "http://ex.org/eal/item",
"http://ex.org/eal/hasAnswerText": {
"@id": "_:b5"
}
}
]
}
Doesn't look good in JSON-LD Playground
JSON-LD playground doesn't do RDF to JSON-LD. Try it on my distiller.
Still looks wrong:
{
"@graph": [
{
"@id": "_:b5",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "42",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@id": "_:b6"
}
},
{
"@id": "_:b6",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first": "43",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest": {
"@list": [
"41"
]
}
},
{
"@id": "http://ex.org/item/2",
"@type": "http://ex.org/eal/item",
"http://ex.org/eal/hasAnswerText": {
"@id": "_:b5"
}
}
]
}
Using that on the distiller link I gave you doing jsonld to jsonld I get the following:
{
"@id": "http://ex.org/item/2",
"http://ex.org/eal/hasAnswerText": {
"@list": [
"42",
"43",
"41"
]
},
"@type": "http://ex.org/eal/item"
}
Were
What are the configurations you are using?
“Serialize” with “jsonld” as both input and output formats.
Cool. So is this the standard behaviour? If I get a JSON-LD document from a server and call compact() I'll get a list instead of rdf:first and rdf:rest? Why does the list items be BNodes?
Compaction does not fold first/last chains. That is done when converting from RDF. With the distiller, your parsing JSON-LD to RDF and then back to JSON-LD, which is why this works.
So I'll refine my suggestion: I believe compact should do that. If I get RDF style list it should be normalized to a regular list.
It was considered both for JSON-LD 1.0 and 1.1 but rejected, as Compaction doesn’t deal with RDF semantics/schema at all. Round-tripping is a reasonable way to do this.
Is there another way to communicate about list items with multiple documents that is supported JSON-LD? My goal is to be able to emit list items as separate documents.