W3C

JSON-LD API 1.0

An Application Programming Interface for the JSON-LD Syntax

W3C Editor's Draft 30 August 2012

This version:
http://dvcs.w3.org/hg/json-ld/raw-file/default/spec/ED/json-ld-api/20120830/index.html
Latest published version:
http://www.w3.org/TR/json-ld-api/
Latest editor's draft:
http://dvcs.w3.org/hg/json-ld/raw-file/default/spec/latest/json-ld-api/index.html
Editors:
Manu Sporny, Digital Bazaar
Gregg Kellogg, Kellogg Associates
Markus Lanthaler, Graz University of Technology
Authors:
Dave Longley, Digital Bazaar
Manu Sporny, Digital Bazaar
Gregg Kellogg, Kellogg Associates
Markus Lanthaler, Graz University of Technology

This document is also available in this non-normative format: diff to previous version


Abstract

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.

Status of This Document

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 currently five 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.

Issue

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 First Public Working Draft does not require that all Working Group members agree on the content of the document.

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.

Table of Contents

1. Preface

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].

1.1 Contributing

There are a number of ways that one may participate in the development of this specification:

2. Introduction

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 a programming environment like JavaScript, Python or Ruby.

There are three major types of transformation that are discussed in this document; compaction, expansion, and RDF conversion.

2.1 Expansion

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:

