This document is also available in this non-normative format: diff to previous version
Copyright © 2010-2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
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 in order to make them easier to work with in programming environments like JavaScript, Python, and Ruby.
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 http://www.w3.org/TR/.
This document has been under development for over 18 months in the JSON for Linking Data Community Group. The document has recently been transferred to the RDF Working Group for review, improvement, and publication along the Recommendation track. The specification has undergone significant development, review, and changes during the course of the last 18 months.
There are several independent interoperable implementations of this specification. There is a fairly complete test suite and a live JSON-LD editor that is capable of demonstrating the features described in this document. While development on implementations, the test suite and the live editor will continue, they are believed to be mature enough to be integrated into a non-production system at this point in time with the expectation that they could be used in a production system within the next year.
It is important for readers to understand that the scope of this document is currently under debate and new features may be added to the specification. Existing features may be modified heavily or removed entirely from the specification upon further review and feedback from the broader community. This is a work in progress and publication as a Working Draft does not require that all Working Group members agree on the content of the document.
There are a number of ways that one may participate in the development of this specification:
This document was published by the RDF Working Group as an Editor's Draft. If you wish to make comments regarding this document, please send them to public-rdf-comments@w3.org (subscribe, archives). All feedback is welcome.
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 5 February 2004 W3C Patent Policy. 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 section is non-normative.
This document is a detailed specification for an Application Programming Interface for the JSON-LD Syntax. 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].
This section is non-normative.
The JSON-LD Syntax specification [JSON-LD] outlines a language that may be used to express Linked Data in JSON. Often, it is useful to be able to transform JSON-LD documents so that they may be easily processed in various programming environments.
There are four major types of transformation that are discussed in this document: expansion, compaction, flattening, and RDF conversion.
This section is non-normative.
Software algorithms are easiest to write when the data that they are processing have a regular form. Since information can be represented by JSON-LD in a variety of different ways, transforming all of these methods into a uniform structure allows the developer to simplify their processing code. For example, note that the following input uses only terms and is fairly compact:
{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", "homepage": { "@id": "http://xmlns.com/foaf/0.1/homepage", "@type": "@id" } }, "@id": "http://me.markus-lanthaler.com/", "name": "Markus Lanthaler", "homepage": "http://www.markus-lanthaler.com/" }
The next input example uses one IRI to express a property, but leaves the rest of the information untouched.
{
"@context": {
"homepage": {
"@id": "http://xmlns.com/foaf/0.1/homepage",
"@type": "@id"
}
},
"@id": "http://me.markus-lanthaler.com/",
"http://xmlns.com/foaf/0.1/name": "Markus Lanthaler",
"homepage": "http://www.markus-lanthaler.com/"
}
While both inputs are valid JSON-LD, writing a program to handle every permutation of possible inputs can be difficult, especially when the incoming context could change as well. To ensure that the data can be given a more uniform structure, JSON-LD introduces the notion of expansion. Expansion performs two important operations. The first is to expand all values that represent IRIs to absolute IRIs. The second is to express all values in expanded form. Running the Expansion algorithm against the examples provided above results in the following output:
[ { "@id": "http://me.markus-lanthaler.com/", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Markus Lanthaler" } ], "http://xmlns.com/foaf/0.1/homepage": [ { "@id": "http://www.markus-lanthaler.com/" } ] } ]
Note that in the output above all context definitions have been removed, all terms and prefixes have been expanded to absolute IRIs, and all JSON-LD values are expressed in expanded form. While the output is more difficult for a human to read, it is easier for a software program to process because of its very regular structure.
This section is non-normative.
While expansion expands a given input as much as possible, compaction performs the opposite operation: it expresses a given input as succinctly as possible. In contrast to expansion which is meant to produce something that is easy to process by software programs, compaction is meant to produce something that is easy to read by software developers. Compaction uses a developer-supplied context to compress IRIs to terms or compact IRIs and JSON-LD values expressed in expanded form to simple values such as strings and numbers.
For example, assume the following expanded JSON-LD input document:
[ { "@id": "http://me.markus-lanthaler.com/", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Markus Lanthaler" } ], "http://xmlns.com/foaf/0.1/homepage": [ { "@id": "http://www.markus-lanthaler.com/" } ] } ]
Additionally, assume the following developer-supplied JSON-LD context:
{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", "homepage": { "@id": "http://xmlns.com/foaf/0.1/homepage", "@type": "@id" } } }
Running the Compaction Algorithm given the context supplied above against the JSON-LD input document provided above would result in the following output:
{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", "homepage": { "@id": "http://xmlns.com/foaf/0.1/homepage", "@type": "@id" } }, "@id": "http://me.markus-lanthaler.com/", "name": "Markus Lanthaler", "homepage": "http://www.markus-lanthaler.com/" }
Note that all IRIs have been compacted to
terms as specified in the context
which consequently has been injected into the output. While compacted
output is most useful to humans, it can often also be used to generate
structures that are easy to program against. Compaction enables developers
to map any expanded document into an application-specific compacted document.
While the context provided above mapped http://xmlns.com/foaf/0.1/name
to name
, it could have also have been mapped to any other term
provided by the developer.
This section is non-normative.
While expansion ensures that a document is in a uniform structure, flattening goes a step further and ensures that also the shape of the data is deterministic. In expanded documents properties of a single node may still be spread across a number of different JSON objects. By flattening a document, all properties of a node are collected in a single JSON object and all blank nodes are labeled with a blank node identifier. Often this drastically simplifies the code to process JSON-LD data.
For example, assume the following JSON-LD input document:
{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", "knows": "http://xmlns.com/foaf/0.1/knows" }, "@id": "http://me.markus-lanthaler.com/", "name": "Markus Lanthaler", "knows": [ { "name": "Manu Sporny", "knows": { "@id": "http://greggkellogg.net/foaf#me" } }, { "@id": "http://greggkellogg.net/foaf#me", "name": "Gregg Kellogg" } ] }
Running the Flattening Algorithm with a context set to null to prevent compaction returns the following document:
[ { "@id": "http://me.markus-lanthaler.com/", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Markus Lanthaler" } ], "http://xmlns.com/foaf/0.1/knows": [ { "@id": "_:t0" }, { "@id": "http://greggkellogg.net/foaf#me" } ] }, { "@id": "_:t0", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Manu Sporny" } ], "http://xmlns.com/foaf/0.1/knows": [ { "@id": "http://greggkellogg.net/foaf#me" } ] }, { "@id": "http://greggkellogg.net/foaf#me", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Gregg Kellogg" } ] } ]
Note how in the output above all properties of a node are collected in a
single JSON object and how the blank node representing
"Manu Sporny" has been assigned the blank node identifier
_:t0
.
To make it easier for humans to read such a flattened document can be compacted by passing a context. Using the same context as the input document, the flattened and compacted document looks as follows:
{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", "knows": "http://xmlns.com/foaf/0.1/knows" }, "@graph": [ { "@id": "http://me.markus-lanthaler.com/", "name": "Markus Lanthaler", "knows": [ { "@id": "_:t0" }, { "@id": "http://greggkellogg.net/foaf#me" } ] }, { "@id": "_:t0", "name": "Manu Sporny", "knows": { "@id": "http://greggkellogg.net/foaf#me" } }, { "@id": "http://greggkellogg.net/foaf#me", "name": "Gregg Kellogg" } ] }
Please note that the flattened and compacted result will always explicitly
designate the default by the @graph
member in the top-level
JSON object. Compaction optimizes that
member away if its value contains just one item.
This section is non-normative.
JSON-LD can be used to serialize data expressed in RDF as described in [RDF-CONCEPTS]. This ensures that data can be round-tripped from and to any RDF syntax without any loss in the fidelity of the data.
For example, assume the following RDF input serialized in Turtle [TURTLE-TR]:
<http://me.markus-lanthaler.com/> <http://xmlns.com/foaf/0.1/name> "Markus Lanthaler" . <http://me.markus-lanthaler.com/> <http://xmlns.com/foaf/0.1/homepage> <http://www.markus-lanthaler.com/> .
Using the Convert from RDF Algorithm a developer could transform this document into expanded JSON-LD:
[ { "@id": "http://me.markus-lanthaler.com/", "http://xmlns.com/foaf/0.1/name": [ { "@value": "Markus Lanthaler" } ], "http://xmlns.com/foaf/0.1/homepage": [ { "@id": "http://www.markus-lanthaler.com/" } ] } ]
Note that the output above could easily be compacted using the technique outlined in the previous section. It is also possible to transform the JSON-LD document back to RDF using the Convert to RDF Algorithm.
All examples and notes as well as sections marked as non-normative in this specification are non-normative. Everything else in this specification is normative.
The keywords must, must not, required, should, should not, recommended, may, and optional in this specification are to be interpreted as described in [RFC2119].
There are two classes of products that can claim conformance to this specification: JSON-LD Implementations and JSON-LD Processors.
A conforming JSON-LD Implementation is a system capable of transforming JSON-LD documents according the algorithms defined in this specification.
A conforming JSON-LD Processor is a conforming JSON-LD Implementation that exposes the application programming interface (API) defined in this specification.
The algorithms in this specification are generally written with more concern for clarity than over efficiency. Thus, JSON-LD Implementations and Processors may implement the algorithms given in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained by the specification's algorithms.
This specification does not define how JSON-LD Implementations or Processors handle non-conforming input documents. This implies that JSON-LD Implementations or Processors must not attempt to correct malformed IRIs or language tags; however, they may issue validation warnings.
Implementers can partially check their level of conformance to this specification by successfully passing the test cases of the JSON-LD test suite [JSON-LD-TESTS]. Note, however, that passing all the tests in the test suite does not imply complete conformance to this specification. It only implies that the implementation conforms to aspects tested by the test suite.
This document uses the following terms as defined in JSON [RFC4627]. Refer to the JSON Grammar section in [RFC4627] for formal definitions.
@context
where the value, or the @id
of the
value, is null explicitly decouples a term's association
with an IRI. A key-value pair in the body of a JSON-LD document whose
value is null has the same meaning as if the key-value pair
was not defined. If @value
, @list
, or
@set
is set to null in expanded form, then
the entire JSON object is ignored.Furthermore, the following terminology is used throughout this document:
_:
.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.
@context
keyword.@value
, @list
,
or @set
keywords, or@graph
keyword.@list
member.The algorithm takes three input variables: an active context,
an active property, and an element to be expanded. To
begin, the active context is set to the result of performing, Context Processing on the passed
expandContext
,
or empty if expandContext
is null, active property is set to null, and
element is set to the JSON-LD input. This algorithm expects the
JSON-LD input to be a well-formed JSON-LD document as defined in [JSON-LD].
@list
and the expanded
item is an array or a list object trigger
a LIST_OF_LISTS_DETECTED
error.@context
member, update the
active context according to the steps outlined in
Context Processing and remove the
@context
member.true
for
the vocabRelative flag).@id
, set the @id
member of result to the result of expanding value
according the IRI Expansion algorithm (passing true
for the documentRelative flag). If value is not a string
trigger an INVALID_ID_VALUE
error.@type
, set the @type
member of result to the result of expanding value
according the IRI Expansion algorithm (passing true
for both the documentRelative and the vocabRelative flag). If value
is neither a string nor an array of
strings trigger an INVALID_TYPE_VALUE
error. Empty arrays are ignored.@value
, set the @value
member of result to value. If value is neither a scalar
nor null trigger an INVALID_VALUE_OBJECT_VALUE
error.@language
, set the @language
member of result to the lowercased value. If value is not
a string, trigger an INVALID_LANGUAGE_VALUE
error.@annotation
, set the @annotation
member of result to value. If value is not a string
trigger an INVALID_ANNOTATION_VALUE
error.@set
or @list
, set the
expanded property member of result to the result of expanding value by
recursively using this algorithm, passing copies of the active context and
active property.@graph
, set the @graph
member of result to the result of expanding value by
recursively using this algorithm, passing copies of the active context and
@graph
as active property.@language
@value
set to the currently
processed item and @language
set to the lowercased key.
If val is not a string, trigger a
LANGUAGE_MAP_INVALID_VALUE
error. Otherwise append
the object to language map values.@annotation
@annotation
set to
key if no such member exists yet and append the resulting
JSON object to annotation map values.@list
and
value is either not an JSON object or a JSON object
without an @list
member, replace value with a
JSON object with an @list
member whose value is set to
value (wrapped in an array if it is not already one).@annotation
member, decrease numProperties
by 1.@value
member,
@language
member, decrease numProperties
by 1 and check that the value of the @value
member is a string. If not,
trigger an INVALID_LANGUAGE_TAGGED_STRING
error.@type
member, decrease
numProperties by 1 and check that the value of the @type
member is a
string. If not, trigger an INVALID_TYPED_VALUE
error.INVALID_VALUE_OBJECT
error.@value
member equals null, set
element to null.@type
member whose value is not an array,
transform it to an array.@list
or @set
member and
numProperties is greater than 1, trigger an
INVALID_SET_OR_LIST_OBJECT
error.@set
member, set element to
the value of that member.@language
member, set element
to null.If, after the algorithm outlined above is run, the resulting element is an
JSON object with just a @graph
member, element is set to
the value of @graph
's value. Finally, if element is a JSON object,
it is wrapped into an array.
Processing of JSON-LD data structure is managed recursively. During processing, each rule is applied using information provided by the active context.
The active context contains the active term definitions
which specify how properties and values have to be interpreted as well as the current
vocabulary mapping and the default language. Each term definition consists
of an IRI mapping and optionally a type mapping from terms to datatypes or
language mapping from terms to language codes, and a container mapping. If an
IRI mapping maps a term to multiple
If a local context is encountered, information from the local context
is merged into the active context. A local context is identified within
a JSON object having a @context
member with a string,
array or a JSON object value.
This algorithm specifies how the active context is updated with a local context. The algorithm takes three input variables: an active context, a local context, and an array of already included remote contexts remoteContexts. To begin, remoteContexts is initialized to an empty array.
All calls of the IRI Expansion algorithm pass the value specified in the
algorithm along with the active context, the currently being processed local context,
and true
for the vocabRelative flag.
RECURSIVE_CONTEXT_INCLUSION
error. Otherwise, add
context to remoteContexts.@context
member recursively invoke
this algorithm passing a copy of active context, the value of the
@context
member as local context, and a copy of
the remoteContexts array. Relative IRIs
are expanded using the remote context's IRI. Otherwise raise an
INVALID_REMOTE_CONTEXT
error.INVALID_LOCAL_CONTEXT
error.@vocab
member: if its value is neither
an absolute IRI, i.e., it does not contain a colon (:
),
nor null, trigger an INVALID_VOCAB_MAPPING
error; otherwise set the active context's
vocabulary mapping to its value and remove the @vocab
member from context.@language
member: if its value is neither
a string nor null, trigger an
INVALID_DEFAULT_LANGUAGE
error; otherwise set the
active context's default language to
its value and remove the @language
member from context.INVALID_TERM_DEFINITION
error@id
member with a value val:
INVALID_PROPERTY_GENERATOR
error.
@type
member with a value val and val
is not a string or does not expand to an absolute IRI using the
IRI Expansion algorithm, raise an
INVALID_TYPE_MAPPING
error. Otherwise set the
IRI mapping of definition to the expanded val.@language
member with a value val
that is a string or null, set the language mapping of
definition to the lowercased val. If val is neither a
string nor null, raise an
INVALID_LANGUAGE_MAPPING
error.@container
member with a value val that
equals @list
, @set
, or @annotation
, set the
container mapping of definition to val.
If val is not one of those values, raise an
INVALID_CONTAINER_MAPPING
error.In JSON-LD documents keys and some values are evaluated to produce an IRI. This section defines an algorithm for transforming strings representing an IRI into an absolute IRI. If IRI expansion occurs during context processing, the local context that is being processed is passed to this algorithm. After application of this algorithm, values processed by this algorithm are said to be in expanded IRI form, although this may also include blank node identifiers and JSON-LD keywords.
The algorithm takes two mandatory and four optional input variables: a value
to be expanded, an active context, two flags documentRelative and
vocabRelative specifying whether value should be interpreted as
relative IRI against the document's base IRI or the
active context's vocabulary mapping,
along with an local context passed when this algorithm is used in
Context Processing, and finally an array
path which is used to detect cyclic IRI mappings.
If not passed, the two flags are set to false
and path is
initialized to an empty array by default.
The algorithm for generating an IRI is:
CYCLIC_IRI_MAPPING
error. Otherwise append value
to path.true
for the vocabRelative flag. If the result
is a property generator, raise an
PROPERTY_GENERATOR_IN_TERM_DEFINITION
error.:
), perform the following steps:
:
).//
or prefix equals _
,
return value as is.true
for the
vocabRelative flag. If the expanded prefix contains a colon (:
)
generate and return an IRI by prepending the expanded prefix to the
(possibly empty) suffix using textual concatenation.true
and the
active context contains a vocabulary mapping, generate and return an
IRI by prepending the IRI of the vocabulary mapping
to the value using textual concatenation.true
, resolve value
against the base IRI as per [RFC3986] and return the resulting IRI. Only the basic
algorithm in section 5.2 of [RFC3986] is used; neither Syntax-Based Normalization
nor Scheme-Based Normalization (as described in sections 6.2.2 and 6.2.3 of [RFC3986])
are performed. Characters additionally allowed in IRI references are treated in the same way that
unreserved characters are treated in URI references, per section 6.5 of [RFC3987]If the result of the algorithm above is a blank node identifier, i.e., a string that begins with
_:
, and no local context has been passed,
generated a new blank node identifier before returning the
final result.
Some values in JSON-LD can be expressed in a compacted form. These values are required to be expanded at times when processing JSON-LD documents. A value is said to be in expanded form after the application of this algorithm.
The algorithm for expanding a value takes an active property and active context. It is implemented as follows:
@graph
or the
active property's type mapping is set to
@id
, add a key-value pair to result where the key is @id
and the value is the result of expanding value according to the
IRI Expansion algorithm passing true
for the
documentRelative flag. Then return result.@value
and the value is value.@type
and the value is the
IRI associated with the type mapping or a newly
generated blank node identifier if the
type mapping is set to a blank node identifier.@language
and the value is the
language tag associated with the language mapping or the active property or the
default language.The algorithm takes a single input variable: an element to be labeled with blank node identifiers.
@list
member, recursively apply this algorithm to all items
of the @list
member's value.@id
member,
create a new @id
member and assign it a new
blank node identifier according the
Generate Blank Node Identifier algorithm.This algorithm is used to generate new
blank node identifiers or to relabel existing
blank node identifiers with a new one to avoid
collision by the introduction of new ones. It needs to keep an identifier map,
a counter, and a prefix between its executions to be able to generate new
blank node identifiers. The counter
is initialized to 0
and prefix is set to _:t
by default.
The algorithm takes a single input variable identifier which might be null.
1
.The algorithm takes four input variables: an active context, an inverse context, an active property, and an element to be compacted. To begin, the active context is set to the result of performing Context Processing on the passed context, inverse context is set to the result of creating an inverse context from the active context, active property is set to null, and element is set to the result of performing the Expansion Algorithm on the JSON-LD input.
compactArrays
option is set to true
, return that item; otherwise return
result.@value
or @id
member,
replace element with the result of the
Value Compaction algorithm. If the updated
element is a scalar, return it as it cannot be further
compacted.@id
, compact value
according the rules of the IRI Compaction algorithm.@type
, compact value
(or each item of value if it is an array) according the rules of the
IRI Compaction algorithm with the
vocabRelative flag set to true
. If value is an
array consisting of just one item, replace value with that item.@graph
, compact value
by recursively invoking this algorithm, passing a copy of the active context,
inverse context, and property as active property
ensuring that the result is an array.true
.true
.@language
or @annotation
@language
or
@annotation
member of item (depending on the value of the
active property's container mapping).@list
member,
@list
, set the active property member of result
to the value of item's @list
member. If such an member already exists
in result, raise an COMPACTION_TO_LIST_OF_LISTS
error; otherwise
continue with the next property-value pair from element.compactArrays
option is set to false
or the active property's
container mapping is set to @list
or @set
, convert the
value of the active property member of result to an array if
it is not one already.If, after the algorithm outlined above is run, the resulting element is an array
replace it with a new JSON object with a single member whose name is the result of
compacting the value @graph
with the IRI Compaction algorithm
and whose value is element. Finally, add a @context
property to element
and set it to the initially passed context.
This section defines an algorithm for transforming an IRI to a term or compact IRI. If a value is passed it is used to choose the best matching term.
This algorithm takes three mandatory and two optional parameters. The mandatory
parameters are the iri to be compacted, an active context,
and an inverse context. Optionally it is possible to pass a value
and a vocabRelative flag which specifies whether the passed iri
should be compacted using the active context's
vocabulary mapping. If the vocabRelative flag is not set
it defaults to false
.
The algorithm for generating a compact IRI is:
@set
, typeOrLanguage, and typeLanguageValue
to null.@annotation
member, set container to
@annotation
.@id
member, set
typeOrLanguage to @type
and typeLanguageValue
to @id
.@value
member,
@type
member, set typeOrLanguage to
@type
and typeLanguageValue to the value of the
@type
member of value.@language
member, set
typeOrLanguage to @language
and
typeLanguageValue to the value of the @language
member of value. If value has no @annotation
member, set container to @language
@value
member is is a string, set typeOrLanguage to
@language
and typeLanguageValue to
@null
.@list
member,
@list
member has at least one item, update
container, typeOrLanguage, and
typeLanguageValue by recursively running the steps
2.1.2 to
2.1.3.4 (which will never be true since list of lists are not
allowed) of this algorithm passing the first item of value's
@list
member as new value.@annotation
member, set
container to @list
.@list
member, recursively run the steps
2.1.2 to
2.1.3.4 (which will never be true since list of lists are not
allowed) of this algorithm passing the item as new value. If
the resulting typeOrLanguage or typeLanguageValue
differ from the current value of typeOrLanguage or
typeLanguageValue, set both to null and stop
processing the @list
items.@list
, set the first item of
queryPath to an array consisting of the two elements
@list
and null
; otherwise set it to an array
consisting of three elements where the first element is the value of container
and the other two elements are @set
and @null
.@null
.@null
. Set the
third item of queryPath to an array whose first element
typeLanguageValue and whose second element is @null
.term
member, return result.term
member, return its value.term
member, i.e., it is
a property generator, continue with the next termIri-termDefinition
pair from inverse context.term
member of termDefinition with a colon
(:
) character and the unmatched part of iri.term
member of result to the compact IRI
and return result.true
, the
active context has a vocabulary mapping, and iri
begins with the IRI of the vocabulary mapping but is longer
term
member of result to
vocabIri and return result.term
member of result to iri and
return result.An active context as produced by the Context Processing algorithm is very efficient for expanding terms and compact IRIs to IRIs but is of limited use for the opposite operation: IRI compaction. Hence, this algorithm introduces the notion of an inverse context which brings the same efficiency to IRI compaction. An inverse context a tree of JSON objects which allow to efficiently select a term for a IRI-value pair.
The value takes an active context and returns the corresponding inverse context.
@null
.@null
if no such mapping exists.propertyGenerators
.term
and append the
term to the term
member of the JSON object for
the term's IRI in inverse context
(append term to inverseContext[iri]['term']
).inverseContext[iri][container]['@type'][type][termType]
, e.g.,
inverseContext['http://...']['@list']['@type']['http://...']['term']
.@null
. Then append the term to
inverseContext[iri][container]['@language'][language][termType]
, e.g.,
inverseContext['http://...']['@list']['@language']['de']['term']
.inverseContext[iri][container]['@null']['@null'][termType]
as well as
inverseContext[iri][container]['@language'][defaultLanguage][termType]
to take the default language into consideration for terms without
explicit language mapping.term
member in inverse context. The result is thus a single
string value.propertyGenerators
member in
inverse context lexicographically (shortest terms come
first).It is possible that multiple terms that differ in their container, type, or language mapping are mapped to the same IRI. The purpose of this algorithm is to query the inverse context to return either the best matching term, or a list of potential property generators along with a term to fall back to if none of the property generators can be applied.
This algorithm takes an inverseContextSubtree, a queryPath
as generated by the IRI Compaction algorithm
and a level parameter which is initialized to 0
if nothing else
is passed. The algorithm returns either a string representing the best matching
term or a JSON object consisting of a
propertyGenerators
member, containing a sorted array of
potential property generators,
and an optional term
member containing a term to fall back
to if none of the property generators
can be applied.
3
, i.e., the deepest nested
JSON object in the inverse context has been reached,
perform the following steps:
propertyGenerators
member,
copy that member into a new JSON object and store that object in
result.term
member and
result is null, return the value of that member;
otherwise result is a JSON object, copy the term
member into result and return result.queryPath[level]
), perform the following steps:
1
as new level.propertyGenerators
member is set to an empty array
and whose term
member is set to tmpResult.propertyGenerator
member of
tmpResult to the propertyGenerator
member of result
unless it is already in result's member. If result has no
term
member but tmpResult does, copy tmpResult's
term
member into result.Expansion transforms all values into expanded formin JSON-LD. This algorithm does the opposite, it compacts an algorithm according the term definition of the passed active property. After the application of this algorithm a value is said to be in compacted form.
This algorithm takes a value, an active context, an inverse context, an active property, and an optional containerValue.
@annotation
and value
has an @annotation
member which equals containerValue, remove that member.@id
,
return the result of performing IRI Compaction on that
member's value.@value
member, perform the following steps:
@type
member, remove the @type
member
from value.@language
member, remove the
@language
member from value.@language
, and value has
a @language
member which equals containerValue, remove the
@language
member from value.@language
member, remove the
@language
member from value.@value
member is a
string, return value.@value
member, return the value of that
member.This algorithm checks if a specific value exists for all IRIs associated with a property generator and if so, it removes them. The algorithm takes five parameters: element, property, value, active context, active property.
propertyGenerators
member of active property perform
the following steps:
@id
member exists (i.e., it is
an unlabeled blank node, in that case node objects are never
considered to be equal.
term
member of active property
since no matching property generator has been found.The algorithm takes two input variables, an element to flatten and a context used to compact the flattened document.
@default
member of
nodeMap; a JSON object representing the default graph.@id
member whose value is set to graphName.@graph
member set to an empty array
(referred to as nodes) to the JSON object which is the
value of the graphName member of nodeMap.@graph
keyword (or its alias)
at the top-level, even if the context is empty or if there is only one element to
put in the @graph
array. This ensures that the returned
document has a deterministic structure.This algorithm creates a JSON object nodeMap holding an indexed
representation of the graphs and nodes
represented in the passed, expanded document. All nodes that are not
uniquely identified by an IRI get assigned a (new) blank node identifier.
The resulting nodeMap will have a member for every graph in the document whose
value is another object with a member for every node represented in the document.
The default graph is stored under the @default
member, all other graphs are
stored under their graph name.
The algorithm takes as input an expanded JSON-LD document element and a reference to
a JSON object nodeMap. Furthermore it has the optional parameters
active graph (which defaults to @default
), an active subject,
active property, and a reference to a JSON object list. The
nodeMap must be initialized to a JSON object consisting of a single member
whose name corresponds with active graph and whose value is an empty JSON object.
@type
member, perform for each item the following
steps:
@id
with the value item.@value
member, perform the following steps:
Handling of free-floating values is still being discussed.
@list
member of list.@list
member, perform
the following steps:
@list
whose value is initialized to an empty array.@list
member as new element and result as list.Handling of free-floating values is still being discussed.
@id
member, store its value in id and remove
the member from element. If id is a blank node identifier, replace it with
a new blank node identifier.@id
whose
value is set to id.@id
whose value is id.@list
member of list.@type
member, merge each value into the @type
of active subject in activeGraph. Then remove the @type
member
from element.@annotation
member, set the @annotation
of active subject in activeGraph to its value. If such a member already
exists in active subject and has a different value, raise a
CONFLICTING_ANNOTATION
error. Otherwise continue and remove the
@annotation
from element.@graph
member, recursively invoke this algorithm passing
the value of the @graph
member as new element and id as new
active subject. Then remove the @graph
member from element.This specification describes algorithms to transform JSON-LD documents to an array of RDF quads and vice-versa. 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 quads but are not required to implement the algorithm exactly as described.
This algorithm hasn't been updated yet.
The algorithm below is designed for in-memory implementations with random access to JSON object elements.
A conforming JSON-LD processor implementing RDF conversion must implement a processing algorithm that results in the same set of RDF quads that the following algorithm generates:
The algorithm takes four input variables: a element to be converted, an active subject, active property and graph name. To begin, the active subject, active property and graph name are set to null, and element is set to the result of performing the Expansion Algorithm on the JSON-LD input which is expected to be a a well-formed JSON-LD document as defined in [JSON-LD]. This removes any existing context to allow the given context to be cleanly applied.
@value
property:
@value
is a number, set the
active object to a typed value using a canonical lexical form
of the value as defined in the section Data Round Tripping.
Set datatype to the value of the @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 active object to a typed value created from the
canonical lexical form of the value. Set datatype to the value of the @type
property if it exists, otherwise xsd:boolean
.@type
property, set the
active object to a typed value.
@language
property, set the
active object to a language-tagged string.
xsd:string
as the datatype.
@list
property the value must be an array.
Process its value as a list as described in List Conversion using
the return value as the active object
@id
property,
the value must be a string, set the active subject to the previously
expanded value (either a blank node or an IRI).@id
property, set the active
subject to newly generated blank node.@type
, set the active property
to rdf:type
.
@graph
,
process value algorithm recursively, using active subject as graph name
and null values for active subject and active property and then
proceed to next property.rdf:type
so set the active object to an IRI.List Conversion is the process of taking an array of values and adding them to a newly
created RDF Collection (see
[RDF-SCHEMA]) by linking each element of the list using rdf:first
and rdf:next
,
terminating the list with rdf:nil
using the following sequence:
The algorithm is invoked with an array array, the active property and returns a value to be used as an active object in the calling location.
This algorithm hasn't been updated yet.
rdf:nil
.
rdf:first
as the active property.
rdf:nil
.rdf:rest
and rest blank node.In some cases, data exists natively in the form of triples or or quads; 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 quads into a JSON-LD document.
When expanding typed values having a datatype of xsd:string
,
the @type
must not be set to xsd:string
and the resulting value
must have only a @value
property.
The conversion algorithm takes a single parameter input in the form of an array of Quad representations.
This algorithm hasn't been updated yet.
rdf:first
,
use the entry in graph.listMap indexed by subject,
initializing it to a new JSON object if nesessary. Represent
object in expanded form, as described in
Value Expansion. Add the
resulting object representation to the entry indexed by
first, and skip to the next quad.rdf:rest
:
@id
and
name represented in expanded IRI form.@id
and
subject represented in expanded IRI form if necessary.rdf:type
, object is not a JSON-LD value, and the
useRdfType
option is not present or false:
@type
, creating an entry in value if necessary.useNativeTypes
option is set to true:
xsd:boolean
, the
converted value is true if the literal
matches the value true
or false
if
the literal matches the value false
.xsd:integer
or
xsd:double
, try to convert the literal to a
JSON number. If the conversion is successful,
store the result in converted value, otherwise
set converted value to value.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].nodes.When converting JSON-LD to RDF JSON-native types such as numbers and booleans are automatically coerced to xsd:integer, xsd:double, or xsd:boolean. Implementers must ensure that the result is in canonical lexical form. A canonical lexical form is a set of literals from among the valid set of literals for a datatype such that there is a one-to-one mapping between the canonical lexical form and a value in the value space as defined in [XMLSCHEMA11-2]. In other words, every value must be converted to a deterministic string representation.
The canonical lexical form 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:
(value).toFixed(0).toString()
The canonical lexical form 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
.
xsd:double's value space is defined by the IEEE double-precision 64-bit
floating point type [IEEE-754-1985]; in JSON-LD the mantissa is rounded to 15 digits after the
decimal point.
To convert the number in JavaScript, implementers can use the following snippet of code:
(value).toExponential(15).replace(/(\d)0*e\+?/,'$1E')
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 form directly.
The canonical lexical form of the boolean values true
and false
are the strings true and false.
When JSON-native numbers, are type coerced, lossless data round-tripping can not be guaranted as rounding errors might occur. Additionally, only literals typed as xsd:integer, xsd:double, and xsd:boolean are automatically converted back to their JSON-native counterparts in when converting from RDF.
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.
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.
The JSON-LD processor interface is the high-level programming structure that developers use to access the JSON-LD transformation methods.
The JSON-LD API signatures are the same across all programming languages. Due
to the fact that asynchronous programming is uncommon in certain languages, developers may
implement a processor with a synchronous interface instead. In that case, the callback
parameter must not be included and the result must be returned as a return value instead.
It is important to highlight that conformant JSON-LD processors must not modify the input parameters.
[Constructor]
interface JsonLdProcessor {
void expand ((object or object[] or DOMString) input, JsonLdCallback
callback, optional JsonLdOptions
? options);
void compact ((object or object[] or DOMString) input, (object or DOMString) context, JsonLdCallback
callback, optional JsonLdOptions
? options);
void flatten ((object or object[] or DOMString) input, (object or DOMString)? context, JsonLdCallback
callback, optional JsonLdOptions
? options);
};
compact
input
using the
context
according to the steps in the
Compaction Algorithm.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
input | (object or object[] or DOMString) | ✘ | ✘ | The JSON-LD object or array of JSON-LD objects to perform the compaction upon or an IRI referencing the JSON-LD document to compact. |
context | (object or DOMString) | ✘ | ✘ | The context to use when compacting the input ; either in the
form of an JSON object or as IRI. |
callback |
| ✘ | ✘ | A callback that is called when processing is complete on
the given input . |
options |
| ✔ | ✔ | A set of options to configure the used algorithms such. This allows, e.g.,
to set the input document's base IRI. This also includes
the optimize flag, which, if set, will allow processor-specific
optimization. |
void
expand
input
according to
the steps in the Expansion Algorithm.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
input | (object or object[] or DOMString) | ✘ | ✘ | The JSON-LD object or array of JSON-LD objects to perform the expansion upon or an IRI referencing the JSON-LD document to expand. |
callback |
| ✘ | ✘ | A callback that is called when processing is complete on
the given input . |
options |
| ✔ | ✔ | A set of options to configure the used algorithms such. This allows, e.g., to set the input document's base IRI. |
void
flatten
input
and
compacts it using the passed context
according to the steps in the Flattening Algorithm.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
input | (object or object[] or DOMString) | ✘ | ✘ | The JSON-LD object or array of JSON-LD objects or an IRI referencing the JSON-LD document to flatten. |
context | (object or DOMString) | ✔ | ✘ | The context to use when compacting the flattened input ; either
in the form of an JSON object or as IRI. If
null is passed, the result will not be compacted but keept
in expanded form. |
callback |
| ✘ | ✘ | A callback that is called when processing is complete on the given
input . |
options |
| ✔ | ✔ | A set of options to configure the used algorithms such. This allows, e.g., to set the input document's base IRI. |
void
JSON-LD processors utilize callbacks in order to return information in an asynchronous manner to calling applications. This section details the parameters sent to those callbacks.
The JsonLdCallback
is called when processing of an API method
of JsonLdProcessor
has been completed successfully or been
terminated by an error.
callback JsonLdCallback = void (JsonLdProcessingError
error, object or object[] document);
JsonLdCallback
Parameterserror
of type JsonLdProcessingError
null
, then no error occurred. If
the value is non-null
, a processing error occurred
and the details will be contained within the error
object.document
of type array of object or objectThis section describes datatype definitions used within the JSON-LD API.
The JsonLdOptions
type is used to pass various options to the JsonLdProcessor
methods.
dictionary JsonLdOptions {
DOMString base;
object or DOMString expandContext = null;
boolean compactArrays = true;
boolean optimize = false;
boolean useRdfType = false;
boolean useNativeTypes = true;
};
JsonLdOptions
Membersbase
of type DOMStringcompactArrays
of type boolean, defaulting to true
true
, the JSON-LD processor replaces arrays with just
one element with that element during compaction. If set to false
,
all arrays will remain arrays even if they have just one element.
expandContext
of type object or DOMString, defaulting to null
optimize
of type boolean, defaulting to false
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.
useNativeTypes
of type boolean, defaulting to true
true
, the JSON-LD processor will try to convert
typed values to JSON native types instead of using the
expanded object form when converting from RDF.
xsd:boolean
values will be converted to true or false.
xsd:integer
and xsd:double
values will be
converted to
JSON numbers.
useRdfType
of type boolean, defaulting to false
true
, the JSON-LD processor will use the
expanded rdf:type
IRI as the property instead of
@type
when converting from RDF.
Developers should note that the details of error handling are being actively debated.
The JsonLdProcessingError
type is used to report errors to a
JsonLdCallback
.
dictionary JsonLdProcessingError {
JsonLdErrorCode
code;
DOMString? message;
};
JsonLdProcessingError
Memberscode
of type JsonLdErrorCode
message
of type DOMString, nullableThe JsonLdErrorCode represent the collection of valid JSON-LD error codes.
enum JsonLdErrorCode {
"INVALID_SYNTAX",
"LOAD_ERROR",
"LIST_OF_LISTS_DETECTED"
};
Enumeration description | |
---|---|
INVALID_SYNTAX | A violation of the grammar as defined by the JSON-LD syntax specification [JSON-LD] was detected. |
LOAD_ERROR | There was a problem encountered loading a remote context. |
LIST_OF_LISTS_DETECTED | A list of lists was detected. List of lists are not supported in this version of JSON-LD due to the algorithmic complexity associated with conversion to RDF. |
A large amount of thanks goes out to the JSON-LD Community Group participants who worked through many of the technical issues on the mailing list and the weekly telecons - of special mention are Niklas Lindström, François Daoust, Lin Clark, and Zdenko 'Denny' Vrandečić. 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. The work of Dave Lehn and Mike Johnson are appreciated for reviewing, and performing several implementations of the specification. Ian Davis is thanked for his work on RDF/JSON. Thanks also to Nathan Rixham, Bradley P. Allen, Kingsley Idehen, Glenn McDonald, Alexandre Passant, Danny Ayers, Ted Thibodeau Jr., Olivier Grisel, Josh Mandel, Eric Prud'hommeaux, David Wood, Guus Schreiber, Pat Hayes, Sandro Hawke, and Richard Cyganiak or their input on the specification.