JSON [[!RFC4627]] has proven to be a highly useful object serialization and messaging format. JSON-LD [[!JSON-LD]] harmonizes the representation of Linked Data in JSON by outlining a common JSON representation format for expressing directed graphs; mixing both Linked Data and non-Linked Data in a single document. This document outlines an Application Programming Interface and a set of algorithms for programmatically transforming JSON-LD documents.

This document is an experimental work in progress.

Introduction

JSON, as specified in [[!RFC4627]], is a simple language for representing data on the Web. Linked Data is a technique for creating a graph of interlinked data across different documents or Web sites. Data entities are described using IRIs, which are typically dereferencable and thus may be used to find more information about an entity, creating a "Web of Knowledge". JSON-LD is intended to be a simple publishing method for expressing not only Linked Data in JSON, but also for adding semantics to existing JSON.

JSON-LD is designed as a light-weight syntax that can be used to express Linked Data. It is primarily intended to be a way to use Linked Data in Javascript and other Web-based programming environments. It is also useful when building interoperable Web services and when storing Linked Data in JSON-based document storage engines. It is practical and designed to be as simple as possible, utilizing the large number of JSON parsers and libraries available today. It is designed to be able to express key-value pairs, RDF data, RDFa [[RDFA-CORE]] data, Microformats [[MICROFORMATS]] data, and Microdata [[MICRODATA]]. That is, it supports every major Web-based structured data model in use today.

The syntax does not necessarily require applications to change their JSON, but allows to easily add meaning by adding context in a way that is either in-band or out-of-band. The syntax is designed to not disturb already deployed systems running on JSON, but provide a smooth upgrade path from JSON to JSON with added semantics. Finally, the format is intended to be easy to parse, efficient to generate, convertible to RDF in one pass, and require a very small memory footprint in order to operate.

How to Read this Document

This document is a detailed specification for a serialization of Linked Data in JSON. The document is primarily intended for the following audiences:

To understand the basics in this specification you must first be familiar with JSON, which is detailed in [[!RFC4627]]. You must also understand the JSON-LD Syntax [[!JSON-LD]], which is the base syntax used by all of the algorithms in this document. To understand the API and how it is intended to operate in a programming environment, it is useful to have working knowledge of the JavaScript programming language [[ECMA-262]] and WebIDL [[!WEBIDL]]. To understand how JSON-LD maps to RDF, it is helpful to be familiar with the basic RDF concepts [[!RDF-CONCEPTS]].

Examples may contain references to existing vocabularies and use prefixes to refer to vocabularies. The following is a list of all vocabularies and their prefix abbreviations, as used in this document:

JSON [[RFC4627]] defines several terms which are used throughout 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 an ordered collection of values. An array structure is represented as square brackets surrounding zero or more values (or elements). Elements are separated by commas. Within JSON-LD, array order is not preserved by default, unless specific markup is provided. This is because the basic data model of JSON-LD is a linked data graph, which is inherently unordered.
string
A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes. A character is represented as a single character string.
number
A number is 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
Boolean values.
null
The use of the null value within JSON-LD is used to ignore or reset values.
subject definition
A JSON object used to represent a subject and one or more properties of that subject. A JSON object is a subject definition if it does not contain the keys @value, @list or @set and it has one or more keys other than @id.
subject reference
A JSON object used to reference a subject having only the @id key.

Linked Data

The following definition for Linked Data is the one that will be used for this specification.

  1. Linked Data is a set of documents, each containing a representation of a linked data graph.
  2. A linked data graph is an unordered labeled directed graph, where nodes are subjects or objects, and edges are properties.
  3. A subject is any node in a linked data graph with at least one outgoing edge.
  4. A subject SHOULD be labeled with an IRI (an Internationalized Resource Identifier as described in [[!RFC3987]]).
  5. An object is a node in a linked data graph with at least one incoming edge.
  6. An object MAY be labeled with an IRI.
  7. An object MAY be a subject and object at the same time.
  8. A property is an edge of the linked data graph.
  9. A property SHOULD be labeled with an IRI.
  10. An IRI that is a label in a linked data graph SHOULD be dereferencable to a Linked Data document describing the labeled subject, object or property.
  11. A literal is an object with a label that is not an IRI

