Skip to content

About

A JSON-based RDF serialisation format. Suitable for serialising datasets and for communications between AI agents.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RDF logo

RDF Dataflow

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 Dataflow breaks 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.

The Dataflow format

  • types.mts describes this format.
  • The content type for Dataflow messages is application/x-rdfdataflow+json.
  • The file extension for Dataflow files is .rdfdataflow.json.

Sample Dataflow messages

A simple message containing a dataset

"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" }
    ]
  ]
}

A message containing a more complex dataset

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" }
    ]
  ]
}

A message containing prose

"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" }
    ]
  ]
}

Dataflow compared to other RDF formats

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 Dataflow breaks 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 Dataflow is 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.

Usage example

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>

Running the usage example

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'

∎

About

A JSON-based RDF serialisation format. Suitable for serialising datasets and for communications between AI agents.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages