The JSON-LD API 1.0

An Application Programming Interface for the JSON-LD Syntax

Unofficial Draft 12 January 2012

Editors:
Manu Sporny, Digital Bazaar
Gregg Kellogg, Kellogg Associates
Dave Longley, Digital Bazaar
Authors:
Dave Longley, Digital Bazaar
Manu Sporny, Digital Bazaar
Gregg Kellogg, Kellogg Associates

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.

Status of This Document

This document is merely a public working draft of a potential specification. It has no official standing of any kind and does not represent the support or consensus of any standards organisation.

This document is an experimental work in progress.

Table of Contents

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

1.1 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 Web 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 (or members). 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 (see Lists). 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 is undefined within JSON-LD.
Supporting null in JSON-LD might have a number of advantages and should be evaluated. This is currently an open issue.

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

1.3 Contributing

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

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

2.1 JsonLdProcessor

[NoInterfaceObject]
interface JsonLdProcessor {
    object    expand (object input, optional object? context) raises (InvalidContext);
    object    compact (object input, optional object? context) raises (InvalidContext, ProcessingError);
    object    frame (object input, object frame, object options) raises (InvalidFrame);
    DOMString normalize (object input, optional object? context) raises (InvalidContext);
    void      triples (object input, JsonLdTripleCallback tripleCallback, optional object? context) raises (InvalidContext);
};

2.1.1 Methods

compact
Compacts the given input 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.
ParameterTypeNullableOptionalDescription
inputobjectThe JSON-LD object to perform compaction on.
contextobjectThe base context to use when compacting the input.
ExceptionDescription
InvalidContext
INVALID_SYNTAXA 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_ERRORThere was a problem encountered loading a remote context.
ProcessingError
LOSSY_COMPACTIONThe compaction would lead to a loss of information, such as a @language value.
CONFLICTING_DATATYPESThe target datatype specified in the coercion rule and the datatype for the typed literal do not match.
Return type: object
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.
ParameterTypeNullableOptionalDescription
inputobjectThe JSON-LD object to copy and perform the expansion upon.
contextobjectAn external context to use additionally to the context embedded in input when expanding the input.
ExceptionDescription
InvalidContext
INVALID_SYNTAXA 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_ERRORThere was a problem encountered loading a remote context.
Return type: object
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.
ParameterTypeNullableOptionalDescription
inputobjectThe JSON-LD object to perform framing on.
frameobjectThe frame to use when re-arranging the data.
optionsobjectA set of options that will affect the framing algorithm.
ExceptionDescription
InvalidFrame
INVALID_SYNTAXA frame must be either an object or an array of objects, if the frame is neither of these types, this exception is thrown.
MULTIPLE_EMBEDSA 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.
Return type: object
normalize
Normalizes the given input according to the steps in the Normalization Algorithm. The input must be copied, normalized and returned if there are no errors. If the compaction fails, null must be returned. The output is the serialized representation returned from the Normalization Algorithm. It's still an open question if the result is a DOMString representing the serialized graph in JSON-LD, or an array representation which is in normalized form.
ParameterTypeNullableOptionalDescription
inputobjectThe JSON-LD object to perform normalization upon.
contextobjectAn external context to use additionally to the context embedded in input when expanding the input.
ExceptionDescription
InvalidContext
INVALID_SYNTAXA 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_ERRORThere was a problem encountered loading a remote context.
Return type: DOMString
triples
Processes the input according to the RDF Conversion Algorithm, calling the provided tripleCallback for each triple generated.
ParameterTypeNullableOptionalDescription
inputobjectThe JSON-LD object to process when outputting triples.
tripleCallbackJsonLdTripleCallbackA callback that is called whenever a processing error occurs on the given input.
This callback should be aligned with the RDF API.
contextobjectAn external context to use additionally to the context embedded in input when expanding the input.
ExceptionDescription
InvalidContext
INVALID_SYNTAXA 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_ERRORThere was a problem encountered loading a remote context.
Return type: void

2.2 JsonLdTripleCallback

The JsonLdTripleCallback is called whenever the processor generates a triple during the triple() call.

[NoInterfaceObject Callback]
interface JsonLdTripleCallback {
    void triple (DOMString subject, DOMString property, DOMString objectType, DOMString object, DOMString? datatype, DOMString? language);
};

