Streaming JSON-LD

W3C Editor's Draft

This version:
https://w3c.github.io/json-ld-streaming/
Latest published version:
https://www.w3.org/TR/json-ld-streaming/
Latest editor's draft:
https://w3c.github.io/json-ld-streaming/
Editor:
Some Body
Participate:
GitHub w3c/json-ld-streaming
File a bug
Commit history
Pull requests

Abstract

JSON-LD [JSON-LD] offers a JSON-based serialization for Linked Data. One of the primary uses of JSON-LD is its ability for RDF exchange across the Web. This can be done by first serializing RDF to JSON-LD, after which others can deserialize JSON-LD to RDF.

Since RDF datasets may contain many triples, and JSON-LD documents don't have size limits, such documents could become very large. For these cases, the ability to serialize and parse JSON-LD in a streaming way offers many advantages, as large documents can be parsed with only a limited amount of memory, and processed chunks can be emitted as soon as they are processed, as opposed to waiting until the whole dataset or document has been processed.

The recommended processing algorithms do not work in a streaming manner, as these first load all required data in memory, after which this data can be processed. This note discusses the processing of JSON-LD in a streaming way. Concretely, a set of guidelines is introduced for efficiently serializing and deserializing JSON-LD in a streaming way. These guidelines are encapsulated in a JSON-LD streaming profile, so that implementations can detect JSON-LD documents that conform to this profile, and may apply streaming optimizations.

Status of This Document

This is a preview

Do not attempt to implement this version of the specification. Do not reference this version as authoritative in any way. Instead, see https://w3c.github.io/json-ld-streaming/ for the Editor's draft.

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This is an unofficial proposal.

This document was published by the JSON-LD Working Group as an Editor's Draft.

GitHub Issues are preferred for discussion of this specification. Alternatively, you can send comments to our mailing list. Please send them to public-json-ld-wg@w3.org (archives).

Publication as an Editor's Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. The group does not expect this document to become a W3C Recommendation. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 March 2019 W3C Process Document.

1. Introduction

This document discusses the concerns on serializing and deserializing JSON-LD in a streaming manner. This document is primarily intended for the following audiences:

To understand the basics in this note you must first be familiar with JSON, which is detailed in [RFC8259]. You must also understand the JSON-LD syntax defined in the JSON-LD 1.1 Syntax specification [JSON-LD11], which is the base syntax used for streaming processing. To understand how JSON-LD maps to RDF, it is helpful to be familiar with the basic RDF concepts [RDF11-CONCEPTS].

2. Streaming Document Form

There are multiple ways of describing data in JSON-LD, each having their own use cases. This section introduces a streaming JSON-LD document form, which enables JSON-LD documents to be processed in a streaming manner.

2.1 Importance of Key Ordering

The order in which key-value pairs occur in JSON-LD nodes conveys no meaning. For instance, the following two JSON-LD documents have the same meaning, even though they are syntactically different.

Example 1: Name, homepage and image come after @id
{
  "@context": "http://schema.org/",
  "@id": "https://www.rubensworks.net/#me",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg"
}
Example 2: Name, homepage and image come before @id
{
  "@context": "http://schema.org/",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg",
  "@id": "https://www.rubensworks.net/#me"
}

In a streaming JSON-LD document, the ordering of (some) keys is important. This is because streaming JSON-LD processors may require the presence of some keys before others can be processed, and ordering keys in certain ways may lead to better processing performance.

In the two snippets before, the first example can be processed more efficiently by a streaming processor. Concretely, a streaming JSON-LD deserializer can emit an RDF triple each time a property ("name", "url", "image") has been read, because the "@id" has been defined before. This is because the "@id" defines the RDF subject, the property key defines the RDF predicate, and the property value defines RDF object. This ensures that all required information is needed for constructing and emitting and RDF triple each time a property is encountered.

For the second example, where the "@id" is only defined at the end, a streaming deserializer would have to buffer the properties until the "@id" key is encountered. Since the RDF subject of our triples is defined via "@id", the RDF triples can only be emitted after this last key has been read.

2.2 Required Key Ordering

In order for a JSON-LD document to be a in a streaming document form, the keys in each JSON node MUST be ordered according to the following order:

  1. @context
  2. @type where its value indicates a type-scoped context.
  3. Other properties

Each of these keys is optional, and may be omitted. Only those that are present must occur in the following order.

This order is important because the @context and @type entries can change the meaning of all following entries in the node and its children. This means that these MUST always be processed before all other entries.

Note

Entries in nodes have a defined order when serialized as JSON. However, this this order is not always kept by JSON parsing libraries. This means that streaming processors MUST make use of JSON parsers that preserve this order to be effective.

2.4 Examples

Hereafter, a couple of JSON-LD document examples are listed that either adhere, adhere with non-recommended order, or not adhere to the streaming document form.

2.4.1 Valid Examples