Example 1
var input1 = {
  "@context": "http://json-ld.org/contexts/person.jsonld"
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

The next input example uses one IRI to express a property, but leaves the rest of the information untouched.

Example 2
var input2 = {
  "@context": "http://json-ld.org/contexts/person.jsonld"
  "http://xmlns.com/foaf/0.1/name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

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 are IRIs to their fully expanded form. The second is to express all values in expanded form. To transform both inputs above to the same representation, the developer could do the following:

Example 3
function expansionCallback(output) {
   console.log(output);
}

// the second parameter is 'null' because the developer does not wish to
// inject another context value
jsonld.expand(input1, null, expansionCallback);
jsonld.expand(input2, null, expansionCallback);

The output for both calls above will be:

Example 4
[{
  "http://xmlns.com/foaf/0.1/name": [{
    "@value": "Manu Sporny"
  }],
  "http://xmlns.com/foaf/0.1/homepage": [{
    "@id": "http://manu.sporny.org/"
  }]
}]

Note that in the example above; all context definitions have been removed, all term and prefixes have been expanded to full IRIs, and all literals 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.

2.2 Compaction

While expansion expands a given input as much as possible, compaction performs the opposite operation - expressing a given input as succinctly as possible. While expansion 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 compresses all IRIs to terms or prefixes, and compacts all literals expressed in expanded form as much as possible.

The following example expresses input that has already been fully expanded:

Example 5
var expandedInput = [{
  "http://xmlns.com/foaf/0.1/name": [{
    "@value": "Manu Sporny"
  }],
  "http://xmlns.com/foaf/0.1/homepage": [{
    "@id": "http://manu.sporny.org/"
  }]
}]

A developer that wants to transform the data above into a more human-readable form, could do the following using the JSON-LD API:

Example 6
function compactionCallback(output) {
   console.log(output);
}

jsonld.compact(expandedInput, "http://json-ld.org/contexts/person.jsonld", compactionCallback);

The following would be the result of the call above:

Example 7
{
  "@context": "http://json-ld.org/contexts/person.jsonld"
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

Note that all of the terms have been compressed and the context has been injected into the output. While compacted output is most useful to humans, it can also be carefully used to generate structures that are easy to use for developers to program against as well.

2.3 Conversion to and from RDF

JSON-LD can be used to losslessly express the RDF data model as described in the RDF Concepts document [RDF-CONCEPTS]. This ensures that data can be round-tripped from any RDF syntax, like N-Triples or TURTLE, without any loss in the fidelity of the data. Assume the following RDF input in N-Triples format:

Example 8
var data = "
<http://manu.sporny.org/about/#manu> <http://xmlns.com/foaf/0.1/name> \"Manu Sporny\" .\n
<http://manu.sporny.org/about/#manu> <http://xmlns.com/foaf/0.1/homepage> <http://manu.sporny.org/> .";

A developer can use the JSON-LD API to transform the markup above into a JSON-LD document:

Example 9
function conversionCallback(result)
{
  console.log("JSON-LD Document: ", result);
};

jsonld.fromRDF(data, conversionCallback, {"format": "ntriples"});

The following expanded output would be the result of the call above:

Example 10
[{
  "@id": "http://manu.sporny.org/about/#manu",
  "http://xmlns.com/foaf/0.1/name": [{
    "@value": "Manu Sporny"
  }],
  "http://xmlns.com/foaf/0.1/homepage": [{
    "@id": "http://manu.sporny.org/"
  }]
}]

Note that the output above, could easily be compacted to produce the following using the technique outlined in the previous section:

Example 11
{
  "@context": "http://json-ld.org/contexts/person.jsonld",
  "@id": "http://manu.sporny.org/about/#manu",
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

Transforming the node above back to RDF is as simple as calling the toRDF() method:

Example 12
var jsonldDocument = ...; // assign the JSON-LD document here

function rdfCallback(quads)
{
  console.log("RDF Data: ", quads);
};

jsonld.toRDF(jsonldDocument, rdfCallback);

2.4 Framing and Normalization

Issue

There are currently two other API methods that are in active development and were not ready for publication at the time this document was published. Framing allows a developer to force a different layout for the data and effectively perform query-by-example on JSON-LD documents - this is most useful when a JSON-LD-based REST API does not know the exact form of the data it is getting in, but still wants to operate upon it if some bare essentials are found in the data. JSON-LD normalization allows JSON-LD documents to be deterministically serialized such that they can be digitally signed or be used to find the differences between two linked data graphs. It is expected that framing will be a part of the final API. It is expected that normalization will be an optional feature that JSON-LD processors may implement.

3. The Application Programming Interface

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.

3.1 General Terminology

Issue

The intent of the Working Group and the Editors of this specification is to eventually align terminology used in this document with the terminology used in the RDF Concepts document to the extent to which it makes sense to do so. In general, if there is an analogue to terminology used in this document in the RDF Concepts document, the preference is to use the terminology in the RDF Concepts document.

The following is an explanation of the general terminology used in this document:

JSON object
An object structure is represented as a pair of curly brackets surrounding zero or more name-value pairs. A name is a string. A single colon comes after each name, separating the name from the value. A single comma separates a value from a following name. The names within an object should be unique.
array
An array is represented as square brackets surrounding zero or more values that are separated by commas.
string
A string is a sequence of zero or more Unicode (UTF-8) characters, wrapped in double quotes, using backslash escapes (if necessary). A character is represented as a single character string.
number
A number is similar to that used in most programming languages, except that the octal and hexadecimal formats are not used and that leading zeros are not allowed.
true and false
Values that are used to express one of two possible boolean states.
null
The use of the null value within JSON-LD is used to ignore or reset values.
keyword
A JSON key that is specific to JSON-LD, specified in the JSON-LD Syntax specification [JSON-LD] in the section titled Syntax Tokens and Keywords.
context
A a set of rules for interpreting a JSON-LD document as specified in The Context of the [JSON-LD] specification.
IRI
An Internationalized Resource Identifier as described in [RFC3987].
Linked Data
A set of documents, each containing a representation of a linked data graph.
linked data graph or dataset
An unordered labeled directed graph, where nodes are IRIs or Blank Nodes, or other values. A linked data graph is a generalized representation of a RDF graph as defined in [RDF-CONCEPTS].
named graph
A linked data graph that is identified by an IRI.
graph name
The IRI identifying a named graph.
default graph
When executing an algorithm, the graph where data should be placed if a named graph is not specified.
node
A piece of information that is represented in a linked data graph.
node definition
A JSON object used to represent a node and one or more properties of that node. A JSON object is a node definition if it does not contain they keys @value, @list or @set and it has one or more keys other than @id.
node reference
A JSON object used to reference a node having only the @id key.
blank node
A node in the linked data graph that does not contain a de-referenceable identifier because it is either ephemeral in nature or does not contain information that needs to be linked to from outside of the linked data graph. A blank node is assigned an identifier starting with the prefix _:.
property
The IRI label of an edge in a linked data graph.
subject
A node in a linked data graph with at least one outgoing edge, related to an object node through a property.
object
A node in a linked data graph with at least one incoming edge.
quad
A piece of information that contains four items; a subject, a property, an object, and a graph name.
literal
An object expressed as a value such as a string, number or in expanded form.

3.2 JsonLdProcessor

The JSON-LD processor interface is the high-level programming structure that developers use to access the JSON-LD transformation methods.

Note

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 processor with a synchronous interface instead. In that case, the callback parameter must not be included and the result must be returned as return value instead.

[NoInterfaceObject]
interface JsonLdProcessor {
    void expand (object or object[] or IRI input, object or IRI? context, JsonLdCallback callback, optional JsonLdOptions? options);
    void compact (object or object[] or IRI input, object or IRI context, JsonLdCallback callback, optional JsonLdOptions? options);
    void flatten (object or object[] or IRI input, string or IRI graph, object or IRI? context, JsonLdCallback callback, optional JsonLdOptions? options);
    void fromRDF (Quad[] input, JsonLdCallback callback, optional JsonLdOptions? options);
    void toRDF (object or object[] or IRI input, QuadCallback callback, optional JsonLdOptions? options);
};

3.2.1 Methods

compact
Compacts the given 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 appropriate exception must be thrown.
INVALID_SYNTAX
A general syntax error was detected in the @context. For example, if a @type key maps to anything other than @id or an absolute IRI, this exception would be raised.
LOAD_ERROR
There was a problem encountered loading a remote context.
LOSSY_COMPACTION
The compaction would lead to a loss of information, such as a @language value.
CONFLICTING_DATATYPES
The target datatype specified in the coercion rule and the datatype for the typed literal do not match.
LIST_OF_LISTS_DETECTED
A list of lists was detected. This is not supported in this version of JSON-LD.
ParameterTypeNullableOptionalDescription
inputobject or object[] or IRI✘✘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.
contextobject or IRI✘✘The context to use when compacting the input; either in the form of an JSON object or as IRI.
callbackJsonLdCallback✘✘A callback that is called when processing is complete on the given input.
optionsJsonLdOptions✔✔A set of options that may affect the expansion algorithm such as, e.g., the input document's base IRI. This also includes optimize, which if set will cause processor-specific optimization.
Return type: void
expand
Expands the given 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.
INVALID_SYNTAX
A general syntax error was detected in the @context. For example, if a @type key maps to anything other than @id or an absolute IRI, this exception would be raised.
LOAD_ERROR
There was a problem encountered loading a remote context.
LIST_OF_LISTS_DETECTED
A list of lists was detected. This is not supported in this version of JSON-LD.
ParameterTypeNullableOptionalDescription
inputobject or object[] or IRI✘✘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.
contextobject or IRI✔✘An optional external context to use additionally to the context embedded in input when expanding the input.
callbackJsonLdCallback✘✘A callback that is called when processing is complete on the given input.
optionsJsonLdOptions✔✔A set of options that may affect the expansion algorithm such as, e.g., the input document's base IRI.
Return type: void
flatten
Flattens the given 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.
Issue

It is still being discussed if the flatten() method should be added or not. See ISSUE-109.

ParameterTypeNullableOptionalDescription
inputobject or object[] or IRI✘✘The JSON-LD object or array of JSON-LD objects to flatten or an IRI referencing the JSON-LD document to flatten.
graphstring or IRI✘✘The graph in the document that should be flattened. To return the default graph @default has to be passed, for the merged graph @merged and for any other graph the IRI identifying the graph has to be passed. The default value is @merged.
contextobject or IRI✔✘An optional external context to use additionally to the context embedded in input when expanding the input.
callbackJsonLdCallback✘✘A callback that is called when processing is complete on the given input.
optionsJsonLdOptions✔✔A set of options that may affect the expansion algorithm such as, e.g., the input document's base IRI.
Return type: void
fromRDF
Creates a JSON-LD document given an set of Quads.
ParameterTypeNullableOptionalDescription
inputQuad[]✘✘A dataset represented as an array of Quads.
callbackJsonLdCallback✘✘A callback that is called when processing is complete on the given input.
optionsJsonLdOptions✔✔A set of options that will affect the algorithm. This includes notType, which if set to true causes the resulting document to use rdf:type as a property, instead of @type.
Return type: void
toRDF
Processes the input according to the Convert to RDF Algorithm, calling the provided callback for each Quad generated.
INVALID_SYNTAX
A general syntax error was detected in the @context. For example, if a @type key maps to anything other than @id or an absolute IRI, this exception would be raised.
LOAD_ERROR
There was a problem encountered loading a remote context.
LIST_OF_LISTS_DETECTED
A list of lists was detected. This is not supported in this version of JSON-LD.
ParameterTypeNullableOptionalDescription
inputobject or object[] or IRI✘✘The JSON-LD object or array of JSON-LD objects to convert to RDF or a IRI referencing the JSON-LD document to convert to RDF.
callbackQuadCallback✘✘A callback that is called when a Quad is created from processing the given input.
optionsJsonLdOptions✔✔A set of options that may affect the conversion to RDF such as, e.g., the input document's base IRI.
Return type: void

3.3 Callbacks

3.3.1 JsonLdCallback

The JsonLdCallback is used to return a processed JSON-LD representation as the result of processing an API method.

[NoInterfaceObject Callback]
interface JsonLdCallback {
    void jsonLd (object or object[] jsonld);
};
3.3.1.1 Methods
jsonLd
This callback is invoked when processing is complete.
ParameterTypeNullableOptionalDescription
jsonldobject or object[]✘✘The processed JSON-LD document.
Return type: void

3.3.2 QuadCallback

The QuadCallback is called whenever the processor generates a quad during the quad() call.

[NoInterfaceObject Callback]
interface QuadCallback {
    void quad (Quad quad);
};
3.3.2.1 Methods
quad
This callback is invoked whenever a quad is generated by the processor.
ParameterTypeNullableOptionalDescription
quadQuad✘✘The quad.
Return type: void

3.4 Data Structures

This section describes datatype definitions used within the JSON-LD API.

3.4.1 IRI

The IRI datatype is a string representation of an IRI.

typedef DOMString IRI;
This datatype indicates that the string is interpreted as an Internationalized Resource Identifier [RFC3987] identifying a document, which when parsed as JSON yields either a JSON object or array.

3.4.2 JsonLdOptions

The JsonLdOptions type is used to pass various options to the JsonLdProcessor methods.

dictionary JsonLdOptions {
    IRI?    base;
    boolean compactArrays = true;
    boolean optimize = false;
    boolean useRdfType = false;
    boolean useNativeTypes = true;
};
3.4.2.1 Dictionary JsonLdOptions Members
base of type IRI, nullable
The Base IRI to use when expanding the document. This overrides the value of input if it is a IRI. If not specified and input is not an IRI, the base IRI defaults to the current document IRI if in a browser context, or the empty string if there is no document context.
compactArrays of type boolean, defaulting to true
If set to 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.
optimize of type boolean, defaulting to false
If set to 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
If set to true, the JSON-LD processor will try to convert datatyped literals 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
If set to true, the JSON-LD processor will use the expanded rdf:type IRI as the property instead of @type when converting from RDF.

The following data structures are used for representing data about RDF quads. They are used for normalization, and RDF conversion.

3.4.3 Quad

The Quad interface represents an RDF Quad. See [RDF-CONCEPTS] definition for RDF triple, which most closely aligns to Quad.

[NoInterfaceObject]
interface Quad {
    readonly attribute Node  subject;
    readonly attribute Node  property;
    readonly attribute Node  object;
    readonly attribute Node? graphName;
};
3.4.3.1 Attributes
graphName of type Node, readonly, nullable
If present, the name associated with the Quad identifying it as a member of a named graph. If it is missing, the quad is a member of the default graph.
This element is at risk, and may be removed.
object of type Node, readonly
The object associated with the Quad.
property of type Node, readonly
The property associated with the Quad. Within JSON-LD, an RDF predicate is refered to as a property
subject of type Node, readonly
The subject associated with the Quad.

3.4.4 Node

Node is the base class of IRI, BlankNode, and Literal. It is the IDL representation of a linked data graph node.

[NoInterfaceObject]
interface Node {
};

3.4.5 IRI

A node that is an IRI.

[NoInterfaceObject]
interface IRI : Node {
    readonly attribute DOMString value;
};
3.4.5.1 Attributes
value of type DOMString, readonly
The IRI identifier of the node as a [UNICODE] string.

3.4.6 Blank Node

A node in the linked data graph that does not contain a de-reference-able identifier because it is either ephemeral in nature or does not contain information that needs to be linked to from outside of the linked data graph. A blank node is assigned an identifier starting with the prefix _: and an implementation dependent, auto-generated suffix that is unique to all information associated with the particular blank node.

[NoInterfaceObject]
interface BlankNode : Node {
    readonly attribute DOMString identifier;
};
3.4.6.1 Attributes
identifier of type DOMString, readonly
The temporary identifier of the blank node. The identifier must not be relied upon in any way between two separate processing runs of the same document or with a different document.
Note

Developers and authors must not assume that the value of a blank node will remain the same between two processing runs. BlankNode values are only valid for the most recent processing run on the document. BlankNode values will often be generated differently by different processors.

Note

Implementers must ensure that BlankNode values are unique within the current environment, two BlankNodes are considered equal if, and only if, their values are strictly equal.

3.4.7 Literal

Literals represent values such as numbers, dates and strings in RDF data. A Literal is comprised of three attributes:

  • a lexical form of the value
  • an optional language tag
  • a datatype specified by an IRI

Literals representing plain text in a natural language may have a language tag specified by a string token, as specified in [BCP47], normalized to lowercase (e.g., 'en', 'fr', 'en-gb'). They also have a datatype attribute such as xsd:string. If unspecified, the datatype defaults to xsd:string.

Literals representing values with a specific datatype, such as the integer 72, may have a datatype attribute specified in the form of a IRI (e.g., xsd:integer).

See[RDF-CONCEPTS] definition for literal.

[NoInterfaceObject]
interface Literal : Node {
    readonly attribute DOMString  value;
    readonly attribute DOMString? language;
    readonly attribute IRI?       datatype;
};
3.4.7.1 Attributes
datatype of type IRI, readonly, nullable
An optional datatype identified by a IRI.
language of type DOMString, readonly, nullable
An optional language tag as defined in [BCP47], normalized to lowercase.
value of type DOMString, readonly
The lexical form of the Literal's value.

4. Algorithms

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.

4.1 Algorithm Terms

active subject
the currently active subject that the processor should use when processing.
active property
the currently active property that the processor should use when processing. The active property is represented in the original lexical form, which is used for finding coercion mappings in the active context.
active object
the currently active object that the processor should use when processing.
active context
a context that is used to resolve terms while the processing algorithm is running. The active context is the context contained within the processor state.
compact IRI
a compact IRI is has the form of prefix and suffix and is used as a way of expressing an IRI without needing to define separate term definitions for each IRI contained within a common vocabulary identified by prefix.
local context
a context that is specified within a JSON object, specified via the @context keyword.
processor state
the processor state, which includes the active context, active subject, and active property. The processor state is managed as a stack with elements from the previous processor state copied into a new processor state when entering a new JSON object.
JSON-LD input
The JSON-LD data structure that is provided as input to the algorithm.
JSON-LD output
The JSON-LD data structure that is produced as output by the algorithm.
term
A term is a short word defined in a context that may be expanded to an IRI
prefix
A prefix is a term that expands to a vocabulary base IRI. It is typically used along with a suffix to form a compact IRI to create an IRI within a vocabulary.
language-tagged string
A language-tagged string is a literal without a datatype, including a language. See languaged-tagged string in [RDF-CONCEPTS].
typed literal
A typed literal is a literal with an associated IRI which indicates the literal's datatype. See literal in [RDF-CONCEPTS].

4.2 Context Processing

Processing of JSON-LD data structure is managed recursively. During processing, each rule is applied using information provided by the active context. Processing begins by pushing a new processor state onto the processor state stack. If a local context is encountered, information from the local context is merged into the active context.

The active context is used for expanding properties and values of a JSON object (or elements of an array) using a term mapping. It is also used to maintain coercion mappings from terms to datatypes, language mappings from terms to language codes, and list mappings and set mappings for terms. Processors must use the lexical form of the property when creating a mapping, as lookup is performed on lexical forms, not expanded IRI representations.

A local context is identified within a JSON object having a @context property with a string, array or a JSON object value. When processing a local context, special processing rules apply:

  1. Create a new, empty local context.
  2. Let context be the value of @context
    1. If context equals null, clear the active context.
    2. If context is an array, process each element as context in order by starting at Step 2.1.
    3. If context is a string, it must have a lexical form of absolute IRI.
      1. Dereference context.
      2. If the resulting document is a JSON document, extract the top-level @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.
    4. If context is a JSON object, perform the following steps:
      1. If context has a @language property, it must have a value of a simple string with the lexical form described in [BCP47], or null. Add the language to the local context.
      2. If value has a @vocab key, it must have a value of a simple string with the lexical form of an absolute IRI, or null. Add the vocabulary mapping to the local context.
      3. Otherwise, for each property in context perform the following steps:
        1. If the property's value is a simple string, determine the IRI mapping value by performing IRI Expansion on the associated value. If the result of the IRI mapping is an absolute IRI, merge the property into the local context term mapping, unless the property is a JSON-LD keyword, in which case throw an exception.
        2. Otherwise, if the property's value is null remove mapping, coercion, container and language information associated with property from the local context.
        3. Otherwise, the property's value must be a JSON object.
          1. If the property is a JSON-LD keyword and the value has @id, @language or @type properties, throw an exception.
            Issue
            Undecided if @type or @graph can take a @container with @set.
          2. If the property has the form of term, its value must have an @id property with a string value which must have the form of a term, compact IRI, or absolute IRI. Determine the IRI mapping by performing IRI Expansion on the associated value. If the result of the IRI mapping is an absolute IRI, merge the property into the local context term mapping.
          3. If the property has the form of of a compact IRI or absolute IRI, the value may have a @id property with a string value which must have the form of a term, compact IRI, or absolute IRI. Determine the IRI mapping by performing IRI Expansion on the associated value. If the result of the IRI mapping is an absolute IRI, merge the property into the local context term mapping.
          4. If the value has a @type property, its value must have the form of a term, compact IRI, absolute IRI, or the keyword @id. Determine the IRI by performing IRI Expansion on the associated value. If the result of the IRI mapping is an absolute IRI or @id, merge into the local context coercion mapping using the lexical value of the property.
          5. If the value has a @container property, its value must be @list or @set. Merge the list mapping or set mapping into the local context using the lexical value of the property.
          6. If the value has a @language property but no @type property, the value of the @language property must be a string or null. Merge the language mapping into the local context using the lexical value of the property.
        4. Merge the local context into the active context.
        5. Repeat Step 2.4.2 until no entries are added to the local context.
Note

It can be difficult to distinguish between a compact IRI and an absolute IRI, as a compact IRI may seem to be a valid IRI scheme. When performing repeated IRI expansion, a term used as a prefix may not have a valid mapping due to dependencies in resolving term definitions. By continuing Step 2.3.2 until no changes are made, mappings to IRIs created using an undefined term prefix will eventually expand to an absolute IRIs.

Issue 43 concerns performing IRI expansion in the key position of a context definition.

4.3 IRI Expansion

Keys and some values are evaluated to produce an IRI. This section defines an algorithm for transforming a value representing an IRI into an actual IRI.

IRIs may be represented as an absolute IRI, a term, a compact IRI, or as a value relative to @vocab.

An absolute IRI is defined in [RFC3987] containing a scheme along with path and optional query and fragment segments. A relative IRI is an IRI that is relative some other absolute IRI; in the case of JSON-LD this is the base location of the document.

The algorithm for generating an IRI is:

  1. If the active context contains a term mapping for the value using a case-sensitive comparison, use the mapped value as an IRI.
  2. Otherwise, split the value into a prefix and suffix from the first occurrence of ':'.
  3. If the prefix is a '_' (underscore), the value represents a named blank node.
  4. If the active context contains a term mapping for prefix using a case-sensitive comparison, and suffix does not does not begin with '//' (i.e., it does not match a hier-part including authority (as defined in [RFC3986]), generate an IRI by prepending the mapped prefix to the (possibly empty) suffix using textual concatenation. Note that an empty suffix and no suffix (meaning the value contains no ':' string at all) are treated equivalently.
  5. Otherwise, if the IRI being processed does not contain a colon and is a property, i.e., a key in a JSON object, or the value of @type and the active context has a @vocab mapping, join the mapped value to the suffix using textual concatenation.
  6. Otherwise, if the IRI being processed does not contain a colon and is not a property, i.e., not a key in a JSON object treat it as a relative IRI and resolve it against the base IRI as per [RFC3986] using only the basic algorithm in section 5.2. Neither Syntax-Based Normalization nor Scheme-Based Normalization (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].
  7. Otherwise, use the value directly as an IRI.

4.4 IRI Compaction

Some keys and values are expressed using IRIs. This section defines an algorithm for transforming an IRI (iri) to a term or compact IRI using the terms specified in the active context using an optional value.

4.4.1 IRI Compaction Algorithm

The algorithm for generating a compact IRI is:

  1. Create an empty list of terms terms that will be populated with terms that are ranked according to how closely they match value. Initialize highest rank to 0, and set a flag list container to false.
  2. For each term in the active context:
    1. If the term's IRI is not a complete match against iri, continue to the next term.
    2. If value is a JSON object containing only the property @list:
      1. If term has a @container set to @set, continue to the next term.
      2. If list container is true and term does not have a container set to @list and value is null, continue to the next term.
    3. Otherwise, if term has a container set to @list, continue to the next term.
    4. Set rank to the term rank of value by passing passing term, value, and active context to the Term Rank Algorithm.
    5. If rank is greater than 0:
      1. If term has a container set to @set, then add 1 to rank.
      2. If value is a JSON object containing only the property @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.
      3. Otherwise, if rank is greater than or equal to highest rank:
        1. If rank is greater than highest rank, clear terms and set highest rank to rank.
        2. Add term to terms.
  3. If terms is empty, and the active context has a @vocab which is a prefix of iri where the resulting relative IRI is not a term in the active context. The resulting relative IRI is the unmatched part of iri.
  4. If terms is empty, add a compact IRI representation of iri for each term in the active context which maps to an IRI which is a prefix for iri where the resulting compact IRI is not a term in the active context. The resulting compact IRI is the term associated with the partially matched IRI in the active context concatenated with a colon (:) character and the unmatched part of iri.
  5. If terms is empty, the IRI being processed is a property or the value of @type and @vocab is not null and matches the beginning of iri, return the unmatched portion of iri. Otherwise return iri.
  6. Otherwise, return the shortest and lexicographically least value in terms.

4.4.2 Term Rank Algorithm

When selecting among multiple possible terms for a given property, it may be that multiple terms are defined with the same IRI, but differ in @type, @container or @language. The purpose of this algorithm is to take a term and a value and give it a term rank. The selection can then be based, partly, on the term having the highest term rank.

Given a term term, value, and active context determine the term rank using the following steps:

  1. If value is null, term rank is 3.
  2. Otherwise, if value is a JSON object containing only the property @list:
    1. If the @list property is an empty array, if term has @container set to @list, term rank is 1, otherwise 0.
    2. Otherwise, return the sum of the term ranks for every entry in the list.
  3. Otherwise, value must be a node definition, node reference, or a JSON object having a @value.
    1. If value has a @value property:
      1. If value has a @type property matching a @type coercion for term, term rank is 3, otherwise if term has no @type coercion and no @language, term rank is 1, otherwise 0.
      2. Otherwise, if @value is not a string, if term has no @type or @language it is 2, otherwise 1.
      3. Otherwise, if value has no @language property, if term has @language null, or term has no @type or @language and the active context has no @language, term rank is 3, otherwise 0.
      4. Otherwise, if value has a @language property matching a @language definition for term (or term has no @type or @language definition and @language in the active context matches the value @language), term rank is 3, otherwise if term has no @type coercion and no @language, term rank is 1, otherwise 0.
    2. Otherwise, if term has @type coerced to @id, term rank is 3, otherwise if term has no @type coercion and no @language, term rank is 1, otherwise 0.
  4. Return term rank.

4.5 Value Expansion

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 active property and active context. It is implemented as follows:

  1. If value is null, the value is already expanded.
  2. If active property is @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.
  3. Otherwise, if active property is not a keyword, then expand value into an object:
    1. Set the first key-value pair to @value and the unexpanded value.
    2. If the active property is the target of typed literal coercion, set the second key-value pair to @type and the associated coercion datatype expanded according to the IRI Expansion rules.
    3. Otherwise, if the active property is the target of language tagging, set the second key-value pair to @language and value of the language tagging from the active context.
  4. Otherwise, value is already expanded.

4.6 Value Compaction

Some values, such as IRIs and typed literals, may be expressed in an expanded form (expanded value) 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 active property and active context. It is implemented as follows:

  1. If value only has one property and the active context has no default language, then the compacted value is the value of @value.
  2. Otherwise, if active property is @graph, the compacted value is the value associated with the @id key, processed according to the IRI Compaction steps.
  3. Otherwise, if the active context contains a coercion target for the key that matches the expression of the value, compact the value using the following steps:
    1. If the coercion target is an @id, the compacted value is the value associated with the @id key, processed according to the IRI Compaction steps.
    2. If the coercion target is a typed literal, the compacted value is the value associated with the @value key.
  4. Otherwise, if value contains an @id key, the compacted value is value with the value of @id processed according to the IRI Compaction steps.
  5. Otherwise, if the active context contains a @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.
  6. Otherwise, if the value contains a @type key, the compacted value is value with the @type value processed according to the IRI Compaction steps.
  7. Otherwise, the value is not modified.

4.7 Expansion

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 other JSON-LD API methods.

For example, assume the following JSON-LD input document:

Example 13
{
   "@context":
   {
      "name": "http://xmlns.com/foaf/0.1/name",
      "homepage": {
        "@id": "http://xmlns.com/foaf/0.1/homepage",
        "@type", "@id"
      }
   },
   "name": "Manu Sporny",
   "homepage": "http://manu.sporny.org/"
}

Running the JSON-LD Expansion algorithm against the JSON-LD input document provided above would result in the following output:

Example 14
{
   "http://xmlns.com/foaf/0.1/name": "Manu Sporny",
   "http://xmlns.com/foaf/0.1/homepage": {
      "@id": "http://manu.sporny.org/"
   }
}

4.7.1 Expansion Algorithm

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 context, or empty if context is null, active property is set to null, and element is set to the JSON-LD input.

  1. If element is an array, process each entry in element recursively using this algorithm, passing copies of the active context and active property. If has a @container set to @list and any entry in element is an array, or is a JSON object containing a @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.
  2. Otherwise, if element is an object
    1. If element has a @context property, update the active context according to the steps outlined in Context Processing and remove the @context property.
    2. Then, proceed and process each property and value in element as follows:
      1. Remove property from element, expand property according to the steps outlined in IRI Expansion. Set the active property to the original un-expanded property if property is not a keyword.
      2. If property does not expand to a keyword or an absolute IRI (i.e., it doesn't contain a colon), continue with the next property from element.
      3. If value is null and property is not @value, continue with the next property from element.
      4. If the property is @id the value must be a string. Expand the value according to IRI Expansion.
      5. Otherwise, if the property is @type:
        1. If value is a string, expand according to IRI Expansion.
        2. Otherwise, if value is a JSON Object, it must be empty (used for Framing).
        3. Otherwise, if value is an array, all elements must be strings. Expand value for each of its entries according to IRI Expansion.
      6. Otherwise, if the property is @value or @language the value must not be a JSON object or an array.
      7. Otherwise, if the property is @list or @set expand value recursively using this algorithm, passing copies of the active context and active property. If the expanded value is not an array, convert it to an array. If property is @list and any entry in value is a JSON object containing an @list property, throw an exception, as lists of lists are not supported.
      8. Otherwise, expand value recursively using this algorithm, passing copies of the active context and active property.
      9. If property is not a keyword and active property has a @container @list and the expanded value is not null, convert value to an object with an @list property whose value is set to value (unless value is already in that form).
      10. Convert value to array form unless value is null or property is @id, @type, @value, or @language.
      11. If value is not null, either merge value into an existing property property of element or create a new property property with value as value.
    3. If the processed element has an @value property
      1. element must not have more than one other property, which can either be @language or @type with a string value.
      2. if the value of @value equals null, replace element with the value of @value.
    4. Otherwise, if element has an @type property and its value is not in the form of an array, convert it to an array.
    5. If element has an @set or @list property, it must be the only property. Set element to the value of @set; leave @list untouched.
    6. If element has just a @language property, set element to null.
  3. Otherwise, expand element according to the Value Expansion rules, passing copies of the active context and active property.

If, after the algorithm outlined above is run, the resulting element is an JSON object with just a @graph property, element is set to the value of @graph's value. Finally, if element is a JSON object, it is wrapped into an array.

4.8 Compaction

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:

Example 15
{
  "http://xmlns.com/foaf/0.1/name": "Manu Sporny",
  "http://xmlns.com/foaf/0.1/homepage": {
    "@id": "http://manu.sporny.org/"
  }
}

Additionally, assume the following developer-supplied JSON-LD context:

Example 16
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
    "homepage": {
      "@id": "http://xmlns.com/foaf/0.1/homepage",
      "@type": "@id"
    }
  }
}

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:

Example 17
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
    "homepage": {
      "@id": "http://xmlns.com/foaf/0.1/homepage",
      "@type": "@id"
    }
  },
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

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.

4.8.1 Compaction Algorithm

The algorithm takes three input variables: an active 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, active property is set to null, and element is set to the result of performing the Expansion Algorithm on the JSON-LD input. This removes any existing context to allow the given active context to be cleanly applied.

  1. If element is an array, process each entry in element recursively using this algorithm, passing a copy of the active context and the active property. If element has a single item and the compactArrays option is set to true, the compacted value is that item; otherwise the compacted value is element.
  2. Otherwise, if element is an object:
    1. If element has an @value property or element is a node reference, return the result of performing Value Compaction on element using active property.
    2. Otherwise, if the active property has a @container mapping to @list and element has a corresponding @list property, recursively compact that property's value passing a copy of the active context and the active property ensuring that the result is an array with all null values removed. If there already exists a value for active property in element and the full IRI of property is also coerced to @list, throw an exception. Otherwise store the resulting array as value of active property if empty or property otherwise.
    3. Otherwise, construct output as a new JSON object used for returning the result of compacting element. For each property and value in element:
      1. If property is @id or @type
        1. Set active property to the result of performing IRI Compaction on property.
        2. If value is a string, the compacted value is the result of performing IRI Compaction on value.
        3. Otherwise, value must be an array. Perform IRI Compaction on every entry of value. If value contains just one entry and the compactArrays option is set to true, value is set to that entry.
        4. Add active property and the compacted value to output.
      2. Otherwise, value must be an array.
      3. If value is empty:
        1. Set active property to the result of performing IRI Compaction on property.
        2. Create an entry in output for active property and value.
      4. For each item in value:
        1. Set active property to the result of performing IRI Compaction for property and item using the active context.
        2. Compact item by recursively performing this algorithm passing a copy of the active context and the active property.
        3. If an entry already exists in output for active property, convert it to an array if necessary, and append the compacted value.
        4. Otherwise, if the compacted value is not an array and active property has a @container mapping to @set or if the compactArrays option is set to false, convert value to an array.
        5. Create an entry in output for active property and value.
  3. Otherwise, return element as the compacted element.
    Issue
    Perhaps this should also call Value Compaction on native types and strings, which could consolidate potential transformation in one place.

If, after the algorithm outlined above is run, the resulting element is an array, put element into the @graph property of a new JSON object and then set element to that JSON object. Finally, add a @context property to element and set it to the initially passed context.

4.9 Flattening

Flattening is the process of taking a JSON-LD document, expanding it, labeling all unlabeled nodes with a blank node identifier, and returning an array of the nodes defined in the document.

Issue

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:

Example 18
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
    "knows": "http://xmlns.com/foaf/0.1/knows"
  },
  "@id": "http://example.com/markus",
  "name": "Markus Lanthaler",
  "knows": {
    "name": "Manu Sporny"
  }
}

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:

Example 19
[
  {
    "@id": "http://example.com/markus",
    "http://xmlns.com/foaf/0.1/knows": [ { "@id": "_:t0" } ],
    "http://xmlns.com/foaf/0.1/name": [ { "@value": "Markus Lanthaler" } ]
  },
  {
    "@id": "_:t0",
    "http://xmlns.com/foaf/0.1/name": [ { "@value": "Manu Sporny" } ]
  }
]

4.9.1 Flattening Algorithm

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).

  1. Expand element according the Expansion Algorithm.
  2. Generate a nodeMap according the Node Map Generation Algorithm.
  3. Initialize an empty array result.
  4. If nodeMap has no property graph, return result, otherwise set definitions to its value.
  5. Foreach property and value of of definitions:
    1. Add value to result.
  6. Return result.