2.2.1 Methods

triple
This callback is invoked whenever a triple is generated by the processor.
ParameterTypeNullableOptionalDescription
subjectDOMStringThe subject IRI that is associated with the triple.
propertyDOMStringThe property IRI that is associated with the triple.
objectTypeDOMStringThe type of object that is associated with the triple. Valid values are IRI and literal.
objectDOMStringThe object value associated with the subject and the property.
datatypeDOMStringThe datatype associated with the object.
languageDOMStringThe language associated with the object in BCP47 format.
No exceptions.
Return type: void

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

3.1 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.
:
The separator for JSON keys and values that use the prefix mechanism.

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

3.2 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.
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.
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 with a context that may be expanded to an IRI
prefix
A prefix is a term that expands to a Web Vocabulary base IRI. It is typically used along with a suffix to create an IRI within a Web 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.

3.3 Context

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 keys and values of a JSON object (or elements of a list (see List Processing)) using a term mapping. It is also used to maintain coercion mappings from IRIs associated with terms to datatypes, and list mappings for IRIs associated with terms.

A local context is identified within a JSON object having a key of @context with 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 value be the value of @context
    1. If value is an array, process each element as value, in order using Step 2.
    2. If value is a simple string, it must have a lexical form of absolute IRI.
      1. Dereference value.
      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 value to the extracted content, or an empty JSON Object if no value exists.
      3. Merge the of local context into the active context.
  3. If value is a JSON object, perform the following steps:
    1. If value has a @language key, it must have a value of a simple string or null. Add the language to the local context.
    2. Otherwise, for each key in value having the lexical form of NCName (see [XML-NAMES]), or is an empty string,
      1. If the key's value is a simple string, the value must have the form of term, prefix:suffix, absolute IRI. 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 key-value pair into the local context term mapping.
      2. Otherwise, the key's value must be a JSON object.
        1. The value must have a @id key with a string value, the value must have the form of term, prefix:suffix, absolute IRI. 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 key-value pair into the local context term mapping.
        2. If the value has a @type key, the value must have the form of term, prefix:suffix, 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.
        3. If the value has a @list key, the value must be true or false. Merge into the local context list mapping.
      3. Merge the local context into the active context.
      4. Repeat Step 3.2 until no entries are added to the local context.

It can be difficult to distinguish between a prefix:suffix and an absolute IRI, as a prefix 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 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.

3.4 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 prefix:suffix construct.

The algorithm for generating an IRI is:

  1. Split the value into a prefix and suffix from the first occurrence of ':'.
  2. If the prefix is a '_' (underscore), the value represents a named blank node.
  3. If the active context contains a term mapping for prefix using a case-sensitive comparison, 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.
  4. 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.

3.5 IRI Compaction

Some keys and values are expressed using IRIs. This section defines an algorithm for transforming an IRI to a compact IRI using the terms specified in the local context.

The algorithm for generating a compacted IRI is:

  1. Search every key-value pair in the active context for a term that is a complete match against the IRI. If a complete match is found, the resulting compacted IRI is the term associated with the IRI in the active context.
  2. If a complete match is not found, search for a partial match from the beginning of the IRI. For all matches that are found, the resulting compacted IRI is the term associated with the partially matched IRI in the active context concatenated with a colon (:) character and the unmatched part of the string. If there is more than one compacted IRI produced, the final value is the shortest and lexicographically least value of the entire set of compacted IRIs.

3.6 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 true, false or number, expand the value by adding a two new key-value pairs. The first key-value pair will be @value and the string representation of value. The second key-value pair will be @type>, and the expanded version of xsd:boolean, xsd:integer, or xsd:double, depending on value.
  2. Otherwise, if active property is the target of an @id coercion, expand the value by adding a new 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 the target of typed literal coercion, expand value by adding two new key-value pairs. The first key-value pair will be @value and the unexpanded value. The second key-value pair will be @type and the associated coercion datatype expanded according to the IRI Expansion rules.
  4. Otherwise, if the active context has a @language, expand value by adding two new key-value pairs. The first key-value pair will be @value and the unexpanded value. The second key-value pair will be @language and value of @language from the active context.
  5. Otherwise, value is already expanded.

