JSON [[!RFC4627]] has proven to be a highly useful object serialization and messaging format. JSON-LD [[!JSON-LD]] harmonizes the representation of Linked Data in JSON by outlining a common JSON representation format for expressing directed graphs; mixing both Linked Data and non-Linked Data in a single document. This document outlines an Application Programming Interface and a set of algorithms for programmatically transforming JSON-LD documents.
This document is an experimental work in progress.
JSON, as specified in [[!RFC4627]], is a simple language for representing
data on the Web. Linked Data is a technique for creating a graph of interlinked data across
different
documents or Web sites. Data entities are described using
JSON-LD is designed as a light-weight syntax that can be used to express Linked Data. It is primarily intended to be a way to use Linked Data in Javascript and other Web-based programming environments. It is also useful when building interoperable Web services and when storing Linked Data in JSON-based document storage engines. It is practical and designed to be as simple as possible, utilizing the large number of JSON parsers and libraries available today. It is designed to be able to express key-value pairs, RDF data, RDFa [[RDFA-CORE]] data, Microformats [[MICROFORMATS]] data, and Microdata [[MICRODATA]]. That is, it supports every major Web-based structured data model in use today.
The syntax does not necessarily require applications to change their JSON, but allows to easily add meaning by adding context in a way that is either in-band or out-of-band. The syntax is designed to not disturb already deployed systems running on JSON, but provide a smooth upgrade path from JSON to JSON with added semantics. Finally, the format is intended to be easy to parse, efficient to generate, convertible to RDF in one pass, and require a very small memory footprint in order to operate.
This document is a detailed specification for a serialization of Linked Data in JSON. The document is primarily intended for the following audiences:
To understand the basics in this specification you must first be familiar with JSON, which is detailed in [[!RFC4627]]. You must also understand the JSON-LD Syntax [[!JSON-LD]], which is the base syntax used by all of the algorithms in this document. To understand the API and how it is intended to operate in a programming environment, it is useful to have working knowledge of the JavaScript programming language [[ECMA-262]] and WebIDL [[!WEBIDL]]. To understand how JSON-LD maps to RDF, it is helpful to be familiar with the basic RDF concepts [[!RDF-CONCEPTS]].
Examples may contain references to existing vocabularies and use
dc, e.g., dc:title)foaf, e.g., foaf:knows)rdf, e.g., rdf:type)xsd, e.g., xsd:integer)JSON [[RFC4627]] defines several terms which are used throughout this document:
@value, @list or @set and it has one or more keys other than @id.@id key.
The following definition for
Note that the definition for
There are a number of ways that one may participate in the development of this specification:
This API provides a clean mechanism that enables developers to convert JSON-LD data into a a variety of output formats that are easier to work with in various programming languages. If a JSON-LD API is provided in a programming environment, the entirety of the following API MUST be implemented.
input according to
the steps in the Expansion Algorithm. The
input MUST be copied, expanded and returned if there are
no errors. If the expansion fails, an appropriate exception MUST be thrown.
input when expanding the input.input.@context.
For example, if a @type key maps to anything other than
@id or an input using the
context according to the steps in the
Compaction Algorithm. The
input MUST be copied, compacted and returned if there are
no errors. If the compaction fails, an appropirate exception MUST be
thrown.
input; either in the
form of an input.optimize,
which if set will cause processor-specific optimization.@context.
For example, if a @type key maps to anything other than
@id or an @language value.input using the
frame according to the steps in the
Framing Algorithm. The input
is used to build the framed output and is returned if there are no errors.
If there are no matches for the frame, input; either
in the form of an input.input according to
the steps in the Flattening Algorithm. The
input MUST be flattened and returned if there are
no errors. If the flattening fails, an appropriate exception MUST be thrown.
It is still being discussed if the flatten() method should be added or not. See ISSUE-109.
@default has to be passed, for the merged graph @merged
and for any other graph the @merged.input when expanding the input.input.@context.
For example, if a @type key maps to anything other than
@id or an input.notType,
which if set to rdf:type
as a property, instead of @type.input according to the
Convert to RDF Algorithm, calling
the provided callback for each Statement generated.
input.@context.
For example, if a @type key maps to anything other than
@id or an The JsonLdCallback is used to return a processed JSON-LD representation as the result of processing an API method.
The StatementCallback is called whenever the processor generates a
statement during the statement() call.
This section describes datatype definitions used within the JSON-LD API.
The URL datatype is a string representation of an
JSON object
or array.
The JsonLdOptions type is used to convery a set of options to an interface method.
object or object[].true, the JSON-LD processor is allowed to
optimize the output of the Compaction Algorithm
to produce even compacter representations. The algorithm for compaction
optimization is beyond the scope of this specification and thus
not defined. Consequently, different implementations MAY implement
different optimization algorithms.true, the JSON-LD processor will not use the
@type property when generating the output, and will use the
expanded rdf:type IRI as the property instead of @type.The following data structures are used for representing data about RDF statements (triples or quads). They are used for normalization, fromRDF, and from toRDF interfaces.
The Statement interface represents an RDF Statement.
Node is the base class of NamedNode, BlankNode, and LiteralNode.
The nominalValue of an Node is refined by
each interface which extends Node.
Provides access to the string name of the current interface,
normally one of "IRI", "BlankNode" or "LiteralNode".
This method serves to disambiguate instances of Node which are otherwise identical, such as NamedNode and BlankNode.
A node identified by an
A BlankNode is a reference to an unnamed resource (one for which an IRI is not known), and may be used in a Statement as a unique reference to that unnamed resource.
Developers and authors must not assume that the nominalValue of a BlankNode will remain the same between two processing runs. BlankNode nominalValues are only valid for the most recent processing run on the document. BlankNodes nominalValues will often be generated differently by different processors.
Implementers MUST ensure that BlankNode nominalValues are unique within the current environment, two BlankNodes are considered equal if, and only if, their nominalValues are strictly equal.
LiteralNodes represent values such as numbers, dates and strings in RDF data. A LiteralNode is comprised of three attributes:
nominalValuelanguage represented by a string tokendatatype specified by a NamedNodeLiteralNodes representing plain text in a natural language may have a
language attribute specified by a text string token, as specified in
[[!BCP47]], normalized to lowercase
(e.g., 'en', 'fr', 'en-gb').
They may also have a datatype attribute such as xsd:string.
LiteralNodes representing values with a specific datatype, such as
the integer 72, may have a datatype attribute specified in the form
of a NamedNode (e.g.,
<http://www.w3.org/2001/XMLSchema#integer>).
All algorithms described in this section are intended to operate on language-native data structures. That is, the serialization to a text-based JSON document isn't required as input or output to any of these algorithms and language-native data structures MUST be used where applicable.
JSON-LD specifies a number of syntax tokens and
@context@id@language@type@value@container@list@set@graph:@default@explicit@omitDefault@embed@nullAll JSON-LD tokens and keywords are case-sensitive.
@context Processing of JSON-LD data structure is managed recursively.
During processing, each rule is applied using information provided by the
The
A @context
property with a
@context
@context
element using the JSON Pointer "/@context" as described in [[!JSON-POINTER]]. Set context
to the extracted content and process it by starting at Step 2.1.@language property, it MUST have a value of a
simple @id, @language or @type properties, throw an exception.
@type or @graph can take a
@container with @set.
@id property with a string value which MUST have the form of a @id property with a string value which MUST have the
form of a @type property, its value MUST have the form of a @id.
Determine the IRI by performing IRI Expansion on the associated value.
If the result of the IRI mapping is an @id, merge into the
@container property, its value MUST be @list or
@set. Merge the @language property but no @type property, the value of the
@language property MUST be a It can be difficult to distinguish between a
Issue 43 concerns performing IRI expansion in the key position of a context definition.
Keys and some values are evaluated to produce an
An
The algorithm for generating an IRI is:
Previous versions of this specification used @base and @vocab to define IRI prefixes
used to resolve
Some keys and values are expressed using
The algorithm for generating a
0,
and set a flag list container to false.@list:
@container set to @set, continue
to the next term.true and term does not have a
container set to @list, continue to the next term.container set to @list,
continue to the next term.0:
container set to @set, then add
1 to rank.@list
and list container is false and term has a container
set to @list, then set list container to true, clear
terms, set highest rank to rank, and add term to terms.When selecting among multiple possible terms for a given property, it may be that multiple
@type, @container
or @language. The purpose of this algorithm is to take a
Given a
3.@list:
@list property is an empty array, if term has @container
set to @list, 1, otherwise 0.@value.
@value property:
@type property matching a
@type coercion for term, 3, otherwise if term has no @type
coercion and no @language, 1, otherwise 0.@value is not a @type or @language it is 2, otherwise 1.@language property, if term has
@language @type or
@language and the @language,
3, otherwise 0.@language property matching a
@language definition for term (or
term has no @type or @language definition and
@language in the @language), 3, otherwise if term has no @type
coercion and no @language, 1, otherwise 0.@type coerced to @id,
3, otherwise
if term has no @type coercion and no @language,
1, otherwise 0.Some values in JSON-LD can be expressed in a compact form. These values are required to be expanded at times when processing JSON-LD documents.
The algorithm for expanding a value takes an
@graph or the target of an @id coercion,
expand the value into an object with a key-value pair where the key is @id and the value is
the expanded IRI according to the IRI Expansion rules.@value and the unexpanded value.@type and the associated coercion datatype expanded according to the
IRI Expansion rules.
@language and value of the language tagging from the Some values, such as IRIs and typed literals, may be expressed in an expanded form in JSON-LD. These values are required to be compacted at times when processing JSON-LD documents.
The algorithm for compacting an expanded value value takes an
@value.@graph, the compacted value is the
value associated with the @id key, processed according to
the IRI Compaction steps.@id, the compacted
value is the value associated with the @id key,
processed according to the
IRI Compaction steps.@value key.@id key, the compacted value is value with
the value of @id processed according to the
IRI Compaction steps.@language, which
matches the @language of the value, or the value has only a @value key, the compacted
value is the value associated with the @value key.@type key, the compacted value
is value with the @type value processed according to the
IRI Compaction steps.This algorithm is used by the Framing Algorithm and
Convert From RDF Algorithm to deterministicly name
The variable next identifier is initialized to prefix appended with 0.
Expansion is the process of taking a JSON-LD document and applying a context such that all IRI, datatypes, and literal values are expanded so that the context is no longer necessary. JSON-LD document expansion is typically used as a part of Framing.
For example, assume the following JSON-LD input document:
Running the JSON-LD Expansion algorithm against the JSON-LD input document provided above would result in the following output:
The algorithm takes three input variables: an
@container set to @list and any entry in element is an
@list property,
throw an exception, as lists of lists are not allowed.
If the expanded entry is null, drop it. If it's an array, merge its entries with element's entries.@context property, update the @context
property.@value, continue with the next
property from element.@id the value MUST be a @type:
@id.@value or @language the value MUST NOT be a
@list or @set expand value
recursively using this algorithm, passing copies of the @list and any entry in value is a
@list property, throw an exception, as
lists of lists are not supported.@container @list
and the expanded value is not @list property whose value is
set to value (unless value is already in that form).@id, @type, @value, or @language.@value property
@language or @type
with a @value equals @value.@type property and its value is not in the form of an
@set or @list property, it MUST be the only property.
Set element to the value of @set; leave @list untouched.@language property, set element to If, after the algorithm outlined above is run, the resulting element is an @graph
property, element is set to the value of @graph's value. Finally, if element is a
Compaction is the process of taking a JSON-LD document and applying a context such that the most compact form of the document is generated. JSON is typically expressed in a very compact, key-value format. That is, full IRIs are rarely used as keys. At times, a JSON-LD document may be received that is not in its most compact form. JSON-LD, via the API, provides a way to compact a JSON-LD document.
For example, assume the following JSON-LD input document:
Additionally, assume the following developer-supplied JSON-LD context:
Running the JSON-LD Compaction algorithm given the context supplied above against the JSON-LD input document provided above would result in the following output:
The compaction algorithm also enables the developer to map any expanded
format into an application-specific compacted format. While the context
provided above mapped http://xmlns.com/foaf/0.1/name to
name, it could have also mapped it to any arbitrary string
provided by the developer.
The algorithm takes three input variables: an
@value property or element is a @container mapping to @list
and element has a corresponding @list property, recursively compact that
property's value passing a copy of the @list (or appropriate alias from
@id or @type
@container mapping to @set,
create an entry in output for If, after the algorithm outlined above is run, the resulting element is an @graph property of a new @context property to element and set it to the initially passed context.
JSON-LD Framing allows developers to query by example and force a specific tree layout to a JSON-LD document.
A JSON-LD document is a representation of a directed graph. A single
directed graph can have many different serializations, each expressing
exactly the same information. Developers typically work with trees, represented as
Framing is the process of taking a JSON-LD document, which expresses a
graph of information, and applying a specific graph layout
(called a
Framing makes use of the Subject Map Generation algorithm to place each object defined in the JSON-LD document into a flat list of objects, allowing them to be operated upon by the framing algorithm.
@id to a parent This algorithm is a work in progress. Presently, it only works for documents without named graphs.
The framing algorithm takes an
Create @merged property of the result of performing the
Subject Map Generation algorithm on
expanded input. Also create results as an empty
Invoke the recursive algorithm using
The following series of steps is the recursive portion of the framing algorithm:
@type property containing
one or more @type property including any of those @type property only
a empty @type property, regardless of the actual values.@embed and @explicit using the current values
for @id and id.@id equal to id, element has
already been embedded and can be overwritten, so set embedOn to @list, then
create a @list and
the value of an empty array. Append list to property in
output. Process each listitem in the @list array as follows:
@id of listitem as the key
and the @list as @list in list.@id of item as the key and
the @omitDefault which is @omitDefault but the value of @preserve and a value that is a copy of the value
of @default in frame if it exists, or the string
@null otherwise.At the completion of the recursive algorithm, results will contain the top-level
The final two steps of the framing algorithm require
results to be compacted according to the
Compaction Algorithm by using the
context provided in the @graph keyword at the top-level, even if the context is empty or if there
is only one element to put in the @graph array. Subsequently, replace all key-value
pairs where the key is @preserve with the value from the key-pair. If the value
from the key-pair is @null, replace the value with
The algorithm needs to be updated to consider @graph. See
ISSUE-118 for details.
The Subject Map Generation algorithm takes as input an expanded JSON-LD document and results in a @default property and the merged graph
under the @merged property, all other graphs are stored under their respective
The algorithm takes as input the initially empty subjectMap, the expanded JSON-LD document as element,
null as parent, false for the list flag, false for the iri flag,
and @default as graph.
If the values of @type would be expanded as everything else to @id form as proposed in
ISSUE-120, the iri flag could be eliminated.
@value property:
@list property, create a new @list property whose value is an empty array and recursively call this algorithm by passing subjectMap,
the value of the @list property of element as element, flattenedList as parent,
true for the list flag, false for the iri flag and graph. Add flattenedList
to parent and return.@id is not an @merge or if the @id
property does not exist, set id to a @id
property as id.@id property whose value equals id and
add it to parent if it doesn't exist yet in parent or the list flag is set to true.@id property whose value equals id and add it as value of the id
property of the @id ordered by property:
@type, create a new property @type in subject whose value is an empty
array and recursively call this algorithm by passing subjectMap, value as element, the @type
property of subject as parent, false for the list flag, true for the iri
flag and graph. Then continue with the next property from element.@graph, recursively call this algorithm by passing subjectMap, value as
element, false for the list flag, false for the
iri flag and id as graph. Then continue with the next property from element.false for the list flag, false for the iri
flag and graph._: and the iri flag is set to true,
map element to a new blank node identifier to avoid collisions.false, check if element is already in parent. If so, return.After the above outlined algorithm has been executed, the subject map for all graphs including the default graph are contained in subjectMap. To also create the subject map for the merged graph, perform the following steps:
false for the list flag, false for the iri flag and
@merged for graph.This algorithm replaces an already embedded
The algorithm is invoked with a
@id of id,
removing that definition from the map, and then removing the dependents for the parent id
recursively by repeating this step. This step will terminate when there are no more embed
entries containing the removed @id in their
parent chain.This algorithm recursively embeds property values in
@list,
then create a new @list and
a value of an empty array and add it to output, appending if output
is an array, and appending to @list as @id of item:
Flattening is the process of taking a JSON-LD document, expanding
it, labeling all unlabeled nodes with a
It is still being discussed if the flatten() method should be added or not. See ISSUE-109.
For example, assume the following JSON-LD input document:
Running the JSON-LD Flattening algorithm for the merged graph (@merged) against
the JSON-LD input document provided above would result in the following output:
The algorithm takes two input variables, an element to flatten and the
graph for which the node definitions should be returned. If graph
is not set, it will default to @merged which represents the result of
merging all graphs including the default graph (@default).
When coercing numbers to xsd:integer or xsd:double
as it, e.g., happens during RDF Conversion, implementers MUST
ensure that the result is a canonical lexical representation in the form of a
The canonical lexical representation of an integer, i.e., a number without fractions
or a number coerced to xsd:integer, is a finite-length sequence of decimal
digits (0-9) with an optional leading minus sign; leading zeroes are prohibited.
To convert the number in JavaScript, implementers can use the following snippet of code:
The canonical lexical representation of a double, i.e., a number with fractions
or a number coerced to xsd:double, consists of a mantissa followed by the
character "E", followed by an exponent. The mantissa MUST be a decimal number. The exponent
MUST be an integer. Leading zeroes and a preceding plus sign (+) are prohibited
in the exponent. If the exponent is zero, it must be indicated by E0.
For the mantissa, the preceding optional plus sign is prohibited and the decimal point is
required. Leading and trailing zeroes are prohibited subject to the following: number
representations must be normalized such that there is a single digit which is non-zero to the
left of the decimal point and at least a single digit to the right of the decimal point unless
the value being represented is zero. The canonical representation for zero is 0.0E0.
To convert the number in JavaScript, implementers can use the following snippet of code:
xsd:double's value space is defined by the IEEE double-precision 64-bit floating point type [[!IEEE-754-1985]].
When data such as decimals need to be normalized, JSON-LD authors should not use values that are going to undergo automatic conversion. This is due to the lossy nature of xsd:double values. Authors should instead use the expanded object form to set the canonical lexical representation directly.
When JSON-native datatypes, like
At this point, myObj1 and myObj2 will have different
values for the "number" property. myObj1 will have the number
42, while myObj2 have an object consisting of
@value set to the string "42" and @type
set to the expanded value of xsd:nonNegativeInteger.
Some JSON serializers, such as PHP's native implementation in some versions,
backslash-escape the forward slash character. For example, the value
http://example.com/ would be serialized as http:\/\/example.com\/.
This is problematic as other JSON parsers might not understand those escaping characters.
There is no need to backslash-escape forward slashes in JSON-LD. To aid interoperability
between JSON-LD processors, a JSON-LD serializer MUST NOT backslash-escape forward slashes.
A JSON-LD document MAY be converted between other RDF-compatible document formats using the algorithms specified in this section.
The JSON-LD Processing Model describes processing rules for extracting RDF from a JSON-LD document, and for transforming an array of Statement retrieved by processing another serialization format into JSON-LD. Note that many uses of JSON-LD may not require generation of RDF.
The processing algorithms described in this section are provided in order to demonstrate how one might implement a JSON-LD to RDF processor. Conformant implementations are only required to produce the same type and number of statements during the output process and are not required to implement the algorithm exactly as described.
JSON-LD is intended to have an easy to parse grammar that closely models existing practice in using JSON for describing object representations. This allows the use of existing libraries for parsing JSON.
As with other grammars used for describing
Data described with JSON-LD may be considered to be the representation of a graph made
up of
The algorithm below is designed for in-memory implementations with random access to
A conforming JSON-LD processor implementing RDF conversion MUST implement a processing algorithm that results in the same set of RDF Statements that the following algorithm generates:
The algorithm takes five input variables: a element to be converted, an
@value property:
@value is a @type property if it exists, otherwise
either xsd:integer or xsd:double, depending
on if the value contains a fractional and/or an exponential component.@value is true or false,
set the @type
property if it exists, otherwise xsd:boolean.@type property, set the
@language property, use its value to set the language of the plain literal.
@list property the value MUST be an @id property,
the value MUST be a @id property, set the @type, set the rdf:type.
@graph,
process value algorithm recursively, using rdf:type so set the List Conversion is the process of taking an rdf:first and rdf:next,
terminating the list with rdf:nil using the following sequence:
The algorithm is invoked with an
rdf:nil.
rdf:first as the rdf:nil.rdf:rest and rest In some cases, data exists natively in Triples or Quads form; for example, if the data was originally represented in an RDF graph or triple/quad store. This algorithm is designed to simply translate an array of Statements into a JSON-LD document.
The conversion algorithm takes a single parameter input in the form of an array of Statement representations.
rdf:first,
use the entry in graph.listMap indexed by subject,
initializing it to a new rdf:rest:
@id and
a string representation of name.@id and
a string representation of subject if necessary.rdf:type and the notType
option is present and not @type, creating an entry in value if necessary.rdf:nil:
@list representation to the array value for
key, creating an entry in value if necessary.@id in value.@list initialized to a new array
containing the value of first from entry.@graph in entry containing the ordered entries
from graphs[subject].subjects.This section is included merely for standards community review and will be submitted to the Internet Engineering Steering Group if this specification becomes a W3C Recommendation.
application/json MIME media type.eval()
function. It is RECOMMENDED that a conforming parser does not attempt to
directly evaluate the JSON-LD frame and instead purely parse the
input into a language-native data structure.Fragment identifiers have no meaning with application/frame-ld+json resources.
The
Processors MUST act as if the initial context is defined in the outer-most level when processing JSON-LD documents.
Should we define other default prefixes?
The editors would like to thank Mark Birbeck, who provided a great deal of the initial push behind the JSON-LD work via his work on RDFj, Dave Lehn and Mike Johnson who reviewed, provided feedback, and performed several implementations of the specification, and Ian Davis, who created RDF/JSON. Thanks also to Nathan Rixham, Bradley P. Allen, Kingsley Idehen, Glenn McDonald, Alexandre Passant, Danny Ayers, Ted Thibodeau Jr., Olivier Grisel, Niklas Lindström, Markus Lanthaler, and Richard Cyganiak for their input on the specification.