4.9.2 Node Map Generation

The Node Map Generation algorithm takes as input an expanded JSON-LD document and results in a JSON object nodeMap holding a flat representation of the graphs and nodes represented in the document. All nodes that are not uniquely identified by an IRI get assigned a (new) blank node identifier. The resulting nodeMap document will have a property for every graph in the document whose value is another object with a property for every node represented in the document. While the default graph is stored under the @default property and the merged graph under the @merged property, all other graphs are stored under their respective IRIs.

The algorithm takes as input the expanded JSON-LD document as element, the initially empty nodeMap, @default as graph, and null as list.

  1. If element is an array, process each entry in element recursively, using this algorithm and return.
  2. If element is not a JSON object or if it has a @value property, then if list is not null, append element to list and return.
  3. If the @id property exists and is an IRI, set id to its value, otherwise set it to a blank node identifier created by the Generate Blank Node Identifier algorithm.
  4. If list is not null, append a new node reference to list using id at the value for @id.
  5. Let nodes be the value in nodeMap where the key is graph; if no such value exists, insert a new JSON object for the key graph. If id is not in nodes, create a new JSON object node with id as the value for @id. Let node be the value of id in nodes.
  6. For each property that is not @id and each value in element ordered by property:
    1. If property is @graph, recursively call this algorithm passing value for element, nodeMap, null for list and if graph is @merged use graph, otherwise use id for graph and then continue.
    2. If property is not @type and is a keyword, merge property and value into node and then continue.
    3. For each value v in the array value:
      1. If v is a node definition or node reference:
        1. If the property @id is not an IRI or it does not exist, map v to a new blank node identifier to avoid collisions. If one does not already exist, add a node reference for v into node for property.
        2. Recursively call this algorithm passing v for value, nodeMap, graph, and null for list.
      2. Otherwise if v has the property @list then recursively call this algorithm with the value of @list as element, nodeMap, graph, and a new array flattenedList as list. Create a new JSON object with the property @list set to flattenedList and add it to node for property.
      3. Otherwise, if property is @type and v is not an IRI, generate a new blank node identifier and add it to node for property.
      4. Otherwise, add v to node for property.