3.7 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 the value may be expressed as true, false or number, the value is the native representation of the @value value.
  2. 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.
  3. Otherwise, if value contains an @id key, the compacted value is value with the value of @id processed according to the IRI Compaction steps.
  4. 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.
  5. Otherwise, if the value contains a @type key, the compacted value is value with the @type value processed according to the IRI Compaction steps.
  6. Otherwise, the value is not modified.

3.8 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 or Normalization.

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

{
   "@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:

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

3.8.1 Expansion Algorithm

The algorithm takes three input variables: an active context, an active property, and a value to be expanded. To begin, the active context is set to the initial context, active property is set to nil, and value is set to the JSON-LD input.

  1. If value is an array, process each item in value recursively using this algorithm, passing copies of the active context and active property.
  2. Otherwise, if value is an object
    1. Update the active context according to the steps outlined in the context section and remove it from the expanded result.
    2. For each key and value in value:
      1. If the key is @id or @type and the value is a string, expand the value according to IRI Expansion.
      2. Otherwise, if the key is @value, the value must be a string and is not subject to further expansion.
      3. Otherwise, if the key is not a keyword, expand the key according to IRI Expansion rules and set as active property.
      4. If the value is an array, and active property is subject to @list expansion, replace the value with a new key-value key where the key is @list and value set to the current value.
      5. If the value is an array, process each item in the array recursively using this algorithm, passing copies of the active context and active property.
      6. If the value is an object, process the object recursively using this algorithm, passing copies of the active context and active property.
      7. Otherwise, expand the value according to the Value Expansion rules, passing active property.
    3. Remove the context from the object.
  3. Otherwise, expand value according to the Value Expansion rules, passing active property.

3.9 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:

{
  "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:

{
  "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:

{
  "@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.

3.9.1 Compaction Algorithm

The algorithm takes two input variables: an active property, and a value to be expanded. To begin, the active property is set to nil, and value 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. The active context to the given context.

  1. If value is an array, process each item in value recursively using this algorithm, passing a copy of the active property.
  2. Otherwise, if value is an object, for each key and value in value
    1. If the key is @id or @type
      1. If the value of the key is a string, the compacted value is the result of performing IRI Compaction on the value.
      2. Otherwise, the compacted value is the result of performing this algorithm on the value with the current active property.
    2. Otherwise:
      1. If the key is not a keyword, set as active property and compact according to IRI Compaction.
      2. If the value is an object
        1. If the value contains only an @id key or the value contains a @value key, the compacted value is the result of performing Value Compaction on the value.
        2. Otherwise, if the value contains only a @list key, and the active property is subject to list coercion, the compacted value is the result of performing this algorithm on that value.
        3. Otherwise, the compacted value is the result of performing this algorithm on the value.
      3. Otherwise, if the value is an array, the compacted value is the result of performing this algorithm on the value.
      4. Otherwise, the value is already compacted.
  3. Otherwise, the compacted value is the value.

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

The JSON-LD document below expresses a library, a book and a chapter:

{
  "@context": {
    "Book":         "http://example.org/vocab#Book",
    "Chapter":      "http://example.org/vocab#Chapter",
    "contains":     {
      "@id": "http://example.org/vocab#contains",
      "@type": "@id"
    },
    "creator":      "http://purl.org/dc/terms/creator",
    "description":  "http://purl.org/dc/terms/description",
    "Library":      "http://example.org/vocab#Library",
    "title":        "http://purl.org/dc/terms/title"
  },
  "@id":
  [{
    "@id": "http://example.com/library",
    "@type": "Library",
    "contains": "http://example.org/library/the-republic"
  },
  {
    "@id": "http://example.org/library/the-republic",
    "@type": "Book",
    "creator": "Plato",
    "title": "The Republic",
    "contains": "http://example.org/library/the-republic#introduction"
  },
  {
    "@id": "http://example.org/library/the-republic#introduction",
    "@type": "Chapter",
    "description": "An introductory chapter on The Republic.",
    "title": "The Introduction"
  }]
}

Developers typically like to operate on items in a hierarchical, tree-based fashion. Ideally, a developer would want the data above sorted into top-level libraries, then the books that are contained in each library, and then the chapters contained in each book. To achieve that layout, the developer can define the following frame:

{
  "@context": {
    "Book":         "http://example.org/vocab#Book",
    "Chapter":      "http://example.org/vocab#Chapter",
    "contains":     "http://example.org/vocab#contains",
    "creator":      "http://purl.org/dc/terms/creator"
    "description":  "http://purl.org/dc/terms/description"
    "Library":      "http://example.org/vocab#Library",
    "title":        "http://purl.org/dc/terms/title"
  },
  "@type": "Library",
  "contains": {
    "@type": "Book",
    "contains": {
      "@type": "Chapter"
    }
  }
}

When the framing algorithm is run against the previously defined JSON-LD document, paired with the frame above, the following JSON-LD document is the end result:

{
  "@context": {
    "Book":         "http://example.org/vocab#Book",
    "Chapter":      "http://example.org/vocab#Chapter",
    "contains":     "http://example.org/vocab#contains",
    "creator":      "http://purl.org/dc/terms/creator"
    "description":  "http://purl.org/dc/terms/description"
    "Library":      "http://example.org/vocab#Library",
    "title":        "http://purl.org/dc/terms/title"
  },
  "@id": "http://example.org/library",
  "@type": "Library",
  "contains": {
    "@id": "http://example.org/library/the-republic",
    "@type": "Book",
    "creator": "Plato",
    "title": "The Republic",
    "contains": {
      "@id": "http://example.org/library/the-republic#introduction",
      "@type": "Chapter",
      "description": "An introductory chapter on The Republic.",
      "title": "The Introduction"
    },
  },
}

3.10.1 Framing Algorithm Terms

This algorithm is a work in progress, do not implement it. There was also a recent update to the algorithm in order to auto-embed frame-unspecified data (if the explicit inclusion flag is not set) in order to preserve graph information. This change is particularly important for comparing subgraphs (or verifying digital signatures on subgraphs). This change is not yet reflected in the algorithm below.

input frame
the initial frame provided to the framing algorithm.
framing context
a context containing the object embed flag, the explicit inclusion flag and the omit default flag.
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 missing properties flag
a flag specifying that properties that are missing from the JSON-LD input should be omitted from the output.
omit default flag
Referenced from framing context, but not defined
match limit
A value specifying the maximum number of matches to accept when building arrays of values during the framing algorithm. A value of -1 specifies that there is no match limit.
map of embedded subjects
A map that tracks if a subject has been embedded in the output of the Framing Algorithm.

3.10.2 Framing Algorithm

The framing algorithm takes JSON-LD input that has been normalized according to the Normalization Algorithm (normalized input), an input frame that has been expanded according to the Expansion Algorithm (expanded frame), and a number of options and produces JSON-LD output. The following series of steps is the recursive portion of the framing algorithm:

  1. Initialize the framing context by setting the object embed flag, clearing the explicit inclusion flag, and clearing the omit missing properties flag. Override these values based on input options provided to the algorithm by the application.
  2. Generate a list of frames by processing the expanded frame:
    1. If the expanded frame is not an array, set match limit to 1, place the expanded frame into the list of frames, and set the JSON-LD output to null.
    2. If the expanded frame is an empty array, place an empty object into the list of frames, set the JSON-LD output to an array, and set match limit to -1.
    3. If the expanded frame is a non-empty array, add each item in the expanded frame into the list of frames, set the JSON-LD output to an array, and set match limit to -1.
  3. Create a match array for each expanded frame in the list of frames halting when either the match limit is zero or the end of the list of frames is reached. If an expanded frame is not an object, the processor must throw a Invalid Frame Format exception. Add each matching item from the normalized input to the matches array and decrement the match limit by 1 if:
    1. The expanded frame has an rdf:type that exists in the item's list of rdf:types. Note: the rdf:type can be an array, but only one value needs to be in common between the item and the expanded frame for a match.
    2. The expanded frame does not have an rdf:type property, but every property in the expanded frame exists in the item.

    matches array not defined anywhere.

  4. Process each item in the match array with its associated match frame:
    1. If the match frame contains an @embed keyword, set the object embed flag to its value. If the match frame contains an @explicit keyword, set the explicit inclusion flag to its value. Note: if the keyword exists, but the value is neither true or false, set the associated flag to true.
    2. If the object embed flag is cleared and the item has the @id property, replace the item with the value of the @id property.
    3. If the object embed flag is set and the item has the @id property, and its IRI is in the map of embedded subjects, throw a Duplicate Embed exception.
    4. If the object embed flag is set and the item has the @id property and its IRI is not in the map of embedded subjects:
      1. If the explicit inclusion flag is set, then delete any key from the item that does not exist in the match frame, except @id.
      2. For each key in the match frame, except for keywords and rdf:type:
        1. If the key is in the item, then build a new recursion input list using the object or objects associated with the key. If any object contains an @id value that exists in the normalized input, replace the object in the recursion input list with a new object containing the @id key where the value is the value of the @id, and all of the other key-value pairs for that subject. Set the recursion match frame to the value associated with the match frame's key. Replace the value associated with the key by recursively calling this algorithm using recursion input list, recursion match frame as input.
        2. If the key is not in the item, add the key to the item and set the associated value to an empty array if the match frame key's value is an array or null otherwise.
        3. If value associated with the item's key is null, process the omit missing properties flag:
          1. If the value associated with the key in the match frame is an array, use the first frame from the array as the property frame, otherwise set the property frame to an empty object.
          2. If the property frame contains an @omitDefault keyword, set the omit missing properties flag to its value. Note: if the keyword exists, but the value is neither true or false, set the associated flag to true.
          3. If the omit missing properties flag is set, delete the key in the item. Otherwise, if the @default keyword is set in the property frame set the item's value to the value of @default.
    5. If the JSON-LD output is null set it to the item, otherwise, append the item to the JSON-LD output.
  5. Return the JSON-LD output.

The final, non-recursive step of the framing algorithm requires the JSON-LD output to be compacted according to the Compaction Algorithm by using the context provided in the input frame. The resulting value is the final output of the compaction algorithm and is what should be returned to the application.

What are the implications for framing lists?

3.11 Normalization

This algorithm is a work in progress, do not implement it.

Normalization is the process of taking JSON-LD input and performing a deterministic transformation on that input that results in a normalized and serialized JSON-LD representation.

Normalization is achieved by transforming JSON-LD input to RDF, as described in RDF Conversion, invoking the normalization procedure as described in [RDF-NORMALIZATION], returning the serialized results.

There an open issue (ISSUE-53) on the purpose and results of performing normalization. Previous versions of the specification generated JSON-LD as the result of the normalization algorithm, however normalization is a process required across different linked data serializations. To be useful, a graph requires an identical normalized representation that is independent of the data format originally used for markup, or the way in which language features or publisher preferences create differences in the markup of identical graphs.

It may be that the need for either or both of flattening algorithm or to retrieve such a cryptographic signature.

Normalization is useful when comparing two graphs against one another, when generating a detailed list of differences between two graphs, and when generating a cryptographic digital signature for information contained in a graph or when generating a hash of the information contained in a graph.

The example below is an un-normalized JSON-LD document:

{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
    "homepage": {
      "@id": "http://xmlns.com/foaf/0.1/homepage",
      "@type": "@id"
    },
    "xsd": "http://www.w3.org/2001/XMLSchema#"
  },
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

The example below is the normalized form of the JSON-LD document above:

Whitespace is used below to aid readability. The normalization algorithm for JSON-LD removes all unnecessary whitespace in the fully normalized form.

Not clear that whitespace must be normalized, as the JSON-LD representation can't be used directly to create a signature, but would be based on the serialized result of [RDF-NORMALIZATION].

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

Notice how all of the terms have been expanded and sorted in alphabetical order. Also, notice how the subject has been labeled with a named blank node. Normalization ensures that any arbitrary graph containing exactly the same information would be normalized to exactly the same form shown above.

3.11.1 Normalization Algorithm

The normalization algorithm transforms the JSON-LD input into RDF, normalizes it according to [RDF-NORMALIZATION] and then transforms back to JSON-LD. The result is an object representation that deterministically represents a RDF graph.

  1. Transform the JSON-LD input to RDF according to the steps in the RDF Conversion Algorithm.
  2. Perform [RDF-NORMALIZATION] of that RDF to create a serialized N-Triples representation of the RDF graph.
  3. Construct a JSON array array to serve as the output object.
  4. For each triple in the N-Triples document having subject, predicate, and object:
    1. If predicate is http://www.w3.org/1999/02/22-rdf-syntax-ns#first, let object representation be object represented in expanded form as described in Value Expansion.
      1. Set value as the last entry in array.
      2. If the last entry in value is subject, replace it with the a JSON object having a key/value pair of @list and an array containing object representation.
      3. Otherwise, the last key/value entry in value must be a JSON object having a single key of @list with a value that is an array. Append object representation.
    2. Otherwise, if predicate is http://www.w3.org/1999/02/22-rdf-syntax-ns#rest, ignore this triple.
    3. Otherwise, if the last entry in array is not a JSON Object with an @id having a value of subject:
      1. Create a new JSON Object with key/value pair of @id and a string representation of subject and use as value.
      2. Otherwise, set value to that value.
    4. If predicate is http://www.w3.org/1999/02/22-rdf-syntax-ns#type:
      1. If value has an key/value pair of @type and an array, append the string representation of object to that array.
      2. Otherwise, if value has an key of @type, replace that value with a new array containing the existing value and a string representation of object.
      3. Otherwise, create a new entry in value with a key of @type and value being a string representation of object.
    5. Otherwise, let key by the string representation of predicate and let object representation be object represented in expanded form as described in Value Expansion.
    6. If value has an key/value pair of key and an array, append object representation to that array.
    7. Otherwise, if value has an key of key, replace that value with a new array containing the existing value and object representation.
    8. Otherwise, create a new entry in value with a key of key and object representation.
  5. Return array as the normalized graph representation.

3.12 Data Round Tripping

When normalizing xsd:double values, implementers must ensure that the normalized value is a string. In order to generate the string from a double value, output equivalent to the printf("%1.6e", value) function in C must be used where "%1.6e" is the string formatter and value is the value to be converted.

To convert the a double value in JavaScript, implementers can use the following snippet of code:

// the variable 'value' below is the JavaScript native double value that is to be converted
(value).toExponential(6).replace(/(e(?:\+|-))([0-9])$/, '$10$2')

When data needs 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.

Some JSON serializers, such as PHP's native implementation, backslash-escapes the forward slash character. For example, the value http://example.com/ would be serialized as http:\/\/example.com\/ in some versions of PHP. This is problematic when generating a byte stream for processes such as normalization. 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.

Round-tripping data can be problematic if we mix and match coercion rules with JSON-native datatypes, like integers. Consider the following code example:

var myObj = { "@context" : {
                "number" : {
                  "@id": "http://example.com/vocab#number",
                  "@type": "xsd:nonNegativeInteger"
                }
              },
              "number" : 42 };

// Map the language-native object to JSON-LD
var jsonldText = jsonld.normalize(myObj);

// Convert the normalized object back to a JavaScript object
var myObj2 = jsonld.parse(jsonldText);

At this point, myObj2 and myObj will have different values for the "number" value. myObj will be the number 42, while myObj2 will be the string "42". This type of data round-tripping error can bite developers. We are currently wondering if having a "coercion validation" phase in the parsing/normalization phases would be a good idea. It would prevent data round-tripping issues like the one mentioned above.

3.13 RDF Conversion

A JSON-LD document may be converted to any other RDF-compatible document format using the algorithm specified in this section.

The JSON-LD Processing Model describes processing rules for extracting RDF from a JSON-LD document. Note that many uses of JSON-LD may not require generation of RDF.

The processing algorithm described in this section is 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 triples during the output process and are not required to implement the algorithm exactly as described.

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

An Internationalized Resource Identifier (IRI), as described in [RFC3987], is a mechanism for representing unique identifiers on the web. In Linked Data, an IRI is commonly used for expressing a subject, a property or an object.

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.

3.13.2 RDF Conversion Algorithm Terms

default graph
the destination graph for all triples generated by JSON-LD markup.

3.13.3 RDF Conversion 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 default graph that the following algorithm generates:

  1. Create a new processor state with with the active context set to the initial context and active subject and active property initialized to NULL.
  2. If a JSON object is detected, perform the following steps:
    1. If the JSON object has a @context key, process the local context as described in Context.
    2. Create a copy of the current JSON object, changing keys that map to JSON-LD keywords with those keywords. Use the new JSON object in subsequent steps.
    3. If the JSON object has a @value key, set the active object to a literal value as follows:
      1. as a typed literal if the JSON object contains a @type key after performing IRI Expansion on the specified@type.
      2. otherwise, as a plain literal. If the JSON object contains a @language key, use it's value to set the language of the plain literal.
      3. If the neither the active subject nor the active property, generate a triple representing the active subject, the active property and the active object.
      4. Return the active object to the calling location.
    4. If the JSON object has a @list key and the value is an array process the value as a list as described in List Conversion.
    5. If the JSON object has a @id key:
      1. If the value is a string, set the active object to the result of performing IRI Expansion. Generate a triple representing the active subject, the active property and the active object. Set the active subject to the active object.
      2. Create a new processor state copies of the active context, active subject and active property.
        1. Process the value starting at Step 2.
        2. Proceed using the previous processor state.
    6. If the JSON object does not have a @id key, set the active object to newly generated blank node. Generate a triple representing the active subject, the active property and the active object. Set the active subject to the active object.
    7. For each key in the JSON object that has not already been processed, perform the following steps:
      1. If the key is @type, set the active property to rdf:type.
      2. Otherwise, set the active property to the result of performing IRI Expansion on the key.
      3. If the active property is the target of a @list coercion, and the value is an array, process the value as a list as described in in List Conversion.
      4. Otherwise, create a new processor state copies of the active context, active subject and active property and process the value starting at Step 2 and proceed using the previous processor state.
    8. Return the active object to the calling location.
  3. If a regular array is detected, process each value in the array by doing the following returning the result of processing the last value in the array:
    1. Create a new processor state using copies of the active context, active subject and active property and process the value starting at Step 2 then proceed using the previous processor state.
  4. If a string is detected:
    1. If the active property is the target of a @id coercion, set the active object by performing IRI Expansion on the string.
    2. Otherwise, if the active property is the target of coercion, set the active object by creating a typed literal using the string and the coercion key as the datatype IRI.
    3. Otherwise, set the active object to a plain literal value created from the string. If the active context contains a language key with a non-null value, use it's value to set the language of the plain literal.
    Generate a triple representing the active subject, the active property and the active object.
  5. If a number is detected, generate a typed literal using a string representation of the value with datatype set to either xsd:integer or xsd:double, depending on if the value contains a fractional and/or an exponential component. Generate a triple using the active subject, active property and the generated typed literal.
  6. Otherwise, if true or false is detected, generate a triple using the active subject, active property and a typed literal value created from the string representation of the value with datatype set to xsd:boolean.

3.13.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 the active context and returns a value to be used as an active object.

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

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

B. Initial Context

The initial context is defined with the following default entries:

{
  "@context": {
    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": { "@type": "@id"}
  }
}

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?

C. References

C.1 Normative references

[JSON-LD]
Manu Sporny, Gregg Kellogg. The JSON-LD Syntax Latest. W3C Editor's Draft. URL: http://json-ld.org/spec/latest/json-ld-syntax/
[JSON-POINTER]
P. Bryan, Ed. JSON Pointer Latest. IETF Draft. URL: http://www.ietf.org/id/draft-pbryan-zyp-json-pointer-01.txt
[RDF-CONCEPTS]
Graham Klyne; Jeremy J. Carroll. Resource Description Framework (RDF): Concepts and Abstract Syntax. 10 February 2004. W3C Recommendation. URL: http://www.w3.org/TR/2004/REC-rdf-concepts-20040210
[RDF-NORMALIZATION]
Manu Sporny, Dave Longley. RDF Graph Normalization Latest. W3C Editor's Draft. URL: http://json-ld.org/spec/latest/rdf-graph-normalization/
[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
[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]
Cameron McCormack. Web IDL. 27 September 2011. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2011/WD-WebIDL-20110927/

C.2 Informative references

[ECMA-262]
ECMAScript Language Specification. December 1999. URL: http://www.ecma-international.org/publications/standards/Ecma-262.htm
[MICRODATA]
Ian Hickson; et al. Microdata 04 March 2010. W3C Working Draft. URL: http://www.w3.org/TR/microdata/
[MICROFORMATS]
Microformats. URL: http://microformats.org
[RDFA-CORE]
Shane McCarron; et al. RDFa Core 1.1: Syntax and processing rules for embedding RDF through attributes. 15 December 2011. W3C Working Draft. URL: http://www.w3.org/TR/2011/WD-rdfa-core-20111215
[XML-NAMES]
Richard Tobin; et al. Namespaces in XML 1.0 (Third Edition). 8 December 2009. W3C Recommendation. URL: http://www.w3.org/TR/2009/REC-xml-names-20091208/