Note that the definition for Linked Data above is silent on the topic of unlabeled nodes. Unlabeled nodes are not considered Linked Data. However, this specification allows for the expression of unlabled nodes, as most graph-based data sets on the Web contain a number of associated nodes that are not named and thus are not directly de-referenceable.

Contributing

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

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.

JsonLdProcessor

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.
object or object[] or URL input
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.
ObjectOrURL? context
An optional external context to use additionally to the context embedded in input when expanding the input.
JsonLdCallback callback
A callback that is called when processing is complete on the given input.
optional JsonLdOptions options
A set of options that MAY affect the expansion algorithm such as, e.g., the input document's base IRI.
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.
void 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 appropirate exception MUST be thrown.
object or object[] or URL input
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.
object or URL context
The context to use when compacting the input; either in the form of an JSON object or as IRI.
JsonLdCallback callback
A callback that is called when processing is complete on the given input.
optional JsonLdOptions options
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.
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.
void frame()
Frames the given input using the frame according to the steps in the Framing Algorithm. The input is used to build the framed output and is returned if there are no errors. If there are no matches for the frame, null MUST be returned. Exceptions MUST be thrown if there are errors.
object or object[] or URL input
The JSON-LD object or array of JSON-LD objects to perform the framing upon or an IRI referencing the JSON-LD document to frame.
object or URL frame
The frame to use when re-arranging the data of input; either in the form of an JSON object or as IRI.
JsonLdCallback callback
A callback that is called when processing is complete on the given input.
optional JsonLdOptions options
A set of options that MAY affect the framing algorithm such as, e.g., the input document's base IRI.
INVALID_SYNTAX
A frame must be either an object or an array of objects, if the frame is neither of these types, this exception is thrown.
MULTIPLE_EMBEDS
A subject IRI was specified in more than one place in the input frame. More than one embed of a given subject IRI is not allowed, and if requested, MUST result in this exception.
LIST_OF_LISTS_DETECTED
A list of lists was detected. This is not supported in this version of JSON-LD.
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.

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

object or object[] or URL input
The JSON-LD object or array of JSON-LD objects to flatten or an IRI referencing the JSON-LD document to flatten.
string or URL graph
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.
ObjectOrURL? context
An optional external context to use additionally to the context embedded in input when expanding the input.
JsonLdCallback callback
A callback that is called when processing is complete on the given input.
optional JsonLdOptions options
A set of options that MAY affect the expansion algorithm such as, e.g., the input document's base IRI.
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.
void fromRDF()
Creates a JSON-LD document given an set of Statements.
Statement[] input
An array of RDF statements.
JsonLdCallback callback
A callback that is called when processing is complete on the given input.
optional JsonLdOptions options
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.
void toRDF()
Processes the input according to the Convert to RDF Algorithm, calling the provided callback for each Statement generated.
object or object[] or URL input
The JSON-LD object or array of JSON-LD objects to convert to RDF or an IRI referencing the JSON-LD document to convert to RDF.
StatementCallback callback
A callback that is called when a Statement is created from processing the given input.
optional JsonLdOptions options
A set of options that MAY affect the conversion to RDF such as, e.g., the input document's base IRI.
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.

Callbacks

JsonLdCallback

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

void jsonLd()
This callback is invoked when processing is complete.
ObjectOrObjectArray jsonld
The processed JSON-LD document.

StatementCallback

The StatementCallback is called whenever the processor generates a statement during the statement() call.

void statement()
This callback is invoked whenever a statement is generated by the processor.
Statement statement
The statement.

Data Structures

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

URL

The URL datatype is a string representation of an IRI.

This datatype indicates that the IRI is interpreted as a Universal Resource Locator identifying a document, which when parsed as JSON yields either a JSON object or array.

JsonLdOptions

The JsonLdOptions type is used to convery a set of options to an interface method.

URL base
The Base IRI to use when expanding the document. This overrides the value of input if it is a URL or if it is a object or object[].
boolean optimize
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.
boolean noType
If set to true, the JSON-LD processor will not use the @type property when generating the output, and will use the expanded rdf:type IRI as the property instead of @type.

The following data structures are used for representing data about RDF statements (triples or quads). They are used for normalization, fromRDF, and from toRDF interfaces.

Statement

The Statement interface represents an RDF Statement.

readonly attribute Node subject
The subject associated with the Statement.
readonly attribute Node property
The property associated with the Statement.
readonly attribute Node object
The object associated with the Statement.
readonly attribute Node? name
The name associated with the Statement identifying it as a member of a named graph. If the attribute is present, it indicates that this statement is a member of a named graph associated with name. If it is missing, the statement is a member of the default graph.

Node

Node is the base class of NamedNode, BlankNode, and LiteralNode.

readonly attribute DOMString nominalValue

The nominalValue of an Node is refined by each interface which extends Node.

readonly attribute DOMString interfaceName

Provides access to the string name of the current interface, normally one of "IRI", "BlankNode" or "LiteralNode".

This method serves to disambiguate instances of Node which are otherwise identical, such as NamedNode and BlankNode.

NamedNode

A node identified by an IRI. NamedNodes are defined by International Resource Identifier [[!IRI]].

readonly attribute DOMString nominalValue
The IRI identifier of the node.

Blank Node

A BlankNode is a reference to an unnamed resource (one for which an IRI is not known), and may be used in a Statement as a unique reference to that unnamed resource.

readonly attribute DOMString nominalValue
The temporary identifier of the BlankNode. The nominalValue MUST NOT be relied upon in any way between two separate processing runs of the same document.

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

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

LiteralNode

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

  • a lexical representation of the nominalValue
  • an optional language represented by a string token
  • an optional datatype specified by a NamedNode

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