After the above outlined algorithm has been executed, the node map for all graphs including the default graph are contained in nodeMap. To also create the node map for the merged graph, execute the algorithm again, but pass @merged for graph.

4.9.3 Generate Blank Node Identifier

This algorithm is used by the Node Map Generation Algorithm to deterministically name blank node identifiers. It uses a identifier map and prefix and takes a possibly null identifier and returns a new identifier based on prefix.

The variable next identifier is initialized to prefix appended with 0. The default value of prefix is _:t.

  1. If the old identifier is not null and is in the identifier map, return the mapped identifier.
  2. Otherwise, if the old identifier is not null, create a new entry in identifier map initialized to the current value of next identifier. Increment next identifier by adding one to the integer suffix. Return the mapped identifier.
  3. Otherwise, increment next identifier by adding one to the integer suffix and return its original value.

4.10 RDF Conversion

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 Quad 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 quads during the output process and are not required to implement the algorithm exactly as described.

4.10.1 Overview

This section is non-normative.

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 Linked Data, a key concept is that of a node in a linked data graph. Nodes may be of three basic types. The first is the IRI, which is used to refer to nodes in other linked data graphs. The second is the blank node, which are nodes for which an external name does not exist, or is not known. The third is a Literal, which express values such as strings, dates and other information having a lexical form, possibly including an explicit language or datatype.

