JSON-LD Framing allows developers to query by example and force a specific tree layout to a JSON-LD document.
This document is an experimental work in progress.
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.
This document is a detailed specification for a serialization of Linked Data in JSON. The document is primarily intended for the following audiences:
There are a number of ways that one may participate in the development of this specification:
Framing is used to shape the data in a JSON-LD document, using an example frame document which is used to both match the flattened data and show an example of how the resulting data should be shaped. Matching is performed by using properties present in in the frame to find objects in the data that share common values. Matching can be done either using all properties present in the frame, or any property in the frame. By chaining together objects using matched property values, objects can be embedded within one another.
A frame also includes a context, which is used for compacting the resulting framed output.
For example, assume the following JSON-LD frame:
This frame document describes an embedding structure that would place
objects with type
ex:Library at the top, with objects of
ex:Book that were linked to the library object using
ex:contains property embedded as property values. It also
places objects of type
ex:Chapter within the referencing ex:Book object
as embedded values of the book object.
When using a flattened set of objects that match the frame components:
The Frame Algorithm can create a new document which follows the structure of the frame:
The Framing Algorithm does this by
first expanding both the input frame and document. It then creates
a map of flattened subjects. The outer-most node object within the frame
is used to match objects in the map, in this case looking for node objects
which have an
Library, and a
contains property with another
frame used to match values of that property. The input document contains
exactly one such node object. The value of contains also has
a node object, which is then treated as a frame to match the set of subjects
contains values of the
Library object, and so forth.
A frame may specify properties that don't exist in an input file. If the
explicit inclusion flag is
false, the framing algorithm
will add a property and value to the result. The
in a node object or value object provides a default value to use in the resulting
output document. If there is no
@default value, the property will be output
null value. (See
for ways to avoid this).
The value of the property in the frame is not otherwise used in the output document. It's purpose is for frame matching and finding default values. Note the description value for Library in the following example.
Framing can be controlled using API options, or by adding framing keywords within the frame as described in .
Framing flags set using keywords have effect only for the frame in which they appear, and for implicit frames which are created for objects where no frame object exists.
The object embed flag determines if a referenced
node object is embedded as a property value of a referencing
object, or kept as a node reference.
The initial value for the object embed flag is set using the
Consider the following frame
based on the default
@last value of the object embed flag:
Because, the default for the object embed flag is
(in addition to the explicit inclusion flag being
non-listed properties are added two the output, and implicitly embedded
using a default empty frame. As a result, the same output used in the
Framed library objects above is generated.
However, if the
@embed property is added explicitly with a
@never, the values for Book and Chapter will be excluded.
The explicit inclusion flag used to determine
properties which will be included in the output document.
The default value is
false, which means that properties
present in an input node object that are not in the associated frame will be
included in the output object.
The initial value for the explicit inclusion flag is set using the
true, only properties present in
the input frame will be placed into the output.
For example, take an expanded version of the library frame which include some properties from the input, but omit others.
The resulting output will exclude properties for Book which are not explicitly listed in the frame object:
The omit default flag changes the way framing generates output when a property described in the frame is not present in the input document. The initial value for the omit default flag is set using the omitDefault option. See for a futher discussion.
The require all flag is used in frame matching to determine when a
node object from an input document matches a frame. When
matching, an object may include
@type and other
properties, a match is made when any property value in the
object matches the node pattern in the frame object if
the value of the require all flag is
default). If the flag value is
true, then all
properties in the frame object must be present in the node
object for the node to match.
A frame may include @reverse, or a value of a term defined using @reverse to invert the relationships in the output object. For example, the Library example can be inverted using the following frame:
Using the flattened library example above, results in the following:
Frames can include
@graph, which allows information from named graphs
contained within a JSON-LD document to be exposed within it's proper
graph context. By default, framing uses a merged graph, composed of all
the node objects across all graphs within the input. By using
within a frame, the output document can include information specifically
from named graphs contained within the input document.
The following example uses a variation on our library theme where information
is split between the default graph, and a graph named
There is one class of products that can claim conformance to this specification: JSON-LD Processors.
A conforming JSON-LD Processor is a system which can perform the Framing operation in a manner consistent with the algorithms defined in this specification.
JSON-LD Processors MUST NOT attempt to correct malformed IRIs or language tags; however, they MAY issue validation warnings. IRIs are not modified other than conversion between relative and absolute IRIs.
The algorithms in this specification are generally written with more concern for clarity than efficiency. Thus, JSON-LD Processors MAY implement the algorithms given in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained by the specification's algorithms.
Implementers can partially check their level of conformance to this specification by successfully passing the test cases of the JSON-LD test suite [[JSON-LD-TESTS]]. Note, however, that passing all the tests in the test suite does not imply complete conformance to this specification. It only implies that the implementation conforms to aspects tested by the test suite.
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.
Reference to JSON data structures are interpreted using their abstract representation for the purpose of describing algorithms.
This specification adds a number of keywords (framing keywords) to the ones defined in the [[!JSON-LD]] specification:
@embedas the following:
@embednor object embed flag is not specified.
Any other value for
@embed is invalid and indicates that an
invalid @embed value
error has been detected and processing is aborted.
nullshould be returned, which would otherwise be removed when Compacting.
All JSON-LD tokens and keywords are case-sensitive.
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 Node Map Generation algorithm to place each object defined in the JSON-LD document into a map of flattened subjects, allowing them to be operated upon by the Framing algorithm.
A valid JSON-LD Frame is a superset of a valid JSON-LD document, allowing additional content, which is preserved through expansion. The Grammar defined in [[JSON-LD]] is extended as follows:
@defaultMAY include the value
@null, or an array containing only
@null, in addition to other values allowed in the grammar for values of keys expanding to absolute IRIs. Processors MUST preserve this value when expanding. All other key/value pairs of a default object MUST be ignored.
@typemay also be an empty JSON object, or an array containing only an empty JSON object. Processors MUST preserve this value when expanding.
@graphkey at the top level. Nodes with a subject that is also a named graph, where the frame object contains
@graph, extend framing to node objects from the assocated named graph.
The framing algorithm takes an JSON-LD input (expanded input), which MUST be a JSON-LD document in expanded form, an input frame (expanded frame), which MUST be a JSON-LD frame in expanded form, a context (context), and a number of options and produces JSON-LD output.
If an error is detected in the expanded frame, a processor MUST generate a JsonLdFramingError with code set to invalid frame. Need more specifics as to what constitutes a valid frame.
Set graph map to the result of performing the Node Map Generation algorithm on expanded input.
If the frameDefault option
is present with the value
true, set graph name to
Otherwise, create merged node map using the the Merge Node Maps algorithm
with graph map and add merged node map as the value of
in graph map and set graph name to
The recursive algorithm operates with a framing state (state),
created initially using
the object embed flag set to
the explicit inclusion flag set to
the require all flag set to
the omit default flag set to
graph map, graph name,
along with map of flattened subjects
set to the property associated with graph name in graph map,
graph stack set to an empty array, and
link set to an empty dictionary. The initial values of the
object embed flag, require all flag, and omit default flag
MUST be overridden by values set in options.
Also initialize results as an empty array.
Processors MAY use other runtime options to set different framing state defaults for values of state.
Invoke the recursive algorithm using framing state (state),
the keys from the map of flattened subjects as subjects,
expanded frame (frame), result as parent, and
null as active property.
The recursive algorithm adds elements to parent either by appending
the element to parent, if it is an array, or by appending it
to an array associated with active property in parent, if it is a dictionary.
Note that if parent is an array, active property MUST be
and if it is a dictionary, it MUST NOT be
The following series of steps is the recursive portion of the framing algorithm:
Can we remove sorting, or make it subject to a processing flag? In general, sorting is a performance problem for JSON-LD, and inhibits stream processing.
@idand id and add output to link associated with id.
@linkand id is in link, node already exists in results. Add the associated node object from link to parent and do not perform additional processing for this node.
@neveror if a circular reference would be created by an embed, add output to parent and do not perform additional processing for this node.
@last, remove any existing embedded node from parent accociate with graph name in state. Requires sorting of subjects. We could consider
@sample, to embed just the first matched node. With sorting, we could also consider
@graph, set recurse to
true, unless graph name in state is
@mergedand set subframe to a new empty dictionary.
@graphin frame, or a new empty dictionary, if it does not exist, and set recurse to
true, unless graph name in state is
@graphas active property.
true, processors MUST NOT add any values for property to output, and the following steps are skipped.
@list, then each listitem in the list is processed in sequence and added to a new list dictionary in output:
@idfrom listitem as the sole member of a new subjects array, the first value from
@listin frame as frame, list as parent, and
@listas active property. If frame does not exist, create a new frame using a new dictionary with properties for
@requireAlltaken from embed, explicit and requireAll. Could this use the list array, and
nullfor active property?
@idfrom item as the sole member of a new subjects array, the first value from property in frame as frame, output as parent, and property as active property. If frame does not exist, create a new frame using a new dictionary with properties for
@requireAlltaken from embed, explicit and requireAll.
@omitDefaultwith a value of
true, or does not contain
@omitDefaultand the value of the omit default flag is
@preserveand a value that is a copy of the value of
@defaultin frame if it exists, or the string
@reverse, then for each reverse property and sub frame that are the values of
@reverseproperty in output with a new dictionary reverse dict as its value.
nullas active property, and the array value of reverse property in reverse dict as parent.
Using result from the recursive algorithm, set compacted results to the result of using the
method using results, context, and
If compacted results does not have a top-level
@graph keyword, or if its value is
not an array, modify compacted results to place the non
of compacted results into a dictionary contained within the array value of
Recursively, replace all key-value pairs in compacted results
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
If, after replacement, an array contains only the value null remove the value, leaving
an empty array.
Return compacted results.
The Frame Matching Algorithm is used as part of the Framing algorithm
to determine if a particular node object matches the critera set in a frame.
In general, a node object matches a frame if it meets the matches on
or if it matches given one of several different properties (or all properties, if the
require all flag is present.).
As matching is performed on expanded node objects, all values will be in the form of an array.
Node matching uses a combination of JSON constructs to match any, zero, or some specific values:
@id, which allows a match on any of the listed IRIs.
@languagemay also be an array of one or more string values.
The frame matching algorithm takes the framing state (state), a list of subjects to match from the map of flattened subjects (subjects), a frame to match against (frame), and the requireAll flag and returns a list of matched subjects by filtering each node in subjects as follows:
Frame matching follows an order of precedence, first attempting to match on a particular
@type (or lack of
@type), then by matching on any or all
of a set of properties, if neither
@type are in the frame.
@idproperty including any IRI or blank node in the
@idproperty in frame.
@typeproperty in frame includes any IRI in values.
@typeproperty in frame is
@typeproperty in frame is
@defaultwith any value, and any other property in node has a non-default match.
match none, and further matching is aborted.
The Value Pattern Matching Algorithm is used as part of the Framing
and Frame Matching algorithms. A value object
matches a value pattern using the
match none and
@language, in addition to allowing a specific value to match a
set of values defined using the array form for each value
The algorithm takes a value pattern (pattern) and value object (value) as parameters. Value matches pattern using the following algorithm:
@languagein value, or null if none exists.
@languagein value pattern, or null if none exists.
wildcard, or null, or t1 is
nulland t2 is null or
match none, and
wildcard, or null, or l1 is
nulland l2 is null or
This API provides a clean mechanism that enables developers to convert JSON-LD data into a a variety of output formats that are easier to work with in various programming languages. If a JSON-LD API is provided in a programming environment, the entirety of the following API MUST be implemented.
The JSON-LD Processor interface is the high-level programming structure that developers use to access the JSON-LD transformation methods. The definition below is an experimental extension of the interface defined in the [[JSON-LD-API]].
The JsonLdProcessor interface
input using frame
according to the steps in the Framing
expandmethod using frame and options with
processingModeset to "json-ld-framing-1.1-expand-frame".
@contextfrom frame, if it exists, or to a new empty context, otherwise.
@graphset the frameDefault option to options with the value
input; either in the form of an JSON object or as IRI.
JSON-LD Framing extends the error interface and codes defined in [[JSON-LD-API]].
@embedis not one recognized for the object embed flag.
This section describes datatype definitions used within the JSON-LD API.
The JsonLdContext type is used to refer to a value that that may be a JSON object, a string representing an IRI, or an array of JSON objects and strings.
See JsonLdContext definition in [[!JSON-LD-API]].
The JsonLdOptions type is used to pass various options to the JsonLdProcessor methods.
In addition to those options defined in [[JSON-LD API]], framing defines these additional options:
truesets the flag to
@last, while an value of
falsesets the flag to
See JsonLdOptions definition in [[!JSON-LD-API]].
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/jsonMIME media type.
eval()function. It is RECOMMENDED that a conforming parser does not attempt to directly evaluate the JSON-LD frame and instead purely parse the input into a language-native data structure.
Fragment identifiers have no meaning with application/frame-ld+json resources.
The following is a list of open issues being worked on for the next release.
A large amount of thanks goes out to the JSON-LD Community Group participants who worked through many of the technical issues on the mailing list and the weekly telecons - of special mention are Niklas Lindström, François Daoust, and Zdenko 'Denny' Vrandečić. The editors would like to thank Mark Birbeck, who provided a great deal of the initial push behind the JSON-LD work via his work on RDFj. The work of Dave Lehn and Mike Johnson are appreciated for reviewing, and performing several implementations of the specification. Ian Davis is thanked for this work on RDF/JSON. Thanks also to Nathan Rixham, Bradley P. Allen, Kingsley Idehen, Glenn McDonald, Alexandre Passant, Danny Ayers, Ted Thibodeau Jr., Olivier Grisel, Josh Mandel, Eric Prud'hommeaux, David Wood, Guus Schreiber, Pat Hayes, Sandro Hawke, and Richard Cyganiak for their input on the specification.