LiteralNodes representing values with a specific datatype, such as the integer 72, may have a datatype attribute specified in the form of a NamedNode (e.g., <http://www.w3.org/2001/XMLSchema#integer>).

readonly attribute DOMString nominalValue
The lexical representation of the LiteralNodes value.
readonly attribute DOMString? language
An optional language string as defined in [[!BCP47]], normalized to lowercase.
readonly attribute NamedNode? datatype
An optional datatype identified by a NamedNode.

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.

Syntax Tokens and Keywords

JSON-LD specifies a number of syntax tokens and keywords that are using in all algorithms described in this section:

@context
Used to set the local context.
@id
Sets the active subject.
@language
Used to specify the language for a literal.
@type
Used to set the type of the active subject or the datatype of a literal.
@value
Used to specify the value of a literal.
@container
Used to set the container of a particular value.
@list
Used to express an ordered set of data.
@set
Used to express an unordered set of data.
@graph
Used to explicitly express a linked data graph.
:
The separator for JSON keys and values that use compact IRIs.
@default
Used in Framing to set the default value for an output property when the framed subject definition does not include such a property.
@explicit
Used in Framing to override the value of explicit inclusion flag within a specific frame.
@omitDefault
Used in Framing to override the value of omit default flag within a specific frame.
@embed
Used in Framing to override the value of object embed flag within a specific frame.
@null
Used in Framing when a value of null should be returned, which would otherwise be removed when Compacting.

All JSON-LD tokens and keywords are case-sensitive.

Algorithm Terms

initial context
a context that is specified to the algorithm before processing begins. The contents of the initial context is defined in Appendix B.
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.
blank node
a blank node is a resource which is neither an IRI nor a literal. Blank nodes may be named or unnamed and often take on the role of a variable that may represent either an IRI or a literal.
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.
plain literal
A plain literal is a literal without a datatype, possibly including a language.
typed literal
A typed literal is a literal with an associated IRI which indicates the literal's datatype.

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 and initializing the active context with the initial context. 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 representations, 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, reset the active context to the initial 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 or null. Add the language to the local context.
      2. 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.
            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.

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 resolve to absolute IRIs.

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

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 or a compact IRI.

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, use the value directly as an IRI.

Previous versions of this specification used @base and @vocab to define IRI prefixes used to resolve relative IRIs. It was determined that this added too much complexity, but the issue can be re-examined in the future based on community input.

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.

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, 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, 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.
  4. If terms is empty, return iri.
  5. Otherwise, return the shortest and lexicographically least value in terms.

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 subject definition, subject 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.

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.

Value Compaction

Some values, such as IRIs and typed literals, may be expressed in an expanded form in JSON-LD. These values are required to be compacted at times when processing JSON-LD documents.

The algorithm for compacting an expanded value value takes an active property and active context. It is implemented as follows:

  1. If value only has one property, 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.

Generate Blank Node Identifier

This algorithm is used by the Framing Algorithm and Convert From RDF Algorithm to deterministicly 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.

  1. If the old identifier is not null and is in identifier map return the mapped identifier.
  2. Otherwise, if 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.

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

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


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


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 to the initial context 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 subject reference, the expanded value is the result of performing IRI Expansion on the value of @id.
        3. Otherwise, if value is a JSON Object, it must be empty (used for Framing).
        4. Otherwise, if value is an array, all elements must be either a string or subject reference. Expand value for each of its entries using the previous three steps.
      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.

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:


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


Running the JSON-LD Compaction algorithm given the context supplied above against the JSON-LD input document provided above would result in the following output:


The compaction algorithm also enables the developer to map any expanded format into an application-specific compacted format. While the context provided above mapped http://xmlns.com/foaf/0.1/name to name, it could have also mapped it to any arbitrary string provided by the developer.

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, 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 subject 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 and removing null values. Return either the result as an array, as an object with a key of @list (or appropriate alias from active context).
    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, value is set to that entry.
        4. Add active property and the expanded 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, create an entry in output for active property and value as an array.
        5. Otherwise, create an entry in output for active property and value.
  3. Otherwise, return element as the compacted element.
    Perhaps this should also call Value Compaction on native types and strings, which could consolodate 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.

Framing

JSON-LD Framing allows developers to query by example and force a specific tree layout to a JSON-LD document.

A JSON-LD document is a representation of a directed graph. A single directed graph can have many different serializations, each expressing exactly the same information. Developers typically work with trees, represented as JSON objects. While mapping a graph to a tree can be done, the layout of the end result must be specified in advance. A Frame can be used by a developer on a JSON-LD document to specify a deterministic layout for a graph.

Framing is the process of taking a JSON-LD document, which expresses a graph of information, and applying a specific graph layout (called a Frame).

Framing makes use of the Subject Map Generation algorithm to place each object defined in the JSON-LD document into a flat list of objects, allowing them to be operated upon by the framing algorithm.

Framing Algorithm Terms

input frame
the initial frame provided to the framing algorithm.
framing context
a context containing a map of embeds, the object embed flag, the explicit inclusion flag and the omit default flag.
map of embeds
a map that tracks if a subject is to be embedded in the output of the Framing Algorithm; it maps a subject @id to a parent JSON object and property or parent array.
object embed flag
a flag specifying that objects should be directly embedded in the output, instead of being referred to by their IRI.
explicit inclusion flag
a flag specifying that for properties to be included in the output, they must be explicitly declared in the framing context.
omit default flag
a flag specifying that properties that are missing from the JSON-LD input, but present in the input frame should be omitted from the output.
map of flattened subjects
a map of subjects that is the result of the Subject Map Generation algorithm.

Framing Algorithm

This algorithm is a work in progress. Presently, it only works for documents without named graphs.

The framing algorithm takes an JSON-LD input (expanded input) and an input frame (expanded frame) that have been expanded according to the Expansion Algorithm, and a number of options and produces JSON-LD output.

Create framing context using null for the map of embeds, the object embed flag set to true, the explicit inclusion flag set to false, and the omit default flag set to false along with map of flattened subjects set to the @merged property of the result of performing the Subject Map Generation algorithm on expanded input. Also create results as an empty array.

Invoke the recursive algorithm using framing context (state), the map of flattened subjects (subjects), expanded frame (frame), result as parent, and null as active property.

The following series of steps is the recursive portion of the framing algorithm:

  1. Validate frame.
  2. Create a set of matched subjects by filtering subjects checking the map of flattened subjects against frame:
    1. If frame has a @type property containing one or more IRIs match any subject definition with a @type property including any of those IRIs.
    2. Otherwise, if frame has a @type property only a empty JSON object, matches any subject definition with a @type property, regardless of the actual values.
    3. Otherwise, match if the subject definition contains all of the non-keyword properties in frame.
  3. Get values for embedOn and explicitOn by looking in frame for the keys @embed and @explicit using the current values for object embed flag and explicit inclusion flag from state if not found.
  4. For each id and subject from the set of matched subjects, ordered by id:
    1. If the active property is null, set the map of embeds in state to an empty map.
    2. Initialize output with @id and id.
    3. Initialize embed with parent and active property to property.
    4. If embedOn is true, and id is in map of embeds from state:
      1. Set existing to the value of id in map of embeds and set embedOn to false.
      2. If existing has a parent which is an array containing a JSON object with @id equal to id, element has already been embedded and can be overwritten, so set embedOn to true.
      3. Otherwise, existing has a parent which is a subject definition. Set embedOn to true if any of the items in parent property is a subject definition or subject reference for id because the embed can be overwritten.
      4. If embedOn is true, existing is already embedded but can be overwritten, so Remove Embedded Definition for id.
    5. If embedOn is false, add output to parent by either appending to parent if it is an array, or appending to active property in parent otherwise.
    6. Otherwise:
      1. Add embed to map of embeds for id.
      2. Process each property and value in the matched subject, ordered by property:
        1. If property is a keyword, add property and a copy of value to output and continue with the next property from subject.
        2. If property is not in frame:
          1. If explicitOn is false, Embed values from subject in output using subject as element and property as active property.
          2. Continue to next property.
        3. Process each item from value as follows:
          1. If item is a JSON object with the key @list, then create a JSON object named list with the key @list and the value of an empty array. Append list to property in output. Process each listitem in the @list array as follows:
            1. If listitem is a subject reference process listitem recursively using this algorithm passing a new map of subjects that contains the @id of listitem as the key and the subject definition from the original map of flattened subjects as the value. Pass the first value from frame for property as frame, list as parent, and @list as active property.
            2. Otherwise, append a copy of listitem to @list in list.
          2. If item is a subject reference process item recursively using this algorithm passing a new map as subjects that contains the @id of item as the key and the subject definition from the original map of flattened subjects as the value. Pass the first value from frame for property as frame, output as parent, and property as active property.
            Passing a subject reference doesn't work if this map is used recursively. Presently pass subject definition from original map of flattened subjects.
          3. Otherwise, append a copy of item to active property in output.
      3. Process each property and value in frame, where property is not a keyword, ordered by property:
        1. Set property frame to the first item in value or a newly created JSON object if value is empty.
        2. Skip to the next property in frame if property is in output or if property frame contains @omitDefault which is true or if it does not contain @omitDefault but the value of omit default flag true.
        3. Set the value of property in output to a new JSON object with a property @preserve and a value that is a copy of the value of @default in frame if it exists, or the string @null otherwise.
      4. Add output to parent. If parent is an array, append output, otherwise append output to active property in parent.

At the completion of the recursive algorithm, results will contain the top-level subject definitions.

The final two steps of the framing algorithm require results to be compacted according to the Compaction Algorithm by using the context provided in the input frame. If the frame has no context, compaction is performed with an empty context (not a null context). The compaction result MUST use the @graph keyword at the top-level, even if the context is empty or if there is only one element to put in the @graph array. Subsequently, replace all key-value pairs where the key is @preserve with the value from the key-pair. If the value from the key-pair is @null, replace the value with null. If, after replacement, an array contains only the value null remove the value, leaving an empty array. The resulting value is the final JSON-LD output.

The algorithm needs to be updated to consider @graph. See ISSUE-118 for details.

Subject Map Generation

The Subject Map Generation algorithm takes as input an expanded JSON-LD document and results in a JSON object subjectMap holding a flat representation of the graphs and nodes represented in the document. All nodes that are not uniquelly identified by an IRI get assigned a (new) blank node identifier. The resulting subjectMap 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 initially empty subjectMap, the expanded JSON-LD document as element, null as parent, false for the list flag, false for the iri flag, and @default as graph.

If the values of @type would be expanded as everything else to @id form as proposed in ISSUE-120, the iri flag could be eliminated.

  1. If element is an array, process each entry in element recursively, using this algorithm.
  2. Otherwise, if element is a JSON object without a @value property:
    1. If element has a @list property, create a new JSON object flattenedList with a @list property whose value is an empty array and recursively call this algorithm by passing subjectMap, the value of the @list property of element as element, flattenedList as parent, true for the list flag, false for the iri flag and graph. Add flattenedList to parent and return.
    2. If the property @id is not an IRI and graph is not @merge or if the @id property does not exist, set id to a blank node identifer created by the Generate Blank Node Identifier algorithm; otherwise use the value of the @id property as id.
    3. If parent is not null, create new object with an @id property whose value equals id and add it to parent if it doesn't exist yet in parent or the list flag is set to true.
    4. If there already exists a id property in the JSON object of the graph property of subjectMap, set subject to the value of that property.
    5. Otherwise, create a new object with an @id property whose value equals id and add it as value of the id property of the JSON object at the graph property of subjectMap.
    6. For each property and value in element other than @id ordered by property:
      1. If property is @type, create a new property @type in subject whose value is an empty array and recursively call this algorithm by passing subjectMap, value as element, the @type property of subject as parent, false for the list flag, true for the iri flag and graph. Then continue with the next property from element.
      2. If property is @graph, recursively call this algorithm by passing subjectMap, value as element, null for parent, false for the list flag, false for the iri flag and id as graph. Then continue with the next property from element.
      3. If property is a keyword, merge property and value into subject.
      4. Otherwise, if no property property exists yet in subject create one and initialize it with an empty array. Then recursively call this algorithm by passing subjectMap, value as element, the property property of subject as parent, false for the list flag, false for the iri flag and graph.
  3. Otherwise
    1. If element is a string that begins with the characters _: and the iri flag is set to true, map element to a new blank node identifier to avoid collisions.
    2. If the list flag is set to false, check if element is already in parent. If so, return.
    3. Add element to parent.

After the above outlined algorithm has been executed, the subject map for all graphs including the default graph are contained in subjectMap. To also create the subject map for the merged graph, perform the following steps:

  1. Foreach property graph and value graphMap in subjectMap:
    1. Foreach property subject and value value in graphMap:
      1. Call the algorithm outlined above by passing subjectMap, value as element, null as parent, false for the list flag, false for the iri flag and @merged for graph.

Remove Embedded Definition

This algorithm replaces an already embedded subject definition with a subject reference. It then recursively removes any entries in the map of embeds that had the removed subject definition in their parent chain.

About as clear as mud

The algorithm is invoked with a framing context and subject id id.

  1. Find embed from map of embeds for id.
  2. Let parent and property be from embed.
  3. If parent is an array, replace the subject definition that matches id with a subject reference. If parent is a JSON object, replace the subject definition for property that matches id with a subject reference.
  4. Remove dependents for id in map of embeds by scanning the map for entries with parent that have an @id of id, removing that definition from the map, and then removing the dependents for the parent id recursively by repeating this step. This step will terminate when there are no more embed entries containing the removed subject definition's @id in their parent chain.

Embed Values

This algorithm recursively embeds property values in subject definition output, given a framing context, input subject definition element, active property, and output.

  1. For each item in active property of element:
    1. If item is a JSON object with the key @list, then create a new JSON object with a key @list and a value of an empty array and add it to output, appending if output is an array, and appending to active property otherwise. Recursively call this algorithm passing item as element, @list as active property, and the new array as output. Continue to the next item.
    2. If item is a subject reference:
      1. If map of embeds does not contain an entry for the @id of item:
        1. Initialize embed with output as parent and active property as property and add to map of embeds.
        2. Initialize a new subject definition o to act as the embedded subject definition.
        3. For each property and value in the expanded definition for item in subjects:
          1. Add property and a copy of value to o if property is a keyword.
          2. Otherwise, recursively call this algorithm passing value as element, property as active property and o as output.
      2. Set item to o.
  2. If output is an array, append a copy of item, otherwise append a copy of item to active property in output.

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.

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

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


Running the JSON-LD Flattening algorithm for the merged graph (@merged) against the JSON-LD input document provided above would result in the following output:


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 subjectMap according the Subject Map Generation Algorithm.
  3. Initialize an empty array result.
  4. If subjectMap 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.

Data Round Tripping

When coercing numbers to xsd:integer or xsd:double as it, e.g., happens during RDF Conversion, implementers MUST ensure that the result is a canonical lexical representation in the form of a string. A canonical lexical representation 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 representation and a value in the value space as defined in [[!XMLSCHEMA-2]]. In other words, every value MUST be converted to a deterministic string representation.

The canonical lexical representation of an integer, i.e., a number without fractions or a number coerced to xsd:integer, is a finite-length sequence of decimal digits (0-9) with an optional leading minus sign; leading zeroes are prohibited. To convert the number in JavaScript, implementers can use the following snippet of code:


The canonical lexical representation of a double, i.e., a number with fractions or a number coerced to xsd:double, consists of a mantissa followed by the character "E", followed by an exponent. The mantissa MUST be a decimal number. The exponent MUST be an integer. Leading zeroes and a preceding plus sign (+) are prohibited in the exponent. If the exponent is zero, it must be indicated by E0. For the mantissa, the preceding optional plus sign is prohibited and the decimal point is required. Leading and trailing zeroes are prohibited subject to the following: number representations must be normalized such that there is a single digit which is non-zero to the left of the decimal point and at least a single digit to the right of the decimal point unless the value being represented is zero. The canonical representation for zero is 0.0E0. To convert the number in JavaScript, implementers can use the following snippet of code:


xsd:double's value space is defined by the IEEE double-precision 64-bit floating point type [[!IEEE-754-1985]].

When data such as decimals need to be normalized, JSON-LD authors should not use values that are going to undergo automatic conversion. This is due to the lossy nature of xsd:double values. Authors should instead use the expanded object form to set the canonical lexical representation directly.

When JSON-native datatypes, like numbers, are type coerced, lossless data round-tripping can not be guaranted. Consider the following code example:


At this point, myObj1 and myObj2 will have different values for the "number" property. myObj1 will have the number 42, while myObj2 have an object consisting of @value set to the string "42" and @type set to the expanded value of xsd:nonNegativeInteger.

Some JSON serializers, such as PHP's native implementation in some versions, backslash-escape the forward slash character. For example, the value http://example.com/ would be serialized as http:\/\/example.com\/. This is problematic as other JSON parsers might not understand those escaping characters. There is no need to backslash-escape forward slashes in JSON-LD. To aid interoperability between JSON-LD processors, a JSON-LD serializer MUST NOT backslash-escape forward slashes.

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 Statement retrieved by processing another serialization format into JSON-LD. Note that many uses of JSON-LD may not require generation of RDF.

The processing algorithms described in this section are provided in order to demonstrate how one might implement a JSON-LD to RDF processor. Conformant implementations are only required to produce the same type and number of statements during the output process and are not required to implement the algorithm exactly as described.

Overview

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 resource. Resources may be of three basic types: NamedNode, representing IRIs for describing externally named entities, BlankNode, resources for which an external name does not exist, or is not known, and LiteralNode, which describe terminal entities such as strings, dates and other representations having a lexical representation possibly including an explicit language or datatype.

Data described with JSON-LD may be considered to be the representation of a graph made up of subject and object resources related via a property resource. However, specific implementations may choose to operate on the document as a normal JSON description of objects having attributes.

RDF Conversion Algorithm Terms

graph name
A IRI or Blank Node used to identify statements belonging to a named graph.

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 Statements 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.
      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, set the active object to a plain literal. If element contains a @language property, use its value to set the language of the plain literal.
    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 Statement 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 Statement using active subject,active property, active object and graph name.
  5. Return active object.

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.

This algorithm does not support lists containing lists.
  1. If array is empty return rdf:nil.
  2. Otherwise, generate a Statement 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 Statement using first blank node, rdf:rest and rest blank node.
    4. Set first blank node to rest blank node.
    5. Return first blank node.

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

The conversion algorithm takes a single parameter input in the form of an array of Statement representations.

  1. Construct defaultGraph as a JSON object containing subjects and listMap,each an empty JSON object.
  2. Construct graphs as a JSON object containing defaultGraph identified by an empty string.
  3. For each statement 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 statement.
    3. If property is rdf:rest:
      1. If object is a BlankNode, 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 statement.
    4. If name is not null, and defaultGraph.subjects 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.subjects 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 notType option is present and not true:
      1. Append the string representation of object to the array value for the key @type, creating an entry in value if necessary.
    7. 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.
    8. 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 BlankNode, 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.subjects 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].subjects.
  7. Return array as the result.