Data described with JSON-LD may be considered to be a graph made up of subject and object nodes related via a property node. Specific implementations may also choose to operate on the document as a normal JSON description of objects having attributes. Both approaches are valid ways to interact with JSON-LD documents.

4.10.2 Parsing Examples

This section is non-normative.

The following examples show simple transformations of JSON-LD documents to Turtle [TURTLE-TR].

The first example uses a simple document containing a simple FOAF profile:

Example 20
{
  "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
  "@id": "http://greggkellogg.net/foaf#me",
  "@type": "foaf:Person",
  "foaf:name": "Gregg Kellogg",
  "foaf:knows": {
    "@type": "foaf:Person",
    "foaf:name": "Manu Sporny"
  }
}

This translates fairly directly to a similar Turtle document:

Example 21
@prefix foaf: <http://xmlns.com/foaf/0.1/>.

<http://greggkellogg.net/foaf#me> a foaf:Person;
  foaf:name "Gregg Kellogg";
  foaf:knows [ a foaf:Person; foaf:name "Manu Sporny"].

The actual parsing steps first require that the JSON-LD document be expanded, to eliminate the @context:

Example 22
[{
  "@id": "http://greggkellogg.net/foaf#me",
  "@type": ["http://xmlns.com/foaf/0.1/Person"],
  "http://xmlns.com/foaf/0.1/name": [{"@value": "Gregg Kellogg"}],
  "http://xmlns.com/foaf/0.1/knows": [{
    "@type": ["http://xmlns.com/foaf/0.1/Person"],
    "http://xmlns.com/foaf/0.1/name": [{"@value": "Manu Sporny"}]
  }]
}]