Example 3: Valid streaming document with @context, @id, and other properties
{
  "@context": {
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image"
  },
  "@id": "https://www.rubensworks.net/#me",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg"
}
Example 4: Valid streaming document with @context, blank @id, and other properties
{
  "@context": {
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image"
  },
  "@id": "_:blank_node",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg"
}
Example 5: Valid streaming document with nested nodes
{
  "@context": {
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image",
    "knows": "http://schema.org/knows"
  },
  "@id": "https://www.rubensworks.net/#me",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg",
  "knows": {
    "@id": "https://greggkellogg.net/foaf#me",
    "name": "Gregg Kellogg",
  }
}
Example 6: Valid streaming document with nested nodes and embedded context
{
  "@context": {
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image",
    "knows": "http://schema.org/knows"
  },
  "@id": "https://www.rubensworks.net/#me",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg",
  "knows": {
    "@context": {
      "name": "http://xmlns.com/foaf/0.1/name"
    },
    "@id": "https://greggkellogg.net/foaf#me",
    "name": "Gregg Kellogg",
  }
}
Example 7: Valid streaming document with @context, @type-scoped context, @id, and other properties
{
  "@context": {
    "Person": {
      "@id": "http://schema.org/Person",
      "@context": {
        "name": "http://schema.org/name",
        "url": "http://schema.org/url",
        "image": "http://schema.org/image"
      }
    }
  },
  "@id": "https://www.rubensworks.net/#me",
  "@type": "Person",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg"
}
Example 8: Valid streaming document with @context, plain @type, @id, and other properties
{
  "@context": {
    "Person": "http://schema.org/Person",
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image"
  },
  "@id": "https://www.rubensworks.net/#me",
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg",
  "@type": "Person" // Defines no type-scoped context, so may appear anywhere
}

2.4.3 Invalid Examples

Example 11: Invalid streaming document where @context comes too late
{
  "@id": "https://www.rubensworks.net/#me",
  "@context": { // @context must come before @id
    "name": "http://schema.org/name",
    "url": "http://schema.org/url",
    "image": "http://schema.org/image"
  },
  "name": "Ruben Taelman",
  "url": "https://www.rubensworks.net/",
  "image": "https://www.rubensworks.net/img/ruben.jpg"
}
Example 12: Invalid streaming document where @id comes too late
{
  "http://schema.org/name": "Ruben Taelman",
  "@id": "https://www.rubensworks.net/#me", // @id must come before name
  "http://schema.org/url": "https://www.rubensworks.net/",
  "http://schema.org/image": "https://www.rubensworks.net/img/ruben.jpg"
}

2.5 Streaming Document Profile

JSON-LD documents can be signaled or requested in streaming document form. The profile URI identifying the streaming document form is http://www.w3.org/ns/json-ld#streaming.

The following example illustrates how this profile parameter can be used to request an a streaming document over HTTP.

GET /ordinary-json-document.json HTTP/1.1
Host: example.com
Accept: application/ld+json;profile=http://www.w3.org/ns/json-ld#streaming

Requests the server to return the requested resource as JSON-LD in streaming document form.

3. Streaming RDF Form

TODO: order in which RDF triples appear

3.1 Required Triple Ordering

TODO

3.2 Streaming RDF Profile

TODO

4. Streaming Processing

Whenever a JSON-LD document is present in streaming document form, a processor MAY process it in a streaming way.

This section describes high-level guidelines for processing JSON-LD in a streaming way. Concretely, guidelines are given for deserializing JSON-LD to RDF, and serializing RDF to JSON-LD. Further details on processing can be found in the JSON-LD processing algorithms

4.1 Deserialization

A streaming deserializer MAY be implemented by considering a JSON-LD document as a stream of incoming characters. By reading character-by-character, a deserializer can detect the contained JSON nodes and its key-value pairs.

A streaming deserializer MAY assume that the required key ordering of a streaming document is present. If a different order is detected, an error MAY be thrown with error code "invalid streaming key order".

The first expected entry in a node is @context. If such an entry is present, all following entries in this node can make us of it, possibly inheriting parts of the context from parent nodes. If such an entry is not present, only contexts from parent nodes are considered for this node.

If an @type entry is detected, it is checked whether or not it defines a type-scoped context according to the current node's context. If this defines a type-scoped context, the context for the current node is overridden.
Additionally, the @type must emit rdf:type triples based on the current node's subject and values. This subject will possibly only be determined later on, which will require buffering of these incomplete triples.

If an @id entry is detected, the RDF subject for the current node is defined for later usage. Any other entries that are detected before @id must be buffered until @id is found, or the node closes (which sets the subject to a blank node).

For every other property, the default JSON-LD algorithms are followed assuming the current node's subject.

4.2 Serialization

TODO

A. References

A.1 Informative references

[JSON-LD]
JSON-LD 1.0. Manu Sporny; Gregg Kellogg; Markus Lanthaler. W3C. 16 January 2014. W3C Recommendation. URL: https://www.w3.org/TR/json-ld/
[JSON-LD11]
JSON-LD 1.1. Gregg Kellogg; Pierre-Antoine Champin; Dave Longley. W3C. 5 March 2020. W3C Candidate Recommendation. URL: https://www.w3.org/TR/json-ld11/
[RDF11-CONCEPTS]
RDF 1.1 Concepts and Abstract Syntax. Richard Cyganiak; David Wood; Markus Lanthaler. W3C. 25 February 2014. W3C Recommendation. URL: https://www.w3.org/TR/rdf11-concepts/
[RFC8259]
The JavaScript Object Notation (JSON) Data Interchange Format. T. Bray, Ed.. IETF. December 2017. Internet Standard. URL: https://tools.ietf.org/html/rfc8259