IANA Considerations

This section is included merely for standards community review and will be submitted to the Internet Engineering Steering Group if this specification becomes a W3C Recommendation.

application/ld-frame+json

Type name:
application
Subtype name:
ld-frame+json
Required parameters:
None
Optional parameters:
None
Encoding considerations:
The same as the application/json MIME media type.
Security considerations:
Since a JSON-LD frame is intended to specify a deterministic layout for a JSON-LD graph, the serialization SHOULD NOT be passed through a code execution mechanism such as JavaScript's eval() function. It is RECOMMENDED that a conforming parser does not attempt to directly evaluate the JSON-LD frame and instead purely parse the input into a language-native data structure.
Interoperability considerations:
Not Applicable
Published specification:
The JSON-LD specification.
Applications that use this media type:
Any programming environment that requires the exchange of directed graphs. Implementations of JSON-LD have been created for JavaScript, Python, Ruby, PHP and C++.
Additional information:
Magic number(s):
Not Applicable
File extension(s):
.jsonldf
Macintosh file type code(s):
TEXT
Person & email address to contact for further information:
Manu Sporny <msporny@digitalbazaar.com>
Intended usage:
Common
Restrictions on usage:
None
Author(s):
Manu Sporny, Gregg Kellogg, Markus Lanthaler, Dave Longley
Change controller:
W3C

Fragment identifiers have no meaning with application/frame-ld+json resources.

Initial Context

The initial context is defined with the following default entries:


Processors MUST act as if the initial context is defined in the outer-most level when processing JSON-LD documents.

Should we define other default prefixes?

Acknowledgements

The editors would like to thank Mark Birbeck, who provided a great deal of the initial push behind the JSON-LD work via his work on RDFj, Dave Lehn and Mike Johnson who reviewed, provided feedback, and performed several implementations of the specification, and Ian Davis, who created RDF/JSON. Thanks also to Nathan Rixham, Bradley P. Allen, Kingsley Idehen, Glenn McDonald, Alexandre Passant, Danny Ayers, Ted Thibodeau Jr., Olivier Grisel, Niklas Lindström, Markus Lanthaler, and Richard Cyganiak for their input on the specification.