The process of translating this to RDF then operates over each node definition to find a subject, each property to find an RDF predicate, and each value of that property to find an object. In this case, each property has just a single object: foaf:name identifies a literal, and foaf:knows identifies a second node definition similar to Turtle's blankNodePropertyList.

After expansion, JSON-LD numbers, booleans, typed literals, language-tagged-strings, and IRIs become explicit, and can be directly transformed into their RDF representations.

Example 23
[{
  "@id": "http://greggkellogg.net/foaf#me",
  "@type": ["http://xmlns.com/foaf/0.1/Person"],
  "http://xmlns.com/foaf/0.1/name": [{"@value": "Gregg Kellogg"}],
  "http://xmlns.com/foaf/0.1/currentProject": [{"@id": "http://json-ld.org/"}],
  "http://xmlns.com/foaf/0.1/birthday": [{
    "@value": "1957-02-27",
    "@type": "http://www.w3.org/2001/XMLSchema#date"
  }],
  "http://xmlns.com/foaf/0.1/knows": [{
    "@type": ["http://xmlns.com/foaf/0.1/Person"],
    "http://xmlns.com/foaf/0.1/name": [{"@value": "Manu Sporny"}]
  }]
}]

Translates to:

Example 24
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.

<http://greggkellogg.net/foaf#me> a foaf:Person;
  foaf:name "Gregg Kellogg";
  foaf:currentProject <http://json-ld.org/>;
  foaf:birthday "1957-02-27"^^xsd:date;
  foaf:knows [ a foaf:Person; foaf:name "Manu Sporny"].

