RDF Dataflow (or Dataflow for short) is a JSON-based message format for RDF-star, which is a superset of RDF 1.1.
RDF has a dual purpose here:
- Data — It's a way of representing (semantic) data. This is the original purpose of RDF.
- A language for machines —
RDF Dataflowbreaks new ground by introducing the RDF as language concept. RDF can serve as a new language for machines and software, mainly for those that have AI/LLM capabilities, but not only. Indeed, an RDF statement can be seen as being structured as a subject+verb+object triple, and can be converted to a human language.
Dataflow 2.x fully supports both uses of RDF:
- A Dataflow message can contain an RDF dataset, where the order of statements is not significant, and where duplicate statements are just a waste of bandwidth.
- Prose mode — Dataflow messages can contain prose whereby machines communicate with each other. Such a message is structured as an ordered array of RDF statements, where the duplication of statements is significant.
types.mtsdescribes this format.- The content type for Dataflow messages is
application/x-rdfdataflow+json. - The file extension for Dataflow files is
.rdfdataflow.json.
"https://site.example/#jim's name is Jim."
{
"rdfdataflow": { "version": "2.0" },
"dataset": [
[
{ "type": "iri", "value": "https://site.example/#jim" },
{ "type": "iri", "value": "https://schema.org/givenName" },
{ "type": "literal", "value": "Jim" }
]
]
}Contains a statement about a statement: "https://site.example/#xyz's name is Xyz. https://site.example/#xyz's name is Xyz since 1999-12-25."
{
"rdfdataflow": { "version": "2.0" },
"head": {
"prefixes": {
"ex" : "https://site.example/",
"schema": "https://schema.org/",
"xsd" : "http://www.w3.org/2001/XMLSchema#"
}
},
"dataset": [
[
{ "type": "iri", "value": "ex:xyz" },
{ "type": "iri", "value": "schema:givenName" },
{ "type": "literal", "value": "Xyz", "language": "tr" }
],
[
{
"type": "triple",
"value": [
{ "type": "iri", "value": "ex:xyz" },
{ "type": "iri", "value": "schema:givenName" },
{ "type": "literal", "value": "Xyz", "language": "tr" }
]
},
{ "type": "iri", "value": "ex:since" },
{ "type": "literal", "value": "1999-12-25", "datatype": "xsd:date" }
]
]
}"https://site.example/jimbo's name is Jim Bo. https://site.example/jimbo's mailbox is mailto:jim.bo@site.example."
{
"rdfdataflow": { "version": "2.0" },
"head": {
"prefixes": {
"ex" : "https://site.example/",
"foaf": "http://xmlns.com/foaf/0.1/",
"xsd" : "http://www.w3.org/2001/XMLSchema#"
}
},
"prose": [
[
{ "type": "iri", "value": "ex:jimbo" },
{ "type": "iri", "value": "foaf:name" },
{ "type": "literal", "value": "Jim Bo" }
],
[
{ "type": "iri", "value": "ex:jimbo" },
{ "type": "iri", "value": "foaf:mbox" },
{ "type": "literal", "value": "mailto:jim.bo@site.example", "datatype": "xsd:anyURI" }
]
]
}RDF Dataflow is suitable whenever:
- RDF-star support is required, in particular whenever making statements about statements should be possible.
- Serialisers and deserialisers should be easy to implement.
- Document completeness (= non-truncation) should be easy to verify by examining the document contents.
Where the other RDF formats are currently falling short:
-
RDF Dataflowbreaks new ground with its prose mode. All the other RDF formats are only geared toward representing data. -
The SPARQL 1.1 Query Results JSON Format does not support RDF-star, and its purpose is to serialise many types of SPARQL results, not only RDF datasets.
RDF Dataflowis derived from this format. -
JSON-LD is another JSON-based format. This format ensures non-truncation, and RDF-star support is in the works, but this is a terse and human-unfriendly format for which serialisers and deserialisers are non-trivial to program.
-
Turtle and TriG support RDF-star, but writing serialisers and deserialisers for those formats is non-trivial, and they make it impossible to ensure that a document hasn't been truncated, unless a special vocabulary such as qrmm is used to ensure content integrity.
-
N-Quads and N-Triples support RDF-star, but writing serialisers and deserialisers for those formats is somewhat more difficult than for
RDF Dataflow, and these formats also make it impossible to ensure that a document hasn't been truncated, unless a special vocabulary such as qrmm is used to ensure content integrity.
RDF to Dataflow to JSON and back.
description = ''' RDF to Dataflow to JSON and back '''
import N3 from 'https://esm.sh/gh/rdfjs/N3.js@v2.0.3/src/index.js';
import {
DATAFLOW_VERSION, DATAFLOW_CONTENT_TYPE, DATAFLOW_FILE_EXTENSION, DataflowMessage
} from 'https://esm.sh/gh/doga/rdf-dataflow@2.0.4/mod.mjs';
const
datasetFactory = new N3.StoreFactory(),
dataFactory = N3.DataFactory,
displayDataset = dataset => {
console.group('\nRDF dataset:');
for (const quad of dataset) {
console.group('Quad:');
if(quad.subject.termType === 'Quad') {
console.group('Subject quad:');
console.info(`Subject: ${quad.subject.subject.value}`)
console.info(`Predicate: ${quad.subject.predicate.value}`)
console.info(`Object: ${quad.subject.object.value}`)
console.groupEnd();
} else {
console.info(`Subject: ${quad.subject.value}`)
}
console.info(`Predicate: ${quad.predicate.value}`)
console.info(`Object: ${quad.object.value}`)
console.groupEnd();
}
console.groupEnd();
},
// Create an in-memory RDF dataset, and import Turtle data into the dataset.
dataset = datasetFactory.dataset(),
turtleData = `
# "<https://site.example/xyz>'s name is Xyz."
PREFIX ex: <https://site.example/>
PREFIX schema: <https://schema.org/>
ex:xyz schema:givenName 'Xyz'@tr.
`,
parser = new N3.Parser(),
turtleDataQuads = parser.parse(turtleData);
dataset.addAll(turtleDataQuads);
// Programmatically add quads to the dataset.
dataset.add(dataFactory.quad( // "<https://site.example/xyz>'s name is Xyz since December 25, 1999."
dataFactory.triple(
dataFactory.namedNode('https://site.example/xyz'),
dataFactory.namedNode('https://schema.org/givenName'),
dataFactory.literal('Xyz', 'tr-TR')
),
dataFactory.namedNode('https://site.example/since'),
dataFactory.literal('1999-12-25', dataFactory.namedNode('http://www.w3.org/2001/XMLSchema#date'))
));
displayDataset(dataset);
// Build a Dataflow message containing a dataset.
const message = DataflowMessage.fromRDF(
dataset,
{
prefixes: {
ex : 'https://site.example/',
schema: 'https://schema.org/',
xsd : 'http://www.w3.org/2001/XMLSchema#'
}
}
);
message.print();
console.info(JSON.stringify(message.toObject(), null, 2));
const
/**
* An RDF dataset read from a Dataflow message.
* @type {Object} A DatasetCore object.
* @see {@link https://rdf.js.org/dataset-spec/#datasetcore-interface | DatasetCore}
**/
rdfDataset = message.toRDF();
// Build a Dataflow message containing prose.
const message2 = DataflowMessage.fromRDF(
// In prose, the order and repetition of statements are significant
[
// <https://site.example/jimbo>'s name is Jim Bo.
dataFactory.quad(
dataFactory.namedNode('https://site.example/jimbo'),
dataFactory.namedNode('http://xmlns.com/foaf/0.1/name'),
dataFactory.literal('Jim Bo')
),
// <https://site.example/jimbo>'s mailbox is "mailto:jim.bo@site.example".
dataFactory.quad(
dataFactory.namedNode('https://site.example/jimbo'),
dataFactory.namedNode('http://xmlns.com/foaf/0.1/mbox'),
dataFactory.literal(
'mailto:jim.bo@site.example',
dataFactory.namedNode('http://www.w3.org/2001/XMLSchema#anyURI')
)
),
],
{
prefixes: {
ex : 'https://site.example/',
foaf: 'http://xmlns.com/foaf/0.1/',
xsd : 'http://www.w3.org/2001/XMLSchema#',
},
isProse: true
}
);
message2.print();
console.info(JSON.stringify(message2.toObject(), null, 2));
const
/**
* Prose read from a Dataflow message.
* @type {Object[]} An array of quads.
* @see {@link https://rdf.js.org/data-model-spec/#quad-interface | Quad}
**/
prose = message2.toRDF(),
/**
* Dataflow message is read from JSON.
*/
message3 = DataflowMessage.fromObject(
{
"rdfdataflow": { "version": "2.0" },
"head": {
"prefixes": {
"ex" : "https://site.example/",
"foaf": "http://xmlns.com/foaf/0.1/",
"xsd" : "http://www.w3.org/2001/XMLSchema#"
}
},
"prose": [
[
{
"type" : "triple",
"value": [
{ "type": "iri", "value": "ex:jimbo" },
{ "type": "iri", "value": "foaf:name" },
{ "type": "literal", "value": "Jim Bo", "language": "en-US"}
]
},
{ "type": "iri", "value": "ex:since" },
{ "type": "literal", "value": "1999-12-25", "datatype": "xsd:date" }
]
]
}
);
message3.print();Sample output for the code above:
RDF dataset:
Quad:
Subject: https://site.example/xyz
Predicate: https://schema.org/givenName
Object: Xyz
Quad:
Subject quad:
Subject: https://site.example/xyz
Predicate: https://schema.org/givenName
Object: Xyz
Predicate: https://site.example/since
Object: 1999-12-25
Dataflow message containing an RDF dataset:
Statements:
Statement:
Subject:
<https://site.example/xyz>
Predicate:
<https://schema.org/givenName>
Object:
"Xyz"@tr
Statement:
Subject:
Triple:
Subject:
<https://site.example/xyz>
Predicate:
<https://schema.org/givenName>
Object:
"Xyz"@tr-tr
Predicate:
<https://site.example/since>
Object:
"1999-12-25"^^<http://www.w3.org/2001/XMLSchema#date>
{
"rdfdataflow": {
"version": "2.0"
},
"head": {
"prefixes": {
"ex": "https://site.example/",
"schema": "https://schema.org/",
"xsd": "http://www.w3.org/2001/XMLSchema#"
}
},
"dataset": [
[
{
"type": "iri",
"value": "ex:xyz"
},
{
"type": "iri",
"value": "schema:givenName"
},
{
"type": "literal",
"value": "Xyz",
"language": "tr"
}
],
[
{
"type": "triple",
"value": [
{
"type": "iri",
"value": "ex:xyz"
},
{
"type": "iri",
"value": "schema:givenName"
},
{
"type": "literal",
"value": "Xyz",
"language": "tr-tr"
}
]
},
{
"type": "iri",
"value": "ex:since"
},
{
"type": "literal",
"value": "1999-12-25",
"datatype": "xsd:date"
}
]
]
}Dataflow message containing prose:
Statements:
Statement:
Subject:
<https://site.example/jimbo>
Predicate:
<http://xmlns.com/foaf/0.1/name>
Object:
"Jim Bo"^^<http://www.w3.org/2001/XMLSchema#string>
Statement:
Subject:
<https://site.example/jimbo>
Predicate:
<http://xmlns.com/foaf/0.1/mbox>
Object:
"mailto:jim.bo@site.example"^^<http://www.w3.org/2001/XMLSchema#anyURI>
{
"rdfdataflow": {
"version": "2.0"
},
"head": {
"prefixes": {
"ex": "https://site.example/",
"foaf": "http://xmlns.com/foaf/0.1/",
"xsd": "http://www.w3.org/2001/XMLSchema#"
}
},
"prose": [
[
{
"type": "iri",
"value": "ex:jimbo"
},
{
"type": "iri",
"value": "foaf:name"
},
{
"type": "literal",
"value": "Jim Bo"
}
],
[
{
"type": "iri",
"value": "ex:jimbo"
},
{
"type": "iri",
"value": "foaf:mbox"
},
{
"type": "literal",
"value": "mailto:jim.bo@site.example",
"datatype": "xsd:anyURI"
}
]
]
}Dataflow message containing prose:
Statements:
Statement:
Subject:
Triple:
Subject:
<https://site.example/jimbo>
Predicate:
<http://xmlns.com/foaf/0.1/name>
Object:
"Jim Bo"@en-US
Predicate:
<https://site.example/since>
Object:
"1999-12-25"^^<http://www.w3.org/2001/XMLSchema#date>
Run the code above by typing this in your terminal (requires Deno 2+):
deno run --allow-net --allow-run --allow-env --allow-read jsr:@andrewbrey/mdrb@3.0.4 --dax=false --mode=isolated 'https://raw.githubusercontent.com/doga/rdf-dataflow/refs/heads/main/README.md'∎