4.10.3 Convert to RDF Algorithm

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 five 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. This removes any existing context to allow the given context to be cleanly applied.

  1. If element is a JSON object, perform the following steps:
    1. Set active object to null.
    2. If element has a @value property:
      1. If the value of @value is a number, set the active object to a typed literal using a string representation 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.

        It is being discussed if the automatic mapping of JSON-native types to the XSD type system should be configurable or not.

      2. Otherwise, if the value of @value is true or false, set the active object to a typed literal created from the string representation of the value. Set datatype to the value of the @type property if it exists, otherwise xsd:boolean.
      3. Otherwise, if element contains a @type property, set the active object to a typed literal.
      4. Otherwise, if element contains a @language property, set the active object to a language-tagged string.
      5. Otherwise, set the active object to a typed literal using xsd:string as the datatype.
    3. If element has a @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
    4. If active object is not null:
      1. If neither active subject nor active property are null, generate a Quad representing active subject, active property, active object, and graph name.
      2. Return active object.
    5. If element has a @id property, the value must be a string, set the active subject to the previously expanded value (either a blank node or an IRI).
    6. Otherwise, if element does not have a @id property, set the active subject to newly generated blank node.
    7. Process each property and value in element, ordered by property, as follows:
      1. If property is @type, set the active property to rdf:type.
      2. Otherwise, if property is @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.
      3. Otherwise, if property is a keyword, skip this step.
      4. Otherwise, set active property to the IRI value of property.
      5. Process value recursively using this algorithm, passing copies of active subject, active property and graph name.
    8. Set active object to active subject.
  2. Otherwise, if element is an array, process each value in the array as follows, process element recursively using this algorithm, using copies of active subject, active property, and graph name.
  3. Otherwise, if element is a string, then the active property must be rdf:type so set the active object to an IRI.
  4. If any of these steps created an active object and neither active subject nor active property are null, generate a Quad using active subject,active property, active object and graph name.
  5. Return active object.

4.10.4 List Conversion

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.

Note
This algorithm does not support lists containing lists.
  1. If array is empty return rdf:nil.
  2. Otherwise, generate a Quad using using the active subject, active property and a newly generated blank node identified as first blank node.
  3. For each element in array other than the last element:
    1. Create a processor state using first blank node as the active subject, and rdf:first as the active property.
      1. Process the value starting at Step 1.
      2. Proceed using the previous processor state.
    2. Unless this is the last element in array, generate a new blank node identified as rest blank node, otherwise use rdf:nil.
    3. Generate a new Quad using first blank node, rdf:rest and rest blank node.
    4. Set first blank node to rest blank node.
    5. Return first blank node.

4.10.5 Convert from RDF Algorithm

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 Quads into a JSON-LD document.

When expanding typed literal 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.

  1. Construct defaultGraph as a JSON object containing nodes and listMap, each an empty JSON object.
  2. Construct graphs as a JSON object containing defaultGraph identified by an empty string.
  3. For each quad in input:
    1. Set graph to the entry in graphs identified by name, initializing it to a new entry using the mechanism described in Step 1.
    2. If property is 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.
    3. If property is rdf:rest:
      1. If object is a blank node, use the entry in graph.listMap indexed by subject, initializing it to a new JSON object if necessary. Add the nominalValue of object to the entry indexed by rest.
      2. Skip to the next quad.
    4. If name is not null, and defaultGraph.nodes does not contain an entry for name, create a new entry for name from a new JSON object with key/value pair of @id and a string representation of name.
    5. Set value as the entry from graph.nodes for subject, initializing it to a new JSON object with key/value pair of @id and a string representation of subject if necessary.
    6. If property is rdf:type and the useRdfType option is not present or false:
      1. Append the string representation of object to the array value for the key @type, creating an entry in value if necessary.
    7. If object is a typed literal and the useNativeTypes option is set to true:
      1. Generate a converted value:
        1. If the literal's type is xsd:boolean, the converted value is true if the literal matches the value true or false if the literal matches the value false.
        2. If the literal's type is 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.
        3. Otherwise, do not perform a conversion. Set the converted value to the value.
      2. Append the converted value to the array value for the key, creating an entry in value if necessary.
    8. Otherwise, if object is rdf:nil:
      1. Let key be the string representation of property.
      2. Append an empty @list representation to the array value for key, creating an entry in value if necessary.
    9. Otherwise,
      1. Let key be the string representation of property and let object representation be object represented in expanded form as described in Value Expansion.
      2. If object is a blank node, use the entry in graph.listMap indexed by object, initializing it to a new JSON object if nesessary. Add an entry for head with object representation.
      3. Append object representation to the array value for key, creating an entry in value if necessary.
  4. For each name and graph in graphs:
    1. For each subject and entry in graph where entry has both head and first keys:
      1. Set value to the value of head in entry.
      2. Remove the entry for @id in value.
      3. Add an entry to value for @list initialized to a new array containing the value of first from entry.
      4. While entry has a key for rest:
        1. Set entry to the value of graph.listMap for entry.rest.
        2. Add the value for entry.first to the list array.
  5. Create array as an empty array.
  6. For each subject and entry in defaultGraph.nodes ordered by subject:
    1. Add entry to array.
    2. If graphs has an entry for subject, add a property @graph in entry containing the ordered entries from graphs[subject].nodes.
  7. Return array as the result.

5. Data Round Tripping

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 a canonical lexical form in the form of a string. 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:

Example 25
(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:

Example 26
(value).toExponential(15).replace(/(\d)0*e\+?/,'$1E')
Note

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.

It is being discussed if the automatic mapping of JSON-native types to the XSD type system should be configurable or not.

Note

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. Acknowledgements

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, 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 this 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 for their input on the specification.

B. References

B.1 Normative references

[BCP47]
A. Phillips; M. Davis. Tags for Identifying Languages September 2009. IETF Best Current Practice. URL: http://tools.ietf.org/html/bcp47
[IEEE-754-1985]
IEEE. IEEE Standard for Binary Floating-Point Arithmetic. See http://standards.ieee.org/reading/ieee/std_public/description/busarch/754-1985_desc.html
[JSON-LD]
The JSON-LD Syntax Manu Sporny, Gregg Kellogg, Markus Lanthaler Editors. World Wide Web Consortium (work in progress). 22 May 2012. Editor's Draft. This edition of the JSON-LD Syntax specification is http://json-ld.org/spec/ED/json-ld-syntax/20120522/. The latest edition of the JSON-LD Syntax is available at http://json-ld.org/spec/latest/json-ld-syntax/
[JSON-POINTER]
JSON Pointer P. Bryan, Ed. IETF Draft. URL: http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-02
[RDF-CONCEPTS]
RDF 1.1 Concepts and Abstract Syntax Richard Cyganiak, David Wood, Editors. World Wide Web Consortium (work in progress). 30 May 2012. Editor's Draft. This edition of the JSON-LD Syntax specification is http://www.w3.org/TR/2011/WD-rdf11-concepts-20110830/. The latest edition of the JSON-LD Syntax is available at http://www.w3.org/TR/rdf11-concepts/
[RDF-SCHEMA]
Dan Brickley; Ramanathan V. Guha. RDF Vocabulary Description Language 1.0: RDF Schema. 10 February 2004. W3C Recommendation. URL: http://www.w3.org/TR/2004/REC-rdf-schema-20040210
[RFC3986]
T. Berners-Lee; R. Fielding; L. Masinter. Uniform Resource Identifier (URI): Generic Syntax. January 2005. Internet RFC 3986. URL: http://www.ietf.org/rfc/rfc3986.txt
[RFC3987]
M. Dürst; M. Suignard. Internationalized Resource Identifiers (IRIs). January 2005. Internet RFC 3987. URL: http://www.ietf.org/rfc/rfc3987.txt
[RFC4627]
D. Crockford. The application/json Media Type for JavaScript Object Notation (JSON) July 2006. Internet RFC 4627. URL: http://www.ietf.org/rfc/rfc4627.txt
[WEBIDL]
Web IDL Cameron McCormack, Editor. World Wide Web Consortium. 19 April 2012. Candidate Recommendataion. This edition of Web IDL is http://www.w3.org/TR/2012/CR-WebIDL-20120419/. The latest edition of Web IDL is available at http://dev.w3.org/2006/webapi/WebIDL/
[XMLSCHEMA11-2]
Henry S. Thompson; et al. W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes. 5 April 2012. W3C Recommendation URL: http://www.w3.org/TR/2012/REC-xmlschema11-2-20120405/

B.2 Informative references

[ECMA-262]
ECMAScript Language Specification. June 2011. URL: http://www.ecma-international.org/publications/standards/Ecma-262.htm
[TURTLE-TR]
Eric Prud'hommeaux, Gavin Carothers. Turtle: Terse RDF Triple Language. 09 August 2011. W3C Working Draft. URL: http://www.w3.org/TR/2011/WD-turtle-20110809/
[UNICODE]
The Unicode Consortium. The Unicode Standard. 2003. Defined by: The Unicode Standard, Version 4.0 (Boston, MA, Addison-Wesley, ISBN 0-321-18578-1), as updated from time to time by the publication of new versions URL: http://www.unicode.org/unicode/standard/versions/enumeratedversions.html