<!DOCTYPE html>
<html lang="en">
<head>
<title>JSON-LD 1.1 Processing Algorithms and API</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" src="https://www.w3.org/Tools/respec/respec-w3c" class="remove"></script>
<script type="text/javascript" src="common/common.js" class="remove" defer></script>
<script type="text/javascript" src="common/jsonld.js" class="remove"></script>
<script type="text/javascript" class="remove">
var respecConfig = {
localBiblio: jsonld.localBiblio,
specStatus: "ED",
copyrightStart: "2010",
shortName: "json-ld11-api",
prevVersion: "https://www.w3.org/TR/2020/PR-json-ld11-api-20200507/",
previousPublishDate: "2020-05-07",
previousMaturity: "PR",
prevRecURI: "https://www.w3.org/TR/2014/REC-json-ld-api-20140116/",
errata: "https://w3c.github.io/json-ld-api/errata/",
edDraftURI: "https://w3c.github.io/json-ld-api/",
testSuiteURI: "https://w3c.github.io/json-ld-api/tests/",
implementationReportURI:"https://w3c.github.io/json-ld-api/reports/",
crEnd: "2020-04-03",
prEnd: "2020-06-18",
github: "https://github.com/w3c/json-ld-api",
includePermalinks: true,
doJsonLd: true,
highlightVars: true,
pluralize: true,
xref: ["json-ld11", "json-ld11-api", "json-ld11-framing"],
editors: [
{ name: "Gregg Kellogg",
url: "https://greggkellogg.net/",
w3cid: "44770",
note: "v1.0 and v1.1" },
{ name: "Dave Longley",
url: "https://digitalbazaar.com/author/dlongley/",
w3cid: "48025",
company: "Digital Bazaar",
companyURL: "https://digitalbazaar.com/",
note: "v1.1" },
{ name: "Pierre-Antoine Champin",
url: "http://champin.net/",
company: "LIRIS - Université de Lyon",
companyURL: "https://liris.cnrs.fr/",
w3cid: "42931",
note: "v1.1" },
],
formerEditors: [
{ name: "Markus Lanthaler",
url: "https://www.markus-lanthaler.com/",
company: "Google",
companyURL: "https://www.google.com/",
note: "v1.0" },
{ name: "Manu Sporny",
url: "http://manu.sporny.org/",
company: "Digital Bazaar",
companyURL: "https://digitalbazaar.com/",
note: "v1.0" }
],
authors: [
{ name: "Dave Longley",
url: "https://digitalbazaar.com/",
company: "Digital Bazaar",
companyURL: "https://digitalbazaar.com/",
note: "v1.0 and v1.1" },
{ name: "Gregg Kellogg",
url: "https://greggkellogg.net/",
w3cid: "44770",
note: "v1.0 and v1.1" },
{ name: "Markus Lanthaler",
url: "https://www.markus-lanthaler.com/",
company: "Google",
companyURL: "https://www.google.com/",
note: "v1.0" },
{ name: "Manu Sporny",
url: "http://manu.sporny.org/",
company: "Digital Bazaar",
companyURL: "https://digitalbazaar.com/",
note: "v1.0" },
{ name: "Niklas Lindström",
url: "http://neverspace.net/",
note: "v1.0" }
],
group: "wg/json-ld",
wgPublicList: "public-json-ld-wg",
maxTocLevel: 2,
alternateFormats: [ {uri: "json-ld11-api.epub", label: "EPUB"} ]
};
</script>
<script>
document.addEventListener("DOMContentLoaded", () => {
for (const button of document.querySelectorAll(".ds-selector-tabs .selectors button")) {
button.onclick = () => {
const ex = button.closest(".ds-selector-tabs");
ex.querySelector("button.selected").classList.remove("selected");
ex.querySelector(".selected").classList.remove("selected");
button.classList.add('selected');
ex.querySelector("." + button.dataset.selects).classList.add("selected");
}
}
for (const elem of document.querySelectorAll(".show-changes")) {
elem.onclick = () => {
if (elem.classList.contains("selected")) {
elem.classList.remove("selected");
for (const changed of document.querySelectorAll(".changed")) {
changed.classList.remove("highlight");
}
} else {
elem.classList.add("selected");
for (const changed of document.querySelectorAll(".changed")) {
changed.classList.add("highlight");
}
}
}
}
});
</script>
<style>
.hl-bold {font-weight: bold; color: #0a3;}
.comment {color: #999;}
.error a {
color: #ff4500;
border-bottom: 1px dotted #ff4500;
text-decoration: none;
}
.example > pre.context:before {
content: "Context";
float: right;
font: x-large Arial, sans-serif;
color: gray;
border: solid thin black;
padding: 0.2em;
}
.example > pre.frame:before {
content: "Frame";
float: right;
font: x-large Arial, sans-serif;
color: gray;
border: solid thin black;
padding: 0.2em;
}
.example > pre.input:before {
content: "Input";
float: right;
font: x-large Arial, sans-serif;
color: gray;
border: solid thin black;
padding: 0.2em;
}
.example > pre.result:before {
content: "Result";
float: right;
font: x-large Arial, sans-serif;
color: gray;
border: solid thin black;
padding: 0.2em;
}
.example > pre.turtle:before {
content: "Turtle";
float: right;
font: x-large Arial, sans-serif;
color: gray;
border: solid thin black;
padding: 0.2em;
}
.algorithm ol {
counter-reset: numsection;
list-style-type: none;
}
.algorithm ol>li {
margin: 0.5em 0;
}
.algorithm ol>li:before {
font-weight: bold;
counter-increment: numsection;
content: counters(numsection, ".") ") ";
}
.highlight.changed, .show-changes {
background-color: lime;
}
.show-changes.selected:before {
content: "de-highlight";
}
.show-changes:before {
content: "highlight";
}
.ds-selector-tabs {
padding-bottom: 2em;
}
.ds-selector-tabs .selectors {
padding: 0;
border-bottom: 1px solid #ccc;
height: 28px;
}
.ds-selector-tabs .selectors button {
display: inline-block;
min-width: 54px;
text-align: center;
font-size: 11px;
font-weight: bold;
height: 27px;
padding: 0 8px;
line-height: 27px;
transition: all,0.218s;
border-top-right-radius: 2px;
border-top-left-radius: 2px;
color: #666;
border: 1px solid transparent;
}
.ds-selector-tabs .selectors button:first-child {
margin-left: 2px;
}
.ds-selector-tabs .selectors button.selected {
color: #202020 !important;
border: 1px solid #ccc;
border-bottom: 1px solid #fff !important;
}
.ds-selector-tabs .selectors button:hover {
background-color: transparent;
color: #202020;
cursor: pointer;
}
.ds-selector-tabs pre:not(.preserve), .ds-selector-tabs table:not(.preserve) {
display: none;
}
.ds-selector-tabs pre.selected, .ds-selector-tabs table.selected {
display: block;
}
a.playground {
display: inline-block;
width: 150px;
border: 1px solid transparent;
border-top-right-radius: 2px;
border-top-left-radius: 2px;
background-color: rgb(192, 192, 192);
text-decoration: none;
font-size: 13px;
margin-bottom: 10px;
}
a[href].playground {
padding: 4px 0 3px 8px;
border-bottom: none;
text-decoration: none;
color: #666;
}
</style>
</head>
<body>
<section id="abstract">
<p>This specification defines a set of algorithms for programmatic transformations
of JSON-LD documents. Restructuring data according to the defined transformations
often dramatically simplifies its usage. Furthermore, this document proposes
an Application Programming Interface (API) for developers implementing the
specified algorithms.</p>
<p>This specification describes a superset of the features defined in
[[[JSON-LD10-API]]] [[JSON-LD10-API]]
and, except where noted,
the algorithms described in this specification are fully compatible
with documents created using [[[JSON-LD10]]] [[JSON-LD10]].</p>
</section>
<section id="sotd">
<p>This document has been developed by the
<a href="https://www.w3.org/2018/json-ld-wg/">JSON-LD Working Group</a> and was derived from the <a href="https://www.w3.org/community/json-ld/">JSON-LD Community Group's</a> <a href="https://www.w3.org/2018/jsonld-cg-reports/json-ld-api/">Final Report</a>.</p>
<p>There is a
<a href="https://json-ld.org/playground/">live JSON-LD playground</a> that is capable
of demonstrating the features described in this document.</p>
<p>This specification is intended to <a href='https://www.w3.org/2019/Process-20190301/#rec-rescind'>supersede</a> the [[[JSON-LD10-API]]] [[JSON-LD10-API]] specification. </p>
<section>
<h2>Set of Documents</h2>
<p>This document is one of three JSON-LD 1.1 Recommendations produced by the
<a href="https://www.w3.org/2018/json-ld-wg/">JSON-LD Working Group</a>:</p>
<ul>
<li>[[[JSON-LD11]]]</li>
<li><a href="">JSON-LD 1.1 Processing Algorithms and API</a></li>
<li>[[[JSON-LD11-FRAMING]]]</li>
</ul>
</section>
</section>
<section class="informative">
<h1>Introduction</h1>
<p>This document is a detailed specification of the JSON-LD processing algorithms.
The document is primarily intended for the following audiences:</p>
<ul>
<li>Software developers who want to implement the algorithms to transform
JSON-LD documents.</li>
<li>Web authors and developers who want a very detailed view of how
a <a>JSON-LD Processor</a> operates.</li>
<li>Developers who want an overview of the proposed JSON-LD API.</li>
</ul>
<p>To understand the basics in this specification you must first be familiar with
<a data-cite="RFC8259" data-no-xref="">JSON</a>, which is detailed in [[RFC8259]]. You must also understand the
JSON-LD syntax defined in the <a data-cite="JSON-LD11" data-no-xref="">JSON-LD 1.1 Syntax specification</a> [[JSON-LD11]], 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 [[ECMASCRIPT]] and
WebIDL [[WEBIDL]]. To understand how JSON-LD maps to RDF, it is helpful to be
familiar with the basic RDF concepts [[RDF11-CONCEPTS]].</p>
<section class="informative">
<h2>How to Read this Document</h2>
<p>This document is a detailed specification for a serialization of Linked
Data in JSON. The document is primarily intended for the following audiences:</p>
<ul>
<li>Software developers who want to implement processors and APIs for
JSON-LD</li>
</ul>
<p>A companion document, the JSON-LD 1.1 specification
[[JSON-LD11]], specifies the grammar of JSON-LD documents.</p>
<p>To understand the basics in this specification you must first be familiar with
<a data-cite="RFC8259" data-no-xref="">JSON</a>, which is detailed in [[RFC8259]].</p>
<p>This document can highlight changes since the [[[JSON-LD10]]] version.
Select to <button class="show-changes"></button> changes.</p>
</section>
<section class="informative">
<h2>Contributing</h2>
<p>There are a number of ways that one may participate in the development of
this specification:</p>
<ul>
<li>Technical discussion typically occurs on the public mailing list:
<a href="https://lists.w3.org/Archives/Public/public-json-ld-wg/">public-json-ld-wg@w3.org</a></li>
<li>The working group uses <a href="https://irc.w3.org/?channels=json-ld">#json-ld</a>
IRC channel is available for real-time discussion on <a href="https://irc.w3.org">irc.w3.org</a>.</li>
<li>The <a href="https://webchat.freenode.net/?channels=json-ld">#json-ld</a>
IRC channel is also available for real-time discussion on irc.freenode.net.</li>
</ul>
</section>
<section class="informative">
<h2>Typographical conventions</h2>
<div data-include="common/typographical-conventions.html"></div>
</section>
<section class="normative">
<h2>Terminology</h2>
<p>This document uses the following terms as defined in external specifications
and defines terms specific to JSON-LD.</p>
<div data-include="common/terms.html"></div>
<section>
<h4>Algorithm Terms</h4>
<p>The Following terms are used within specific algorithms.</p>
<div data-include="common/algorithm-terms.html"></div>
</section>
<section id="api-keywords">
<h2>Syntax Tokens and Keywords</h2>
<p>In addition to the <a>keywords</a> defined in the JSON-LD 1.1 Syntax specification [[JSON-LD11]],
this specification adds an additional <a>keyword</a> to support
[[[JSON-LD11-FRAMING]]] [[JSON-LD11-FRAMING]]:</p>
<dl data-sort>
<dt><code>@preserve</code></dt>
<dd>Used in an expanded document created as the result of the
<a data-cite="JSON-LD11-FRAMING#framing-algorithm">Framing algorithm</a>
to represent values that might otherwise be removed as part of the
<a href="#expansion-algorithm">Expansion algorithm</a>.</dd>
</dl>
</section>
</section>
<section class="informative">
<h3>Example Conventions</h3>
<p>Note that in the examples used in this document, output
is of necessity shown in serialized form as JSON. While the algorithms
describe operations on the <a>JSON-LD internal representation</a>, when
they as displayed as examples, the JSON serialization is used. In particular,
the internal representation use of <a>maps</a> are represented using
<a>JSON objects</a>.</p>
<pre class="example nohighlight input" data-transform="updateExample"
title="Sample JSON-LD document">
</pre>
<p>In the <a>internal representation</a>, the example above would be of a
<a>map</a> containing <code>@context</code>, <code>@id</code>, <code>name</code>, and <code>knows</code> <a>entries</a>,
with either <a>maps</a>, <a>strings</a>, or <a>arrays</a> of
maps or strings values. In the JSON serialization, <a>JSON objects</a> are used
for maps, while arrays and strings are serialized using a
convention common to many programming languages.</p>
</section>
</section>
<section class="informative">
<h1>Features</h1>
<p>The JSON-LD 1.1 Syntax specification [[JSON-LD11]] defines a syntax to
express Linked Data in JSON. Because there is more than one way to
express Linked Data using this syntax, it is often useful to be able to
transform JSON-LD documents so that they may be more easily consumed by
specific applications.</p>
<p class="changed">To allow these algorithms to be adapted for syntaxes
other than JSON, the algorithms operate on the <a>JSON-LD internal representation</a>,
which uses the generic
concepts of <a>arrays</a>, <a>maps</a>,
<a>strings</a>, <a>numbers</a>, <a>booleans</a>, and <a>null</a> to describe
the data represented by a JSON document. Algorithms act on this
<a>internal representation</a> with API entry points responsible for
transforming between the concrete and internal representations.</p>
<p>JSON-LD uses <a>contexts</a> to allow Linked Data
to be expressed in a way that is specifically tailored to a particular
person or application. By providing a <a>context</a>,
JSON data can be expressed in a way that is a natural fit for a particular
person or application whilst also indicating how the data should be
understood at a global scale. In order for people or applications to
share data that was created using a <a>context</a> that is different
from their own, a JSON-LD processor must be able to transform a document
from one <a>context</a> to another. Instead of requiring JSON-LD
processors to write specific code for every imaginable
<a>context</a> switching scenario, it is much easier to specify a
single algorithm that can remove any <a>context</a>. Similarly,
another algorithm can be specified to subsequently apply any
<a>context</a>. These two algorithms represent the most basic
transformations of JSON-LD documents. They are referred to as
<a>expansion</a> and <a>compaction</a>, respectively.</p>
<p class="changed">JSON-LD 1.1 introduces new features that are
compatible with [[[JSON-LD10]]] [[JSON-LD10]],
but if processed by a JSON-LD 1.0 processor may produce different results.
Processors default to `json-ld-1.1`, unless the
<a data-link-for="JsonLdOptions">processingMode</a> API option
is explicitly set to `json-ld-1.0`.
Publishers are encouraged to use the <code>@version</code> <a>map entry</a> within a <a>context</a>
set to `1.1` to ensure that JSON-LD 1.0 processors will not misinterpret JSON-LD 1.1 features.</p>
<p>There are four major types of transformation that are discussed in this
document: expansion, compaction, flattening, and RDF serialization/deserialization.</p>
<section class="informative">
<h2>Expansion</h2>
<p>The algorithm that removes <a>context</a> is
called <dfn data-lt="expanded|expanding">expansion</dfn>. Before performing any other
transformations on a JSON-LD document, it is easiest to
remove any <a>context</a> from it and to make data structures
more regular.</p>
<p>To get an idea of how context and data structuring affects the same data,
here is an example of JSON-LD that uses only <a>terms</a>
and is fairly compact:</p>
<aside class="example ds-selector-tabs"
title="JSON-LD document using only terms">
<div class="selectors">
<button class="selected input" data-selects="compacted">Compacted (Input)</button>
<button data-selects="expanded">Expanded (Result)</button>
<button data-selects="statements">Statements</button>
<button data-selects="turtle">Turtle</button>
<a class="playground" target="_blank" href="">PG</a>
</div>
<pre class="compacted selected" data-transform="updateExample">
</pre>
<pre class="expanded result"
data-result-for="JSON-LD document using only terms-compacted"
data-transform="updateExample">
</pre>
<table class="statements"
data-result-for="JSON-LD document using only terms-expanded">
<thead><tr><th>Subject</th><th>Property</th><th>Value</th></tr></thead>
<tbody>
<tr><td>http://me.markus-lanthaler.com/</td><td>foaf:name</td><td>Markus Lanthaler</td></tr>
<tr><td>http://me.markus-lanthaler.com/</td><td>http://xmlns.com/foaf/0.1/homepage</td><td>http://www.markus-lanthaler.com/</td></tr>
</tbody>
</table>
<pre class="turtle"
data-content-type="text/turtle"
data-result-for="JSON-LD document using only terms-expanded"
data-transform="updateExample"
data-to-rdf>
</pre>
</aside>
<p>The next input example uses one <a>IRI</a> to express a <a>property</a>
and a <a>map</a> to encapsulate a value, but
leaves the rest of the information untouched.</p>
<aside class="example ds-selector-tabs"
title="Sample JSON-LD document using an IRI instead of a term to express a property">
<div class="selectors">
<button class="selected input" data-selects="compacted">Compacted (Input)</button>
<button data-selects="expanded">Expanded (Result)</button>
<button data-selects="statements">Statements</button>
<button data-selects="turtle">Turtle</button>
<a class="playground" target="_blank" href="">PG</a>
</div>
<pre class="compacted input selected nohighlight" data-transform="updateExample">
</pre>
<pre class="expanded result"
data-result-for="Sample JSON-LD document using an IRI instead of a term to express a property-compacted"
data-transform="updateExample">
</pre>
<table class="statements"
data-result-for="Sample JSON-LD document using an IRI instead of a term to express a property-expanded">
<thead><tr><th>Subject</th><th>Property</th><th>Value</th></tr></thead>
<tbody>
<tr><td>http://me.markus-lanthaler.com/</td><td>foaf:name</td><td>Markus Lanthaler</td></tr>
<tr><td>http://me.markus-lanthaler.com/</td><td>http://xmlns.com/foaf/0.1/homepage</td><td>http://www.markus-lanthaler.com/</td></tr>
</tbody>
</table>
<pre class="turtle"
data-content-type="text/turtle"
data-result-for="Sample JSON-LD document using an IRI instead of a term to express a property-expanded"
data-transform="updateExample"
data-to-rdf>
</pre>
</aside>
<p>Note that both inputs are valid JSON-LD and both represent the same
information. The difference is in their <a>context</a> information
and in the data structures used. A JSON-LD processor can remove
<a>context</a> and ensure that the data is more regular by employing
<a>expansion</a>.</p>
<p><a>Expansion</a> has two important goals: removing any contextual
information from the document, and ensuring all values are represented
in a regular form. These goals are accomplished by expanding all <a>entry</a> keys
to <a>IRIs</a> and by expressing all
values in <a>arrays</a> in
<a>expanded form</a>. <a>Expanded form</a> is the most verbose
and regular way of expressing of values in JSON-LD; all contextual
information from the document is instead stored locally with each value.
Running the <a href="#expansion-algorithm">Expansion algorithm</a>
(<a data-link-for="JsonLdProcessor">expand()</a>)
operation) against the above examples results in the following output:</p>
<pre class="example result nohighlight" data-transform="updateExample"
data-result-for="Sample JSON-LD document using an IRI instead of a term to express a property-compacted"
title="Expanded JSON-LD document using an IRI">
</pre>
<p class="changed">The example above is the JSON-LD serialization of the output of the
<a href="#expansion-algorithm">expansion algorithm</a>,
where the algorithm's use of <a>maps</a> are replaced with <a>JSON objects</a>.</p>
<p>Note that in the output above all <a>context</a> definitions have
been removed, all <a>terms</a> and
<a>compact IRIs</a> have been expanded to absolute
<a>IRIs</a>, and all
<a>JSON-LD values</a> are expressed in
<a>arrays</a> in <a>expanded form</a>. While the
output is more verbose and difficult for a human to read, it establishes a
baseline that makes JSON-LD processing easier because of its very regular
structure.</p>
</section>
<section class="informative">
<h2>Compaction</h2>
<p>While <a>expansion</a> removes <a>context</a> from a given
input, <dfn data-lt="compact|compacting|compacted|compacts">compaction</dfn>'s primary function is to
perform the opposite operation: to express a given input according to
a particular <a>context</a>. <a>Compaction</a> applies a
<a>context</a> that specifically tailors the way information is
expressed for a particular person or application. This simplifies applications
that consume JSON or JSON-LD by expressing the data in application-specific
terms, and it makes the data easier to read by humans.</p>
<p><a>Compaction</a> uses a developer-supplied <a>context</a> to
shorten <a>IRIs</a> to <a>terms</a> or
<a>compact IRIs</a> and
<a>JSON-LD values</a> expressed in
<a>expanded form</a> to simple values such as <a>strings</a>
or <a>numbers</a>.</p>
<p>For example, assume the following expanded JSON-LD input document:</p>
<pre id="sample-document"
class="example expanded input nohighlight" data-transform="updateExample"
title="Expanded sample document">
</pre>
<p>Additionally, assume the following developer-supplied JSON-LD
<a>context</a>:</p>
<pre id="sample-document-context"
class="example context nohighlight"
data-transform="updateExample"
data-context-for="Expanded sample document"
title="JSON-LD context">
</pre>
<p>Running the <a href="#compaction-algorithm">Compaction Algorithm</a>
(<a data-link-for="JsonLdProcessor">compact()</a>)
operation) given the context supplied above against the JSON-LD input
document provided above would result in the following output:</p>
<aside class="example ds-selector-tabs"
title="Compacted sample document">
<div class="selectors">
<a class="playground"
data-result-for="#sample-document"
data-context="#sample-document-context"
data-compact
target="_blank"
href="">PG</a>
</div>
<pre class="result compacted selected nohighlight" data-transform="updateExample"
data-result-for="Expanded sample document"
data-context="JSON-LD context"
data-compact
title="Compacted sample document">
</pre>
</aside>
<p class="changed">The example above is the JSON-LD serialization of the output of the
<a href="#compaction-algorithm">compaction algorithm</a>,
where the algorithm's use of <a>maps</a> are replaced with <a>JSON objects</a>.</p>
<p>Note that all <a>IRIs</a> have been compacted to
<a>terms</a> as specified in the <a>context</a>,
which has been injected into the output. While compacted output is
useful to humans, it is also used to generate structures that are easy to
program against. Compaction enables developers to map any expanded document
into an application-specific compacted document. While the context provided
above mapped <code>http://xmlns.com/foaf/0.1/name</code> to <code>name</code>, it
could also have been mapped to any other term provided by the developer.</p>
</section>
<section class="informative">
<h2>Flattening</h2>
<p>While expansion ensures that a document is in a uniform structure,
<dfn data-lt="flattened">flattening</dfn> goes a step further to ensure that the shape of the data
is deterministic. In expanded documents, the <a>properties</a> of a single
<a>node</a> may be spread across a number of different
<a class="changed">node objects</a>. By flattening a
document, all <a>properties</a> of a <a>node</a> are collected in a single
<a class="changed">node object</a> and all <a>blank nodes</a>
are labeled with a <a>blank node identifier</a>. This may drastically
simplify the code required to process JSON-LD data in certain applications.</p>
<p>For example, assume the following JSON-LD input document:</p>
<pre id="json-ld-document-in-compact-form"
class="example compacted input nohighlight" data-transform="updateExample"
title="JSON-LD document in compact form">
</pre>
<p>Running the <a href="#flattening-algorithm">Flattening Algorithm</a>
(<a data-link-for="JsonLdProcessor">flatten()</a>)
operation) with a context set to <a>null</a> to prevent compaction
returns the following document:</p>
<aside class="example ds-selector-tabs"
title="Flattened sample document">
<div class="selectors">
<a class="playground"
data-result-for="#json-ld-document-in-compact-form"
data-flatten
target="_blank"
href="">PG</a>
</div>
<pre class="original result selected nohighlight" data-transform="updateExample"
data-result-for="JSON-LD document in compact form"
data-flatten>
</pre>
</aside>
<p class="changed">The example above is the JSON-LD serialization of the output of the
<a href="#flattening-algorithm">flattening algorithm</a>,
where the algorithm's use of <a>maps</a> are replaced with <a>JSON objects</a>.</p>
<p>Note how in the output above all <a>properties</a> of a <a>node</a> are collected in a
single <a class="changed">node object</a> and how the <a>blank node</a> representing
"Dave Longley" has been assigned the <a>blank node identifier</a>
<code>_:b0</code>.</p>
<p>To make it easier for humans to read or for certain applications to
process it, a flattened document can be compacted by passing a <a>context</a>. Using
the same context as the input document, the flattened and compacted document
looks as follows:</p>
<aside class="example ds-selector-tabs"
title="Flattened and compacted sample document">
<div class="selectors">
<a class="playground"
data-result-for="#json-ld-document-in-compact-form"
data-context="#json-ld-document-in-compact-form"
data-flatten
target="_blank"
href="">PG</a>
</div>
<pre class="result selected nohighlight" data-transform="updateExample"
data-result-for="JSON-LD document in compact form"
data-context="JSON-LD document in compact form"
data-flatten
title="Flattened and compacted sample document">
</pre>
</aside>
<p>Please note that the result of flattening and <a>compacting</a> a document
is always a <a class="changed">map</a>,
<span class="changed">(represented as a <a>JSON object</a> when serialized)</span>,
which contains an <code>@graph</code>
<a>entry</a> that represents the <a>default graph</a>.</p>
</section>
<section class="informative">
<h2>RDF Serialization/Deserialization</h2>
<p>JSON-LD can be used to serialize RDF data as described in
[[RDF11-CONCEPTS]]. This ensures that data can be round-tripped to and from
any RDF syntax without any loss in fidelity.</p>
<p>For example, assume the following RDF input serialized in Turtle [[TURTLE]]:</p>
<pre class="example nohighlight" data-transform="updateExample"
data-content-type="text/turtle"
data-from-rdf
title="Sample Turtle document">
</pre>
<p>Using the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
a developer could transform this document into expanded JSON-LD:</p>
<pre class="example nohighlight" data-transform="updateExample"
data-result-for="Sample Turtle document"
data-from-rdf
title="Sample Turtle document converted to JSON-LD">
</pre>
<p class="changed">The example above is the JSON-LD serialization of the output of the
<a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>,
where the algorithm's use of <a>maps</a> are replaced with <a>JSON objects</a>.</p>
<p>Note that the output above could easily be compacted using the technique outlined
in the previous section. It is also possible to deserialize the JSON-LD document back
to RDF using the <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>.</p>
</section>
</section>
<section id="conformance">
<p>There are two classes of products that can claim conformance to this
specification: <a>JSON-LD Processors</a>,
and <a>RDF Serializers/Deserializers</a>.</p>
<p>A conforming <a>JSON-LD Processor</a> is a system which can perform the
<a href="#expansion-algorithm">Expansion</a>, <a href="#compaction-algorithm">Compaction</a>,
and <a href="#flattening-algorithm">Flattening</a> operations
<span class="changed">in a manner consistent with
the algorithms defined in this specification</span>.</p>
<p><a>JSON-LD Processors</a> MUST NOT
attempt to correct malformed <a>IRIs</a> or <a>language tags</a>;
however, they SHOULD issue validation warnings.
IRIs are not modified other than conversion between
<a data-lt="relative IRI reference">relative</a> and absolute <a>IRIs</a>.</p>
<p>A conforming <dfn data-lt="RDF Serializers/Deserializers">RDF Serializer/Deserializer</dfn> is a system that can
<a href="#deserialize-json-ld-to-rdf-algorithm">deserialize JSON-LD to RDF</a> and
<a href="#serialize-rdf-as-json-ld-algorithm">serialize RDF as JSON-LD</a> as
defined in this specification.</p>
<p class="changed">Unless specified using
<a data-link-for="JsonLdOptions">processingMode</a> API option,
the <a>processing mode</a> is set using the <code>@version</code> <a>entry</a>
in a local <a>context</a> and
affects the behavior of algorithms including <a>expansion</a> and <a>compaction</a>.
Once set, it is an error to attempt to change to a different processing mode,
and processors MUST generate,
a <a data-link-for="JsonLdErrorCode">processing mode conflict</a>
error and abort further processing.</p>
<p>The algorithms in this specification are generally written with more concern for clarity
than efficiency. Thus, <a>JSON-LD Processors</a> 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.</p>
<p>In algorithm steps that describe operations on <a>keywords</a>, those steps
also apply to <a>keyword aliases</a>.</p>
<p class="note">Implementers can partially check their level of conformance to
this specification by successfully passing the test cases of the
<a href="https://w3c.github.io/json-ld-api/tests/">JSON-LD test suite</a>.
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.</p>
<p>This specification makes use of the following namespace prefixes:</p>
<table class="simple">
<thead><tr>
<th>Prefix</th>
<th>IRI</th>
</tr></thead>
<tbody>
<tr>
<td>rdf</td>
<td>http://www.w3.org/1999/02/22-rdf-syntax-ns#</td>
</tr>
<tr>
<td>xsd</td>
<td>http://www.w3.org/2001/XMLSchema#</td>
</tr>
</tbody>
</table>
</section>
<section><h1>Context Processing Algorithms</h1>
<p>The following sections describe algorithms for processing a JSON-LD context.</p>
<section><h2>Context Processing Algorithm</h2>
<p>When processing a JSON-LD data structure, each processing rule is applied
using information provided by the <a>active context</a>. This
section describes how to produce an <a>active context</a>.</p>
<p>The <a>active context</a> consists of:</p>
<ul>
<li>the active <a>term definitions</a> which specify how
keys and values have to be interpreted (<a>array</a> of <a>term definitions</a>),</li>
<li>the current <dfn data-lt="context-base-iri" data-lt-noDefault>base IRI</dfn> (<a>IRI</a>),</li>
<li class="changed">the <dfn>original base URL</dfn> (<a>IRI</a>),</li>
<li class="changed">an <dfn data-lt="context-inverse" data-lt-noDefault>inverse context</dfn> (<a>inverse context</a>),</li>
<li>an optional <a>vocabulary mapping</a> (<a>IRI</a>),</li>
<li>an optional <a>default language</a> (<a>string</a>),</li>
<li class="changed">an optional <a>default base direction</a> (`"ltr"` or `"rtl"`),</li>
<li class="changed">and an optional <dfn>previous context</dfn> (<a>context</a>),
used when a non-propagated <a>context</a> is defined.</li>
</ul>
<p>Each <a>term definition</a> consists of:</p>
<ul>
<li>an <dfn>IRI mapping</dfn> (<a>IRI</a>),</li>
<li class="changed">a <dfn>prefix flag</dfn> (<a>boolean</a>),</li>
<li class="changed">a <dfn>protected</dfn> flag (<a>boolean</a>),</li>
<li>a <dfn>reverse property</dfn> flag (<a>boolean</a>),</li>
<li class="changed">an optional <dfn>base URL</dfn> (<a>IRI</a>),</li>
<li class="changed">an optional <a>context</a> (<a>context</a>),</li>
<li>an optional <dfn>container mapping</dfn> (<a>array</a> of <a>strings</a>),
<li class="changed">an optional <dfn>direction mapping</dfn> (`"ltr"` or `"rtl"`),</li>
<li class="changed">an optional <dfn>index mapping</dfn> (<a>string</a>),</li>
<li>an optional <dfn>language mapping</dfn> (<a>string</a>),</li>
<li class="changed">an optional <dfn>nest value</dfn> (<a>string</a>),</li>
<li>and an optional <dfn>type mapping</dfn> (<a>IRI</a>).</li>
</ul>
<p>A <a>term definition</a> can not only be used to map a <a>term</a>
to an IRI, but also to map a <a>term</a> to a <a>keyword</a>,
in which case it is referred to as a <dfn>keyword alias</dfn>.</p>
<p>When processing, <var>active context</var> is initialized
<span class="changed">with a `null` <a data-lt="context-inverse">inverse context</a>,</span>
without any <a>term definitions</a>,
<a>vocabulary mapping</a>, <a class="changed">default base direction</a>, or <a>default language</a>.
If a <a>local context</a> is encountered during processing, a new
<var>active context</var> is created by cloning the existing
<var>active context</var>. Then the information from the
<a>local context</a> is merged into the new <var>active context</var>.
Given that <a>local contexts</a> may contain
references to remote contexts, this includes their retrieval.</p>
<section class="informative">
<h3>Overview</h3>
<p>First we prepare a new <a>active context</a> <var>result</var> by cloning
the current <a>active context</a>. Then we normalize the form of the original
<a>local context</a> to an <a>array</a>.
<a>Local contexts</a> may be in the form of a
<a class="changed">map</a>, a <a>string</a>, or an <a>array</a> containing
a combination of the two. Finally we process each <a>context</a> contained
in the <a>local context</a> <a>array</a> as follows.</p>
<p>If <a>context</a> is a <a>string</a>, it represents a reference to
a remote context. We dereference the remote context and replace <a>context</a>
with the value of the <code>@context</code> <a>entry</a> of the top-level object in the
retrieved JSON-LD document.
If there's no such <a>entry</a>, an
<a data-link-for="JsonLdErrorCode">invalid remote context</a>
has been detected. Otherwise, we process <a>context</a> by recursively using
this algorithm ensuring that there is no cyclical reference.</p>
<p>If <a>context</a> is a <a class="changed">map</a>,
it is a <a data-cite="JSON-LD11#dfn-context-definition">context definition</a>.
We first update
the <a class="changed" data-lt="context-base-iri">base IRI</a>,
<span class="changed">the <a>default base direction</a></span>,
the <a>default language</a>,
<span class="changed">context propagation</span>,
<span class="changed">the <a>processing mode</a></span>,
and the <a>vocabulary mapping</a>
by processing six specific keywords:
<code>@base</code>,
<code class='changed'>@direction</code>,
<code>@language</code>,
<code class="changed">@propagate</code>,
<code class="changed">@version</code>,
and <code>@vocab</code>.
These are handled before any other <a>entries</a> in the <a>local context</a> because
they affect how the other <a>entries</a> are processed.
<span class="changed">If <a>context</a> contains <code>@import</code>, it is retrieved and is reverse-merged
into the containing context, allowing JSON-LD 1.0 contexts to be upgraded to JSON-LD 1.1.</span>
Please note that <code>@base</code> is ignored when processing remote contexts.</p>
<p class="changed">If <a>context</a> is not to be propagated,
a reference to the <a>previous context</a> is retained so that
it may be rolled back when a new <a>node object</a> is entered.
By default, all contexts are propagated, other than <a>type-scoped contexts</a>.</p>
<p class="changed">
When an <a>active context</a> is initialized, the value
of the <a>original base URL</a>
is initialized from the original {{RemoteDocument/documentUrl}}
of the document containing the initial <a>context</a>, if available,
otherwise from the {{JsonLdOptions/base}} API option.
This is necessary when resetting the <a>active context</a>
by setting it to `null`
to retain the original default <a class="changed" data-lt="context-base-iri">base IRI</a>.</p>
<p class="changed">When initialized, or when any entry of
an <a>active context</a> is changed,
or any associated <a>term definition</a> is added, changed, or removed,
the <a data-lt="context-inverse">inverse context</a> field
in <a>active context</a> is set to `null`.</p>
<p>Then, for every other <a>entry</a> in <a>local context</a>, we update
the <a>term definition</a> in <var>result</var>. Since
<a>term definitions</a> in a <a>local context</a>
may themselves contain <a>terms</a> or
<a>compact IRIs</a>, we may need to recurse.
When doing so, we must ensure that there is no cyclical dependency,
which is an error. After we have processed any
<a>term definition</a> dependencies,
we update the current <a>term definition</a>,
which may be a <a>keyword alias</a>.</p>
<p>Finally, we return <var>result</var> as the new <a>active context</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>This algorithm specifies how a new <a>active context</a> is updated
with a <a>local context</a>. The algorithm takes three required
<span class="changed">and four optional</span>
input variables.
The required inputs are
an <var>active context</var>,
a <var>local context</var>,
<span class="changed">and a <var>base URL</var> used when resolving relative context URLs</span>.
The optional inputs are
an <a>array</a> <var>remote contexts</var>,
defaulting to a new empty <a>array</a>, which is used to detect cyclical context inclusions,
<span class="changed">
<var>override protected</var>, defaulting to <code>false</code>,
which is used to allow changes to protected terms,
<var>propagate</var>, defaulting to <code>true</code>
to mark <a>term definitions</a> associated with non-propagated <a>contexts</a>,
and <var>validate scoped context</var> defaulting to <code>true</code>,
which is used to limit recursion when validating possibly recursive <a>scoped contexts</a>.</span>.
</p>
<ol>
<li>Initialize <var>result</var> to the result of cloning
<var>active context</var>,
<span class="changed">with <a data-lt="context-inverse">inverse context</a> set to `null`.</span>.</li>
<li class="changed">If <var>local context</var> is an object containing the member <code>@propagate</code>,
its value MUST be <a>boolean</a> <code>true</code> or <code>false</code>,
set <var>propagate</var> to that value.
<div class="note">Error handling is performed in <a href="#step-propagate-entry">step 5.11</a>.</div></li>
<li class="changed">If <var>propagate</var> is <code>false</code>, and <var>result</var>
does not have a <a>previous context</a>, set <a>previous context</a>
in <var>result</var> to <var>active context</var>.</li>
<li>If <var>local context</var> is not an <a>array</a>,
set <var>local context</var> to an <a>array</a> containing only
<var>local context</var>.</li>
<li>
For each item <var>context</var> in <var>local context</var>:
<ol>
<li>If <var>context</var> is <code>null</code>:
<ol>
<li class="changed">If <var>override protected</var> is <code>false</code> and <var>active context</var>
contains any <a>protected</a> <a>term definitions</a>,
an <a data-link-for="JsonLdErrorCode">invalid context nullification</a>
has been detected and processing is aborted.</li>
<li>Initialize <var>result</var> as a
newly-initialized <a>active context</a>,
<span class="changed">
setting both <a data-lt="context-base-iri">base IRI</a> and <a>original base URL</a> to the value of
<a>original base URL</a> in <var>active context</var></span>,
and, if <var>propagate</var> is <code>false</code>,
<a>previous context</a> in <var>result</var>
to the previous value of <var>result</var>.</li>
<li>Continue with the next <var>context</var>.</li>
</ol>
</li>
<li id="alg-context-string">If <var>context</var> is a <a>string</a>,
<ol>
<li>Initialize <var>context</var> to the result of resolving <var>context</var> against
<var>base URL</var>. If <var>base URL</var> is not a valid <a>IRI</a>,
then <var>context</var> MUST be a valid <a>IRI</a>, otherwise
a <a data-link-for="JsonLdErrorCode">loading document failed</a> error
has been detected and processing is aborted.
<div class="note">
<var>base URL</var> is often not the same as {{JsonLdOptions/base}}
or the <a class="changed" data-lt="context-base-iri">base IRI</a> of the <var>active context</var>.
</div>
</li>
<li id="alg-context-validate-scoped" class="changed">If <var>validate scoped context</var> is <code>false</code>,
and <var>remote contexts</var> already includes <var>context</var>
do not process <var>context</var> further and continue to any next
<var>context</var> in <var>local context</var>.</li>
<li>If the number of entries in the <var>remote contexts</var> array
exceeds a processor defined limit, a
<a data-link-for="JsonLdErrorCode">context overflow</a>
error has been detected and processing is aborted;
otherwise, add <var>context</var> to <var>remote contexts</var>.</li>
<li class="changed">If <var>context</var> was previously dereferenced,
then the processor MUST NOT do a further dereference, and
<a>context</a> is set to the
previously established <a>internal representation</a>:
set <var>context document</var> to the previously dereferenced document,
and set <var>loaded context</var> to the value of the `@context`
<a>entry</a> from the document in <var>context document</var>.
<div class="note">Only the `@context` <a>entry</a> need be retained.</div>
</li>
<li class="changed">Otherwise, set <var>context document</var>
to the {{RemoteDocument}} obtained
by dereferencing <var>context</var> using
the <a>LoadDocumentCallback</a>, passing <var>context</var>
for {{LoadDocumentCallback/url}},
and <code>http://www.w3.org/ns/json-ld#context</code> for <a data-link-for="LoadDocumentOptions">profile</a>
and for <a data-link-for="LoadDocumentOptions">requestProfile</a>.
<ol>
<li id="alg-context-deref-error">If <var>context</var> cannot be dereferenced,
<span class="changed">
or the {{RemoteDocument/document}} from <var>context document</var>
cannot be transformed into the <a>internal representation</a>
</span>,
a <a data-link-for="JsonLdErrorCode">loading remote context failed</a>
error has been detected and processing is aborted.</li>
<li>If the {{RemoteDocument/document}} has no
top-level <a class="changed">map</a> with an <code>@context</code> <a>entry</a>, an
<a data-link-for="JsonLdErrorCode">invalid remote context</a>
has been detected and processing is aborted.</li>
<li>Set <var>loaded context</var> to the value of that <a>entry</a>.</li>
</ol>
</li>
<li>Set <var>result</var> to the result of recursively calling this algorithm,
passing <var>result</var> for <var>active context</var>,
<var>loaded context</var> for <var>local context</var>,
<span class="changed">
the {{RemoteDocument/documentUrl}} of <var>context document</var> for <var>base URL</var>,
</span>
<span class="changed">a copy of</span> <var>remote contexts</var>,
<span class="changed">and <var>validate scoped context</var></span>.
<div class="note">If <var>context</var> was previously dereferenced,
<a>processors</a> MUST make provisions for retaining the <var>base URL</var>
of that <a>context</a> for this step to enable the resolution of any
relative context URLs that may be encountered during processing.</div>
</li>
<li>Continue with the next <var>context</var>.</li>
</ol>
</li>
<li>If <var>context</var> is not a <a class="changed">map</a>, an
<a data-link-for="JsonLdErrorCode">invalid local context</a>
error has been detected and processing is aborted.</li>
<li>Otherwise, <var>context</var> is a <a data-cite="JSON-LD11#dfn-context-definition">context definition</a>.</li>
<li class="changed">If <var>context</var> has an <code>@version</code> <a>entry</a>:
<ol>
<li>If the associated value is not <code>1.1</code>,
an <a data-link-for="JsonLdErrorCode">invalid @version value</a>
has been detected, and processing is aborted.
<div class="note">The use of `1.1` for the value of `@version` is intended to
cause a JSON-LD 1.0 processor to stop processing.
Although it is clearly meant to be related to JSON-LD 1.1, it does not
otherwise adhere to the requirements for <a href="https://semver.org/">Semantic Versioning</a>.
Implementations may require
<a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic#Minimizing_the_effect_of_accuracy_problems">special consideration</a>
when comparing the values of <a>numbers</a> with a non-zero fractional part.</div>
</li>
<li>If <a>processing mode</a>
is set to `json-ld-1.0`,
a <a data-link-for="JsonLdErrorCode">processing mode conflict</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li class="changed">If <var>context</var> has an <code>@import</code> <a>entry</a>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid context entry</a>
error has been detected and processing is aborted.</li>
<li>Otherwise, if the value of `@import` is not a <a>string</a>,
an <a data-link-for="JsonLdErrorCode">invalid @import value</a>
error has been detected and processing is aborted.</li>
<li>Initialize <var>import</var> to the result of resolving the value of <code>@import</code> against
<var>base URL</var>.</li>
<li>Dereference <var>import</var> using
the <a>LoadDocumentCallback</a>, passing <var>import</var>
for {{LoadDocumentCallback/url}},
and <code>http://www.w3.org/ns/json-ld#context</code> for <a data-link-for="LoadDocumentOptions">profile</a>
and for <a data-link-for="LoadDocumentOptions">requestProfile</a>.</li>
<li>If <var>import</var> cannot be dereferenced,
<span>or cannot be transformed into the <a>internal representation</a></span>,
a <a data-link-for="JsonLdErrorCode">loading remote context failed</a>
error has been detected and processing is aborted.</li>
<li>If the dereferenced document has no
top-level <a>map</a> with an <code>@context</code> <a>entry</a>,
or if the value of <code>@context</code> is not a <a data-cite="JSON-LD11#dfn-context-definition">context definition</a>
(i.e., it is not an <a>map</a>),
an <a data-link-for="JsonLdErrorCode">invalid remote context</a>
has been detected and processing is aborted; otherwise,
set <var>import context</var> to the value of that <a>entry</a>.</li>
<li>If <var>import context</var> has a <code>@import</code> <a>entry</a>,
an <a data-link-for="JsonLdErrorCode">invalid context entry</a>
error has been detected and processing is aborted.</li>
<li>Set <var>context</var> to the result of merging <var>context</var>
into <var>import context</var>, replacing common entries
with those from <var>context</var>.</li>
</ol>
</li>
<li>If <var>context</var> has an <code>@base</code> <a>entry</a> and <var>remote contexts</var> is empty, i.e., the currently
being processed context is not a remote context:
<ol>
<li>Initialize <var>value</var> to the value associated with the
<code>@base</code> <a>entry</a>.</li>
<li>If <var>value</var> is <code>null</code>, remove the
<a class="changed" data-lt="context-base-iri">base IRI</a> of <var>result</var>.</li>
<li>Otherwise, if <var>value</var> is an <a>IRI</a>,
the <a class="changed" data-lt="context-base-iri">base IRI</a> of <var>result</var> is set to <var>value</var>.</li>
<li>Otherwise, if <var>value</var> is a <a>relative IRI reference</a> and
the <a class="changed" data-lt="context-base-iri">base IRI</a> of <var>result</var> is not <code>null</code>,
set the <a class="changed" data-lt="context-base-iri">base IRI</a> of <var>result</var> to the result of
resolving <var>value</var> against the current <a class="changed" data-lt="context-base-iri">base IRI</a>
of <var>result</var>.</li>
<li>Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid base IRI</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li>If <var>context</var> has an <code>@vocab</code> <a>entry</a>:
<ol>
<li>Initialize <var>value</var> to the value associated with the
<code>@vocab</code> <a>entry</a>.</li>
<li>If <var>value</var> is <a>null</a>, remove
any <a>vocabulary mapping</a> from <var>result</var>.</li>
<li>Otherwise, if <var>value</var> is
an <a>IRI</a>
or <a>blank node identifier</a>, the <a>vocabulary mapping</a>
of <var>result</var> is set to
<span class="changed">the result of
<a>IRI expanding</a> <var>value</var>
using <code>true</code> for <var>document relative</var>
</span>.
If it is not an <a>IRI</a>, or a <a>blank node identifier</a>, an
<a data-link-for="JsonLdErrorCode">invalid vocab mapping</a>
error has been detected and processing is aborted.
<div class="note">The use of <a>blank node identifiers</a> to value for <code>@vocab</code> is obsolete,
and may be removed in a future version of JSON-LD.</div></li>
</ol>
</li>
<li>If <var>context</var> has an <code>@language</code> <a>entry</a>:
<ol>
<li>Initialize <var>value</var> to the value associated with the
<code>@language</code> <a>entry</a>.</li>
<li>If <var>value</var> is <code>null</code>, remove
any <a>default language</a> from <var>result</var>.</li>
<li>Otherwise, if <var>value</var> is a <a>string</a>, the
<a>default language</a> of <var>result</var> is set to
<var>value</var>.
If it is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid default language</a>
error has been detected and processing is aborted.
<span class="changed">If <var>value</var> is not <a>well-formed</a> according to
<a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of [[BCP47]],
processors SHOULD issue a warning.</span>
<div class="changed note">Processors MAY normalize <a>language tags</a> to lower case.</div>
</li>
</ol>
</li>
<li class="changed">If <var>context</var> has an <code>@direction</code> <a>entry</a>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid context entry</a>
error has been detected and processing is aborted.</li>
<li>Initialize <var>value</var> to the value associated with the
<code>@direction</code> <a>entry</a>.</li>
<li>If <var>value</var> is <code>null</code>, remove
any <a>base direction</a> from <var>result</var>.</li>
<li>Otherwise, if <var>value</var> is a <a>string</a>, the
<a>base direction</a> of <var>result</var> is set to
<var>value</var>. If it is not `null`, `"ltr"`, or `"rtl"`, an
<a data-link-for="JsonLdErrorCode">invalid base direction</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li id="step-propagate-entry" class="changed">If <var>context</var> has an <code>@propagate</code> <a>entry</a>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid context entry</a>
error has been detected and processing is aborted.</li>
<li>Otherwise, if the value of `@propagate` is not <a>boolean</a> <code>true</code> or <code>false</code>,
an <a data-link-for="JsonLdErrorCode">invalid @propagate value</a>
error has been detected and processing is aborted.
<div class="note">The <a>previous context</a> is actually set earlier in this algorithm;
the previous two steps exist for error checking only.</div>
</li>
</ol>
</li>
<li>Create a <a class="changed">map</a> <var>defined</var> to keep
track of whether or not a <a>term</a> has already been defined
or is currently being defined during recursion.</li>
<li id="alg-context-create-defns">For each <var>key</var>-<var>value</var> pair in <var>context</var> where
<var>key</var> is not
<code>@base</code>,
<code class="changed">@direction</code>,
<code class="changed">@import</code>,
<code>@language</code>,
<code class="changed">@propagate</code>,
<code class="changed">@protected</code>,
<code>@version</code>, or
<code>@vocab</code>,
invoke the
<a href="#create-term-definition">Create Term Definition algorithm</a>,
passing <var>result</var> for <var>active context</var>,
<var>context</var> for <var>local context</var>, <var>key</var>,
<var>defined</var>,
<span class="changed">
<var>base URL</var>,
the value of the <code>@protected</code>
entry from <var>context</var>, if any, for <var>protected</var>,
<var>override protected</var>,
and a copy of <var>remote contexts</var>.
</span>
</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
<section><h2>Create Term Definition</h2>
<p>This algorithm is called from the
<a href="#context-processing-algorithm">Context Processing algorithm</a>
to create a <a>term definition</a> in the <a>active context</a>
for a <a>term</a> being processed in a <a>local context</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p><a>Term definitions</a> are created by
parsing the information in the given <a>local context</a> for the
given <a>term</a>. If the given <a>term</a> is a
<a>compact IRI</a>, it may omit an <a>IRI mapping</a> by
depending on its <a>prefix</a> having its own
<a>term definition</a>. If the <a>prefix</a> is
an <a>entry</a> in the <a>local context</a>, then its <a>term definition</a>
must first be created, through recursion, before continuing. Because a
<a>term definition</a> can depend on other
<a>term definitions</a>, a mechanism must
be used to detect cyclical dependencies. The solution employed here
uses a map, <var>defined</var>, that keeps track of whether or not a
<a>term</a> has been defined or is currently in the process of
being defined. This map is checked before any recursion is attempted.</p>
<p>After all dependencies for a <a>term</a> have been defined, the rest of
the information in the <a>local context</a> for the given
<a>term</a> is taken into account, creating the appropriate
<a>IRI mapping</a>, <a>container mapping</a>, and
<a>type mapping</a>,
<a>language mapping</a>,
<span class="changed">or <a>direction mapping</a></span>
for the <a>term</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm has four required <span class="changed">and five optional</span> inputs.
The required inputs are
an <var>active context</var>,
a <var>local context</var>,
a <var>term</var>,
and a map <var>defined</var>.
<span class="changed">The optional inputs are
<var>base URL</var> defaulting to <code>null</code>,
<var>protected</var> which defaults to <code>false</code>,
and <var>override protected</var>, defaulting to <code>false</code>,
which is used to allow changes to protected terms,
an <a>array</a> <var>remote contexts</var>,
defaulting to a new empty <a>array</a>, which is used to detect cyclical context inclusions,
and <var>validate scoped context</var> defaulting to <code>true</code>,
which is used to limit recursion when validating possibly recursive <a>scoped contexts</a>.</span>.
</p>
<ol>
<li>If <var>defined</var> contains the <a>entry</a> <var>term</var> and the associated
value is <code>true</code> (indicating that the
<a>term definition</a> has already been created), return. Otherwise,
if the value is <code>false</code>, a
<a data-link-for="JsonLdErrorCode">cyclic IRI mapping</a>
error has been detected and processing is aborted.</li>
<li>If <var>term</var> is the empty string (`""`),
an <a data-link-for="JsonLdErrorCode">invalid term definition</a>
error has been detected and processing is aborted.
Otherwise, set the value associated with <var>defined</var>'s <var>term</var> <a>entry</a> to
<code>false</code>. This indicates that the <a>term definition</a>
is now being created but is not yet complete.</li>
<li>Initialize <var>value</var> to a copy of the value associated with the <a>entry</a>
<var>term</var> in <var>local context</var>.</li>
<li class="changed">If <var>term</var> is `@type`,
and <a>processing mode</a> is `json-ld-1.0`,
a <a data-link-for="JsonLdErrorCode">keyword redefinition</a> error has
been detected and processing is aborted.
At this point,
<var>value</var> MUST be a <a>map</a> with only either or both of the following <a>entries</a>:
<ul>
<li>An entry for <code>@container</code> with value <code>@set</code>.</li>
<li>An entry for <code>@protected</code>.</li>
</ul>
Any other value means that a
<a data-link-for="JsonLdErrorCode">keyword redefinition</a> error has
been detected and processing is aborted.</li>
<li><span class="changed">Otherwise</span>, since <a>keywords</a> cannot be overridden,
<var>term</var> MUST NOT be a <a>keyword</a> and a
<a data-link-for="JsonLdErrorCode">keyword redefinition</a>
error has been detected and processing is aborted.
If <var>term</var> has the form of a keyword
(i.e., it matches the ABNF rule `"@"1*ALPHA` from [[RFC5234]]),
return; processors SHOULD generate a warning.</li>
<li class="changed">Initialize <var>previous definition</var> to any existing
<a>term definition</a> for <var>term</var> in <var>active context</var>,
removing that <a>term definition</a> from <var>active context</var>.</li>
<li class="changed">If <var>value</var> is <code>null</code>,
convert it to a <a class="changed">map</a> consisting of a single <a>entry</a> whose
key is <code>@id</code> and whose value is <code>null</code>.</li>
<li>Otherwise, if <var>value</var> is a <a>string</a>, convert it
to a <a class="changed">map</a> consisting of a single <a>entry</a> whose
key is <code>@id</code> and whose value is <var>value</var>.
<span class="changed">Set <var>simple term</var> to <code>true</code></span>.</li>
<li>Otherwise, <var>value</var> MUST be a <a class="changed">map</a>, if not, an
<a data-link-for="JsonLdErrorCode">invalid term definition</a>
error has been detected and processing is aborted.
<span class="changed">Set <var>simple term</var> to <code>false</code></span>.</li>
<li>Create a new <a>term definition</a>, <var>definition</var>,
<span class="changed">initializing <a>prefix flag</a> to `false`,
<a>protected</a> to <var>protected</var>,
and <a>reverse property</a> to `false`</span>.</li>
<li id="alg-ctd-protected" class="changed">If <var>value</var> has an <code>@protected</code> entry,
set the <a>protected</a> flag in <var>definition</var> to the value of this entry.
If the value of `@protected` is not a <a>boolean</a>,
an <a data-link-for="JsonLdErrorCode">invalid @protected value</a> error has been detected and processing is aborted.
If <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>If <var>value</var> contains the <a>entry</a> <code>@type</code>:
<ol>
<li>Initialize <var>type</var> to the value associated with the
<code>@type</code> <a>entry</a>, which MUST be a <a>string</a>. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid type mapping</a>
error has been detected and processing is aborted.</li>
<li>Set <var>type</var> to the result of
<span class="changed"><a>IRI expanding</a> <var>type</var></span>,
using <var>local context</var>, and <var>defined</var>.</li>
<li class="changed">If the expanded <var>type</var> is
`@json` or `@none`, and <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid type mapping</a>
error has been detected and processing is aborted.</li>
<li id="ctd-invalid-type">Otherwise, if the expanded <var>type</var> is
neither <code>@id</code>, nor <code>@json</code>,
nor <code>@none</code>,
nor <code>@vocab</code>,
nor an <a>IRI</a>,
an <a data-link-for="JsonLdErrorCode">invalid type mapping</a>
error has been detected and processing is aborted.</li>
<li>Set the <a>type mapping</a> for <var>definition</var> to <var>type</var>.</li>
</ol>
</li>
<li>If <var>value</var> contains the <a>entry</a> <code>@reverse</code>:
<ol>
<li>If <var>value</var> contains <code>@id</code> or <code>@nest</code>, <a>entries</a>, an
<a data-link-for="JsonLdErrorCode">invalid reverse property</a>
error has been detected and processing is aborted.</li>
<li>If the value associated with the <code>@reverse</code> <a>entry</a>
is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted.</li>
<li>If the value associated with the `@reverse` <a>entry</a> is a string
having the form of a keyword
(i.e., it matches the ABNF rule `"@"1*ALPHA` from [[RFC5234]]),
return; processors SHOULD generate a warning.</li>
<li>Otherwise, set the <a>IRI mapping</a> of <var>definition</var> to the
result of
<span class="changed"><a>IRI expanding</a></span>
the value associated with the <code>@reverse</code> <a>entry</a>,
using <var>local context</var>, and <var>defined</var>.
If the result does not have the <a href="https://tools.ietf.org/html/rfc3987#section-2.2">form</a> of an <a>IRI</a> or a <a>blank node identifier</a>,
an <a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted.</li>
<li>If <var>value</var> contains an <code>@container</code> <a>entry</a>,
set the <a>container mapping</a> of <var>definition</var>
to <span class="changed">an <a>array</a> containing</span> its value;
if its value is neither <code>@set</code>, nor
<code>@index</code>, nor <code>null</code>, an
<a data-link-for="JsonLdErrorCode">invalid reverse property</a>
error has been detected (reverse properties only support set- and
index-containers) and processing is aborted.</li>
<li>Set the <a>reverse property</a> flag of <var>definition</var>
to <code>true</code>.</li>
<li>Set the <a>term definition</a> of <var>term</var> in
<var>active context</var> to <var>definition</var> and the
value associated with <var>defined</var>'s <a>entry</a> <var>term</var> to
<code>true</code> and return.</li>
</ol>
</li>
<li>If <var>value</var> contains the <a>entry</a> <code>@id</code> and its value
does not equal <var>term</var>:
<ol>
<li id="ctd-id-null">If the <code>@id</code> <a>entry</a> of <var>value</var>
is <code>null</code>, the term is not used for IRI expansion, but is
retained to be able to detect future redefinitions of this term.</li>
<li id="ctd-id-not-null">Otherwise:
<ol>
<li>If the value associated with the <code>@id</code> <a>entry</a> is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted.</li>
<li>If the value associated with the `@id` <a>entry</a>
is not a <a>keyword</a>, but
has the form of a <a>keyword</a>
(i.e., it matches the ABNF rule `"@"1*ALPHA` from [[RFC5234]]),
return; processors SHOULD generate a warning.</li>
<li>Otherwise, set the <a>IRI mapping</a> of <var>definition</var> to the
result of
<span class="changed"><a>IRI expanding</a></span>
the value associated with the <code>@id</code> <a>entry</a>,
using <var>local context</var>, and <var>defined</var>.
If the resulting <a>IRI mapping</a> is neither a <a>keyword</a>, nor an
<a>IRI</a>, nor a <a>blank node identifier</a>, an
<a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted; if it equals <code>@context</code>, an
<a data-link-for="JsonLdErrorCode">invalid keyword alias</a>
error has been detected and processing is aborted.</li>
<li id="ctd-contains-colon" class="changed">If the <var>term</var> contains a colon (`:`)
anywhere but as the first or last character of <var>term</var>,
or if it contains a slash (`/`) anywhere:
<ol>
<li>Set the value associated with <var>defined</var>'s <var>term</var> <a>entry</a> to
<code>true</code>.</li>
<li>If the result of <span class="changed"><a>IRI expanding</a></span> <var>term</var>
using <var>local context</var>, and <var>defined</var>,
is not the same as the <a>IRI mapping</a> of <var>definition</var>,
an <a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li class="changed">If <var>term</var> contains neither a colon (`:`) nor a slash (`/`),
<span class="changed"><var>simple term</var> is <code>true</code></span>,
and if the <a>IRI mapping</a> of <var>definition</var>
is either an <a>IRI</a> ending with a <a data-cite="RFC3986#section-2.2">gen-delim</a> character,
or a <a>blank node identifier</a>,
set the <a>prefix flag</a> in <var>definition</var> to <code>true</code>.</li>
</ol>
</li>
</ol>
</li>
<li>
Otherwise if the <var>term</var> contains a colon (`:`)
<span class="changed">anywhere after the first character</span>:
<ol>
<li>If <var>term</var> is a <a>compact IRI</a> with a
<a>prefix</a> that is an <a>entry</a> in <var>local context</var>
a dependency has been found. Use this algorithm recursively passing
<var>active context</var>, <var>local context</var>, the
<a>prefix</a> as <var>term</var>, and <var>defined</var>.</li>
<li>If <var>term</var>'s <a>prefix</a> has a
<a>term definition</a> in <var>active context</var>, set
the <a>IRI mapping</a> of <var>definition</var> to the result of
concatenating the value associated with the <a data-lt="prefix">prefix's</a>
<a>IRI mapping</a> and the <var>term</var>'s <var>suffix</var>.</li>
<li>Otherwise, <var>term</var> is an <a>IRI</a> or
<a>blank node identifier</a>. Set the <a>IRI mapping</a>
of <var>definition</var> to <var>term</var>.</li>
</ol>
</li>
<li class="changed">
Otherwise if the <var>term</var> contains a slash (`/`):
<ol>
<li><var>Term</var> is a <a>relative IRI reference</a>.</li>
<li>Set the <a>IRI mapping</a> of <var>definition</var> to the
result of <span class="changed"><a>IRI expanding</a></span> <var>term</var>.
If the resulting <a>IRI mapping</a> is not an <a>IRI</a>, an
<a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li class="changed">Otherwise, if term is <code>@type</code>, set the <a>IRI mapping</a>
of <var>definition</var> to <code>@type</code>.</li>
<li>Otherwise, if <var>active context</var> has a
<a>vocabulary mapping</a>, the <a>IRI mapping</a>
of <var>definition</var> is set to the result of concatenating the value
associated with the <a>vocabulary mapping</a> and <var>term</var>.
If it does not have a <a>vocabulary mapping</a>, an
<a data-link-for="JsonLdErrorCode">invalid IRI mapping</a>
error been detected and processing is aborted.</li>
<li>If <var>value</var> contains the <a>entry</a> <code>@container</code>:
<ol>
<li id="ctd-container">Initialize <var>container</var> to the value associated with the
<code>@container</code> <a>entry</a>, which MUST be either
<code class="changed">@graph</code>,
<code class="changed">@id</code>,
<code>@index</code>,
<code>@language</code>,
<code>@list</code>,
<code>@set</code>,
<code class="changed">@type</code>,
<span class="changed">
or an <a>array</a> containing exactly any one of those keywords,
an <a>array</a> containing <code>@graph</code> and
either <code>@id</code> or <code>@index</code> optionally
including <code>@set</code>,
or an <a>array</a> containing a combination of <code>@set</code> and any of
<code>@index</code>, <code>@graph</code>,
<code>@id</code>, <code>@type</code>,
<code>@language</code> in any order
</span>.
Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid container mapping</a>
has been detected and processing is aborted.</li>
<li class="changed">If the container value
is <code>@graph</code>, <code>@id</code>, or <code>@type</code>, or is otherwise not a <a>string</a>,
generate an <a data-link-for="JsonLdErrorCode">invalid container mapping</a>
error and abort processing if <a>processing mode</a> is `json-ld-1.0`.</li>
<li>Set the <a>container mapping</a> of <var>definition</var> to
<var>container</var>
<span class="changed">coercing to an <a>array</a>, if necessary</span>.</li>
<li class="changed">If the <a>container mapping</a> of <var>definition</var> includes `@type`:
<ol>
<li>If <var>type mapping</var> in <var>definition</var> is undefined, set it to `@id`.</li>
<li>If <var>type mapping</var> in <var>definition</var> is neither `@id` nor `@vocab`,
an <a data-link-for="JsonLdErrorCode">invalid type mapping</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
</ol>
</li>
<li class="changed">If <var>value</var> contains the <a>entry</a> <code>@index</code>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0` or
<a>container mapping</a> does not include <code>@index</code>,
an <a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>Initialize <var>index</var> to the value associated with the
<code>@index</code> <a>entry</a>.
If the result of <a>IRI expanding</a> that value is not an <a>IRI</a>,
an
<a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>Set the <a>index mapping</a> of <var>definition</var> to <var>index</var></li>
</ol>
</li>
<li class="changed">If <var>value</var> contains the <a>entry</a> <code>@context</code>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`, an
<a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>Initialize <var>context</var> to the value associated with the
<code>@context</code> <a>entry</a>, which is treated as a <a>local context</a>.</li>
<li>Invoke the <a href="#context-processing-algorithm">Context Processing algorithm</a>
using the <var>active context</var>, <var>context</var> as <var>local context</var>,
<var>base URL</var>,
<code>true</code> for <var>override protected</var>,
<span class="changed">a copy of</span> <var>remote contexts</var>,
and <code>false</code> for <var>validate scoped context</var>.
If any error is detected, an
<a data-link-for="JsonLdErrorCode">invalid scoped context</a> error
has been detected and processing is aborted.
<p class="note">The result of the <a href="#context-processing-algorithm">Context Processing algorithm</a>
is discarded; it is called to detect errors at definition time.
If used, the context will be re-processed and applied to the <a>active context</a>
as part of <a>expansion</a> or <a>compaction</a>.</p></li>
<li>Set the <a>local context</a> of <var>definition</var> to <var>context</var>,
and <a>base URL</a> to <var>base URL</var>.</li>
</ol>
</li>
<li>If <var>value</var> contains the <a>entry</a> <code>@language</code> and
does not contain the <a>entry</a> <code>@type</code>:
<ol>
<li>Initialize <var>language</var> to the value associated with the
<code>@language</code> <a>entry</a>, which MUST be either <code>null</code>
or a <a>string</a>.
<span class="changed">If <var>language</var> is not <a>well-formed</a> according to
<a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of [[BCP47]],
processors SHOULD issue a warning.</span>
Otherwise, an <a data-link-for="JsonLdErrorCode">invalid language mapping</a>
error has been detected and processing is aborted.</li>
<li>Set the <a>language mapping</a> of <var>definition</var> to <var>language</var>.
<div class="changed note">Processors MAY normalize <a>language tags</a> to lower case.</div>
</li>
</ol>
</li>
<li class="changed">If <var>value</var> contains the <a>entry</a> <code>@direction</code> and
does not contain the <a>entry</a> <code>@type</code>:
<ol>
<li>Initialize <var>direction</var> to the value associated with the
<code>@direction</code> <a>entry</a>, which MUST be either <code>null</code>,
`"ltr"`, or `"rtl"`. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid base direction</a>
error has been detected and processing is aborted.</li>
<li>Set the <a>direction mapping</a>
of <var>definition</var> to <var>direction</var>.</li>
</ol>
</li>
<li class="changed">If <var>value</var> contains the <a>entry</a> <code>@nest</code>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`, an
<a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>Initialize <a>nest value</a> in <var>definition</var> to the value associated with the
<code>@nest</code> <a>entry</a>, which MUST be a <a>string</a> and
MUST NOT be a keyword other than <code>@nest</code>. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid @nest value</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li class="changed">If <var>value</var> contains the <a>entry</a> <code>@prefix</code>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`, or if
<var>term</var> contains a colon (<code>:</code>) or slash (`/`), an
<a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
<li>Set the <a>prefix flag</a> to the value associated with the
<code>@prefix</code> <a>entry</a>, which MUST be a <a>boolean</a>. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid @prefix value</a>
error has been detected and processing is aborted.</li>
<li>If the <a>prefix flag</a> of <var>definition</var> is set to <code>true</code>,
and its <a>IRI mapping</a> is a <a>keyword</a>,
an <a data-link-for="JsonLdErrorCode">invalid term definition</a>
has been detected and processing is aborted.</li>
</ol>
</li>
<li id="ctd-invalid-entries">If <var>value</var> contains any <a>entry</a> other than <code>@id</code>,
<code>@reverse</code>, <code>@container</code>,
<code class="changed">@context</code>,
<code class="changed">@direction</code>,
<code class="changed">@index</code>,
<code>@language</code>,
<code class="changed">@nest</code>,
<code class="changed">@prefix</code>,
<code class="changed">@protected</code>,
or <code>@type</code>,
an <a data-link-for="JsonLdErrorCode">invalid term definition</a> error has
been detected and processing is aborted.</li>
<li class="changed">If <var>override protected</var> is <code>false</code>
and <var>previous definition</var> exists and is protected;
<ol>
<li>If <var>definition</var> is not the same as <var>previous definition</var>
(other than the value of <a>protected</a>),
a <a data-link-for="JsonLdErrorCode">protected term redefinition</a> error has been detected,
and processing is aborted.</li>
<li>Set <var>definition</var> to <var>previous definition</var> to retain the value
of <a>protected</a>.</li>
</ol>
</li>
<li>Set the <a>term definition</a> of <var>term</var> in
<var>active context</var> to <var>definition</var> and set the value
associated with <var>defined</var>'s <a>entry</a> <var>term</var> to
<code>true</code>.</li>
</ol>
</section>
</section>
<section><h2>Inverse Context Creation</h2>
<p>When there is more than one <a>term</a> that could be chosen
to compact an <a>IRI</a>, it has to be ensured that the <a>term</a>
selection is both deterministic and represents the most context-appropriate
choice whilst taking into consideration algorithmic complexity.</p>
<p>In order to make <a>term</a> selections, the concept of an
<a>inverse context</a> is introduced. An <dfn>inverse context</dfn>
is essentially a reverse lookup table that maps
<a>container mapping</a>,
<a>type mappings</a>, and
<a>language mappings</a> to a simple
<a>term</a> for a given <a>active context</a>. A
<a>inverse context</a> only needs to be generated for an
<a>active context</a> if it is being used for <a>compaction</a>.</p>
<p>To make use of an <a>inverse context</a>, a list of preferred
<a>container mapping</a> and the
<a>type mapping</a> or <a>language mapping</a> are gathered
for a particular value associated with an <a>IRI</a>. These parameters
are then fed to the <a href="#term-selection">Term Selection algorithm</a>,
which will find the <a>term</a> that most appropriately
matches the value's mappings.</p>
<section class="informative">
<h3>Overview</h3>
<p>To create an <a>inverse context</a> for a given
<a>active context</a>, each <a>term</a> in the
<a>active context</a> is visited, ordered by length, shortest
first (ties are broken by choosing the lexicographically least
<a>term</a>). For each <a>term</a>, an entry is added to
the <a>inverse context</a> for each possible combination of
<a>container mapping</a> and <a>type mapping</a>
or <a>language mapping</a> that would legally match the
<a>term</a>. Illegal matches include differences between a
value's <a>type mapping</a> or <a>language mapping</a> and
that of the <a>term</a>. If a <a>term</a> has no
<a>container mapping</a>, <a>type mapping</a>, or
<a>language mapping</a> (or some combination of these), then it
will have an entry in the <a>inverse context</a> using the special
key <code>@none</code>. This allows the
<a href="#term-selection">Term Selection algorithm</a> to fall back
to choosing more generic <a>terms</a> when a more
specifically-matching <a>term</a> is not available for a particular
<a>IRI</a> and value combination.</p>
<p class="changed">Although normalizing <a>language tags</a> is optional,
the <a>inverse context</a> creates entries based on normalized
<a>language tags</a>, so that the proper term can be selected
regardless of representation.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes one required input: the <var>active context</var> that
the <a>inverse context</a> is being created for.</p>
<ol>
<li>Initialize <var>result</var> to an empty <a class="changed">map</a>.</li>
<li>Initialize <var>default language</var> to <code>@none</code>.
If the <var>active context</var> has a <a>default language</a>,
set <var>default language</var> to the <a>default language</a> from the <a>active context</a>
<span class="changed">normalized to lower case</span>.</li>
<li>For each key <a>term</a> and value <a>term definition</a> in
the <var>active context</var>, ordered by shortest <a>term</a>
first (breaking ties by choosing the lexicographically least
<a>term</a>):
<ol>
<li>If the <a>term definition</a> is <code>null</code>,
<a>term</a> cannot be selected during <a>compaction</a>,
so continue to the next <a>term</a>.</li>
<li>Initialize <var>container</var> to <code>@none</code>.
<span class="changed">
If the <a>container mapping</a> is not empty, set <var>container</var>
to the concatenation of all values of the <a>container mapping</a>
in lexicographical order
</span>.</li>
<li>Initialize <var>var</var> to the value of the <a>IRI mapping</a>
for the <a>term definition</a>.</li>
<li>If <var>var</var> is not an <a>entry</a> of <var>result</var>, add
an <a>entry</a> where the key is <var>var</var> and the value
is an empty <a class="changed">map</a> to <var>result</var>.</li>
<li>Reference the value associated with the <var>var</var> <a>entry</a> in
<var>result</var> using the variable <var>container map</var>.</li>
<li>If <var>container map</var> has no <var>container</var> <a>entry</a>,
create one and set its value to a new
<a class="changed">map</a> with <span class="changed">three</span> <a>entries</a>.
The first <a>entry</a> is <code>@language</code> and its value is a new empty
<a class="changed">map</a>, the second <a>entry</a> is <code>@type</code>
and its value is a new empty <a class="changed">map</a>,
<span class="changed">and the third <a>entry</a> is <code>@any</code>
and its value is a new <a>map</a> with the <a>entry</a>
<code>@none</code> set to the <a>term</a> being processed</span>.</li>
<li>Reference the value associated with the <var>container</var> <a>entry</a>
in <var>container map</var> using the variable <var>type/language map</var>.</li>
<li>Reference the value associated with the <code>@type</code>
<a>entry</a> in <var>type/language map</var> using the variable
<var>type map</var>.</li>
<li id="alg-inv-lang-map">Reference the value associated with the <code>@language</code>
<a>entry</a> in <var>type/language map</var> using the variable
<var>language map</var>.</li>
<li>If the <a>term definition</a> indicates that the <a>term</a>
represents a <a>reverse property</a>:
<ol>
<li>If <var>type map</var> does not have an <code>@reverse</code>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li class="changed">Otherwise, if <a>term definition</a> has a
<a>type mapping</a> which is <code>@none</code>:
<ol>
<li>If <var>language map</var> does not have an <code>@any</code>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
<li>If <var>type map</var> does not have an <code>@any</code>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li>Otherwise, if <a>term definition</a> has a
<a>type mapping</a>:
<ol>
<li>If <var>type map</var> does not have an <a>entry</a> corresponding
to the <a>type mapping</a> in <a>term definition</a>,
create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li id="alg-inv-lang-dir" class="changed">Otherwise, if <a>term definition</a> has both
a <a>language mapping</a> and a <a>direction mapping</a>:
<ol>
<li>Create a new variable <var>lang dir</var>.</li>
<li>If neither the <a>language mapping</a> nor the <a>direction mapping</a>
are `null`, set <var>lang dir</var> to the concatenation
of <a>language mapping</a> and <a>direction mapping</a>
separated by an underscore (`"_"`)
normalized to lower case.</li>
<li>Otherwise, if <a>language mapping</a> is not `null`,
set <var>lang dir</var> to the <a>language mapping</a>,
normalized to lower case.
<li>Otherwise, if <a>direction mapping</a> is not `null`,
set <var>lang dir</var> to <a>direction mapping</a>
preceded by an underscore (`"_"`).</li>
<li>Otherwise, set <var>lang dir</var> to `@null`.</li>
<li>If <var>language map</var> does not have a <var>lang dir</var>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li>Otherwise, if <a>term definition</a> has a
<a>language mapping</a> (might be <code>null</code>):
<ol>
<li>If the <a>language mapping</a> equals <code>null</code>,
set <var>language</var> to <code>@null</code>; otherwise
to the <a>language mapping</a>,
<span class="changed">normalized to lower case</span>.</li>
<li>If <var>language map</var> does not have a <var>language</var> <a>entry</a>,
create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li class="changed">Otherwise, if <a>term definition</a> has a
<a>direction mapping</a> (might be <code>null</code>):
<ol>
<li>If the <a>direction mapping</a> equals <code>null</code>,
set <var>direction</var> to <code>@none</code>; otherwise
to <a>direction mapping</a> preceded by an underscore (`"_"`).</li>
<li>If <var>language map</var> does not have a <var>direction</var> <a>entry</a>,
create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li class="changed">Otherwise, if <var>active context</var> has a
<a>default base direction</a>:
<ol>
<li>Initialize a variable <var>lang dir</var>
with the concatenation of <a>default language</a> and <a>default base direction</a>,
separate by an underscore (`"_"`),
normalized to lower case.</li>
<li>If <var>language map</var> does not have a <var>lang dir</var> <a>entry</a>,
create one and set its value to the <a>term</a>
being processed.</li>
<li>If <var>language map</var> does not have an `@none` <a>entry</a>,
create one and set its value to the <a>term</a>
being processed.</li>
<li>If <var>type map</var> does not have an `@none` <a>entry</a>,
create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
<li>Otherwise:
<ol>
<li>If <var>language map</var> does not have a <var>default language</var> <a>entry</a>
<span class="changed">(after being normalized to lower case)</span>,
create one and set its value to the <a>term</a>
being processed.</li>
<li>If <var>language map</var> does not have an <code>@none</code>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
<li>If <var>type map</var> does not have an <code>@none</code>
<a>entry</a>, create one and set its value to the <a>term</a>
being processed.</li>
</ol>
</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
<section><h2>Term Selection</h2>
<p>This algorithm, invoked via the <a href="#iri-compaction">IRI Compaction algorithm</a>,
makes use of an <a data-lt="active context">active context's</a>
<a>inverse context</a> to find the <a>term</a> that is best
used to <a>compact</a> an <a>IRI</a>. Other
information about a value associated with the <a>IRI</a> is given,
including which <a>container mapping</a>
and which <a>type mapping</a> or <a>language mapping</a> would
be best used to express the value.</p>
<section class="informative">
<h3>Overview</h3>
<p>The <a data-lt="inverse context">inverse context's</a> entry for
the <a>IRI</a> will be first searched according to the preferred
<a>container mapping</a>, in the order
that they are given. Amongst <a>terms</a> with a matching
<a>container mapping</a>, preference will be given to those
with a matching <a>type mapping</a> or <a>language mapping</a>,
over those without a <a>type mapping</a> or
<a>language mapping</a>. If there is no <a>term</a>
with a matching <a>container mapping</a> then the <a>term</a>
without a <a>container mapping</a> that matches the given
<a>type mapping</a> or <a>language mapping</a> is selected. If
there is still no selected <a>term</a>, then a <a>term</a>
with no <a>type mapping</a> or <a>language mapping</a> will
be selected if available. No <a>term</a> will be selected that
has a conflicting <a>type mapping</a> or <a>language mapping</a>.
Ties between <a>terms</a> that have the same
mappings are resolved by first choosing the shortest terms, and then by
choosing the lexicographically least term. Note that these ties are
resolved automatically because they were previously resolved when the
<a href="#inverse-context-creation">Inverse Context Creation algorithm</a>
was used to create the <a>inverse context</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>This algorithm has five required inputs. They are:
an <var class="changed">active context</var>,
a <a>keyword</a> or <a>IRI</a> <var>var</var>,
an <a>array</a> <var>containers</var> that represents an
ordered list of preferred <a>container mapping</a>,
a <a>string</a> <var>type/language</var> that indicates whether
to look for a <a>term</a> with a matching <a>type mapping</a>
or <a>language mapping</a>,
and an <a>array</a> representing an ordered list of <var>preferred values</var>
for the <a>type mapping</a> or <a>language mapping</a> to look for.</p>
<ol>
<li class="changed">If the <var>active context</var> has a `null`
<a data-lt='context-inverse'>inverse context</a>,
set <a data-lt='context-inverse'>inverse context</a> in <var>active context</var>
to the result of calling the
<a href="#inverse-context-creation">Inverse Context Creation algorithm</a>
using <var>active context</var>.</li>
<li>Initialize <var>inverse context</var> to the value of
<a data-lt='context-inverse'>inverse context</a> in <var>active context</var>.</li>
<li>Initialize <var>container map</var> to the value associated with
<var>var</var> in the <var>inverse context</var>.</li>
<li>For each item <var>container</var> in <var>containers</var>:
<ol>
<li>If <var>container</var> is not an <a>entry</a> of <var>container map</var>, then
there is no <a>term</a> with a matching
<a>container mapping</a> for it, so continue to the next
<var>container</var>.</li>
<li>Initialize <var>type/language map</var> to the value associated
with the <var>container</var> <a>entry</a> in <var>container map</var>.</li>
<li>Initialize <var>value map</var> to the value associated
with <var>type/language</var> <a>entry</a> in <var>type/language map</var>.</li>
<li>For each <var>item</var> in <var>preferred values</var>:
<ol>
<li>If <var>item</var> is not an <a>entry</a> of <var>value map</var>,
then there is no <a>term</a> with a matching
<a>type mapping</a> or <a>language mapping</a>,
so continue to the next <var>item</var>.</li>
<li>Otherwise, a matching term has been found, return the value
associated with the <var>item</var> <a>entry</a> in
<var>value map</var>.</li>
</ol>
</li>
</ol>
</li>
<li>No matching term has been found. Return <code>null</code>.</li>
</ol>
</section>
<section class="informative">
<h3>Examples</h3>
<p>The following examples are intended to illustrate how the term selection algorithm
behaves for different term definitions and values. It is not comprehensive, but
intended to illustrate different parts of the algorithm.</p>
<section>
<h4>Language Map Term</h4>
<p>If the term definition has <code>"@container": "@language"</code>, it will only match a
<a>value object</a> having no <code>@type</code>.</p>
<aside class="example" data-ignore
title="Term definition with language map">
<pre data-transform="updateExample">
</pre>
<p>The inverse context will contain the following:</p>
<pre data-transform="updateExample">
</pre>
</aside>
<aside class="example" data-ignore title="Language map term with language value">
<p>Given the <a>entry</a> <code>{"http://example.org/t": {"@value": "foo", "@type": "http:/example.org/type"}}</code>,
The algorithm will be invoked as follows:</p>
<dl>
<dt><var>containers</var></dt>
<dd><code>["@language", "@language@set", "@set", "@none", "@index", "@index@set"]</code></dd>
<dt><var>type/language</var></dt>
<dd><code>@language</code></dd>
<dt><var>preferred values</var></dt>
<dd><code>["en", "@none"]</code></dd>
</dl>
<p>The <var>value map</var> will be set to <code>{"@none": "t"}</code>,
as <var>preferred values</var> contains <code>"@none"</code>,
the algorithm returns <code>"t"</code> as the term to use for compaction.</p>
</aside>
</section>
<section>
<h4>Datatyped Term</h4>
<p>If the term definition has a datatype, it will only match a
<a>value object</a> having a matching datatype.</p>
<aside class="example" data-ignore
title="Term definition with datatype">
<pre data-transform="updateExample">
</pre>
<p>The inverse context will contain the following:</p>
<pre data-transform="updateExample">
</pre>
</aside>
<aside class="example" data-ignore title="Datatyped term with datatyped value">
<p>Given the <a>entry</a> <code>{"http://example.org/t": {"@value": "foo", "@type": "http:/example.org/type"}}</code>,
The algorithm will be invoked as follows:</p>
<dl>
<dt><var>containers</var></dt>
<dd><code>["@set", "@none", "@index", "@index@set"]</code></dd>
<dt><var>type/language</var></dt>
<dd><code>@type</code></dd>
<dt><var>preferred values</var></dt>
<dd><code>["http:/example.org/type", "@none"]</code></dd>
</dl>
<p>The <var>value map</var> will be set to <code>{"http:/example.org/type": "t"}</code>,
as <var>preferred values</var> contains <code>"http:/example.org/type"</code>,
the algorithm returns <code>"t"</code> as the term to use for compaction.</p>
</aside>
<aside class="example" data-ignore title="Datatyped term with simple value">
<p>Given the <a>entry</a> <code>{"http://example.org/t": {"@value": "foo"}}</code>,
The algorithm will be invoked as follows:</p>
<dl>
<dt><var>containers</var></dt>
<dd><code>["@set", "@none", "@index", "@index@set", "@language", "@language@set"]</code></dd>
<dt><var>type/language</var></dt>
<dd><code>@language</code></dd>
<dt><var>preferred values</var></dt>
<dd><code>["@null", "@none"]</code></dd>
</dl>
<p>The <var>value map</var> will be set to <code>{"@none": "t"}</code>,
as no key in <var>preferred values</var> matches a key in <var>value map</var>,
the algorithm returns <code>null</code> and no term is found.</p>
</aside>
<aside class="example" data-ignore title="Datatyped term with object value">
<p>Given the <a>entry</a> <code>{"http://example.org/t": {"@id": "http://example.org/id"}}</code>,
The algorithm will be invoked as follows:</p>
<dl>
<dt><var>containers</var></dt>
<dd><code>["@id", "@id@set", "@type", "@set@type", "@set", "@none", "@index", "@index@set"]</code></dd>
<dt><var>type/language</var></dt>
<dd><code>@type</code></dd>
<dt><var>preferred values</var></dt>
<dd><code>["@id", "@vocab", "@none"]</code></dd>
</dl>
<p>The <var>value map</var> will be set to <code>{"http:/example.org/type": "t"}</code>,
as no key in <var>preferred values</var> matches a key in <var>value map</var>,
the algorithm returns <code>null</code> and no term is found.</p>
</aside>
</section>
</section>
</section>
</section>
<section><h1>Expansion Algorithms</h1>
<p>The following sections describe algorithms for expanding JSON-LD
documents, IRIs and values.</p>
<section><h2>Expansion Algorithm</h2>
<p>This algorithm expands a JSON-LD document, such that all <a>context</a>
definitions are removed, all <a>terms</a> and
<a>compact IRIs</a> are expanded to
<a>IRIs</a>,
<a>blank node identifiers</a>, or
<a>keywords</a> and all
<a>JSON-LD values</a> are expressed in
<a>arrays</a> in <a>expanded form</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>Starting with its root <var>element</var>, we can process the
JSON-LD document recursively, until we have a fully
<a>expanded</a> <var>result</var>. When
<a>expanding</a> an <var>element</var>, we can treat
each one differently according to its type, in order to break down the
problem:</p>
<ol>
<li>If the <var>element</var> is <code>null</code>, there is nothing
to expand.</li>
<li>Otherwise, if <var>element</var> is a <a>scalar</a>, we expand it
according to the <a href="#value-expansion">Value Expansion algorithm</a>.</li>
<li>Otherwise, if the <var>element</var> is an <a>array</a>, then we expand
each of its items recursively and return them in a new
<a>array</a>.</li>
<li>Otherwise, <var>element</var> is a <a class="changed">map</a>. We expand
each of its <a>entries</a>, adding them to our <var>result</var>, and then we expand
each value for each <a>entry</a> recursively. Some of the <a>entry</a> keys will be
<a>terms</a> or
<a>compact IRIs</a> and others will be
<a>keywords</a> or simply ignored because
they do not have definitions in the <a>context</a>. Any
<a>IRIs</a> will be expanded using the
<a href="#iri-expansion">IRI Expansion algorithm</a>.
</li>
</ol>
<p>Finally, after ensuring <var>result</var> is in an <a>array</a>,
we return <var>result</var>.</p>
<p class="note">Although the <a data-cite="JSON-LD11#data-model">data model</a>,
based on [[RDF11-CONCEPTS]], does not support multiple unordered property values,
this algorithm does not remove duplicates that
may be found during expansion within an unordered <a>array</a>.
Other algorithms, such as <a href="#compaction-algorithm" class="sectionRef"></a>,
and <a href="#flattening-algorithm" class="sectionRef"></a>, do eliminate
duplicate values from unordered arrays.
A future version of this specification may be updated to remove duplicate
array values when the form a set.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes four required <span class="changed">and three optional</span> input variables.
The required inputs are an <var>active context</var>,
an <var>active property</var>, an <var>element</var> to be expanded,
<span class="changed">and a <var>base URL</var> associated with the {{RemoteDocument/documentUrl}} of the original
document to expand</span>.
<span class="changed">The optional inputs are the
{{JsonLdOptions/frameExpansion}}
flag allowing special forms of input used for <a data-cite="JSON-LD11-FRAMING#dfn-framing">frame expansion</a>,
the {{JsonLdOptions/ordered}} flag, used to order
<a>map entry</a> keys lexicographically, where noted,
and the <var>from map</var> flag, used to control reverting
previous <a>term definitions</a> in the <a>active context</a> associated with non-propagated <a>contexts</a>.
If not passed, the optional flags are set to <code>false</code></span>.</p>
<p class="changed">The algorithm also performs processing steps specific to expanding
a <a>JSON-LD Frame</a>. For a <a>frame</a>, the <code>@id</code> and
<code>@type</code> <a>entries</a> can accept an array of <a>IRIs</a> or
an empty <a>map</a>. The <a>entries</a> of a <a>value object</a> can also
accept an <a>array</a> of <a>strings</a>, or an empty <a>map</a>.
Framing also uses additional keyword <a>entries</a>:
(<code>@explicit</code>, <code>@default</code>,
<code>@embed</code>, <code>@explicit</code>, <code>@omitDefault</code>, or
<code>@requireAll</code>) which are preserved through expansion.
Special processing for a <a>JSON-LD Frame</a> is invoked when the
{{JsonLdOptions/frameExpansion}} flag is set to <code>true</code>.</p>
<p class="note">As mentioned in <a data-cite="JSON-LD11#terms">Terms</a> [[JSON-LD11]],
to avoid forward-compatibility issues, <a>terms</a> should not start with an
<code>@</code> character as future versions of JSON-LD may introduce
additional <a>keywords</a>.
This algorithm will treat such terms like any other term, i.e., they are ignored unless mapped to an <a>IRI</a>.
Implementations of this algorithm may consider providing a
runtime flag to show a warning if such terms are encountered.</p>
<p class="note">The use of empty <a>terms</a> (<code>""</code>) is not
allowed as not all programming languages are able to handle empty JSON keys.
Implementations of this algorithm may consider providing a
runtime flag to show a warning if such terms are encountered.</p>
<p class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD.
Implementations of this algorithm may consider providing a
runtime flag to show a warning if such terms are encountered.</p>
<ol>
<li>If <var>element</var> is <code>null</code>, return <code>null</code>.</li>
<li class="changed">If <var>active property</var> is <code>@default</code>,
initialize the {{JsonLdOptions/frameExpansion}} flag to <code>false</code>.</li>
<li id="alg-expand-property-scoped-context" class="changed">If <var>active property</var> has a <a>term definition</a> in <var>active context</var>
with a <a>local context</a>, initialize <var>property-scoped context</var> to that <a>local context</a>.</li>
<li>If <var>element</var> is a <a>scalar</a>,
<ol>
<li>If <var>active property</var> is <code>null</code> or <code>@graph</code>,
drop the free-floating <a>scalar</a> by returning <code>null</code>.</li>
<li class="changed">If <var>property-scoped context</var> is defined,
set <var>active context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var>, <var>property-scoped context</var> as <var>local context</var>,
and <var>base URL</var> from the <a>term definition</a> for <var>active property</var>
in <var>active context</var>.</li>
<li>Return the result of the
<a href="#value-expansion">Value Expansion algorithm</a>, passing the
<var>active context</var>, <var>active property</var>, and
<var>element</var> as <var>value</var>.</li>
</ol>
</li>
<li>If <var>element</var> is an <a>array</a>,
<ol>
<li>Initialize an empty array, <var>result</var>.</li>
<li>For each <var>item</var> in <var>element</var>:
<ol>
<li>Initialize <var>expanded item</var> to the result of using this
algorithm recursively, passing <var>active context</var>,
<var>active property</var>, <var>item</var> as <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">the {{JsonLdOptions/frameExpansion}}
{{JsonLdOptions/ordered}}</span>,
and <var>from map</var> flags.</li>
<li class="changed">If the <a>container mapping</a>
of <var>active property</var> includes <code>@list</code>,
and <var>expanded item</var> is an
<a>array</a>, set <var>expanded item</var> to a new
<a>map</a> containing the <a>entry</a>
<code>@list</code> where the value is the original
<var>expanded item</var>.</li>
<li>If <var>expanded item</var> is an <a>array</a>, append each
of its items to <var>result</var>. Otherwise, if
<var>expanded item</var> is not null, append it to <var>result</var>.</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</li>
<li>Otherwise <var>element</var> is a <a class="changed">map</a>.</li>
<li id="alg-expand-prev-context" class="changed">If <var>active context</var> has a <a>previous context</a>,
the <var>active context</var> is not propagated.
If <var>from map</var> is undefined or <code>false</code>,
and <var>element</var> does not contain an <a>entry</a> expanding to <code>@value</code>,
and <var>element</var> does not consist of a single <a>entry</a> expanding to <code>@id</code>
(where <a>entries</a> are <span class="changed"><a data-lt="IRI expanding">IRI expanded</a></span>,
set <var>active context</var> to <a>previous context</a> from <var>active context</var>,
as the scope of a term-scoped <a>context</a> does not apply when processing new <a>node objects</a>.</li>
<li id="alg-expand-property-scoped-context2" class="changed">If <var>property-scoped context</var> is defined,
set <var>active context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var>, <var>property-scoped context</var> as <var>local context</var>,
<var>base URL</var> from the <a>term definition</a> for <var>active property</var>,
in <var>active context</var>
and `true` for <var>override protected</var>.</li>
<li>If <var>element</var> contains the <a>entry</a> <code>@context</code>, set
<var>active context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var>, the value of the
<code>@context</code> <a>entry</a> as <var>local context</var>
<span class="changed">and <var>base URL</var></span>.</li>
<li class="changed">Initialize <var>type-scoped context</var> to <var>active context</var>.
This is used for expanding values that may be relevant to any previous
<a>type-scoped context</a>.</li>
<li class="changed">For each <var>key</var> and <var>value</var> in <var>element</var>
ordered lexicographically by <var>key</var>
where <var>key</var> <span class="changed"><a data-lt="IRI expanding">IRI expands</a></span> to <code>@type</code>:
<ol>
<li>Convert <var>value</var> into an <a>array</a>, if necessary.</li>
<li id="expand-type-scoped-context">For each <var>term</var> which is a value of <var>value</var> ordered lexicographically,
if <var>term</var> is a <a>string</a>,
and <var>term</var>'s <a>term definition</a> in <var>type-scoped context</var>
has a <a>local context</a>, set <var>active context</var> to the result
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var>,
the value of the
<var>term</var>'s <a>local context</a> as <var>local context</var>,
<var>base URL</var> from the <a>term definition</a> for <var>value</var>
in <var>active context</var>,
and `false` for <var>propagate</var>.</li>
</ol>
</li>
<li id="alg-expand-initialize-vars">Initialize two empty <a class="changed">maps</a>, <var>result</var>
<span class="changed">and <var>nests</var>.
Initialize <var>input type</var> to expansion of the last value of the first <a>entry</a> in <var>element</var>
expanding to <code>@type</code> (if any), ordering <a>entries</a> lexicographically by key</span>.
Both the key and value of the matched entry are
<span class="changed"><a data-lt="IRI expanding">IRI expanded</a></span>.
</li>
<li id="alg-expand-each-key-value">
For each <var>key</var> and <var>value</var> in <var>element</var>,
ordered lexicographically by <var>key</var> <span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>:
<ol>
<li>If <var>key</var> is <code>@context</code>, continue to
the next <var>key</var>.</li>
<li>Initialize <var>expanded property</var> to the result of
<span class="changed"><a>IRI expanding</a></span> <var>key</var>.</li>
<li>If <var>expanded property</var> is <code>null</code> or it neither
contains a colon (<code>:</code>) nor it is a <a>keyword</a>,
drop <var>key</var> by continuing to the next <var>key</var>.</li>
<li>If <var>expanded property</var> is a <a>keyword</a>:
<ol>
<li>If <var>active property</var> equals <code>@reverse</code>, an
<a data-link-for="JsonLdErrorCode">invalid reverse property map</a>
error has been detected and processing is aborted.</li>
<li>If <var>result</var> already has an <var>expanded property</var> <a>entry</a>,
<span class="changed">other than `@included` or `@type`
(unless <a>processing mode</a> is `json-ld-1.0`)</span>,
a <a data-link-for="JsonLdErrorCode">colliding keywords</a>
error has been detected and processing is aborted.</li>
<li>If <var>expanded property</var> is <code>@id</code>:
<ol>
<li>If <var>value</var> is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid @id value</a>
error has been detected and processing is aborted.
<span class="changed">
When the {{JsonLdOptions/frameExpansion}} flag is set, <var>value</var>
MAY be an empty <a>map</a>, or an <a>array</a> of one
or more <a>strings</a>.</span></li>
<li>Otherwise,
set <var>expanded value</var> to the result of
<span class="changed"><a>IRI expanding</a></span> <var>value</var>
using <code>true</code> for <var>document relative</var>
and `false` for <var>vocab</var>.
<span class="changed">
When the {{JsonLdOptions/frameExpansion}} flag is set, <var>expanded value</var> will be
an <a>array</a> of one or more of the values, with <a>string</a>
values expanded using the <a
href="#iri-expansion">IRI Expansion algorithm</a> as above.</span></li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@type</code>:
<ol>
<li>If <var>value</var>
is neither a <a>string</a> nor an <a>array</a> of
<a>strings</a>, an
<a data-link-for="JsonLdErrorCode">invalid type value</a>
error has been detected and processing is aborted.
<span class="changed">
When the {{JsonLdOptions/frameExpansion}} flag is set, <var>value</var>
MAY be an empty <a>map</a>, or a <a>default object</a>
where the value of `@default` is restricted to be
an <a>IRI</a>.
All other values mean that <a data-link-for="JsonLdErrorCode">invalid type value</a>
error has been detected and processing is aborted.</span></li>
<li class="changed">If <var>value</var>
is an empty <a>map</a>, set <var>expanded value</var> to <var>value</var>.</li>
<li class="changed">Otherwise, if <var>value</var>
is a <a>default object</a>, set <var>expanded value</var> to
a new <a>default object</a> with the value of `@default` set
to the result of
<span class="changed"><a>IRI expanding</a></span> <var>value</var>
using <var class="changed">type-scoped context</var> for <var>active context</var>,
and <code>true</code> for <var>document relative</var>.</li>
<li id="expansion-tsc">Otherwise,
set <var>expanded value</var> to the result of
<span class="changed"><a>IRI expanding</a></span>
each of its values
using <var class="changed">type-scoped context</var> for <var>active context</var>,
and <code>true</code> for <var>document relative</var>.
</li>
<li><span class="changed">If <var>result</var> already has an entry for `@type`,
prepend the value of `@type` in <var>result</var> to <var>expanded value</var>,
transforming it into an <a>array</a>, if necessary.</span>
<div class="note">
No transformation from a <a>string</a> <var>value</var> to an <a>array</a>
<var>expanded value</var> is implied, and the form or <var>value</var>
should be preserved in <var>expanded value</var>.
</div></li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@graph</code>, set
<var>expanded value</var> to the result of using this algorithm
recursively passing <var>active context</var>, <code>@graph</code>
for <var>active property</var>, <var>value</var> for <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>,
<span class="changed">
ensuring that <var>expanded value</var> is an <a>array</a> of one or more <a>maps</a></span>.</li>
<li class="changed">If <var>expanded property</var> is `@included`:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`,
continue with the next <var>key</var> from <var>element</var>.</li>
<li id="alg-expand-included">Set <var>expanded value</var> to the result of using
this algorithm recursively passing <var>active context</var>,
`null` for <var>active property</var>,
<var>value</var> for <var>element</var>,
<var>base URL</var>,
and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags,
ensuring that the result is an <a>array</a>.</li>
<li>If any element of <var>expanded value</var> is not a <a>node object</a>,
an <a data-link-for="JsonLdErrorCode">invalid @included value</a>
error has been detected and processing is aborted.</li>
<li>If <var>result</var> already has an entry for `@included`,
prepend the value of `@included` in <var>result</var> to <var>expanded value</var>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@value</code>:
<ol>
<li id="alg-expand-type-json" class="changed">If
<var>input type</var> is <code>@json</code>,
set <var>expanded value</var> to <var>value</var>.
If <a>processing mode</a> is `json-ld-1.0`,
an <a data-link-for="JsonLdErrorCode">invalid value object value</a>
error has been detected and processing is aborted.</li>
<li>Otherwise, if <var>value</var> is not a <a>scalar</a> or <code>null</code>,
an <a data-link-for="JsonLdErrorCode">invalid value object value</a>
error has been detected and processing is aborted.
<span class="changed">When the {{JsonLdOptions/frameExpansion}} flag is set, <var>value</var>
MAY be an empty <a>map</a> or an array of
<a>scalar</a> values.</span></li>
<li>Otherwise, set <var>expanded value</var> to <var>value</var>.
<span class="changed">When the {{JsonLdOptions/frameExpansion}} flag is set,
<var>expanded value</var> will be an
<a>array</a> of one or more <a>string</a> values
or an <a>array</a> containing an empty <a>map</a>.</span>
</li>
<li>If <var>expanded value</var>
is <code>null</code>, set the <code>@value</code>
<a>entry</a> of <var>result</var> to <code>null</code> and continue with the
next <var>key</var> from <var>element</var>. Null values need to be preserved
in this case as the meaning of an <code>@type</code> <a>entry</a> depends
on the existence of an <code>@value</code> <a>entry</a>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@language</code>:
<ol>
<li>If <var>value</var> is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid language-tagged string</a>
error has been detected and processing is aborted.
<span class="changed">When the {{JsonLdOptions/frameExpansion}} flag is set, <var>value</var>
MAY be an empty <a>map</a> or an array of zero or more
<a>strings</a></span>.</li>
<li><span class="changed">
Otherwise, set <var>expanded value</var> to <var>value</var>.
If <var>value</var> is not <a>well-formed</a> according to
<a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of [[BCP47]],
processors SHOULD issue a warning.
When the {{JsonLdOptions/frameExpansion}} flag is set,
<var>expanded value</var> will be an
<a>array</a> of one or more <a>string</a> values
or an <a>array</a> containing an empty <a>map</a>.</span>
<div class="changed note">Processors MAY normalize <a>language tags</a> to lower case.</div>
</li>
</ol>
</li>
<li class="changed">If <var>expanded property</var> is <code>@direction</code>:
<ol>
<li>If <a>processing mode</a> is `json-ld-1.0`,
continue with the next <var>key</var> from <var>element</var>.</li>
<li>If <var>value</var> is neither `"ltr"` nor `"rtl"`, an
<a data-link-for="JsonLdErrorCode">invalid base direction</a>
error has been detected and processing is aborted.
When the {{JsonLdOptions/frameExpansion}} flag is set, <var>value</var>
MAY be an empty <a>map</a> or an array of zero or more
<a>strings</a>.</li>
<li>Otherwise, set <var>expanded value</var> to <var>value</var>.
When the {{JsonLdOptions/frameExpansion}} flag is set,
<var>expanded value</var> will be an
<a>array</a> of one or more <a>string</a> values
or an <a>array</a> containing an empty <a>map</a>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@index</code>:
<ol>
<li>If <var>value</var> is not a <a>string</a>, an
<a data-link-for="JsonLdErrorCode">invalid @index value</a>
error has been detected and processing is aborted.</li>
<li>Otherwise,
set <var>expanded value</var> to <var>value</var>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@list</code>:
<ol>
<li>If <var>active property</var> is <code>null</code> or
<code>@graph</code>, continue with the next <var>key</var>
from <var>element</var> to remove the free-floating list.</li>
<li id="alg-expand-list-value">Otherwise, initialize <var>expanded value</var> to the result of using
this algorithm recursively passing <var>active context</var>,
<var>active property</var>, <var>value</var> for <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags,
ensuring that the result is an <a>array</a>.</span>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@set</code>, set
<var>expanded value</var> to the result of using this algorithm
recursively, passing <var>active context</var>,
<var>active property</var>, <var>value</var> for <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>If <var>expanded property</var> is <code>@reverse</code>:
<ol>
<li>If <var>value</var> is not a <a class="changed">map</a>, an
<a data-link-for="JsonLdErrorCode">invalid @reverse value</a>
error has been detected and processing is aborted.</li>
<li>Otherwise initialize <var>expanded value</var> to the result of using this
algorithm recursively, passing <var>active context</var>,
<code>@reverse</code> as <var>active property</var>,
<var>value</var> as <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>If <var>expanded value</var> contains an <code>@reverse</code> <a>entry</a>,
i.e., <a>properties</a> that are reversed twice, execute for each of its
<var>property</var> and <var>item</var> the following steps:
<ol>
<li class="changed">Use <a>add value</a> to add <var>item</var>
to the <var>property</var> <a>entry</a> in <var>result</var>
using `true` for <var>as array</var>.</li>
</ol>
</li>
<li>If <var>expanded value</var> contains an <a>entry</a> other than <code>@reverse</code>:
<ol>
<li class="changed">Set <var>reverse map</var> to the value
of the `@reverse` entry in <var>result</var>,
initializing it to an empty <a>map</a>, if necessary.</li>
<li>For each <var>property</var> and <var>items</var> in <var>expanded value</var>
other than <code>@reverse</code>:
<ol>
<li>For each <var>item</var> in <var>items</var>:
<ol>
<li>If <var>item</var> is a <a>value object</a> or <a>list object</a>, an
<a data-link-for="JsonLdErrorCode">invalid reverse property value</a>
has been detected and processing is aborted.</li>
<li class="changed">Use <a>add value</a> to add <var>item</var>
to the <var>property</var> <a>entry</a> in <var>reverse map</var>
using `true` for <var>as array</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>Continue with the next <var>key</var> from <var>element</var>.</li>
</ol>
</li>
<li class="changed">If <var>expanded property</var> is <code>@nest</code>,
add <var>key</var> to <var>nests</var>, initializing it to an empty <a>array</a>,
if necessary.
Continue with the next <var>key</var> from <var>element</var>.</li>
<li class="changed">When the {{JsonLdOptions/frameExpansion}} flag is set,
if <var>expanded property</var> is any other
framing keyword (<code>@default</code>,
<code>@embed</code>, <code>@explicit</code>, <code>@omitDefault</code>, or
<code>@requireAll</code>),
set <var>expanded value</var> to the result of performing the
<a href="#expansion-algorithm">Expansion Algorithm</a>
recursively, passing <var>active context</var>,
<var>active property</var>, <var>value</var> for <var>element</var>,
<var>base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li id="alg-expand-expanded-property-to-result">Unless <var>expanded value</var> is <code>null</code>,
<span class="changed"><var>expanded property</var> is <code>@value</code>,
and <var>input type</var> is not <code>@json</code>,</span>
set the <var>expanded property</var> <a>entry</a> of <var>result</var> to
<var>expanded value</var>.</li>
<li>Continue with the next <var>key</var> from <var>element</var>.</li>
</ol>
</li>
<li>Initialize <var>container mapping</var> to <var>key</var>'s <a>container mapping</a> in
<var>active context</var>.</li>
<li class="changed">If <var>key</var>'s <a>term definition</a> in <var>active context</var>
has a <a>type mapping</a> of <code>@json</code>,
set <var>expanded value</var> to a new <a>map</a>, set the <a>entry</a>
<code>@value</code> to <var>value</var>, and set the entry <code>@type</code> to <code>@json</code>.</li>
<li>Otherwise, if <var>container mapping</var> <span class="changed">includes</span> <code>@language</code> and
<var>value</var> is a <a class="changed">map</a> then <var>value</var>
is expanded from a <a>language map</a>
as follows:
<ol>
<li>Initialize <var>expanded value</var> to an empty
<a>array</a>.</li>
<li class="changed">Initialize <var>direction</var> to the <a>default base direction</a> from <var>active context</var>.</li>
<li class="changed">If <var>key</var>'s <a>term definition</a> in <a>active context</a>
has a <a>direction mapping</a>,
update <var>direction</var> with that value.</li>
<li>For each key-value pair <var>language</var>-<var>language value</var>
in <var>value</var>, ordered lexicographically by <var>language</var> <span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>:
<ol>
<li>If <var>language value</var> is not an <a>array</a>
set <var>language value</var> to an <a>array</a> containing only
<var>language value</var>.</li>
<li>For each <var>item</var> in <var>language value</var>:
<ol>
<li class="changed">If <var>item</var> is `null`,
continue to the next entry in <var>language value</var>.</li>
<li><var>item</var> must be a <a>string</a>,
otherwise an
<a data-link-for="JsonLdErrorCode">invalid language map value</a>
error has been detected and processing is aborted.</li>
<li>Initialize a new <a class="changed">map</a> <var>v</var>
consisting of two
key-value pairs: (<code>@value</code>-<var>item</var>)
and (<code>@language</code>-<var>language</var>).
<span class="changed">If <var>item</var> is neither `@none` nor <a>well-formed</a> according to
<a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of [[BCP47]],
processors SHOULD issue a warning.</span>
<div class="changed note">Processors MAY normalize <a>language tags</a> to lower case.</div>
</li>
<li class="changed">If <var>language</var> is <code>@none</code>,
or expands to <code>@none</code>, remove <code>@language</code> from <var>v</var>.</li>
<li class="changed">
If <var>direction</var> is not `null`,
add an <a>entry</a> for `@direction` to <var>v</var> with <var>direction</var>.</li>
<li>Append <var>v</var> to <var>expanded value</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>Otherwise, if <var>container mapping</var>
<span class="changed">includes</span> <code>@index</code>,
<span class="changed"><code>@type</code>, or <code>@id</code></span> and
<var>value</var> is a <a class="changed">map</a> then <var>value</var>
is expanded from an map as follows:
<ol>
<li>Initialize <var>expanded value</var> to an empty <a>array</a>.</li>
<li class="changed">Initialize <var>index key</var> to
the <var>key</var>'s <a>index mapping</a> in <a>active context</a>,
or <code>@index</code>, if it does not exist.</li>
<li>For each key-value pair <var>index</var>-<var>index value</var>
in <var>value</var>, ordered lexicographically by <var>index</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>:
<ol>
<li class="changed">If <var>container mapping</var> includes `@id` or `@type`,
initialize <var>map context</var> to the <a>previous context</a>
from <var>active context</var> if it exists,
otherwise, set <var>map context</var> to <var>active context</var>.</li>
<li class="changed">If <var>container mapping</var> includes <code>@type</code>
and <var>index</var>'s <a>term definition</a> in
<var>map context</var> has a <a>local context</a>, update
<var>map context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>map context</var> as <var>active context</var>
the value of the <var>index</var>'s <a>local context</a>
as <var>local context</var>
and <var>base URL</var> from the <a>term definition</a> for <var>index</var>
in <var>map context</var>.</li>
<li>Otherwise, set <var>map context</var> to <var>active context</var>.</li>
<li>Initialize <var>expanded index</var> to the result of
<span class="changed"><a>IRI expanding</a></span> <var>index</var>.</li>
<li>If <var>index value</var> is not an <a>array</a>
set <var>index value</var> to an <a>array</a> containing only
<var>index value</var>.</li>
<li id="alg-expand-index-value">Initialize <var>index value</var> to the result of
using this algorithm recursively, passing
<var class="changed">map context</var> as <var>active context</var>,
<var>key</var> as <var>active property</var>,
<var>index value</var> as <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">`true` for <var>from map</var>,
and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>For each <var>item</var> in <var>index value</var>:
<ol class="algorithm changed">
<li id="alg-expand-container-index-graph">If <var>container mapping</var> includes <code>@graph</code>,
<span class="changed">and <var>item</var> is not a <a>graph object</a>,</span>
set <var>item</var> to a new <a>map</a> containing the key-value pair
<code>@graph</code>-<var>item</var>,
ensuring that the value is represented using an <a>array</a>.</li>
<li id="alg-expand-container-index-not-index" class="changed">If <var>container mapping</var> includes <code>@index</code>,
<var>index key</var> is not <code>@index</code>,
and <var>expanded index</var> is not <code>@none</code>:
<ol>
<li>Initialize <var>re-expanded index</var> to the result of calling
the <a href="#value-expansion">Value Expansion algorithm</a>,
passing the <var>active context</var>,
<var>index key</var> as <var>active property</var>,
and <var>index</var> as <var>value</var>.</li>
<li>Initialize <var>expanded index key</var> to the result of
<span class="changed"><a>IRI expanding</a></span> <var>index key</var>.</li>
<li>Initialize <var>index property values</var> to
an <a>array</a> consisting of <var>re-expanded index</var> followed
by the existing values of
the concatenation of <var>expanded index key</var> in <var>item</var>,
if any.</li>
<li>Add the key-value pair (<var>expanded index key</var>-<var>index property values</var>)
to <var>item</var>.</li>
<li>If <var>item</var> is a value object,
it MUST NOT contain any extra properties;
an <a data-link-for="JsonLdErrorCode">invalid value object</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li>Otherwise, if <var>container mapping</var> includes <code>@index</code>,
<var>item</var> does not have an <a>entry</a> <code>@index</code>,
and <var>expanded index</var> is not <code>@none</code>,
add the key-value pair (<code>@index</code>-<var>index</var>) to <var>item</var>.</li>
<li>Otherwise, if <var>container mapping</var> includes <code>@id</code>
<var>item</var> does not have the <a>entry</a> <code>@id</code>,
and <var>expanded index</var> is not `@none`,
add the key-value pair (<code>@id</code>-<var>expanded index</var>) to <var>item</var>,
where <var>expanded index</var> is set to the result of
<span class="changed"><a>IRI expanding</a></span><var>index</var>
using `true` for <var>document relative</var>
and `false` for <var>vocab</var>.</li>
<li id="alg-expand-container-mapping-type">Otherwise, if <var>container mapping</var> includes <code>@type</code>
and <var>expanded index</var> is not <code>@none</code>,
initialize <var>types</var> to a new <a>array</a>
consisting of <var>expanded index</var> followed by any existing
values of <code>@type</code> in <var>item</var>.
Add the key-value pair (<code>@type</code>-<var>types</var>) to <var>item</var>.</li>
<li>Append <var>item</var> to <var>expanded value</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>Otherwise, initialize <var>expanded value</var> to the result of
using this algorithm recursively, passing <var>active context</var>,
<var>key</var> for <var>active property</var>, <var>value</var> for <var>element</var>,
<var class="changed">base URL</var>,
<span class="changed">and the {{JsonLdOptions/frameExpansion}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>If <var>expanded value</var> is <code>null</code>, ignore <var>key</var>
by continuing to the next <var>key</var> from <var>element</var>.</li>
<li>If <var>container mapping</var> <span class="changed">includes</span> <code>@list</code> and
<var>expanded value</var> is not already a <a>list object</a>,
convert <var>expanded value</var> to a <a>list object</a>
by first setting it to an <a>array</a> containing only
<var>expanded value</var> if it is not already an <a>array</a>,
and then by setting it to a <a class="changed">map</a> containing
the key-value pair <code>@list</code>-<var>expanded value</var>.</li>
<li class="changed">If <var>container mapping</var> <span>includes</span>
<code>@graph</code>,
and includes neither <code>@id</code> nor <code>@index</code>,
convert <var>expanded value</var> into an <a>array</a>, if necessary,
then convert each value <var>ev</var> in <var>expanded value</var> into a
<a>graph object</a>:
<ol>
<li>Convert <var>ev</var> into
a <a>graph object</a> by creating a <a>map</a> containing the key-value
pair <code>@graph</code>-<var>ev</var>
where <var>ev</var> is represented as an <a>array</a>.
<div class="note">This may lead to a <a>graph object</a> including another <a>graph object</a>,
if <var>ev</var> was already in the form of a <a>graph object</a>.</div></li>
</ol>
</li>
<li>If the <a>term definition</a> associated to
<var>key</var> indicates that it is a <a>reverse property</a>
<ol>
<li>If <var>result</var> has no <code>@reverse</code> <a>entry</a>, create
one and initialize its value to an empty <a class="changed">map</a>.</li>
<li>Reference the value of the <code>@reverse</code> <a>entry</a> in <var>result</var>
using the variable <var>reverse map</var>.</li>
<li>If <var>expanded value</var> is not an <a>array</a>, set
it to an <a>array</a> containing <var>expanded value</var>.</li>
<li>For each <var>item</var> in <var>expanded value</var>
<ol>
<li>If <var>item</var> is a <a>value object</a> or <a>list object</a>, an
<a data-link-for="JsonLdErrorCode">invalid reverse property value</a>
has been detected and processing is aborted.</li>
<li>If <var>reverse map</var> has no <var>expanded property</var> <a>entry</a>,
create one and initialize its value to an empty <a>array</a>.</li>
<li class="changed">Use <a>add value</a> to add <var>item</var>
to the <var>expanded property</var> <a>entry</a> in <var>reverse map</var>
using `true` for <var>as array</var>.</li>
</ol>
</li>
</ol>
</li>
<li>Otherwise, <var>key</var> is not a <a>reverse property</a>
<span class="changed">use <a>add value</a> to add <var>expanded value</var>
to the <var>expanded property</var> <a>entry</a> in <var>result</var>
using `true` for <var>as array</var>.</span>
</li>
</ol>
</li>
<li id="alg-expand-resolve-nest" class="changed">For each key <var>nesting-key</var> in <var>nests</var>,
ordered lexicographically if {{JsonLdOptions/ordered}} is <code>true</code>:
<ol>
<li>Initialize <var>nested values</var> to the value of <var>nesting-key</var>
in <var>element</var>, ensuring that it is an <a>array</a>.</li>
<li>For each <var>nested value</var> in <var>nested values</var>:
<ol>
<li>If <var>nested value</var> is not a <a>map</a>, or any key within
<var>nested value</var> expands to <code>@value</code>, an
<a data-link-for="JsonLdErrorCode">invalid @nest value</a> error
has been detected and processing is aborted.</li>
<li>Recursively repeat steps
<a href="#alg-expand-property-scoped-context">3</a>,
<a href="#alg-expand-property-scoped-context2">8</a>,
<a href="#alg-expand-each-key-value">13</a>,
and <a href="#alg-expand-resolve-nest">14</a>
using <var>nesting-key</var> for <var>active property</var>, and
<var>nested value</var> for <var>element</var>.
<div class="note">Steps <a href="#alg-expand-property-scoped-context">3</a>
and <a href="#alg-expand-property-scoped-context2">8</a>
may update the <var>active context</var> based on a
property-scoped context associated with <var>nesting-key</var>.
Updates to <var>active context</var> are restricted to the
recursive operation, and do not propogate to subsequent iterations
on <var>nested values</var> and <var>nesting-key</var>.</div>
<div class="note">By invoking steps <a href="#alg-expand-each-key-value">13</a>
and <a href="#alg-expand-resolve-nest">14</a> on <var>nested value</var>
we are able to unfold arbitrary levels of nesting, with results being merged into
<var>result</var>.
Step <a href="#alg-expand-each-key-value">13</a> iterates through each
entry in <var>nested value</var> and expands it, while collecting new
<var>nested values</var> found at each level, until all nesting has been extracted.</div>
</li>
</ol>
</li>
</ol>
</li>
<li>If <var>result</var> contains the <a>entry</a> <code>@value</code>:
<ol>
<li>The <var>result</var> must not contain any <a>entries</a> other than
<code class="changed">@direction</code>,
`@index`,
`@language`,
`@type`,
and `@value`.
It must not contain an `@type` <a>entry</a> if it contains either `@language` or `@direction` <a>entries</a>.
Otherwise, an <a data-link-for="JsonLdErrorCode">invalid value object</a>
error has been detected and processing is aborted.</li>
<li class="changed">If the <var>result</var>'s <code>@type</code> <a>entry</a>
is <code>@json</code>, then the <code>@value</code> <a>entry</a> may
contain any value, and is treated as a <a>JSON literal</a>.</li>
<li id="alg-expand-null-value">Otherwise, if the value of <var>result</var>'s <code>@value</code> <a>entry</a> is
<code>null</code>, or an empty <a>array</a>, return <code>null</code>.</li>
<li>Otherwise, if the value of <var>result</var>'s <code>@value</code> <a>entry</a>
is not a <a>string</a> and <var>result</var> contains the <a>entry</a>
<code>@language</code>, an
<a data-link-for="JsonLdErrorCode">invalid language-tagged value</a>
error has been detected (only <a>strings</a>
can be language-tagged) and processing is aborted.</li>
<li>Otherwise, if the <var>result</var> has an <code>@type</code> <a>entry</a>
and its value is not an <a>IRI</a>, an
<a data-link-for="JsonLdErrorCode">invalid typed value</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
<li>Otherwise, if <var>result</var> contains the <a>entry</a> <code>@type</code>
and its associated value is not an <a>array</a>, set it to
an <a>array</a> containing only the associated value.</li>
<li>Otherwise, if <var>result</var> contains the <a>entry</a> <code>@set</code>
or <code>@list</code>:
<ol>
<li>The <var>result</var> must contain at most one other <a>entry</a>
which must be <code>@index</code>. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid set or list object</a>
error has been detected and processing is aborted.</li>
<li>If <var>result</var> contains the <a>entry</a> <code>@set</code>, then
set <var>result</var> to the <a data-lt="entry">entry's</a> associated value.</li>
</ol>
</li>
<li id="alg-expand-only-language">If <var>result</var> is a <a>map</a> that contains only the <a>entry</a>
<code>@language</code>, <span class="changed">return</span> <code>null</code>.</li>
<li>If <var>active property</var> is <code>null</code> or <code>@graph</code>,
drop free-floating values as follows:
<ol>
<li>If <var>result</var> is a <a>map</a> which is empty,
or contains only the <a>entries</a> <code>@value</code> or <code>@list</code>,
set <var>result</var> to <code>null</code>.</li>
<li>Otherwise, if <var>result</var> is a <a class="changed">map</a> whose only
<a>entry</a> is <code>@id</code>, set <var>result</var> to <code>null</code>.
<span class="changed">
When the {{JsonLdOptions/frameExpansion}} flag is set, a <a>map</a>
containing only the <code>@id</code> <a>entry</a> is retained.</span></li>
</ol>
</li>
<li id="alg-expand-return">Return <var>result</var>.</li>
</ol>
</section>
</section>
<section><h2>IRI Expansion</h2>
<p>In JSON-LD documents, some keys and values may represent
<a>IRIs</a>. This section defines an algorithm for
transforming a <a>string</a> that represents an <a>IRI</a> into
an absolute <a>IRI</a> or <a>blank node identifier</a>.
It also covers transforming <a>keyword aliases</a>
into <a>keywords</a>.</p>
<p><a>IRI</a> expansion may occur during context processing or during
any of the other JSON-LD algorithms. If IRI expansion occurs during context
processing, then the <a>local context</a> and its related <var>defined</var>
map from the <a href="#context-processing-algorithm">Context Processing algorithm</a>
are passed to this algorithm. This allows for <a>term definition</a>
dependencies to be processed via the
<a href="#create-term-definition">Create Term Definition algorithm</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>In order to expand <var>value</var> to an <a>IRI</a>, we must
first determine if it is <code>null</code>, a <a>term</a>, a
<a>keyword alias</a>, or some form of <a>IRI</a>. Based on what
we find, we handle the specific kind of expansion; for example, we expand
a <a>keyword alias</a> to a <a>keyword</a> and a <a>term</a>
to an <a>IRI</a> according to its <a>IRI mapping</a>
in the <a>active context</a>. While inspecting <var>value</var> we
may also find that we need to create <a>term definition</a>
dependencies because we're running this algorithm during context processing.
We can tell whether or not we're running during context processing by
checking <a>local context</a> against <code>null</code>.
We know we need to create a <a>term definition</a> in the
<a>active context</a> when <var>value</var> is
an <a>entry</a> in the <a>local context</a> and the <var>defined</var> map
does not have an <a>entry</a> for <var>value</var> with an associated value of
<code>true</code>. The <var>defined</var> map is used during
<a href="#context-processing-algorithm">Context Processing</a> to keep track of
which <a>terms</a> have already been defined or are
in the process of being defined. We create a
<a>term definition</a> by using the
<a href="#create-term-definition">Create Term Definition algorithm</a>.</p>
<p class="changed note">Values that have the form of a keyword,
but are not keywords (i.e., they begin with `"@"`) do not
map to any value, as they are reserved for future use.
The algorithm returns `null`, so that they will be ignored when encountered.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes two required and four optional input variables. The
required inputs are an <var>active context</var> and a <var>value</var>
to be expanded. The optional inputs are two flags,
<var>document relative</var> and <var>vocab</var>, that specifying
whether <var>value</var> can be interpreted as a <a>relative IRI reference</a>
against the document's base <a>IRI</a> or the
<a data-lt="active context">active context's</a>
<a>vocabulary mapping</a>, respectively, and
a <var>local context</var> and a map <var>defined</var> to be used when
this algorithm is used during <a href="#context-processing-algorithm">Context Processing</a>.
If not passed, the two flags are set to <code>false</code> and
<var>local context</var> and <var>defined</var> are initialized to <code>null</code>.</p>
<ol>
<li>If <var>value</var> is a <a>keyword</a> or <code>null</code>,
return <var>value</var> as is.</li>
<li class="changed">
If <var>value</var> has the form of a keyword
(i.e., it matches the ABNF rule `"@"1*ALPHA` from [[RFC5234]]),
a processor SHOULD generate a warning and return `null`.</li>
<li>If <var>local context</var> is not <code>null</code>, it contains
an <a>entry</a> with a key that equals <var>value</var>, and the value of the <a>entry</a>
for <var>value</var> in <var>defined</var> is not <code>true</code>,
invoke the <a href="#create-term-definition">Create Term Definition algorithm</a>,
passing <var>active context</var>, <var>local context</var>,
<var>value</var> as <var>term</var>, and <var>defined</var>. This will ensure that
a <a>term definition</a> is created for <var>value</var> in
<var>active context</var> during <a href="#context-processing-algorithm">Context Processing</a>.
</li>
<li class="changed">If <var>active context</var> has a <a>term definition</a> for
<var>value</var>, and the associated <a>IRI mapping</a> is a <a>keyword</a>,
return that <a>keyword</a>.</li>
<li>If <var>vocab</var> is <code>true</code> and the
<var>active context</var> has a <a>term definition</a> for
<var>value</var>, return the associated <a>IRI mapping</a>.</li>
<li>If <var>value</var> contains a colon (`:`)
<span class="changed">anywhere after the first character</span>,
it is either
an <a>IRI</a>, a <a>compact IRI</a>, or a
<a>blank node identifier</a>:
<ol>
<li>Split <var>value</var> into a <var>prefix</var> and <var>suffix</var>
at the first occurrence of a colon (<code>:</code>).</li>
<li>If <var>prefix</var> is underscore (<code>_</code>)
or <var>suffix</var> begins with double-forward-slash
(<code>//</code>), return <var>value</var> as it is already an
<a>IRI</a> or a <a>blank node identifier</a>.</li>
<li>If <var>local context</var> is not <code>null</code>, it
contains a <var>prefix</var> <a>entry</a>, and the value
of the <var>prefix</var> <a>entry</a> in <var>defined</var>
is not <code>true</code>, invoke the
<a href="#create-term-definition">Create Term Definition algorithm</a>,
passing <var>active context</var>,
<var>local context</var>, <var>prefix</var> as <var>term</var>,
and <var>defined</var>. This will ensure that a
<a>term definition</a> is created for <a>prefix</a>
in <var>active context</var> during
<a href="#context-processing-algorithm">Context Processing</a>.</li>
<li>If <var>active context</var> contains a <a>term definition</a>
for <var>prefix</var>
<span class="changed">having a non-<code>null</code> <a>IRI mapping</a>
and the <a>prefix flag</a> of the <a>term definition</a> is <code>true</code></span>,
return the result of concatenating the <a>IRI mapping</a>
associated with <var>prefix</var> and <var>suffix</var>.</li>
<li><span class="changed">If <var>value</var> has the <a href="https://tools.ietf.org/html/rfc3987#section-2.2">form</a> of an <a>IRI</a></span>,
return <var>value</var>.</li>
</ol>
</li>
<li>If <var>vocab</var> is <code>true</code>, and
<var>active context</var> has a <a>vocabulary mapping</a>,
return the result of concatenating the <a>vocabulary mapping</a>
with <var>value</var>.</li>
<li>Otherwise, if <var>document relative</var> is <code>true</code>
set <var>value</var> to the result of resolving <var>value</var> against
the <a class="changed" data-lt="context-base-iri">base IRI</a> from <var>active context</var>. Only the basic algorithm in
<a data-cite="RFC3986#section-5.2">section 5.2</a>
of [[RFC3986]] is used; neither
<a data-cite="RFC3986#section-6.2.2">Syntax-Based Normalization</a> nor
<a data-cite="RFC3986#section-6.2.3">Scheme-Based Normalization</a>
are performed. Characters additionally allowed in IRI references are treated
in the same way that unreserved characters are treated in URI references, per
<a data-cite="RFC3987#section-6.5">section 6.5</a>
of [[RFC3987]].</li>
<li>Return <var>value</var> as is.</li>
</ol>
</section>
</section>
<section><h2>Value Expansion</h2>
<p>Some values in JSON-LD can be expressed in a
<a>compact form</a>. These values are required
to be <a>expanded</a> at times when processing
JSON-LD documents. A value is said to be in <dfn>expanded form</dfn>
after the application of this algorithm.</p>
<section class="informative">
<h3>Overview</h3>
<p>If <a>active property</a> has a <a>type mapping</a> in the
<a>active context</a> set to <code>@id</code> or <code>@vocab</code>,
<span class="changed">and the value is a <a>string</a>,</span>
a <a class="changed">map</a> with a single <a>entry</a> <code>@id</code> whose
value is the result of using the
<a href="#iri-expansion">IRI Expansion algorithm</a> on <var>value</var>
is returned.</p>
<p>Otherwise, the result will be a <a class="changed">map</a> containing
an <code>@value</code> <a>entry</a> whose value is the passed <var>value</var>.
Additionally, an <code>@type</code> <a>entry</a> will be included if there is a
<a>type mapping</a> associated with the <a>active property</a>
or an <code>@language</code> <a>entry</a> if <var>value</var> is a
<a>string</a> and there is <a>language mapping</a> associated
with the <a>active property</a>.</p>
<p>Note that values interpreted as <a>IRIs</a> fall into two categories:
those that are <var>document relative</var>, and those that are
<em>vocabulary relative</em>. <a>Properties</a> and values of <code>@type</code>,
along with terms marked as <code>"@type": "@vocab"</code>
are <em>vocabulary relative</em>, meaning that they need to be either
a defined <a>term</a>, a <a>compact IRI</a>
where the <a>prefix</a> is a <a>term</a>,
or a string which is turned into an <a>IRI</a> using
the <a>vocabulary mapping</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes three required inputs: an <var>active context</var>,
an <var>active property</var>, and a <var>value</var> to expand.</p>
<ol>
<li>If the <var>active property</var> has a <a>type mapping</a>
in <var>active context</var> that is <code>@id</code>,
<span class="changed">and the <var>value</var> is a <a>string</a>,</span>
return a new
<a class="changed">map</a> containing a single <a>entry</a> where the
key is <code>@id</code> and the value is the result
<span class="changed"><a>IRI expanding</a></span> <var>value</var>
using `true` for <var>document relative</var>
and `false` for <var>vocab</var>.</li>
<li>If <var>active property</var> has a <a>type mapping</a> in
<var>active context</var> that is <code>@vocab</code>,
<span class="changed">and the <var>value</var> is a <a>string</a>,</span>
return a new
<a class="changed">map</a> containing a single <a>entry</a> where the
key is <code>@id</code> and the value is the result of
<span class="changed"><a>IRI expanding</a></span> <var>value</var>
using <code>true</code> for <var>document relative</var>.</li>
<li>Otherwise, initialize <var>result</var> to a <a class="changed">map</a>
with an <code>@value</code> <a>entry</a> whose value is set to
<var>value</var>.</li>
<li>If <var>active property</var> has a <a>type mapping</a> in
<var>active context</var>,
<span class="changed">other than <code>@id</code>, <code>@vocab</code>, or <code>@none</code>,</span>
add <code>@type</code> to
<var>result</var> and set its value to the value associated with the
<a>type mapping</a>.</li>
<li>Otherwise, if <var>value</var> is a <a>string</a>:
<ol>
<li>Initialize <var>language</var> to the <a>language mapping</a> for <var>active property</var>
in <var>active context</var>, if any, otherwise to the <a>default language</a>
of <var>active context</var>.</li>
<li class="changed">Initialize <var>direction</var> to the <a>direction mapping</a> for <var>active property</var>
in <var>active context</var>, if any, otherwise to the <a>default base direction</a>
of <var>active context</var>.</li>
<li>If <var>language</var> is not `null`,
add <code>@language</code> to <var>result</var> with the value <var>language</var>.</li>
<li class="changed">If <var>direction</var> is not `null`,
add <code>@direction</code> to <var>result</var> with the value <var>direction</var>.</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
</section>
<section><h1>Compaction Algorithms</h1>
<p>The following sections describe algorithms for compacting JSON-LD
documents, IRIs and values.</p>
<section><h2>Compaction Algorithm</h2>
<p>This algorithm compacts a JSON-LD document, such that the given
<a>context</a> is applied. This must result in shortening
any applicable <a>IRIs</a> to
<a>terms</a> or
<a>compact IRIs</a>, any applicable
<a>keywords</a> to
<a>keyword aliases</a>, and
any applicable <a>JSON-LD values</a>
expressed in <a>expanded form</a> to simple values such as
<a>strings</a> or
<a>numbers</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>Starting with its root <var>element</var>, we can process the
JSON-LD document recursively, until we have a fully
<a>compacted</a> <var>result</var>. When
<a>compacting</a> an <var>element</var>, we can treat
each one differently according to its type, in order to break down the
problem:</p>
<ol>
<li>If the <var>element</var> is a <a>scalar</a>, it is
already in <a>compacted form</a>, so we simply return it.</li>
<li>If the <var>element</var> is an <a>array</a>, we compact
each of its items recursively and return them in a new
<a>array</a>.</li>
<li>Otherwise <var>element</var> is a <a class="changed">map</a>. The value
of each <a>entry</a> in element is compacted recursively. Some of the <a>entry</a> keys will be
compacted, using the <a href="#iri-compaction">IRI Compaction algorithm</a>,
to <a>terms</a> or <a>compact IRIs</a>
and others will be compacted from <a>keywords</a> to
<a>keyword aliases</a> or simply left
unchanged because they do not have definitions in the <a>context</a>.
Values will be converted to <a>compacted form</a> via the
<a href="#value-compaction">Value Compaction algorithm</a>. Some data
will be reshaped based on <a>container mapping</a>
specified in the context such as <code>@index</code> or <code>@language</code>
maps.</li>
</ol>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes <span class="changed">three required and two optional</span> input variables.
The required inputs are an <var>active context</var>,
an <var>active property</var>,
and an <var>element</var> to be compacted.
<span class="changed">The optional inputs are the
{{JsonLdOptions/compactArrays}} flag
and the {{JsonLdOptions/ordered}} flag, used to order
<a>map entry</a> keys lexicographically, where noted.
If not passed, both flags are set to <code>false</code></span>.</p>
<ol>
<li class="changed">Initialize <var>type-scoped context</var> to <var>active context</var>.
This is used for compacting values that may be relevant to any previous
<a>type-scoped context</a>.</li>
<li>If <var>element</var> is a <a>scalar</a>, it is already in its most
compact form, so simply return <var>element</var>.</li>
<li>If <var>element</var> is an <a>array</a>:
<ol>
<li>Initialize <var>result</var> to an empty <a>array</a>.</li>
<li>For each <var>item</var> in <var>element</var>:
<ol>
<li>Initialize <var>compacted item</var> to the result of using this
algorithm recursively, passing <var>active context</var>,
<var>active property</var>,
<var>item</var> for <var>element</var>,
<span class="changed">and the {{JsonLdOptions/compactArrays}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>If <var>compacted item</var> is not <code>null</code>, then append
it to <var>result</var>.</li>
</ol>
</li>
<li>If <var>result</var> is empty or contains more than one value,
or {{JsonLdOptions/compactArrays}} is `false`,
<span class="changed">or <var>active property</var> is either `@graph` or `@set`,
or <a>container mapping</a> for <var>active property</var> in
<var>active context</var> includes either <code>@list</code> or <code>@set</code>,</span>
return <var>result</var>.</li>
<li>Otherwise, return the value in <var>result</var>.</li>
</ol>
</li>
<li>Otherwise <var>element</var> is a <a class="changed">map</a>.</li>
<li class="changed">If <var>active context</var> has a <a>previous context</a>,
the <var>active context</var> is not propagated.
If <var>element</var> does not contain an <code>@value</code> <a>entry</a>,
and <var>element</var> does not consist of a single <code>@id</code> entry,
set <var>active context</var> to <a>previous context</a> from <var>active context</var>,
as the scope of a term-scoped <a>context</a> does not apply when processing new <a>node objects</a>.</li>
<li class="changed">If the <a>term definition</a> for <var>active property</var> in <var>active context</var>
has a <a>local context</a>:
<ol>
<li>Set <var>active context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var>,
the value of the <var>active property</var>'s <a>local context</a> as <var>local context</var>,
<span class="changed">
<var>base URL</var> from the <a>term definition</a> for <var>active property</var>
in <var>active context</var>,
and <code>true</code> for <var>override protected</var></span>.</li>
</ol>
</li>
<li>If <var>element</var> has an <code>@value</code> or <code>@id</code>
<a>entry</a> and the result of using the
<a href="#value-compaction">Value Compaction algorithm</a>,
passing <var>active context</var>,
<var>active property</var>, and <var>element</var> as <var>value</var> is
a <a>scalar</a>,
<span class="changed">or the <a>term definition</a> for <var>active property</var>
has a <a>type mapping</a> of <code>@json</code>,</span>
return that result.</li>
<li class="changed">If <var>element</var> is a
<a>list object</a>, and the <a>container mapping</a> for
<var>active property</var> in <var>active context</var> <span class="changed">includes</span> <code>@list</code>,
return the result of using this algorithm recursively, passing
<var>active context</var>,
<var>active property</var>, value of <code>@list</code>
in <var>element</var> for <var>element</var>,
<span class="changed">and the {{JsonLdOptions/compactArrays}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>Initialize <var>inside reverse</var> to <code>true</code> if
<var>active property</var> equals <code>@reverse</code>,
otherwise to <code>false</code>.</li>
<li>Initialize <var>result</var> to an empty <a class="changed">map</a>.</li>
<li class="changed">If <var>element</var> has an <code>@type</code> <a>entry</a>,
create a new array <var>compacted types</var> initialized
by transforming each <var>expanded type</var> of that <a>entry</a>
into its compacted form
<span class="changed">by <a>IRI compacting</a> <var>expanded type</var></span>.
Then, for each <var>term</var>
in <var>compacted types</var> ordered lexicographically:
<ol>
<li id="alg-compact-11_1">If the <a>term definition</a> for <var>term</var> in <var>type-scoped context</var> has a
<a>local context</a>
set <var>active context</var> to the result of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing <var>active context</var> and the value of <var>term</var>'s
<a>local context</a> in <var>type-scoped context</var> as <var>local context</var>
<span class="changed">
<var>base URL</var> from the <a>term definition</a> for <var>term</var>
in <var>type-scoped context</var>,
and `false` for <var>propagate</var></span>.
</li>
</ol>
</li>
<li>For each key <var>expanded property</var> and value <var>expanded value</var>
in <var>element</var>, ordered lexicographically by <var>expanded property</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>:
<ol>
<li>If <var>expanded property</var> is <code>@id</code>:
<ol>
<li>If <var>expanded value</var> is a <a>string</a>,
then initialize <var>compacted value</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded value</var>
with <var>vocab</var> set to `false`</span>.</li>
<li>Initialize <var>alias</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded property</var></span>.</li>
<li>Add an <a>entry</a> <var>alias</var> to <var>result</var> whose value is
set to <var>compacted value</var> and continue to the next
<var>expanded property</var>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@type</code>:
<ol>
<li>If <var>expanded value</var> is a <a>string</a>,
then initialize <var>compacted value</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded value</var>
using <var>type-scoped context</var> for <var>active context</var></span>.</li>
<li>Otherwise, <var>expanded value</var> must be a
<code>@type</code> <a>array</a>:
<ol>
<li>Initialize <var>compacted value</var> to an empty
<a>array</a>.</li>
<li>For each item <var>expanded type</var> in
<var>expanded value</var>:
<ol>
<li>Set <var>term</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded type</var>
using <var>type-scoped context</var> for <var>active context</var></span>.</li>
<li>Append <var>term</var>, to <var>compacted value</var>.</li>
</ol>
</li>
</ol>
</li>
<li>Initialize <var>alias</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded property</var></span>.</li>
<li id="alg-compact-12_2_4" class="changed">Initialize <var>as array</var>
to <code>true</code> if <a>processing mode</a> is `json-ld-1.1` and
the <a>container mapping</a> for <var>alias</var> in the
<var>active context</var> includes <code>@set</code>,
otherwise to the negation of {{JsonLdOptions/compactArrays}}.</li>
<li class="changed">Use <a>add value</a> to add <var>compacted value</var>
to the <var>alias</var> <a>entry</a> in <var>result</var>
using <var>as array</var>.</li>
<li>Continue to the next <var>expanded property</var>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@reverse</code>:
<ol>
<li>Initialize <var>compacted value</var> to the result of using this
algorithm recursively, passing <var>active context</var>,
<code>@reverse</code> for
<var>active property</var>, <var>expanded value</var>
for <var>element</var>,
<span class="changed">and the {{JsonLdOptions/compactArrays}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>For each <var>property</var> and <var>value</var> in <var>compacted value</var>:
<ol>
<li>If the <a>term definition</a> for <var>property</var> in the
<var>active context</var> indicates that <var>property</var> is
a <a>reverse property</a>
<ol>
<li class="changed">Initialize <var>as array</var>
to <code>true</code> if the <a>container mapping</a> for <var>property</var> in the
<var>active context</var> includes <code>@set</code>,
otherwise the negation of {{JsonLdOptions/compactArrays}}.</li>
<li class="changed">Use <a>add value</a> to add <var>value</var>
to the <var>property</var> <a>entry</a> in <var>result</var>
using <var>as array</var>.</li>
<li>Remove the <var>property</var> <a>entry</a> from
<var>compacted value</var>.</li>
</ol>
</li>
</ol>
</li>
<li>If <var>compacted value</var> has some remaining <a>map entries</a>, i.e.,
it is not an empty <a class="changed">map</a>:
<ol>
<li>Initialize <var>alias</var>
<span class="changed">by <a>IRI compacting</a> `@reverse`</span>.</li>
<li>Set the value of the <var>alias</var> <a>entry</a> of <var>result</var> to
<var>compacted value</var>.</li>
</ol>
</li>
<li>Continue with the next <var>expanded property</var> from <var>element</var>.</li>
</ol>
</li>
<li class="changed">If <var>expanded property</var> is <code>@preserve</code>
then:
<ol>
<li>Initialize <var>compacted value</var> to the result of using this
algorithm recursively, passing
<var>active context</var>,
<var>active property</var>,
<var>expanded value</var> for <var>element</var>,
<span class="changed">and the {{JsonLdOptions/compactArrays}}
and {{JsonLdOptions/ordered}} flags</span>.</li>
<li>Add <var>compacted value</var> as the value of <code>@preserve</code>
in <var>result</var> unless <var>expanded value</var> is an empty <a>array</a>.</li>
</ol>
</li>
<li>If <var>expanded property</var> is <code>@index</code> and
<var>active property</var> has a <a>container mapping</a>
in <var>active context</var> that <span class="changed">includes</span> <code>@index</code>,
then the compacted result will be inside of an <code>@index</code>
container, drop the <code>@index</code> <a>entry</a> by continuing
to the next <var>expanded property</var>.</li>
<li>Otherwise, if <var>expanded property</var> is
<code class="changed">@direction</code>,
<code>@index</code>,
<code>@language</code>,
or <code>@value</code>:
<ol>
<li>Initialize <var>alias</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded property</var></span>.</li>
<li>Add an <a>entry</a> <var>alias</var> to <var>result</var> whose value is
set to <var>expanded value</var> and continue with the next
<var>expanded property</var>.</li>
</ol>
</li>
<li>If <var>expanded value</var> is an empty <a>array</a>:
<ol>
<li>Initialize <var>item active property</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded property</var>
using <var>expanded value</var> for <var>value</var>
and <var>inside reverse</var> for <var>reverse</var></span>.</li>
<li class="changed">If the <a>term definition</a> for <var>item active property</var>
in the <var>active context</var> has a <a>nest value</a>
<a>entry</a> (<var>nest term</var>):
<ol>
<li>If <var>nest term</var> is not <code>@nest</code>,
or a <a>term</a> in the <var>active context</var> that expands to <code>@nest</code>,
an <a data-link-for="JsonLdErrorCode">invalid @nest value</a>
error has been detected, and processing is aborted.</li>
<li>If <var>result</var> does not have a <var>nest term</var> <a>entry</a>,
initialize it to an empty <a>map</a>.</li>
<li>Initialize <var>nest result</var> to the value of <var>nest term</var> in <var>result</var>.</li>
</ol>
</li>
<li class="changed">Otherwise, initialize <var>nest result</var> to <var>result</var>.</li>
<li class="changed">Use <a>add value</a> to add an empty <a>array</a>
to the <var>item active property</var> <a>entry</a> in <var>nest result</var>
using <code>true</code> for <var>as array</var>.</li>
</ol>
</li>
<li>
At this point, <var>expanded value</var> must be an
<a>array</a> due to the
<a href="#expansion-algorithm">Expansion algorithm</a>.
For each item <var>expanded item</var> in <var>expanded value</var>:
<ol>
<li>Initialize <var>item active property</var>
<span class="changed">by <a>IRI compacting</a> <var>expanded property</var>
using <var>expanded item</var> for <var>value</var>
and <var>inside reverse</var> for <var>reverse</var></span>.</li>
<li class="changed">If the <a>term definition</a> for <var>item active property</var>
in the <var>active context</var> has a <a>nest value</a>
<a>entry</a> (<var>nest term</var>):
<ol>
<li>If <var>nest term</var> is not <code>@nest</code>,
or a <a>term</a> in the <var>active context</var> that expands to <code>@nest</code>,
an <a data-link-for="JsonLdErrorCode">invalid @nest value</a>
error has been detected, and processing is aborted.</li>
<li>If <var>result</var> does not have a <var>nest term</var> <a>entry</a>,
initialize it to an empty <a>map</a>.</li>
<li>Initialize <var>nest result</var> to the value of <var>nest term</var> in <var>result</var>.</li>
</ol>
</li>
<li>Otherwise, initialize <var>nest result</var> to <var>result</var>.</li>
<li>Initialize <var>container</var> to <a>container mapping</a> for
<var>item active property</var> in <var>active context</var>,
or to a new empty <a>array</a>, if there is no such <a>container mapping</a>.</li>
<li class="changed">Initialize <var>as array</var>
to <code>true</code> if <var>container</var> includes <code>@set</code>,
or if <var>item active property</var> is <code>@graph</code> or <code>@list</code>,
otherwise the negation of {{JsonLdOptions/compactArrays}}.</li>
<li id="alg-compact-12_8_6">Initialize <var>compacted item</var> to the result of using
this algorithm recursively, passing
<var>active context</var>,
<var>item active property</var> for <var>active property</var>,
<var>expanded item</var> for <var>element</var>,
<span class="changed">along with the {{JsonLdOptions/compactArrays}}
and {{JsonLdOptions/ordered}} flags</span>.
If <var>expanded item</var> is a <a>list object</a> or a <a>graph object</a>,
use the value of the `@list` <span class="changed">or `@graph`</span> entries,
respectively, for <var>element</var> instead of <var>expanded item</var>.</li>
<li>If <var>expanded item</var> is a <a>list object</a>:
<ol>
<li>If <var>compacted item</var> is not an <a>array</a>,
then set <var>compacted item</var> to an <a>array</a> containing only
<var>compacted item</var>.</li>
<li>If <var>container</var> does not include <code>@list</code>:
<ol>
<li>Convert <var>compacted item</var> to a
<a>list object</a> by setting it to a
<a class="changed">map</a> containing an <a>entry</a>
where the key is the result of
<span class="changed"><a>IRI compacting</a> `@list`</span>
and the value is the original <var>compacted item</var>.</li>
<li>If <var>expanded item</var> contains the <a>entry</a>
<code>@index</code>-<var>value</var>, then add an <a>entry</a>
to <var>compacted item</var> where the key is the
result of
<span class="changed"><a>IRI compacting</a> `@index`</span>
and value is <var>value</var>.</li>
<li>Use <a>add value</a> to add <var>compacted item</var>
to the <var>item active property</var> <a>entry</a> in
<var>nest result</var>
using <var>as array</var>.</li>
</ol>
</li>
<li class="changed">Otherwise, set the value of the <var>item active property</var> entry
in <var>nest result</var> to <var>compacted item</var>.</li>
</ol>
</li>
<li class="changed">If <var>expanded item</var> is a <a>graph object</a>:
<ol>
<li>If <var>container</var> includes <code>@graph</code> and <code>@id</code>:
<ol>
<li>Initialize <var>map object</var> to the value of <var>item active property</var>
in <var>nest result</var>,
initializing it to a new empty <a>map</a>, if necessary.</li>
<li>Initialize <var>map key</var>
<span class="changed">by <a>IRI compacting</a>
the value of `@id` in <var>expanded item</var>
or <code>@none</code> if no such value exists
with <var>vocab</var> set to <code>false</code>
if there is an <code>@id</code> <a>entry</a> in <var>expanded item</var></span>.</li>
<li class="changed">Use <a>add value</a> to add <var>compacted item</var>
to the <var>map key</var> entry in <var>map object</var>
using <var>as array</var>.</li>
</ol>
</li>
<li>Otherwise, if <var>container</var> includes <code>@graph</code> and <code>@index</code>
and <var>expanded item</var> is a <a>simple graph object</a>:
<ol>
<li>Initialize <var>map object</var> to the value of <var>item active property</var>
in <var>nest result</var>,
initializing it to a new empty <a>map</a>, if necessary.</li>
<li>Initialize <var>map key</var> the value of <code>@index</code> in
<var>expanded item</var> or <code>@none</code>, if no such
value exists.</li>
<li class="changed">Use <a>add value</a> to add <var>compacted item</var>
to the <var>map key</var> entry in <var>map object</var>
using <var>as array</var>.</li>
</ol>
</li>
<li>Otherwise, if <var>container</var> includes <code>@graph</code>
and <var>expanded item</var> is a <a>simple graph object</a>
the value cannot be represented as a map object.
<ol>
<li>If <var>compacted item</var> is an <a>array</a>
with more than one value, it cannot be directly represented,
as multiple objects would be interpreted as different named graphs.
Set <var>compacted item</var> to a new <a>map</a>,
containing the key
from <span class="changed"><a>IRI compacting</a> `@included`</span>
and the original <var>compacted item</var> as the value. </li>
<li class="changed">Use <a>add value</a> to add <var>compacted item</var>
to the <var>item active property</var> entry in <var>nest result</var>
using <var>as array</var>.</li>
</ol>
</li>
<li>Otherwise, <var>container</var> does not include <code>@graph</code>
or otherwise does not match one of the previous cases.
<ol>
<li>Set <var>compacted item</var> to a new map containing
the key
from <span class="changed"><a>IRI compacting</a> `@graph`</span>
using the original <var>compacted item</var> as a value.</li>
<li>If expanded item contains an <code>@id</code> <a>entry</a>,
add an entry in <var>compacted item</var> using the key
from <span class="changed"><a>IRI compacting</a> `@id`</span>
using the value
of <span class="changed"><a>IRI compacting</a> the value of `@id` in <var>expanded item</var>
using `false` for <var>vocab</var></span>.</li>
<li>If expanded item contains an <code>@index</code> <a>entry</a>,
add an entry in <var>compacted item</var> using the key
from <span class="changed"><a>IRI compacting</a> `@index`</span>
and the value of <code>@index</code> in <var>expanded item</var>.</li>
<li class="changed">Use <a>add value</a> to add <var>compacted item</var>
to the <var>item active property</var> entry in <var>nest result</var>
using <var>as array</var>.</li>
</ol>
</li>
</ol>
</li>
<li>
<span class="changed">Otherwise</span>, if <var>container</var> <span class="changed">includes</span> <code>@language</code>,
<code>@index</code>, <span class="changed"><code>@id</code>,
or <code>@type</code></span>
<span class="changed">and <var>container</var> does not include <code>@graph</code></span>:
<ol>
<li class="changed">Initialize <var>map object</var> to the value of <var>item active property</var>
in <var>nest result</var>,
initializing it to a new empty <a>map</a>, if necessary.</li>
<li>Initialize <var>container key</var>
by <span class="changed"><a>IRI compacting</a></span>
either <code>@language</code>, <code>@index</code>, <code>@id</code>, or <code>@type</code>
based on the contents of <var>container</var>.</li>
<li class="changed">Initialize <var>index key</var> to the value of <a>index mapping</a> in
the <a>term definition</a> associated with <var>item active property</var> in <var>active context</var>,
or <code>@index</code>, if no such value exists.</li>
<li>If <var>container</var> includes <code>@language</code> and
<var>expanded item</var> contains a
<code>@value</code> <a>entry</a>, then set <var>compacted item</var>
to the value associated with its <code>@value</code> <a>entry</a>.
Set <var>map key</var> to the value of <code>@language</code> in <var>expanded item</var>, if any.</li>
<li>Otherwise, if <var>container</var> includes <code>@index</code>
and <var>index key</var> is <code>@index</code>,
set <var>map key</var> to the value of <code>@index</code> in <var>expanded item</var>, if any.</li>
<li id="alg-compact-12_8_9_6" class="changed">Otherwise, if <var>container</var> includes <code>@index</code>
and <var>index key</var> is not <code>@index</code>:
<ol>
<li id="alg-compact-12_8_9_6_1">Reinitialize <var>container key</var> by <a>IRI compacting</a>
<var>index key</var> after first <a>IRI expanding</a> it.</li>
<li>Set <var>map key</var> to the first value of <var>container key</var> in <var>compacted item</var>, if any.</li>
<li id="alg-compact-12_8_9_6_3">If there are remaining values in <var>compacted item</var>
for <var>container key</var>, use <a>add value</a> to
add those remaining values to the <var>container key</var> in <var>compacted item</var>.
Otherwise, remove that <a>entry</a> from <var>compacted item</var>.</li>
</ol>
</li>
<li class="changed">Otherwise, if <var>container</var> includes <code>@id</code>, set
<var>map key</var> to the value of <var>container key</var> in
<var>compacted item</var> and remove <var>container key</var> from <var>compacted item</var>.</li>
<li class="changed">Otherwise, if <var>container</var> includes <code>@type</code>:
<ol>
<li>Set <var>map key</var> to the first value of <var>container key</var> in <var>compacted item</var>, if any.</li>
<li id="alg-compact-12_8_9_8_2">If there are remaining values in <var>compacted item</var>
for <var>container key</var>, use <a>add value</a> to
add those remaining values to the <var>container key</var> in <var>compacted item</var>.</li>
<li>Otherwise, remove that <a>entry</a> from <var>compacted item</var>.</li>
<li>If <var>compacted item</var> contains a single <a>entry</a> with a key expanding
to `@id`, set <var>compacted item</var>
to the result of using
this algorithm recursively, passing
<var>active context</var>,
<var>item active property</var> for <var>active property</var>,
and a <a>map</a> composed of the single <a>entry</a> for `@id` from <var>expanded item</var> for <var>element</var>.
</li>
</ol>
</li>
<li>If <var>map key</var> is <code>null</code>,
set it to the result of
<span class="changed"><a>IRI compacting</a> `@none`</span>.</li>
<li class="changed">Use <a>add value</a> to add <var>compacted item</var>
to the <var>map key</var> entry in <var>map object</var>
using <var>as array</var>.</li>
</ol>
</li>
<li id="alg-compact-12_8_10" class="changed">Otherwise, use <a>add value</a> to add <var>compacted item</var>
to the <var>item active property</var> entry in <var>nest result</var>
using <var>as array</var>.</li>
</ol>
</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
<section><h2>IRI Compaction</h2>
<p>This algorithm compacts an <a>IRI</a> to a <a>term</a> or
<a>compact IRI</a>, or a <a>keyword</a> to a
<a>keyword alias</a>. A value that is associated with the
<a>IRI</a> may be passed in order to assist in selecting the most
context-appropriate <a>term</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>If the passed <a>IRI</a> is <code>null</code>,
we simply return <code>null</code>.
Otherwise, we first try to find a <a>term</a> that the <a>IRI</a> or <a>keyword</a>
can be compacted to if it is relative to
<a data-lt="active context">active context's</a> <a>vocabulary mapping</a>.
In order to select the most appropriate <a>term</a>,
we may have to collect information about the passed <var>value</var>.
This information includes determining the preferred <a>container mapping</a>,
<a>type mapping</a> or <a>language mapping</a>
for expressing the <var>value</var>.
For <a data-lt="list object">JSON-LD lists</a>, the <a>type mapping</a>
or <a>language mapping</a> will be chosen based on the most
specific values that work for all items in the list.
Once this information is gathered,
it is passed to the <a href="#term-selection">Term Selection algorithm</a>,
which will return the most appropriate <a>term</a>.</p>
<p>If no <a>term</a> was found that could be used to compact the <a>IRI</a>,
an attempt is made to compact the <a>IRI</a>
using the <a data-lt="active context">active context's</a> <a>vocabulary mapping</a>,
if there is one.
If the <a>IRI</a> could not be compacted,
an attempt is made to find a <a>compact IRI</a>.
<span class="changed">A term will be used to create a <a>compact IRI</a>
only if the <a>term definition</a> contains the <a>prefix flag</a>
with the value <code>true</code>.</span>
If there is no appropriate <a>compact IRI</a>,
<span class="changed">and the <a data-link-for="JsonLdOptions">compactToRelative</a> option is <code>true</code></span>,
the <a>IRI</a> is transformed to a <a>relative IRI reference</a>
using the document's <a>base IRI</a>.
Finally, if the <a>IRI</a> or <a>keyword</a> still could not be compacted,
it is returned as is.</p>
<p class="changed">When considering <a>language mapping</a>,
the <a>direction mapping</a> is also considered, either with, or without,
a <a>language mapping</a>,
and the <a>language mapping</a> is normalized to lower case.</p>
<p class="changed">In the case were this algorithm would return the input <a>IRI</a> as is,
and that <a>IRI</a> can be mistaken for a <a>compact IRI</a> in the <a>active context</a>,
this algorithm will raise an error,
because it has no way to return an unambiguous representation of the original <a>IRI</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>This algorithm takes <span class="changed">two</span> required inputs and three optional inputs.
The required inputs are an <var>active context</var>,
and the <var>var</var> to be compacted.
The optional inputs are a <var>value</var> associated with the <var>var</var>,
a <var>vocab</var> flag which specifies whether the passed <var>var</var>
should be compacted using the <a data-lt="active context">active context's</a> <a>vocabulary mapping</a>,
and a <var>reverse</var> flag which specifies whether a <a>reverse property</a> is being compacted.
If not passed, <var>value</var> is set to <code>null</code>
and both <var>vocab</var> and <var>reverse</var> are both set to <code>false</code>.</p>
<ol>
<li>If <var>var</var> is <code>null</code>, return <code>null</code>.</li>
<li class="changed">If the <var>active context</var> has a `null`
<a data-lt='context-inverse'>inverse context</a>,
set <a data-lt='context-inverse'>inverse context</a> in <var>active context</var>
to the result of calling the
<a href="#inverse-context-creation">Inverse Context Creation algorithm</a>
using <var>active context</var>.</li>
<li>Initialize <var>inverse context</var> to the value of
<a data-lt='context-inverse'>inverse context</a> in <var>active context</var>.</li>
<li>If <var>vocab</var> is <code>true</code> and <var>var</var> is an
<a>entry</a> of <var>inverse context</var>:
<ol>
<li class="changed">Initialize <var>default language</var>
based on the <a data-lt="active context">active context's</a>
<a>default language</a>, normalized to lower case and <a>default base direction</a>:
<ol>
<li>If the <a data-lt="active context">active context's</a> <a>default base direction</a>
is not `null`, to the concatenation of
the <a data-lt="active context">active context's</a> <a>default language</a>
and <a>default base direction</a>, separated by an underscore (`"_"`),
normalized to lower case.</li>
<li>Otherwise, to the <a data-lt="active context">active context's</a> <a>default language</a>,
if it has one,
normalized to lower case,
otherwise to `@none`.</li>
</ol>
</li>
<li class="changed">If <var>value</var> is a <a>map</a> containing an `@preserve` <a>entry</a>,
use the first element from the value of <code>@preserve</code> as <var>value</var>.</li>
<li>Initialize <var>containers</var> to an empty <a>array</a>. This
<a>array</a> will be used to keep track of an ordered list of
preferred <a>container mapping</a> for a <a>term</a>,
based on what is compatible with <var>value</var>.
<div class="note">
Algorithm steps may append the same value to <var>containers</var>,
but the order in which they are added is significant for choosing the most appropriate term.
</div>
</li>
<li>Initialize <var>type/language</var> to <code>@language</code>,
and <var>type/language value</var> to <code>@null</code>. These two
variables will keep track of the preferred
<a>type mapping</a> or <a>language mapping</a> for
a <a>term</a>, based on what is compatible with <var>value</var>.</li>
<li id="alg-iric-value-map" class="changed">If <var>value</var> is a <a>map</a> containing an `@index` <a>entry</a>,
and <var>value</var> is not a <a>graph object</a>
then append the values <code>@index</code> and <code>@index@set</code> to <var>containers</var>.</li>
<li>If <var>reverse</var> is <code>true</code>, set <var>type/language</var>
to <code>@type</code>, <var>type/language value</var> to
<code>@reverse</code>, and append <code>@set</code> to <var>containers</var>.</li>
<li>Otherwise, if <var>value</var> is a <a>list object</a>, then set
<var>type/language</var> and <var>type/language value</var>
to the most specific values that work for all items in
the list as follows:
<ol>
<li>If <code>@index</code> is not an <a>entry</a> in <var>value</var>, then
append <code>@list</code> to <var>containers</var>.</li>
<li>Initialize <var>list</var> to the <a>array</a> associated
with the <code>@list</code> <a>entry</a> in <var>value</var>.</li>
<li>Initialize <var>common type</var> and <var>common language</var> to <code>null</code>. If
<var>list</var> is empty, set <var>common language</var> to
<var>default language</var>.</li>
<li>For each <var>item</var> in <var>list</var>:
<ol>
<li>Initialize <var>item language</var> to <code>@none</code> and
<var>item type</var> to <code>@none</code>.</li>
<li>If <var>item</var> contains an <code>@value</code> <a>entry</a>:
<ol>
<li class="changed">If <var>item</var> contains an `@direction` <a>entry</a>,
then set <var>item language</var> to the concatenation of
the <var>item</var>'s `@language` entry (if any)
the <var>item</var>'s `@direction`, separated by an underscore (`"_"`),
normalized to lower case.</li>
<li>Otherwise, if <var>item</var> contains an <code>@language</code> <a>entry</a>,
then set <var>item language</var> to its associated value,
normalized to lower case.</li>
<li>Otherwise, if <var>item</var> contains a
<code>@type</code> <a>entry</a>, set <var>item type</var> to its
associated value.</li>
<li>Otherwise, set <var>item language</var> to
<code>@null</code>.</li>
</ol>
</li>
<li>Otherwise, set <var>item type</var> to <code>@id</code>.</li>
<li>If <var>common language</var> is <code>null</code>,
set <var>common language</var> to <var>item language</var>.</li>
<li>Otherwise, if <var>item language</var> does not equal
<var>common language</var> and <var>item</var> contains a
<code>@value</code> <a>entry</a>, then set <var>common language</var>
to <code>@none</code> because list items have conflicting
languages.</li>
<li>If <var>common type</var> is <code>null</code>,
set <var>common type</var> to <var>item type</var>.</li>
<li>Otherwise, if <var>item type</var> does not equal
<var>common type</var>, then set <var>common type</var>
to <code>@none</code> because list items have conflicting
types.</li>
<li>If <var>common language</var> is <code>@none</code> and
<var>common type</var> is <code>@none</code>, then
stop processing items in the list because it has been
detected that there is no common language or type amongst
the items.</li>
</ol>
</li>
<li>If <var>common language</var> is <code>null</code>,
set <var>common language</var> to <code>@none</code>.</li>
<li>If <var>common type</var> is <code>null</code>,
set <var>common type</var> to <code>@none</code>.</li>
<li>If <var>common type</var> is not <code>@none</code> then set
<var>type/language</var> to <code>@type</code> and
<var>type/language value</var> to <var>common type</var>.</li>
<li>Otherwise, set <var>type/language value</var> to
<var>common language</var>.</li>
</ol>
</li>
<li class="changed">Otherwise, if <var>value</var> is a <a>graph object</a>,
prefer a mapping most appropriate for the particular value.
<ol>
<li>If <var>value</var> contains an <code>@index</code> <a>entry</a>,
append the values <code>@graph@index</code> and <code>@graph@index@set</code>
to <var>containers</var>.</li>
<li>If <var>value</var> contains an <code>@id</code> <a>entry</a>,
append the values <code>@graph@id</code> and <code>@graph@id@set</code>
to <var>containers</var>.</li>
<li>Append the values <code>@graph</code> <code>@graph@set</code>,
and <code>@set</code>
to <var>containers</var>.</li>
<li>If <var>value</var> does not contain an <code>@index</code> <a>entry</a>,
append the values <code>@graph@index</code> and <code>@graph@index@set</code>
to <var>containers</var>.</li>
<li>If the <var>value</var> does not contain an <code>@id</code> <a>entry</a>,
append the values <code>@graph@id</code> and <code>@graph@id@set</code>
to <var>containers</var>.</li>
<li>Append the values <code>@index</code> and <code>@index@set</code>
to <var>containers</var>.</li>
<li>Set <var>type/language</var> to <code>@type</code>
and set <var>type/language value</var> to <code>@id</code>.</li>
</ol>
</li>
<li>Otherwise:
<ol>
<li>If <var>value</var> is a <a>value object</a>:
<ol>
<li class="changed">If <var>value</var> contains an `@direction` <a>entry</a>
and does not contain an `@index` <a>entry</a>,
then set <var>type/language value</var> to the concatenation of
the <var>value</var>'s `@language` <a>entry</a> (if any)
and the <var>value</var>'s `@direction` <a>entry</a>, separated by an underscore (`"_"`),
normalized to lower case.
Append `@language` and `@language@set` to <var>containers</var>.</li>
<li>Otherwise, if <var>value</var> contains an <code>@language</code> <a>entry</a>
and does not contain an <code>@index</code> <a>entry</a>,
then set <var>type/language value</var> to
the value of `@language` normalized to lower case,
and append <code>@language</code>,
<span class="changed">and <code>@language@set</code></span> to
<var>containers</var>.</li>
<li>Otherwise, if <var>value</var> contains an
<code>@type</code> <a>entry</a>, then set <var>type/language value</var> to
its associated value and set <var>type/language</var> to
<code>@type</code>.</li>
</ol>
</li>
<li>Otherwise, set <var>type/language</var> to <code>@type</code>
and set <var>type/language value</var> to <code>@id</code>,
<span class="changed">and append <code>@id</code>, <code>@id@set</code>,
<code>@type</code>, and <code>@set@type</code></span>,
to <var>containers</var>.</li>
<li>Append <code>@set</code> to <var>containers</var>.</li>
</ol>
</li>
<li>Append <code>@none</code> to <var>containers</var>. This represents
the non-existence of a <a>container mapping</a>, and it will
be the last <a>container mapping</a> value to be checked as it
is the most generic.</li>
<li class="changed">
If <a>processing mode</a> is not `json-ld-1.0` and <var>value</var> is not a <a>map</a>
or does not contain an <code>@index</code> <a>entry</a>,
append <code>@index</code> and <code>@index@set</code> to <var>containers</var>.
<li class="changed">
If <a>processing mode</a> is not `json-ld-1.0` and
<var>value</var> is a <a>map</a> containing only an `@value` <a>entry</a>,
append <code>@language</code> and <code>@language@set</code> to <var>containers</var>.</li>
<li>If <var>type/language value</var> is <code>null</code>,
set <var>type/language value</var> to <code>@null</code>.
This is the key under which <code>null</code> values
are stored in the <var>inverse context</var> <var>entry</var>.</li>
<li>Initialize <var>preferred values</var> to an empty <a>array</a>.
This <a>array</a> will indicate, in order, the preferred values for
a <a data-lt="term">term's</a> <a>type mapping</a> or
<a>language mapping</a>.</li>
<li>If <var>type/language value</var> is <code>@reverse</code>, append
<code>@reverse</code> to <var>preferred values</var>.</li>
<li>If <var>type/language value</var> is <code>@id</code> or <code>@reverse</code> and
<var>value</var> is a <a>map</a> containing an `@id` <a>entry</a>:
<ol>
<li>If the result of
<span class="changed"><a>IRI compacting</a>
the value of the <code>@id</code> <a>entry</a> in <var>value</var></span>
has a <a>term definition</a> in the <var>active context</var>
with an <a>IRI mapping</a> that equals the value of the <code>@id</code> <a>entry</a> in <var>value</var>,
then append <code>@vocab</code>, <code>@id</code>, and
<code>@none</code>, in that order, to <var>preferred values</var>.</li>
<li>Otherwise, append <code>@id</code>, <code>@vocab</code>, and
<code>@none</code>, in that order, to <var>preferred values</var>.</li>
</ol>
</li>
<li>Otherwise, append <var>type/language value</var> and <code>@none</code>, in
that order, to <var>preferred values</var>.
<span class="changed">If <var>value</var> is a <a>list object</a>
with an empty <var>array</var> as the value of `@list`,
set <var>type/language</var> to <code>@any</code>.</span></li>
<li class="changed">Append <code>@any</code> to <var>preferred values</var>.</li>
<li class="changed">If <var>preferred values</var>
contains any entry having an underscore (`"_"`),
append the substring of that entry from the underscore to the end of the string
to <var>preferred values</var>.</li>
<li>Initialize <var>term</var> to the result of the
<a href="#term-selection">Term Selection algorithm</a>, passing
<var>var</var>, <var>containers</var>,
<var>type/language</var>, and <var>preferred values</var>.</li>
<li>If <var>term</var> is not <code>null</code>, return <var>term</var>.</li>
</ol>
</li>
<li>At this point, there is no simple <a>term</a> that <var>var</var>
can be compacted to. If <var>vocab</var> is <code>true</code> and
<var>active context</var> has a <a>vocabulary mapping</a>:
<ol>
<li>If <var>var</var> begins with the
<a data-lt="vocabulary mapping">vocabulary mapping's</a> value
but is longer, then initialize <var>suffix</var> to the substring
of <var>var</var> that does not match. If <var>suffix</var> does not
have a <a>term definition</a> in <var>active context</var>,
then return <var>suffix</var>.</li>
</ol>
</li>
<li>The <var>var</var> could not be compacted using the
<a data-lt="active context">active context's</a> <a>vocabulary mapping</a>.
Try to create a <a>compact IRI</a>, starting by initializing
<var>compact IRI</var> to <code>null</code>. This variable will be used to
store the created <a>compact IRI</a>, if any.</li>
<li>For each <a>term definition</a> <var>definition</var> in <var>active context</var>:
<ol>
<li>If the <a>IRI mapping</a> of <var>definition</var> is `null`,
its <a>IRI mapping</a> equals <var>var</var>,
its <a>IRI mapping</a> is not a substring at the beginning of
<var>var</var>,
<span class="changed"> or <var>definition</var> does not have
a <code>true</code> <a>prefix flag</a>,</span>
<var>definition</var>'s key cannot be used as a <a>prefix</a>.
Continue with the next <var>definition</var>.</li>
<li>Initialize <var>candidate</var> by concatenating <var>definition</var> key,
a colon (<code>:</code>), and the substring of <var>var</var>
that follows after the value of the
<var>definition</var>'s <a>IRI mapping</a>.</li>
<li>If either <var>compact IRI</var> is <code>null</code>, <var>candidate</var> is
shorter or the same length but lexicographically less than
<var>compact IRI</var> and <var>candidate</var> does not have a
<a>term definition</a> in <var>active context</var>, or if that
<a>term definition</a> has an <a>IRI mapping</a>
that equals <var>var</var> and <var>value</var> is <code>null</code>,
set <var>compact IRI</var> to <var>candidate</var>.</li>
</ol>
</li>
<li>If <var>compact IRI</var> is not <code>null</code>, return <var>compact IRI</var>.</li>
<li class="changed">To ensure that the <a>IRI</a> <var>var</var> is
not confused with a <a>compact IRI</a>,
if the <a data-cite="RFC3986#section-3.1">IRI scheme</a> of <var>var</var>
matches any term in <a>active context</a> with <a>prefix flag</a> set to <code>true</code>,
and <var>var</var> has no <a data-cite="RFC3986#section-3.2">IRI authority</a> (preceded by double-forward-slash (<code>//</code>),
an <a data-link-for="JsonLdErrorCode">IRI confused with prefix</a> error has been detected,
and processing is aborted.</li>
<li>If <var>vocab</var> is <code>false</code>,
transform <var>var</var> to a <a>relative IRI reference</a> using
the <span class="changed"><a data-lt="context-base-iri">base IRI</a> from <var>active context</var>, if it exists</span>.
<span class="changed">To avoid confusion with a <a>keyword</a>, if <var>var</var> has the form of a keyword
(i.e., it matches the ABNF rule `"@"1*ALPHA` from [[RFC5234]]),
prepend to it a period followed by a a slash (`./`).</span>
</li>
<li>Finally, return <var>var</var> as is.</li>
</ol>
</section>
</section>
<section><h2>Value Compaction</h2>
<p><a>Expansion</a> transforms all values into <a>expanded form</a>
in JSON-LD. This algorithm performs the opposite operation, transforming
a value into <dfn data-lt="compact form">compacted form</dfn>. This algorithm compacts a
value according to the <a>term definition</a> in the given
<a>active context</a> that is associated with the value's associated
<a>active property</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>The <var>value</var> to compact has either an <code>@id</code> or an
<code>@value</code> <a>entry</a>.</p>
<p>For the former case, if the <a>type mapping</a> of
<a>active property</a> is set to <code>@id</code> or <code>@vocab</code>
and <var>value</var> consists of only an <code>@id</code> <a>entry</a> and, if
the <a>container mapping</a> of <a>active property</a>
<span class="changed">includes</span> <code>@index</code>, an <code>@index</code> <a>entry</a>, <var>value</var>
can be compacted to a <a>string</a> by returning the result of
using the <a href="#iri-compaction">IRI Compaction algorithm</a>
to compact the value associated with the <code>@id</code> <a>entry</a>.
Otherwise, <var>value</var> cannot be compacted and is returned as is.</p>
<p>For the latter case, it might be possible to compact <var>value</var>
just into the value associated with the <code>@value</code> <a>entry</a>.
This can be done if the <a>active property</a> has a matching
<a>type mapping</a> or <a>language mapping</a> and there
is either no <code>@index</code> <a>entry</a> or the <a>container mapping</a>
of <a>active property</a> <span class="changed">includes</span> <code>@index</code>. It can
also be done if <code>@value</code> is the only <a>entry</a> in <var>value</var>
(apart an <code>@index</code> <a>entry</a> in case the <a>container mapping</a>
of <a>active property</a> <span class="changed">includes</span> <code>@index</code>) and
either its associated value is not a <a>string</a>, there is
no <a>default language</a>, or there is an explicit
<code>null</code> <a>language mapping</a> for the
<a>active property</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>This algorithm has <span class="changed">three</span> required inputs: an <var>active context</var>,
an <var>active property</var>, and a <var>value</var>
to be compacted.</p>
<ol>
<li>Initialize <var>result</var> to a copy of <var>value</var>.</li>
<li class="changed">If the <var>active context</var> has a `null`
<a data-lt='context-inverse'>inverse context</a>,
set <a data-lt='context-inverse'>inverse context</a> in <var>active context</var>
to the result of calling the
<a href="#inverse-context-creation">Inverse Context Creation algorithm</a>
using <var>active context</var>.</li>
<li>Initialize <var>inverse context</var> to the value of
<a data-lt='context-inverse'>inverse context</a> in <var>active context</var>.</li>
<li>Initialize <var>language</var> to the <a>language mapping</a> for <var>active property</var>
in <var>active context</var>, if any, otherwise to the <a>default language</a>
of <var>active context</var>.</li>
<li class="changed">Initialize <var>direction</var> to the <a>direction mapping</a> for <var>active property</var>
in <var>active context</var>, if any, otherwise to the <a>default base direction</a>
of <var>active context</var>.</li>
<li id="alg-compval-id-index">If <var>value</var> has an <code>@id</code> <a>entry</a>
and has no other <a>entries</a> other than `@index`:
<ol>
<li>If the <a>type mapping</a> of <var>active property</var>
is set to <code>@id</code>, set <var>result</var> to the result of
<span class="changed"><a>IRI compacting</a>
the value associated with the <code>@id</code> <a>entry</a>
using `false` for <var>vocab</var></span>.</li>
<li>Otherwise, if the <a>type mapping</a> of <var>active property</var>
is set to <code>@vocab</code>, set <var>result</var> to the result of
<span class="changed"><a>IRI compacting</a>
the value associated with the <code>@id</code> <a>entry</a></span>.</li>
</ol>
</li>
<li>Otherwise, if <var>value</var> has an <code>@type</code> <a>entry</a> whose
value matches the <a>type mapping</a> of <var>active property</var>,
set <var>result</var> to the value associated with the <code>@value</code> <a>entry</a>
of <var>value</var>.</li>
<li class="changed">Otherwise, if the <a>type mapping</a> of <var>active property</var> is <code>@none</code>,
or <var>value</var> has an `@type` <a>entry</a>,
and the value of `@type` in <var>value</var> does not match the <a>type mapping</a> of <var>active property</var>,
leave <var>value</var> as is, as value compaction is disabled.
<ol>
<li>Replace any value of <code>@type</code> in <var>result</var> with the result of
<span class="changed"><a>IRI compacting</a></span>
the value of the <code>@type</code> <a>entry</a>.</li>
</ol>
</li>
<li>Otherwise, if the value of the <code>@value</code> <a>entry</a> is not a <a>string</a>:
<ol>
<li>If <var>value</var> has an `@index` <a>entry</a>,
and the <a>container mapping</a> associated to <var>active property</var>
includes <code>@index</code>,
or if <var>value</var> has no `@index` <a>entry</a>,
set <var>result</var> to the value associated with the `@value` <a>entry</a>.</li>
</ol>
</li>
<li id="alg-valcompact-lang-dir">Otherwise, if <var>value</var> has an <code>@language</code> <a>entry</a>
whose value exactly matches <var>language</var>,
<span class="changed">using a case-insensitive comparison</span>
if it is not `null`, or is not present, if <var>language</var> is `null`,
<span class="changed">and the <var>value</var> has an <code>@direction</code> <a>entry</a>
whose value exactly matches <var>direction</var>,
if it is not `null`, or is not present, if <var>direction</var> is `null`</span>:
<ol>
<li>If <var>value</var> has an `@index` <a>entry</a>,
and the <a>container mapping</a> associated to <var>active property</var>
includes <code>@index</code>,
or <var>value</var> has no `@index` <a>entry</a>,
set <var>result</var> to the value associated with the `@value` <a>entry</a>.</li>
</ol>
</li>
<li>If <var>result</var> is a <var>map</var>,
replace each key in <var>result</var> with the result of
<span class="changed"><a>IRI compacting</a> that key</span>.</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
</section>
<section><h1>Flattening Algorithms</h1>
<p>The following sections describe algorithms for flattening JSON-LD documents,
creating node maps, and generating blank nodes.</p>
<section><h2>Flattening Algorithm</h2>
<p>This algorithm flattens an expanded JSON-LD document by collecting all
<a>properties</a> of a <a>node</a> in a single <a class="changed">map</a>
and labeling all <a>blank nodes</a> with
<a>blank node identifiers</a>.
This resulting uniform shape of the document, may drastically simplify
the code required to process JSON-LD data in certain applications.</p>
<section class="informative">
<h3>Overview</h3>
<p>First, a <var>node map</var> is generated using the
<a href="#node-map-generation">Node Map Generation algorithm</a>
which collects all <a>properties</a> of a <a>node</a> in a single
<a class="changed">map</a>. In the next step, the <var>node map</var> is
converted to a JSON-LD document in
<a data-cite="JSON-LD11#flattened-document-form">flattened document form</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes <span class="changed">one required and one optional</span> input variables.
The required input is an <var>element</var> to flatten.
<span class="changed">The optional input is
the {{JsonLdOptions/ordered}} flag, used to order
<a>map entry</a> keys lexicographically, where noted.
If not passed, the {{JsonLdOptions/ordered}} flag is set to <code>false</code></span>.</p>
<p>This algorithm uses the
<a href="#generate-blank-node-identifier">Generate Blank Node Identifier algorithm</a>
to generate new <a>blank node identifiers</a>
and relabel existing <a>blank node identifiers</a>.
The <a href="#generate-blank-node-identifier">Generate Blank Node Identifier algorithm</a>
maintains an <var>identifier map</var>
<span class="changed">to ensure that blank node identifiers in the source
document are consistently remapped to new blank node identifiers
avoiding collisions.</span>
Thus, before this algorithm is run, the <var>identifier map</var> is reset.</p>
<ol>
<li>Initialize <var>node map</var> to a <a class="changed">map</a> consisting of
a single <a>entry</a> whose key is <code>@default</code> and whose value is
an empty <a class="changed">map</a>.</li>
<li>Perform the <a href="#node-map-generation">Node Map Generation algorithm</a>, passing
<var>element</var> and <var>node map</var>.</li>
<li>Initialize <var>default graph</var> to the value of the <code>@default</code>
<a>entry</a> of <var>node map</var>, which is a <a class="changed">map</a> representing
the <a>default graph</a>.</li>
<li>For each key-value pair <var>graph name</var>-<var>graph</var> in <var>node map</var>
where <var>graph name</var> is not <code>@default</code>,
<span class="changed">ordered lexicographically by <var>graph name</var>
if {{JsonLdOptions/ordered}} is <code>true</code></span>,
perform the following steps:
<ol>
<li>If <var>default graph</var> does not have a <var>graph name</var> <a>entry</a>, create
one and initialize its value to a <a class="changed">map</a> consisting of an
<code>@id</code> <a>entry</a> whose value is set to <var>graph name</var>.</li>
<li>Reference the value associated with the <var>graph name</var> <a>entry</a> in
<var>default graph</var> using the variable <var>entry</var>.</li>
<li>Add an <code>@graph</code> <a>entry</a> to <var>entry</var> and set it to an
empty <a>array</a>.</li>
<li>For each <var>id</var>-<var>node</var> pair in <var>graph</var> ordered lexicographically by <var>id</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>,
add <var>node</var> to the <code>@graph</code> <a>entry</a> of <var>entry</var>,
unless the only <a>entry</a> of <var>node</var> is <code>@id</code>.</li>
</ol>
</li>
<li>Initialize an empty <a>array</a> <var>flattened</var>.</li>
<li>For each <var>id</var>-<var>node</var> pair in <var>default graph</var> ordered lexicographically by <var>id</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>,
add <var>node</var> to <var>flattened</var>,
unless the only <a>entry</a> of <var>node</var> is <code>@id</code>.</li>
<li>Return <var>flattened</var>.</li>
</ol>
</section>
</section>
<section id="node-map-generation"><h2>Node Map Generation</h2>
<p>This algorithm creates a <a class="changed">map</a> <var>node map</var> holding an indexed
representation of the <a>graphs</a> and <a>nodes</a>
represented in the passed expanded document. All <a>nodes</a> that are not
uniquely identified by an IRI get assigned a (new) <a>blank node identifier</a>.
The resulting <var>node map</var> will have an <a>map entry</a> for every graph in the document whose
value is another object with an <a>entry</a> for every <a>node</a> represented in the document.
The default graph is stored under the <code>@default</code> <a>entry</a>, all other graphs are
stored under their <a>graph name</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p>The algorithm recursively runs over an expanded JSON-LD document to
collect all <a>entries</a> of a <a>node</a>
in a single <a class="changed">map</a>. The algorithm updates a
<a class="changed">map</a> <var>node map</var> whose keys represent the
<a>graph names</a> used in the document
(the <a>default graph</a> is stored under the <code>@default</code> <a>entry</a>)
and whose associated values are <a class="changed">maps</a>
which index the <a>nodes</a> in the
<a>graph</a>. If a
<a data-lt="entry">entry's</a> value is a <a>node object</a>,
it is replaced by a <a>node object</a> consisting of only an
<code>@id</code> <a>entry</a>. If a <a>node object</a> has no <code>@id</code>
<a>entry</a> or it is identified by a <a>blank node identifier</a>,
a new <a>blank node identifier</a> is generated. This relabeling
of <a>blank node identifiers</a> is
also done for <a>properties</a> and values of
<code>@type</code>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes as input an expanded JSON-LD document <var>element</var> and a reference to
a <a class="changed">map</a> <var>node map</var>. Furthermore it has the optional parameters
<var>active graph</var> (which defaults to <code>@default</code>), an <var>active subject</var>,
<var>active property</var>, and a reference to a <a class="changed">map</a> <var>list</var>. If
not passed, <var>active subject</var>, <var>active property</var>, and <var>list</var> are
set to <code>null</code>.</p>
<ol>
<li>If <var>element</var> is an array, process each <var>item</var> in <var>element</var>
as follows and then return:
<ol>
<li>Run this algorithm recursively by passing <var>item</var> for <var>element</var>,
<var>node map</var>, <var>active graph</var>, <var>active subject</var>,
<var>active property</var>, and <var>list</var>.</li>
</ol>
</li>
<li>Otherwise <var>element</var> is a <a class="changed">map</a>. Reference the
<a class="changed">map</a> which is the value of the <a>active graph</a>
<a>entry</a> of <var>node map</var> using the variable <var>graph</var>. If the
<var>active subject</var> is <code>null</code> <span class="changed">or a <a>map</a></span>, set <var>subject node</var> to <code>null</code>
otherwise reference the <var>active subject</var> <a>entry</a> of <var>graph</var> using the
variable <var>subject node</var>.</li>
<li id="alg-nmg-each-type">For each <var>item</var> in the `@type` <a>entry</a> of <var>element</var>,
if any, or for the value of `@type`, if the value of `@type` exists and is not an <a>array</a>:
<ol>
<li>If <var>item</var> is a <a>blank node identifier</a>, replace it with a newly
<a href="#generate-blank-node-identifier">generated blank node identifier</a>
passing <var>item</var> for <var>identifier</var>.</li>
</ol>
</li>
<li>If <var>element</var> has an <code>@value</code> <a>entry</a>, perform the following steps:
<ol>
<li>If <var>list</var> is <code>null</code>:
<ol>
<li>If <var>subject node</var> <span class="changed">(which must necessarily be a <a>map</a>)</span> does not have an <var>active property</var> <a>entry</a>,
create one and initialize its value to an <a>array</a>
containing <var>element</var>.</li>
<li>Otherwise, compare <var>element</var> against every item in the
<a>array</a> associated with the <var>active property</var>
<a>entry</a> of <var>subject node</var>. If there is no item equivalent to <var>element</var>,
append <var>element</var> to the <a>array</a>. Two
<a class="changed">maps</a> are considered
equal if they have equivalent <a> map entries</a>.</li>
</ol>
</li>
<li>Otherwise, append <var>element</var> to the <code>@list</code> <a>entry</a> of <var>list</var>.</li>
</ol>
</li>
<li>Otherwise, if <var>element</var> has an <code>@list</code> <a>entry</a>, perform
the following steps:
<ol>
<li>Initialize a new <a class="changed">map</a> <var>result</var> consisting of a single <a>entry</a>
<code>@list</code> whose value is initialized to an empty <a>array</a>.</li>
<li>Recursively call this algorithm passing the value of <var>element</var>'s
<code>@list</code> <a>entry</a> for <var>element</var>, <var>node map</var>, <var>active graph</var>,
<var>active subject</var>, <var>active property</var>, and
<var>result</var> for <var>list</var>.</li>
<li class="changed">If <var>list</var> is <code>null</code>,
append <var>result</var> to the value of the <var>active property</var> <a>entry</a>
of <var>subject node</var> <span class="changed">(which must necessarily be a <a>map</a>)</span>.</li>
<li class="changed">Otherwise, append <var>result</var> to the <code>@list</code> <a>entry</a> of <var>list</var>.</li>
</ol>
</li>
<li>Otherwise <var>element</var> is a <a>node object</a>, perform
the following steps:
<ol>
<li>If <var>element</var> has an <code>@id</code> <a>entry</a>, set <var>id</var>
to its value and remove the <a>entry</a> from <var>element</var>. If <var>id</var>
is a <a>blank node identifier</a>, replace it with a newly
<a href="#generate-blank-node-identifier">generated blank node identifier</a>
passing <var>id</var> for <var>identifier</var>.</li>
<li>Otherwise, set <var>id</var> to the result of the
<a href="#generate-blank-node-identifier">Generate Blank Node Identifier algorithm</a>
passing <code>null</code> for <var>identifier</var>.</li>
<li>If <var>graph</var> does not contain an <a>entry</a> <var>id</var>, create one and initialize
its value to a <a class="changed">map</a> consisting of a single <a>entry</a> <code>@id</code> whose
value is <var>id</var>.</li>
<li>Reference the value of the <var>id</var> <a>entry</a> of <var>graph</var> using the
variable <var>node</var>.</li>
<li>If <var>active subject</var> is a <a class="changed">map</a>, a reverse property relationship
is being processed. Perform the following steps:
<ol>
<li>If <var>node</var> does not have a <var>active property</var> <a>entry</a>,
create one and initialize its value to an <a>array</a>
containing <var>active subject</var>.</li>
<li>Otherwise, compare <var>active subject</var> against every item in the
<a>array</a> associated with the <var>active property</var>
<a>entry</a> of <var>node</var>. If there is no item equivalent to <var>active subject</var>,
append <var>active subject</var> to the <a>array</a>. Two
<a class="changed">maps</a> are considered
equal if they have equivalent <a>map entries</a>.</li>
</ol>
</li>
<li>Otherwise, if <var>active property</var> is not <code>null</code>, perform the following steps:
<ol>
<li>Create a new <a class="changed">map</a> <var>reference</var> consisting of a single <a>entry</a>
<code>@id</code> whose value is <var>id</var>.</li>
<li>If <var>list</var> is <code>null</code>:
<ol>
<li>If <var>subject node</var> does not have an <var>active property</var> <a>entry</a>,
create one and initialize its value to an <a>array</a>
containing <var>reference</var>.</li>
<li>Otherwise, compare <var>reference</var> against every item in the
<a>array</a> associated with the <var>active property</var>
<a>entry</a> of <var>subject node</var>. If there is no item equivalent to <var>reference</var>,
append <var>reference</var> to the <a>array</a>. Two
<a class="changed">maps</a> are considered
equal if they have equivalent <a>map entries</a>.</li>
</ol>
</li>
<li>Otherwise, append <var class="changed">reference</var> to the <code>@list</code> <a>entry</a> of <var>list</var>.</li>
</ol>
</li>
<li>If <var>element</var> has an <code>@type</code> <a>entry</a>, append
each item of its associated <a>array</a> to the
<a>array</a> associated with the <code>@type</code> <a>entry</a> of
<var>node</var> unless it is already in that <a>array</a>. Finally
remove the <code>@type</code> <a>entry</a> from <var>element</var>.</li>
<li>If <var>element</var> has an <code>@index</code> <a>entry</a>, set the <code>@index</code>
<a>entry</a> of <var>node</var> to its value. If <a>node</a> already has an
<code>@index</code> <a>entry</a> with a different value, a
<a data-link-for="JsonLdErrorCode">conflicting indexes</a>
error has been detected and processing is aborted. Otherwise, continue by
removing the <code>@index</code> <a>entry</a> from <var>element</var>.</li>
<li>If <var>element</var> has an <code>@reverse</code> <a>entry</a>:
<ol>
<li>Create a <a class="changed">map</a> <var>referenced node</var> with a single <a>entry</a> <code>@id</code> whose
value is <var>id</var>.</li>
<li>Initialize <var>reverse map</var> to the value of the <code>@reverse</code> <a>entry</a> of
<var>element</var>.</li>
<li>For each key-value pair <var>property</var>-<var>values</var> in <var>reverse map</var>:
<ol>
<li>For each <var>value</var> of <var>values</var>:
<ol>
<li>Recursively invoke this algorithm passing <var>value</var> for
<var>element</var>, <var>node map</var>, <var>active graph</var>,
<var>referenced node</var> for <var>active subject</var>, and
<var>property</var> for <var>active property</var>. Passing a
<a class="changed">map</a> for <var>active subject</var> indicates to the
algorithm that a reverse property relationship is being processed.</li>
</ol>
</li>
</ol>
</li>
<li>Remove the <code>@reverse</code> <a>entry</a> from <var>element</var>.</li>
</ol>
</li>
<li>If <var>element</var> has an <code>@graph</code> <a>entry</a>, recursively invoke this
algorithm passing the value of the <code>@graph</code> <a>entry</a> for <var>element</var>,
<var>node map</var>, and <var>id</var> for <var>active graph</var> before removing
the <code>@graph</code> <a>entry</a> from <var>element</var>.</li>
<li class="changed">If <var>element</var> has an `@included` <a>entry</a>,
recursively invoke this algorithm passing the value of the `@included` <a>entry</a> for <var>element</var>,
<var>node map</var>, and <var>active graph</var>
before removing the `@included` <a>entry</a> from <var>element</var>.</li>
<li>Finally, for each key-value pair <var>property</var>-<var>value</var> in <var>element</var> ordered by
<var>property</var> perform the following steps:
<ol>
<li>If <var>property</var> is a <a>blank node identifier</a>, replace it with a newly
<a href="#generate-blank-node-identifier">generated blank node identifier</a>
passing <var>property</var> for <var>identifier</var>.
<div class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD.</div></li>
<li>If <var>node</var> does not have a <var>property</var> <a>entry</a>, create one and initialize
its value to an empty <a>array</a>.</li>
<li>Recursively invoke this algorithm passing <var>value</var> for <var>element</var>,
<var>node map</var>, <var>active graph</var>, <var>id</var> for <var>active subject</var>,
and <var>property</var> for <var>active property</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</section>
</section>
<section class="changed algorithm"><h3>Merge Node Maps</h3>
<p>This algorithm creates a new map of <a>subjects</a> to <a>nodes</a> using all graphs
contained in the <var>graph map</var> created using the <a href="#node-map-generation">Node Map Generation algorithm</a>
to create merged <a>node objects</a> containing information defined for a given <a>subject</a>
in each graph contained in the <var>node map</var>.</p>
<ol>
<li>Create <var>result</var> as an empty <a>map</a></li>
<li>For each <var>graph name</var> and <var>node map</var> in <var>graph map</var>
and for each <var>id</var> and <var>node</var> in <var>node map</var>:
<ol>
<li>Initialize <var>merged node</var> to the value for <var>id</var> in <var>result</var>, initializing it
with a new <a>map</a> consisting of a single <a>entry</a> <code>@id</code> whose value is <var>id</var>, if it does not exist.</li>
<li>For each <var>property</var> and <var>values</var> in <var>node</var>:
<ol>
<li id='alg-merge-node-maps-2_2_1'>If <var>property</var> is a <a>keyword</a> <span class="changed">other than `@type`</span>, add <var>property</var> and values to <var>merged node</var>.</li>
<li>Otherwise, merge each element from <var>values</var> into the values for <var>property</var>
in <var>merged node</var>, initializing it to an empty <a>array</a> if necessary.</li>
</ol>
</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
<section><h2>Generate Blank Node Identifier</h2>
<p>This algorithm is used to generate new
<a>blank node identifiers</a> or to
relabel an existing <a>blank node identifier</a> to avoid collision
by the introduction of new ones.</p>
<section class="informative">
<h3>Overview</h3>
<p>The simplest case is if there exists already a <a>blank node identifier</a>
in the <var>identifier map</var> for the passed <var>identifier</var>, in which
case it is simply returned. Otherwise, a new <a>blank node identifier</a>
is generated. If the passed <var>identifier</var> is not <code>null</code>,
an entry is created in the <var>identifier map</var> associating the
<var>identifier</var> with the <a>blank node identifier</a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes a single input variable <var>identifier</var> which may
be <code>null</code>. The algorithm
maintains an <var>identifier map</var> to relabel existing
<a>blank node identifiers</a> to new <a>blank node identifiers</a>,
<span class="changed">which is reset when the invoking algorithm is initialized</span>.</p>
<ol>
<li>If <var>identifier</var> is not <code>null</code> and has an entry in the
<var>identifier map</var>, return the mapped identifier.</li>
<li>Otherwise, generate a new unique <a>blank node identifier</a>.</li>
<li>If <var>identifier</var> is not <code>null</code>, create a new entry
for <var>identifier</var> in <var>identifier map</var> and set its value
to the new <a>blank node identifier</a>.</li>
<li>Return the new <a>blank node identifier</a>.</li>
</ol>
<p class="note">
One way of generating new <a>blank node identifiers</a> is to maintain a counter
and increment it when generating a new identifier and appending it to
a string such as <code>_:b</code>.
</p>
</section>
</section>
</section>
<section><h1>RDF Serialization/Deserialization Algorithms</h1>
<p>This section describes algorithms to deserialize a JSON-LD document to an
<a>RDF dataset</a> and vice versa. The algorithms are designed for in-memory
implementations with random access to <a class="changed">map</a> elements.</p>
<section><h2>Deserialize JSON-LD to RDF Algorithm</h2>
<p>This algorithm deserializes a JSON-LD document to an <a>RDF dataset</a>.
Please note that RDF does not allow a <a>blank node</a> to be used
as a <a>property</a>, while JSON-LD does. Therefore, by default
<a>triples</a> that would have contained blank nodes as <a>properties</a> are
discarded when interpreting JSON-LD as RDF.</p>
<p class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD.</p>
<p class="changed">If the {{JsonLdOptions/rdfDirection}} option is not `null`, then special processing is used to
convert from an `i18n-datatype` or `compound-literal` form.</p>
<p class="changed">Implementations MUST generate only <dfn>well-formed</dfn>
<a>triples</a> and <a>graph names</a>:</p>
<ul>
<li>An <a>IRI</a> is <a>well-formed</a> if it matches the
<a data-cite="RFC3987#section-2.2">ABNF for <strong>IRI</strong></a> as
described in [[RFC3987]].</li>
<li>A <a>blank node identifier</a> is <a>well-formed</a> if it matches the
<a data-cite="Turtle#sec-grammar-grammar">EBNF for
<strong>BLANK_NODE_LABEL</strong></a> as described in [[Turtle]].
<div class="note">When following the algorithm described here,
all blank node identifiers will be normalized using the <a
href="#generate-blank-node-identifier">Generate Blank Node Identifier
algorithm</a> and automatically adhere to this form.</div>
</li>
<li>A <a>literal</a> is <a>well-formed</a> if it has the
<a>lexical form</a> of a <a>string</a>, any <a>datatype IRI</a> is
<a>well-formed</a>, and any <a>language tag</a> is <a>well-formed</a>
according to <a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of
[[BCP47]].</li>
</ul>
<section class="informative">
<h3>Overview</h3>
<p>The JSON-LD document is expanded and converted to a <var>node map</var> using the
<a href="#node-map-generation">Node Map Generation algorithm</a>.
This allows each graph represented within the document to be
extracted and flattened, making it easier to process each
<a>node object</a>.
Each graph from the <var>node map</var> is processed to extract <a>triple</a>,
to which any (non-default) graph name is applied to create an <a>RDF dataset</a>.
Each <a>node object</a> in the <var>node map</var> has an <code>@id</code> <a>entry</a>
which corresponds to the <a>subject</a>,
the other <a>entries</a> represent <a>predicates</a>.
Each <a>entry</a> value is either an <a>IRI</a> or <a>blank node identifier</a>
or can be transformed to an<a>RDF literal</a>
to generate an <a>triple</a>.
<a>Lists</a> are transformed into an <a>RDF collection</a>
using the <a href="#list-to-rdf-conversion">List to RDF Conversion algorithm.</a></p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes a <a>map</a> <var>node map</var>, which
is the result of the <a href="#node-map-generation">Node Map Generation algorithm</a> and
an <a>RDF dataset</a> <var>dataset</var> into which new <a>graphs</a> and <a>triples</a> are added.
It also takes two optional input variables {{JsonLdOptions/produceGeneralizedRdf}}
and <span class="changed">{{JsonLdOptions/rdfDirection}}</span>.
Unless the {{JsonLdOptions/produceGeneralizedRdf}} option
is set to <code>true</code>, <a>triple</a>
containing a <a>blank node</a> <a>predicate</a>
are excluded from output.</p>
<p class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD,
as is the support for <a>generalized RDF Datasets</a>
and thus the {{JsonLdOptions/produceGeneralizedRdf}} option may be also be removed.</p>
<ol>
<li>For each <var>graph name</var> and <var>graph</var> in <var>node map</var>
ordered by <var>graph name</var>:
<ol>
<li>If <var>graph name</var> is
<span class="changed">not <a>well-formed</a></span>, continue
with the next <var>graph name</var>-<var>graph</var> pair.</li>
<li id="alg-jld2rdf-init-triples" class="changed">If <var>graph name</var> is <code>@default</code>,
initialize <var>triples</var> to the value of the <a data-link-for="RdfDataset">defaultGraph</a>
attribute of <var>dataset</var>.
Otherwise, initialize <var>triples</var> as an empty <a>RdfGraph</a>
and add to <var>dataset</var> using its
{{RdfDataset/add}} method along with <var>graph name</var>
for <a data-lt="RdfDataset-add-graphName">`graphName`</a>.</li>
<li>For each <var>subject</var> and <var>node</var> in <var>graph</var> ordered
by <var>subject</var>:
<ol>
<li>If <var>subject</var> is
<span class="changed">not <a>well-formed</a></span>, continue
with the next <var>subject</var>-<var>node</var> pair.</li>
<li>For each <var>property</var> and <var>values</var> in <var>node</var>
ordered by <var>property</var>:
<ol>
<li>If <var>property</var> is <code>@type</code>, then for each
<var>type</var> in <var>values</var>,
create a new <a>RdfTriple</a>
composed of <var>subject</var>, <code>rdf:type</code> for <a data-link-for="RdfTriple">predicate</a>,
and <var>type</var> for <a data-link-for="RdfTriple">object</a>
<span class="changed">and add to <var>triples</var>
using its {{RdfGraph/add}} method,
unless <var>type</var> is not <a>well-formed</a></span>.</li>
<li>Otherwise, if <var>property</var> is a <a>keyword</a>
continue with the next <var>property</var>-<var>values</var> pair.</li>
<li>Otherwise, if <var>property</var> is a <a>blank node identifier</a> and
the {{JsonLdOptions/produceGeneralizedRdf}} option is not <code>true</code>,
continue with the next <var>property</var>-<var>values</var> pair.
<div class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD,
as is the support for <a>generalized RDF Datasets</a>
and thus the {{JsonLdOptions/produceGeneralizedRdf}} option may be also be removed.</div>
</li>
<li>Otherwise, if <var>property</var> is
<span class="changed">not <a>well-formed</a></span>,
continue with the next <var>property</var>-<var>values</var> pair.</li>
<li>Otherwise, <var>property</var> is an <a>IRI</a> or
<a>blank node identifier</a>. For each <var>item</var>
in <var>values</var>:
<ol>
<li id="alg-jld2rdf-init-list-triples" class="changed">Initialize <var>list triples</var> as an empty <a>array</a>.
<div class="note">
<var>item</var> is a <a>value object</a>, <a class="changed">list object</a>,
or a <a>node object</a>.</div>
</li>
<li id="alg-jld2rdf-add-list-triples">Add a <a>triple</a>
composed of <var>subject</var>, <var>property</var>, and
the result of using the
<a href="#object-to-rdf-conversion">Object to RDF Conversion algorithm</a>
passing <var>item</var>
<span class="changed">and <var>list triples</var></span>
to <var>triples</var> using its {{RdfGraph/add}} method,
unless the result is <code>null</code>,
indicating a <span class="changed">non-<a>well-formed</a> <a>resource</a></span>
that has to be ignored.</li>
<li class="changed">Add all <a>RdfTriple</a> instances from
<var>list triples</var> to <var>triples</var> using
its {{RdfGraph/add}} method.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</section>
</section>
<section><h3>Object to RDF Conversion</h3>
<p>This algorithm takes a <a>node object</a>, <a class="changed">list object</a>, or <a>value object</a>
and transforms it into an <a>resource</a> to be used as the <a>object</a> of an <a>triple</a>.
If a <a>node object</a> containing a <a>relative IRI reference</a> is passed to
the algorithm, <code>null</code> is returned which then causes the resulting
<a>triple</a> to be ignored.
<span class="changed">If the input is a <a>list object</a>, it will also
return the triples created from that input.</span></p>
<section class="informative">
<h3>Overview</h3>
<p><a>Value objects</a> are transformed to
<a>RDF literals</a> as described in
<a class="sectionRef" href="#data-round-tripping"></a>
whereas <a>node objects</a> are transformed
to <a>IRIs</a>,
<a>blank node identifiers</a>,
or <code>null</code>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes as two arguments <var>item</var> which MUST be
either a <a>value object</a>, <a>list object</a>, or <a>node object</a>
and <var>list triples</var>, which is an empty array.</p>
<ol>
<li>If <var>item</var> is a <a>node object</a> and the value of
its <code>@id</code> <a>entry</a> is
<span class="changed">not <a>well-formed</a></span>, return
<code>null</code>.</li>
<li>If <var>item</var> is a <a>node object</a>, return the
<a>IRI</a> or <a>blank node identifier</a> associated
with its <code>@id</code> <a>entry</a>.</li>
<li class="changed">If <var>item</var> is a <a>list object</a>
return the result of the
<a href="#list-to-rdf-conversion">List Conversion algorithm</a>, passing
the value associated with the <code>@list</code> <a>entry</a> from
<var>item</var> and <var>list triples</var>.
</li>
<li>Otherwise, <var>item</var> is a <a>value object</a>. Initialize
<var>value</var> to the value associated with the <code>@value</code>
<a>entry</a> in <var>item</var>.
<li>Initialize <var>datatype</var> to the value associated with the
<code>@type</code> <a>entry</a> of <var>item</var> or <code>null</code> if
<var>item</var> does not have such an <a>entry</a>.</li>
<li id="alg-obj2rdf-datatype" class="changed">If <var>datatype</var> is not `null`
and neither a <a>well-formed</a> <a>IRI</a> nor <code>@json</code>,
return <code>null</code>.</li>
<li class="changed">If <var>item</var> has an <code>@language</code>
<a>entry</a> which is not <a>well-formed</a>, return <code>null</code>.</li>
<li class="changed">If <var>datatype</var> is <code>@json</code>,
convert <var>value</var> to the <a>canonical lexical form</a>
using the result of transforming the <a>internal representation</a> of <var>value</var>
to JSON and set <var>datatype</var> to <code>rdf:JSON</code>.
<div class="issue">The JSON Canonicalization Scheme (JCS) [[?RFC8785]]
is an emerging standard for JSON canonicalization.
This specification will likely be updated to require such a canonical representation.
Users are cautioned from depending on the
<a>JSON literal</a> lexical representation as an <a>RDF literal</a>,
as the specifics of serialization may change in a future revision of this document.</div></li>
<li>If <var>value</var> is <code>true</code> or
<code>false</code>, set <var>value</var> to the <a>string</a>
<code>true</code> or <code>false</code> which is the
<a>canonical lexical form</a> as described in
<a class="sectionRef" href="#data-round-tripping"></a>
If <var>datatype</var> is <code>null</code>,
set <var>datatype</var> to <code>xsd:boolean</code>.</li>
<li id="alg-obj2rdf-double">Otherwise, if <var>value</var> is a <a>number</a> with a non-zero fractional
part (the result of a modulo‑1 operation)
<span class="changed">or an absolute value greater or equal to 10<sup>21</sup></span>,
or <var>value</var> is a <a>number</a>
and <var>datatype</var> equals <code>xsd:double</code>, convert <var>value</var> to a
<a>string</a> in <a>canonical lexical form</a> of
an <a data-cite="XMLSCHEMA11-2#double"><code>xsd:double</code></a> as defined in [[XMLSCHEMA11-2]]
and described in
<a class="sectionRef" href="#data-round-tripping"></a>.
If <var>datatype</var> is <code>null</code>,
set <var>datatype</var> to <code>xsd:double</code>.</li>
<li id="alg-obj2rdf-integer">Otherwise, if <var>value</var> is a <a>number</a>,
convert it to a <a>string</a> in <a>canonical lexical form</a> of
an <a data-cite="XMLSCHEMA11-2#integer"><code>xsd:integer</code></a> as defined in [[XMLSCHEMA11-2]]
and described in
<a class="sectionRef" href="#data-round-tripping"></a>.
If <var>datatype</var> is <code>null</code>,
set <var>datatype</var> to <code>xsd:integer</code>.
<div class="note">It follows from the previous step that <var>value</var>
has no non-zero fractional part.</div></li>
<li>Otherwise, if <var>datatype</var> is <code>null</code>,
set <var>datatype</var> to <code>xsd:string</code> or <code>rdf:langString</code>,
depending on if item has an <code>@language</code> <a>entry</a>.</li>
<li class="changed">If <var>item</var> contains an `@direction` <a>entry</a>
and {{JsonLdOptions/rdfDirection}} is not `null`,
<var>item</var> is a <a>value object</a> which is serialized using special rules.
<ol>
<li id="alg-obj2rdf-direction-language">
Initialize <var>language</var> to the value of `@language` in <var>item</var>
normalized to lower case,
or the empty string (`""`) if there is no such entry.
<div class="note">Generally, language tags are not normalized,
but when creating an `i18n-datatype` or `compound-literal`
values are normalized to lower case for improved interoperability.</div>
</li>
<li>If {{JsonLdOptions/rdfDirection}} is `i18n-datatype`,
set <var>datatype</var> to the result of appending <var>language</var>
and the value of `@direction` in <var>item</var> separated by an underscore (`"_"`)
to `https://www.w3.org/ns/i18n#`.
Initialize <var>literal</var> as an <a>RDF literal</a> using
<var>value</var> and <var>datatype</var>.
<div class="changed note">Processors MAY normalize <a>language tags</a> to lower case.</div>
<div class="note">As `@direction` may be used without `@language`,
it is possible, and legitimate, to create a datatype IRI
such as `http://w3.org/ns/i18n#_ltr`, which does not encode a language tag.</div></li>
<li>Otherwise, if {{JsonLdOptions/rdfDirection}} is `compound-literal`:
<ol>
<li>Initialize <var>literal</var> as a new <a>blank node</a>.</li>
<li>Create a new triple using <var>literal</var> as the subject,
`rdf:value` as the predicate, and the value of `@value` in <var>item</var>
as the object, and add it to <var>list triples</var>.</li>
<li>If the <var>item</var> has an entry for `@language`,
create a new triple using <var>literal</var> as the subject,
`rdf:language` as the predicate, and <var>language</var>
as the object, and add it to <var>list triples</var>.</li>
<li>Create a new triple using <var>literal</var> as the subject,
`rdf:direction` as the predicate, and the value of `@direction` in <var>item</var>
as the object, and add it to <var>list triples</var>.</li>
</ol>
</li>
</ol>
</li>
<li>Otherwise, initialize <var>literal</var> as an <a>RDF literal</a> using
<var>value</var> and <var>datatype</var>. If <var>item</var> has an
<code>@language</code> <a>entry</a>, add the value associated with the
<code>@language</code> <a>entry</a> as the <a>language tag</a> of <var>literal</var>.</li>
<li>Return <var>literal</var>.</li>
</ol>
</section>
</section>
<section><h3>List to RDF Conversion</h3>
<p>List Conversion is the process of taking a <a>list object</a>
and transforming it into an
<a>RDF collection</a>
as defined in RDF Semantics [[RDF11-MT]].</p>
<section class="informative">
<h3>Overview</h3>
<p>For each element of the <a>list</a> a new <a>blank node identifier</a>
is allocated which is used to generate <code>rdf:first</code> and
<code>rdf:rest</code>. The
algorithm returns the list head, which is either the first allocated
<a>blank node identifier</a> or <code>rdf:nil</code> if the
<a>list</a> is empty. If a list element represents an <a>IRI</a>,
the corresponding <code>rdf:first</code> triple is omitted.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>The algorithm takes two inputs: an <a>array</a> <var>list</var>
and an empty <a>array</a> <var>list triples</var> used for returning
the generated <a>triples</a>.</p>
<ol>
<li>If <var>list</var> is empty, return <code>rdf:nil</code>.</li>
<li>Otherwise, create an <a>array</a> <var>bnodes</var> composed of a
<a href="#generate-blank-node-identifier">newly generated blank node identifier</a>
for each entry in <var>list</var>.</li>
<li>For each pair of <var>subject</var> from <var>bnodes</var> and <var>item</var> from <var>list</var>:
<ol>
<li class="changed">Initialize <var>embedded triples</var> to a new empty array.</li>
<li>Initialize <var>object</var> to the result of using the
<a href="#object-to-rdf-conversion">Object to RDF Conversion algorithm</a>
passing <var>item</var>
<span class="changed">and <var>embedded triples</var> for <var>list triples</var></span>.</li>
<li>Unless <var>object</var> is <code>null</code>, append a <a>triple</a>
composed of <var>subject</var>, <code>rdf:first</code>, and <var>object</var>
to <var>list triples</var>.</li>
<li>Initialize <var>rest</var> as the next entry in <var>bnodes</var>, or if that
does not exist, <code>rdf:nil</code>. Append a
<a>triple</a> composed of <var>subject</var>,
<code>rdf:rest</code>, and <var>rest</var> to <var>list triples</var>.</li>
<li class="changed">Append all values from <var>embedded triples</var> to <var>list triples</var></li>
</ol>
</li>
<li>Return the first <a>blank node</a> from <var>bnodes</var> or
<code>rdf:nil</code> if <var>bnodes</var> is empty.</li>
</ol>
</section>
</section>
<section class="algorithm"><h2>Serialize RDF as JSON-LD Algorithm</h2>
<p>This algorithm serializes an <a>RDF dataset</a> consisting of a
<a>default graph</a> and zero or more
<a>named graphs</a> into a JSON-LD document.</p>
<p>In the RDF abstract syntax, <a>RDF literals</a> have a
<a data-cite="RDF11-CONCEPTS#dfn-lexical-form"><dfn>lexical form</dfn></a>, as defined
in [[RDF11-CONCEPTS]]. The form of these literals is used when creating <a>JSON-LD values</a> based on these literals.</p>
<section class="informative">
<h3>Overview</h3>
<p>Iterate through each graph in the dataset, converting each
<a>RDF collection</a> into a <a>list</a>
and generating a JSON-LD document in expanded form for all
<a>RDF literals</a>, <a>IRIs</a>
and <a>blank node identifiers</a>.
If the <a data-link-for="JsonLdOptions">useNativeTypes</a> flag is set to <code>true</code>,
<a>RDF literals</a> with a
<a>datatype IRI</a>
that equals <code>xsd:integer</code> or <code>xsd:double</code> are converted
to a <a>JSON numbers</a> and <a>RDF literals</a>
with a <a>datatype IRI</a>
that equals <code>xsd:boolean</code> are converted to <code>true</code> or
<code>false</code> based on their
<a>lexical form</a>
as described in
<a class="sectionRef" href="#data-round-tripping"></a>.
Unless the <a data-link-for="JsonLdOptions">useRdfType</a> flag is set to true, <code>rdf:type</code>
predicates will be serialized as <code>@type</code> as long as the associated object is
either an <a>IRI</a> or <a>blank node identifier</a>.</p>
<p class="changed">If the {{JsonLdOptions/rdfDirection}} option is not `null`, then special processing is used to
convert from an `i18n-datatype` or `compound-literal` form.</p>
</section>
<section>
<h2>Algorithm</h2>
<p>The algorithm takes one required and four optional inputs:
an <a>RDF dataset</a> <var>dataset</var>
and the four optional arguments are
the <span class="changed">{{JsonLdOptions/ordered}} flag, defaulting to `false`, used to order
<a>map entry</a> keys lexicographically, where noted</span>,
<span class="changed">{{JsonLdOptions/rdfDirection}}</span> defaulting to `null`,
the <a data-link-for="JsonLdOptions">useNativeTypes</a> flag, defaulting to `false`,
and the <a data-link-for="JsonLdOptions">useRdfType</a> flag, defaulting to `false`.</p>
<p>The <var>dataset</var> is <a data-link-for="RdfDataset">iterable</a> to iterate over <a>graphs</a> and <a>graph names</a>
contained within the <a>RdfDataset</a>. Each <a>graph</a> is also <a data-link-for="RdfGraph">iterable</a>
for iterating over <a>triples</a> contained within the <a>RdfGraph</a>.</p>
<ol>
<li>Initialize <var>default graph</var> to an empty <a class="changed">map</a>.</li>
<li>Initialize <var>graph map</var> to a <a class="changed">map</a> consisting
of a single <a>entry</a> <code>@default</code> whose value references
<var>default graph</var>.</li>
<li class="changed">Initialize <var>referenced once</var> to an empty <a>map</a>.</li>
<li class="changed">Initialize <var>compound literal subjects</var> to an empty <a>map</a>.</li>
<li>For each <var>graph</var> in <var>dataset</var>:
<ol>
<li>If <var>graph</var> is the <a>default graph</a>,
initialize <var>name</var> to <code>@default</code>, otherwise to the
<a>graph name</a> associated with <var>graph</var>.</li>
<li>If <var>graph map</var> has no <var>name</var> <a>entry</a>, create one and set
its value to an empty <a class="changed">map</a>.</li>
<li>If <var>compound literal subjects</var> has no <var>name</var> <a>entry</a>, create one and set
its value to an empty <a class="changed">map</a>.</li>
<li>If <var>graph</var> is not the <a>default graph</a> and
<var>default graph</var> does not have a <var>name</var> <a>entry</a>,
create such an <a>entry</a> and initialize its value to a new
<a class="changed">map</a> with a single <a>entry</a> <code>@id</code>
whose value is <var>name</var>.</li>
<li>Reference the value of the <var>name</var> <a>entry</a> in <var>graph map</var>
using the variable <var>node map</var>.</li>
<li class="changed">Reference the value of the <var>name</var> <a>entry</a> in <var>compound literal subjects</var>
using the variable <var>compound map</var>.</li>
<li>For each <a>triple</a> in <var>graph</var>
consisting of <var>subject</var>, <var>predicate</var>, and <var>object</var>:
<ol>
<li>If <var>node map</var> does not have a <var>subject</var> <a>entry</a>,
create one and initialize its value to a new <a class="changed">map</a>
consisting of a single <a>entry</a> <code>@id</code> whose value is
set to <var>subject</var>.</li>
<li>Reference the value of the <var>subject</var> <a>entry</a> in <var>node map</var>
using the variable <var>node</var>.</li>
<li class="changed">If the {{JsonLdOptions/rdfDirection}} option
is `compound-literal` and <var>predicate</var> is `rdf:direction`,
add an entry in <var>compound map</var> for <var>subject</var> with the value `true`.</li>
<li>If <var>object</var> is an <a>IRI</a> or <a>blank node identifier</a>,
and <var>node map</var> does not have an <var>object</var> <a>entry</a>,
create one and initialize its value to a new <a class="changed">map</a>
consisting of a single <a>entry</a> <code>@id</code> whose value is
set to <var>object</var>.</li>
<li>If <var>predicate</var> equals <code>rdf:type</code>, the
<a data-link-for="JsonLdOptions">useRdfType</a> flag is not <code>true</code>, and <var>object</var>
is an <a>IRI</a> or <a>blank node identifier</a>,
append <var>object</var> to the value of the <code>@type</code>
<a>entry</a> of <var>node</var>; unless such an item already exists.
If no such <a>entry</a> exists, create one
and initialize it to an <a>array</a> whose only item is
<var>object</var>. Finally, continue to the next
<a>triple</a>.</li>
<li>Initialize <var>value</var> to the result of using the
<a href="#rdf-to-object-conversion">RDF to Object Conversion algorithm</a>,
passing <var>object</var>,
<span class="changed">{{JsonLdOptions/rdfDirection}}</span>,
and <a data-link-for="JsonLdOptions">useNativeTypes</a>.</li>
<li>If <var>node</var> does not have a <var>predicate</var> <a>entry</a>, create one
and initialize its value to an empty <a>array</a>.</li>
<li>If there is no item equivalent to <var>value</var> in the <a>array</a>
associated with the <var>predicate</var> <a>entry</a> of <var>node</var>, append a
reference to <var>value</var> to the <a>array</a>. Two <a>maps</a>
are considered equal if they have equivalent <a>map entries</a>.</li>
<li class="changed">If <var>object</var> is <code>rdf:nil</code>, it represents
the termination of an <a>RDF collection</a>:
<ol>
<li>Reference the <code>usages</code> <a>entry</a> of the <var>object</var>
<a>entry</a> of <var>node map</var> using the variable <var>usages</var>.</li>
<li>Append a new <a>map</a> consisting of three
<a>entries</a>, <code>node</code>, <code>property</code>, and <code>value</code>
to the <var>usages</var> <a>array</a>. The <code>node</code> <a>entry</a>
is set to a reference to <var>node</var>, <code>property</code> to <var>predicate</var>,
and <code>value</code> to a reference to <var>value</var>.</li>
</ol>
</li>
<li class="changed">Otherwise, if <var>referenced once</var> has an entry for <var>object</var>,
set the <var>object</var> <a>entry</a> of <var>referenced once</var> to <code>false</code>.</li>
<li class="changed">Otherwise, if <var>object</var> is a <a>blank node identifier</a>,
it might represent a list node:
<ol>
<li>Set the <var>object</var> <a>entry</a> of <var>referenced once</var> to a new <a>map</a> consisting of three
<a>entries</a>, <code>node</code>, <code>property</code>, and <code>value</code>
to the <var>usages</var> <a>array</a>. The <code>node</code> <a>entry</a>
is set to a reference to <var>node</var>, <code>property</code> to <var>predicate</var>,
and <code>value</code> to a reference to <var>value</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>For each <var>name</var> and <var>graph object</var> in <var>graph map</var>:
<ol>
<li class="change">If <var>compound literal subjects</var>
has an entry for <var>name</var>, then for each <var>cl</var>
which is a key in that entry:
<ol>
<li>Initialize <var>cl entry</var> to the value of <var>cl</var>
in <var>referenced once</var>,
continuing to the next <var>cl</var> if <var>cl entry</var> is not a <a>map</a>.</li>
<li>Initialize <var>node</var> to the value of `node` in <var>cl entry</var>.</li>
<li>Initialize <var>property</var> to value of `property` in <var>cl entry</var>.</li>
<li>Initialize <var>value</var> to value of `value` in <var>cl entry</var>.</li>
<li>Initialize <var>cl node</var> to the value of <var>cl</var>
in <var>graph object</var>, and remove that <a>entry</a> from <var>graph object</var>,
continuing to the next <var>cl</var> if <var>cl node</var> is not a <a>map</a>.</li>
<li id="alg-serialize-rdf-cl-reference">For each <var>cl reference</var> in the value of <var>property</var> in <var>node</var>
where the value of `@id` in <var>cl reference</var> is <var>cl</var>:
<ol>
<li>Delete the `@id` entry in <var>cl reference</var>.</li>
<li>Add an <a>entry</a> to <var>cl reference</var> for `@value` with the value taken
from the `rdf:value` entry in <var>cl node</var>.</li>
<li>Add an <a>entry</a> to <var>cl reference</var> for `@language` with the value taken
from the `rdf:language` entry in <var>cl node</var>, if any.
If that value is not <a>well-formed</a> according to
<a data-cite="BCP47#section-2.2.9">section 2.2.9</a> of [[BCP47]],
an <a data-link-for="JsonLdErrorCode">invalid language-tagged string</a>
error has been detected and processing is aborted.</li>
<li>Add an <a>entry</a> to <var>cl reference</var> for `@direction` with the value taken
from the `rdf:direction` entry in <var>cl node</var>, if any.
If that value is not `"ltr"` or `"rtl"`, an
<a data-link-for="JsonLdErrorCode">invalid base direction</a>
error has been detected and processing is aborted.</li>
</ol>
</li>
</ol>
</li>
<li>If <var>graph object</var> has no <code>rdf:nil</code> <a>entry</a>, continue
with the next <var>name</var>-<var>graph object</var> pair as the graph does
not contain any lists that need to be converted.</li>
<li>Initialize <var>nil</var> to the value of the <code>rdf:nil</code> <a>entry</a>
of <var>graph object</var>.</li>
<li>For each item <var>usage</var> in the <code>usages</code> <a>entry</a> of
<var>nil</var>, perform the following steps:
<ol>
<li>Initialize <var>node</var> to the value of the value of the
<code>node</code> <a>entry</a> of <var>usage</var>, <var>property</var> to
the value of the <code>property</code> <a>entry</a> of <var>usage</var>,
and <var>head</var> to the value of the <code>value</code> <a>entry</a>
of <var>usage</var>.</li>
<li>Initialize two empty <a>arrays</a> <var>list</var>
and <var>list nodes</var>.</li>
<li>While <var>property</var> equals <code>rdf:rest</code>,
<span class="changed">the value of the <code>@id</code> <a>entry</a>
of <var>node</var> is a <a>blank node identifier</a>,</span>
the value of the <a>entry</a> of <var>referenced once</var> associated with the <code>@id</code>
<a>entry</a> of <code>node</code> is a <a>map</a>,
<var>node</var> has <code>rdf:first</code> and <code>rdf:rest</code> <a>entries</a>,
both of which have as value an <a>array</a> consisting of a single element,
and <var>node</var> has no other <a>entries</a> apart from an optional <code>@type</code>
<a>entry</a> whose value is an array with a single item equal to
<code>rdf:List</code>,
<var>node</var> represents a <a>well-formed</a> list node.
Perform the following steps to traverse the list backwards towards its head:
<ol>
<li>Append the only item of <code>rdf:first</code> <a>entry</a> of
<var>node</var> to the <var>list</var> <a>array</a>.</li>
<li>Append the value of the <code>@id</code> <a>entry</a> of
<var>node</var> to the <var>list nodes</var> <a>array</a>.</li>
<li>Initialize <var>node usage</var> to the value of the <a>entry</a> of <var>referenced once</var> associated with the <code>@id</code>
<a>entry</a> of <code>node</code>.</li>
<li>Set <var>node</var> to the value of the <code>node</code> <a>entry</a>
of <var>node usage</var>, <var>property</var> to the value of the
<code>property</code> <a>entry</a> of <var>node usage</var>, and
<var>head</var> to the value of the <code>value</code> <a>entry</a>
of <var>node usage</var>.</li>
<li>If the <code>@id</code> <a>entry</a> of <var>node</var> is an
<a>IRI</a> instead of a <a>blank node identifier</a>,
exit the while loop.</li>
</ol>
</li>
<li>Remove the <code>@id</code> <a>entry</a> from <var>head</var>.</li>
<li>Reverse the order of the <var>list</var> <a>array</a>.</li>
<li>Add an <code>@list</code> <a>entry</a> to <var>head</var> and initialize
its value to the <var>list</var> <a>array</a>.</li>
<li>For each item <var>node id</var> in <var>list nodes</var>, remove the
<var>node id</var> <a>entry</a> from <var>graph object</var>.</li>
</ol>
</li>
</ol>
</li>
<li>Initialize an empty <a>array</a> <var>result</var>.</li>
<li>For each <var>subject</var> and <var>node</var> in <var>default graph</var>
ordered lexicographically by <var>subject</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>:
<ol>
<li>If <var>graph map</var> has a <var>subject</var> <a>entry</a>:
<ol>
<li>Add an <code>@graph</code> <a>entry</a> to <var>node</var> and initialize
its value to an empty <a>array</a>.</li>
<li>For each key-value pair <var>s</var>-<var>n</var> in the <var>subject</var>
<a>entry</a> of <var>graph map</var> ordered lexicographically by <var>s</var>
<span class="changed">if {{JsonLdOptions/ordered}} is <code>true</code></span>,
append <var>n</var> to the <code>@graph</code> <a>entry</a> of <var>node</var> after
removing its <code>usages</code> <a>entry</a>, unless the only
remaining <a>entry</a> of <var>n</var> is <code>@id</code>.</li>
</ol>
</li>
<li>Append <var>node</var> to <var>result</var> after removing its
<code>usages</code> <a>entry</a>, unless the only remaining <a>entry</a> of
<var>node</var> is <code>@id</code>.</li>
</ol>
</li>
<li>Return <var>result</var>.</li>
</ol>
</section>
</section>
<section><h2>RDF to Object Conversion</h2>
<p>This algorithm transforms an RDF literal to a JSON-LD <a>value object</a>
and a RDF <a>blank node</a> or <a>IRI</a> to an JSON-LD <a>node object</a>.</p>
<section class="informative">
<h3>Overview</h3>
<p><a>RDF literals</a> are transformed to
<a>value objects</a> whereas <a>IRIs</a> and
<a>blank node identifiers</a> are
transformed to <a>node objects</a>.</p>
<p class="changed">Literals with datatype <code>rdf:JSON</code>
are transformed into a value object using the internal representation
based on the lexical-to-value mapping defined in
<a data-cite="JSON-LD11#the-rdf-json-datatype" class="externalDfn">JSON datatype</a> in [[JSON-LD11]],
and <code>@type</code> of <code>@json</code>.</p>
<p class="changed">With the {{JsonLdOptions/rdfDirection}} option set to `i18n-datatype`,
literals with datatype starting with `https://www.w3.org/ns/i18n#`
are transformed into a <a>value object</a> by decoding
the <a>language tag</a> and <a>base direction</a> from the datatype.</p>
<p class="changed">With the {{JsonLdOptions/rdfDirection}} option set to `compound-literal`,
blank node objects using `rdf:direction` are
are transformed into a <a>value object</a> by decoding
the `rdf:value`, `rdf:language`, and `rdf:direction` properties.</p>
<p>If the <a data-link-for="JsonLdOptions">useNativeTypes</a> flag is set to <code>true</code>,
<a>RDF literals</a> with a
<a>datatype IRI</a>
that equals <code>xsd:integer</code> or <code>xsd:double</code> are converted
to a <a>JSON numbers</a> and <a>RDF literals</a>
with a <a>datatype IRI</a>
that equals <code>xsd:boolean</code> are converted to <code>true</code> or
<code>false</code> based on their
<a>lexical form</a>
as described in
<a class="sectionRef" href="#data-round-tripping"></a>.</p>
</section>
<section class="algorithm">
<h3>Algorithm</h3>
<p>This algorithm takes three required inputs:
a <var>value</var> to be converted to a <a class="changed">map</a>,
<span class="changed">{{JsonLdOptions/rdfDirection}}</span>,
and a flag <a data-link-for="JsonLdOptions">useNativeTypes</a>.</p>
<ol>
<li>If <var>value</var> is an <a>IRI</a> or a
<a>blank node identifier</a>, return a new <a class="changed">map</a>
consisting of a single <a>entry</a> <code>@id</code> whose value is set to
<var>value</var>.</li>
<li>Otherwise <var>value</var> is an
<a>RDF literal</a>:
<ol>
<li>Initialize a new empty <a class="changed">map</a> result.</li>
<li>Initialize <var>converted value</var> to <var>value</var>.</li>
<li>Initialize <var>type</var> to <code>null</code></li>
<li>If <a data-link-for="JsonLdOptions">useNativeTypes</a> is <code>true</code>
<ol>
<li>If the
<a>datatype IRI</a>
of <var>value</var> equals <code>xsd:string</code>, set
<var>converted value</var> to the
<a>lexical form</a>
of <var>value</var>.</li>
<li>Otherwise, if the
<a>datatype IRI</a>
of <var>value</var> equals <code>xsd:boolean</code>, set
<var>converted value</var> to <code>true</code> if the
<a>lexical form</a>
of <var>value</var> matches <code>true</code>, or <code>false</code>
if it matches <code>false</code>. If it matches neither,
set <var>type</var> to <code>xsd:boolean</code>.</li>
<li>Otherwise, if the
<a>datatype IRI</a>
of <var>value</var> equals <code>xsd:integer</code> or
<code>xsd:double</code> and its
<a>lexical form</a>
is a valid <code>xsd:integer</code> or <code>xsd:double</code>
according [[XMLSCHEMA11-2]], set <var>converted value</var>
to the result of converting the
<a>lexical form</a>
to a JSON <a>number</a>.</li>
</ol>
</li>
<li class="changed">Otherwise, if <a>processing mode</a> is not `json-ld-1.0`,
and <var>value</var> is a <a>JSON literal</a>,
set <var>converted value</var> to the result of
turning the lexical value of <var>value</var>
into the <a>JSON-LD internal representation</a>, and set <var>type</var> to <code>@json</code>.
If the lexical value of <var>value</var> is not valid JSON according to
the <a data-cite="RFC8259#section-2">JSON Grammar</a> [[RFC8259]],
an <a data-link-for="JsonLdErrorCode">invalid JSON literal</a>
error has been detected and processing is aborted.</li>
<li class="changed">Otherwise, if the <a>datatype IRI</a> of <var>value</var> starts with `https://www.w3.org/ns/i18n#`,
and {{JsonLdOptions/rdfDirection}} is `i18n-datatype`:
<ol>
<li>Set <var>converted value</var> to the <a>lexical form</a> of <var>value</var>.</li>
<li>If the string prefix of the <a data-cite="RFC3986#section-3.5">fragment identifier</a>
of the <a>datatype IRI</a> up until the underscore (`"_"`) is not empty,
add an <a>entry</a> `@language` to <var>result</var> and set its value to that prefix.
<div class="note">As `@direction` may be used without `@language`,
it is possible, and legitimate, to create a datatype IRI
such as `http://w3.org/ns/i18n#_ltr`, which does not encode a language tag.</div></li>
<li>Add an <a>entry</a> `@direction` to <var>result</var> and set its value to the substring of the
<a data-cite="RFC3986#section-3.5">fragment identifier</a> following
the underscore (`"_"`).</li>
</ol>
</li>
<li>Otherwise, if <var>value</var> is a
<a>language-tagged string</a>
add an <a>entry</a> <code>@language</code> to <var>result</var> and set its value to the
<a>language tag</a> of <var>value</var>.</li>
<li>Otherwise, set <var>type</var> to the
<a>datatype IRI</a>
of <var>value</var>, unless it equals <code>xsd:string</code> which is ignored.</li>
<li>Add an <a>entry</a> <code>@value</code> to <var>result</var> whose value
is set to <var>converted value</var>.</li>
<li>If <var>type</var> is not <code>null</code>, add an <a>entry</a> <code>@type</code>
to <var>result</var> whose value is set to <var>type</var>.</li>
<li>Return <var>result</var>.</li>
</ol>
</li>
</ol>
</section>
</section>
<section><h2>Data Round Tripping</h2>
<p>When <a href="#deserialize-json-ld-to-rdf-algorithm">deserializing JSON-LD to RDF</a>
JSON-native <a>numbers</a> are automatically
type-coerced to <code>xsd:integer</code> or <code>xsd:double</code>
depending on whether the <a>number</a> has a non-zero fractional part
or not (the result of a modulo‑1 operation), the boolean values
<code>true</code> and <code>false</code> are coerced to <code>xsd:boolean</code>,
and <a>strings</a> are coerced to <code>xsd:string</code>.
The <span class="changed">JSON</span>, numeric, or boolean values themselves are converted to
<dfn>canonical lexical form</dfn>, i.e., a deterministic string
representation as defined in [[XMLSCHEMA11-2]].</p>
<p>The <a>canonical lexical form</a> of an <em>integer</em>, i.e., a
<a>number</a> with no non-zero fractional part
<span class="changed">and an absolute value less than 10<sup>21</sup>,</span>
or a <a>number</a> coerced to <code>xsd:integer</code>,
is a finite-length sequence of decimal
digits (<code>0-9</code>) with an optional leading minus sign; leading
zeros are prohibited. In JavaScript, implementers can use the following
snippet of code to convert an integer to
<a>canonical lexical form</a>:</p>
<pre class="example nohighlight" data-transform="updateExample"
data-ignore
title="Sample integer serialization implementation in JavaScript">
</pre>
<p>The <a>canonical lexical form</a> of a <em>double</em>, i.e., a
<a>number</a>
<span class="changed">with a non-zero fractional part or an absolute value greater or equal to 10<sup>21</sup></span>,
or a <a>number</a>
coerced to <code>xsd:double</code>, consists of a mantissa followed by the
character <code>E</code>, followed by an exponent. The mantissa is a
decimal number and the exponent is an integer. Leading zeros and a
preceding plus sign (<code>+</code>) are prohibited in the exponent.
If the exponent is zero, it is indicated by <code>E0</code>. For the
mantissa, the preceding optional plus sign is prohibited and the
decimal point is required. Leading and trailing zeros 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 <code>0.0E0</code>.
<code>xsd:double</code>'s value space is defined by the IEEE
double-precision 64-bit floating point type [[IEEE-754-2008]] whereas
the value space of JSON <a>numbers</a> is not
specified; when deserializing JSON-LD to RDF the mantissa is rounded to
15 digits after the decimal point. In JavaScript, implementers
can use the following snippet of code to convert a double to
<a>canonical lexical form</a>:</p>
<pre class="example nohighlight" data-transform="updateExample"
data-ignore
title="Sample floating point number serialization implementation in JavaScript">
</pre>
<p>The <a>canonical lexical form</a> of the <em>boolean</em>
values <code>true</code> and <code>false</code> are the strings
<code>true</code> and <code>false</code>.</p>
<p class="changed">The <a>canonical lexical form</a> of a <a>JSON literal</a>
is the result of serializing the <a>internal representation</a>
into the JSON format [[RFC8259]] in compliance with the constraints of the <strong>value space</strong> description within
<a data-cite="JSON-LD11#the-rdf-json-datatype">The <code>rdf:JSON</code> Datatype</a> of [[JSON-LD11]].</p>
<aside class="example changed" data-ignore
title="Canonicalized JSON literal">
<pre class="original input" data-transform="updateExample">
</pre>
<p>The example shows the value of "e" as a native JSON array including
unnecessary whitespace, a number and an object. The result
eliminates the whitespace, uses a canonical number representation,
and reorders the <a>map entries</a> lexicographically:</p>
<pre class="turtle result"
data-content-type="text/turtle"
data-result-for="Canonicalized JSON literal-original"
data-transform="updateExample"
data-to-rdf>
</pre>
</aside>
<p>When JSON-native <a>numbers</a> are deserialized
to RDF, lossless data round-tripping cannot be guaranteed, as rounding
errors might occur. When
<a href="#serialize-rdf-as-json-ld-algorithm">serializing RDF as JSON-LD</a>,
similar rounding errors might occur. Furthermore, the datatype or the lexical
representation might be lost. An <code>xsd:double</code> with a value
of <code>2.0</code> will, e.g., result in an <code>xsd:integer</code>
with a value of <code>2</code> in <a>canonical lexical form</a>
when converted from RDF to JSON-LD and back to RDF. It is important
to highlight that in practice it might be impossible to losslessly
convert an <code>xsd:integer</code> to a <a>number</a> because
its value space is not limited. While the JSON specification [[RFC8259]]
does not limit the value space of <a>numbers</a>
either, concrete implementations typically do have a limited value
space.</p>
<p>To ensure lossless round-tripping the
<a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
specifies a <a data-link-for="JsonLdOptions">useNativeTypes</a> flag which controls whether
<a>RDF literals</a>
with a <a>datatype IRI</a>
equal to <code>xsd:integer</code>, <code>xsd:double</code>, or
<code>xsd:boolean</code> are converted to their JSON-native
counterparts. If the <a data-link-for="JsonLdOptions">useNativeTypes</a> flag is set to
<code>false</code>, all literals remain in their original string
representation.</p>
<p>Some JSON serializers, such as PHP's native implementation in some versions,
backslash-escape the forward slash character. For example, the value
<code>http://example.com/</code> would be serialized as <code>http:\/\/example.com\/</code>.
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, forward slashes MUST NOT be
backslash-escaped.</p>
</section>
</section>
<section><h2>The Application Programming Interface</h2>
<p>This API provides a clean mechanism that enables developers to convert
JSON-LD data into a variety of output formats that are often easier to
work with.</p>
<p>The JSON-LD API uses <a data-cite="ECMASCRIPT#sec-promise-objects">Promises</a> to represent
the result of the various deferred operations.
<a data-cite="ECMASCRIPT#sec-promise-objects">Promises</a> are defined in [[ECMASCRIPT]].
General use within specifications can be found in [[promises-guide]].
<span class="changed">Implementations MAY chose to implement in an appropriate way for their native environments
as long as they generally use the same methods, arguments, and options
and return the same results.</span></p>
<p class="note">Interfaces are marked `[Exposed=JsonLd]`,
which creates a global interface.
The use of WebIDL in JSON-LD, while appropriate for use within browsers,
is not limited to such use.</p>
<section><h3>The <dfn>JsonLdProcessor</dfn> Interface</h3>
<p>The <a>JsonLdProcessor</a> interface is the high-level programming structure
that developers use to access the JSON-LD transformation methods.</p>
<p>It is important to highlight that implementations do not modify the input parameters.
If an error is detected, the {{Promise}} is
rejected with a <a>JsonLdError</a> having an appropriate {{JsonLdError/code}}
and processing is stopped.</p>
<p>If the <a data-link-for="JsonLdOptions">documentLoader</a>
option is specified, it is used to dereference remote documents and contexts.
The {{RemoteDocument/documentUrl}}
in the returned <a>RemoteDocument</a>
is used as <a>base IRI</a> and the
{{RemoteDocument/contextUrl}}
is used instead of looking at the HTTP Link Header directly. For the sake of simplicity, none of the algorithms
in this document mention this directly.</p>
<pre class="idl">
/*
* The JsonLd interface is created to expose the JsonLdProcessor interface.
*/
[Global=JsonLd, Exposed=JsonLd]
interface JsonLd {};
[Exposed=JsonLd]
interface JsonLdProcessor {
constructor();
static Promise<JsonLdRecord> compact(
JsonLdInput input,
optional JsonLdContext context = null,
optional JsonLdOptions options = {});
static Promise<sequence<JsonLdRecord>> expand(
JsonLdInput input,
optional JsonLdOptions options = {});
static Promise<JsonLdRecord> flatten(
JsonLdInput input,
optional JsonLdContext context = null,
optional JsonLdOptions options = {});
static Promise<sequence<JsonLdRecord>> fromRdf(
RdfDataset input,
optional JsonLdOptions options = {});
static Promise<RdfDataset> toRdf(
JsonLdInput input,
optional JsonLdOptions options = {});
};
</pre>
<dl data-sort>
<dt><dfn data-dfn-for="JsonLdProcessor">compact()</dfn></dt>
<dd class="algorithm">
<p><a>Compacts</a> the given <a data-lt="jsonldprocessor-compact-input">input</a> using the
<var>context</var> according to the steps in the <a href="#compaction-algorithm">Compaction algorithm</a>:</p>
<p class="changed">The final output is a <a>map</a>
derived from <var>compacted output</var>.
If <var>compacted output</var> is an <a>array</a>, it is
included with an entry of (a possibly aliased) <code>@graph</code>
with the value of <var>compacted output</var>,
otherwise <var>compacted output</var> is used as the <a>map</a> result.
If <a data-lt="jsonldprocessor-compact-context">context</a> not <code>null</code>,
an <code>@context</code> entry is added to the <a>map</a> result.</p>
<ol>
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li class="changed">If the provided <a data-lt="jsonldprocessor-compact-input">input</a>
is a <a>RemoteDocument</a>,
initialize <var>remote document</var> to <a data-lt="jsonldprocessor-compact-input">input</a>.</li>
<li>Otherwise, if the provided <a data-lt="jsonldprocessor-compact-input">input</a>
is a <a>string</a> representing the <a>IRI</a> of a remote document, await and dereference it as <var>remote document</var>
using <a>LoadDocumentCallback</a>, passing <a data-lt="jsonldprocessor-compact-input">input</a>
for {{LoadDocumentCallback/url}},
and the {{JsonLdOptions/extractAllScripts}} option from <a data-lt="jsonldprocessor-compact-options">options</a>
for <a data-link-for="LoadDocumentOptions">extractAllScripts</a>.</li>
<li>Set <var>expanded input</var> to the result of
using the <a data-link-for="JsonLdProcessor">expand()</a> method
using either <var>remote document</var>
or <a data-lt="jsonldprocessor-compact-input">input</a>
if there is no <var>remote document</var>
for <a data-lt="jsonldprocessor-expand-input">input</a>,
and <a data-lt="jsonldprocessor-compact-options">options</a>,
<span class="changed">with {{JsonLdOptions/ordered}} set to <code>false</code></span>,
<span class="changed">and {{JsonLdOptions/extractAllScripts}} defaulting to <code>false</code></span>.</li>
<li class="changed">Set <var>context base</var> to the {{RemoteDocument/documentUrl}}
from <var>remote document</var>, if available, otherwise to the {{JsonLdOptions/base}} option
from <a data-lt="jsonldprocessor-compact-options">options</a>.</li>
<li>If <a data-lt="jsonldprocessor-compact-context">context</a> is a <a class="changed">map</a>
having an <code>@context</code> <a>entry</a>,
set <var>context</var> to that <a data-lt="entry">entry's</a> value,
otherwise to <a data-lt="jsonldprocessor-compact-context">context</a>.</li>
<li class="changed">Initialize <var>active context</var>
to the result of the <a href="#context-processing-algorithm">Context Processing algorithm</a>
passing a new empty <a>context</a> as <var>active context</var>
<var>context</var> as <var>local context</var>,
and <var>context base</var> as <var>base URL</var>.</li>
<li>Set <a data-lt="context-base-iri">base IRI</a> in <var>active context</var> to the {{JsonLdOptions/base}} option from <a data-lt="jsonldprocessor-compact-options">options</a>, if set;
otherwise, if the <a data-link-for="JsonLdOptions">compactToRelative</a> option is <strong>true</strong>,
to the IRI of the currently being processed document, if available;
otherwise to <code>null</code>.</li>
<li>Set <var>compacted output</var> to the result of using the <a href="#compaction-algorithm">Compaction algorithm</a>,
using <a>active context</a>,
<code>null</code> for <var>active property</var>,
<var>expanded input</var> as <var>element</var>,
and the {{JsonLdOptions/compactArrays}}
<span class="changed">and {{JsonLdOptions/ordered}}</span>
flags from <a data-lt="jsonldprocessor-compact-options">options</a>.
<ol id="api-compact-post-processing" class="changed">
<li>If <var>compacted output</var> is an empty <a>array</a>,
replace it with a new <a>map</a>.</li>
<li>Otherwise, if <var>compacted output</var> is an <a>array</a>,
replace it with a new <a>map</a> with a single <a>entry</a>
whose key is the result of
<span class="changed"><a>IRI compacting</a> `@graph`</span>
and value is <var>compacted output</var>.</li>
<li>If <a data-lt="jsonldprocessor-compact-context">context</a> was not <code>null</code>,
add an <code>@context</code> <a>entry</a> to <var>compacted output</var> and set its value
to the provided <var>context</var>.</li>
</ol>
</li>
<li>Resolve the <var>promise</var> with <var>compacted output</var>
<span class="changed">transforming <var>compacted output</var> from the
<a>internal representation</a> to a JSON serialization</span>.</li>
</ol>
<dl class="parameters">
<dt><dfn data-lt="jsonldprocessor-compact-input" data-lt-noDefault>input</dfn></dt>
<dd>The <a class="changed">map</a>,
array of <a class="changed">maps</a> to perform the compaction upon,
or an <a>IRI</a> referencing the JSON-LD document to compact.</dd>
<dt><dfn data-lt="jsonldprocessor-compact-context" data-lt-noDefault>context</dfn></dt>
<dd>The context to use when <a>compacting</a> the <a data-lt="jsonldprocessor-compact-input">input</a>;
it can be specified by using a <a class="changed">map</a>,
an <a>IRI</a>,
or an array consisting of <a class="changed">maps</a> and <a>IRI</a>s.</dd>
<dt><dfn data-lt="jsonldprocessor-compact-options" data-lt-noDefault>options</dfn></dt>
<dd>A set of options to configure the algorithms.
This allows, e.g., to set the input document's base <a>IRI</a>.
<span class="changed">The {{JsonLdOptions}} type defines default option values.</span>
</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="JsonLdProcessor">expand()</dfn></dt>
<dd class="algorithm">
<p><a href="#expansion">Expands</a> the given <a data-lt="jsonldprocessor-expand-input">input</a>
according to the steps in the <a href="#expansion-algorithm">Expansion algorithm</a>:</p>
<ol>
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li class="changed">If the provided <a data-lt="jsonldprocessor-expand-input">input</a>
is a <a>RemoteDocument</a>,
initialize <var>remote document</var> to <a data-lt="jsonldprocessor-expand-input">input</a>.</li>
<li>Otherwise, if the provided <a data-lt="jsonldprocessor-expand-input">input</a>
is a <a>string</a> representing the <a>IRI</a> of a remote document, await and dereference it as <var>remote document</var>
using <a>LoadDocumentCallback</a>, passing <a data-lt="jsonldprocessor-expand-input">input</a>
for {{LoadDocumentCallback/url}},
the {{JsonLdOptions/extractAllScripts}} option from <a data-lt="jsonldprocessor-expand-options">options</a>
for <a data-link-for="LoadDocumentOptions">extractAllScripts</a>.</li>
<li class="changed">If {{RemoteDocument/document}}
from <var>remote document</var> is a <a>string</a>, transform into the <a>internal representation</a>.
If {{RemoteDocument/document}} cannot be transformed to the <a>internal representation</a>,
reject <var>promise</var> passing a <a data-link-for="JsonLdErrorCode">loading document failed</a> error.</li>
<li>Initialize a new empty <var>active context</var>.
The <a data-lt="context-base-iri">base IRI</a> and <a>original base URL</a> of the <var>active context</var> is set to the {{RemoteDocument/documentUrl}}
from <var>remote document</var>, if available;
otherwise to the {{JsonLdOptions/base}} option from <a data-lt="jsonldprocessor-expand-options">options</a>.
If set, the {{JsonLdOptions/base}} option from <a data-lt="jsonldprocessor-expand-options">options</a> overrides the <a data-lt="context-base-iri">base IRI</a>.</li>
<li>If the {{JsonLdOptions/expandContext}} option in <a data-lt="jsonldprocessor-expand-options">options</a> is set,
update the <var>active context</var> using the <a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing the {{JsonLdOptions/expandContext}} as <var>local context</var>
and the <a>original base URL</a> from <var>active context</var> as <var>base URL</var>.
If {{JsonLdOptions/expandContext}} is a <a class="changed">map</a> having an <code>@context</code> <a>entry</a>,
pass that <a data-lt="entry">entry's</a> value instead for <var>local context</var>.</li>
<li>If <var>remote document</var> has a {{RemoteDocument/contextUrl}},
update the <var>active context</var> using the <a href="#context-processing-algorithm">Context Processing algorithm</a>,
passing the {{RemoteDocument/contextUrl}} as <var>local context</var>,
and {{RemoteDocument/contextUrl}} as <var>base URL</var>.</li>
<li>Set <var>expanded output</var> to the result of using the <a href="#expansion-algorithm">Expansion algorithm</a>,
passing the <var>active context</var>,
{{RemoteDocument/document}} from <var>remote document</var> or <a data-lt="jsonldprocessor-expand-input">input</a>
if there is no <var>remote document</var> as <var>element</var>,
`null` as <var>active property</var>,
{{RemoteDocument/documentUrl}} as <var>base URL</var>, if available,
otherwise to the {{JsonLdOptions/base}} option
from <a data-lt="jsonldprocessor-expand-options">options</a>,
and the <span class="changed">{{JsonLdOptions/frameExpansion}}</span>
and <span class="changed">and {{JsonLdOptions/ordered}}</span>
flags from <a data-lt="jsonldprocessor-expand-options">options</a>.
<div class="note changed">If there is no <var>remote document</var>,
then <a data-lt="jsonldprocessor-expand-input">input</a> is
a <a>JsonLdRecord</a> or a <code>sequence</code> of
<a>JsonLdRecords</a>, which are implicitly already in the
<a>internal representation</a>.</div>
<ol id="api-expand-post-processing" class="changed">
<li>If <var>expanded output</var> is a
<a class="changed">map</a> that contains only an <code>@graph</code> <a>entry</a>,
set <var>expanded output</var> that value.</li>
<li>If <var>expanded output</var> is <code>null</code>,
set <var>expanded output</var> to an empty <a>array</a>.</li>
<li>If <var>expanded output</var> is not an <a>array</a>,
set <var>expanded output</var> to an <a>array</a> containing only <var>expanded output</var>.</li>
</ol>
</li>
<li>Resolve the <var>promise</var> with <var>expanded output</var>
<span class="changed">transforming <var>expanded output</var> from the
<a>internal representation</a> to a JSON serialization</span>.</li>
</ol>
<dl class="parameters">
<dt><dfn data-lt="jsonldprocessor-expand-input" data-lt-noDefault>input</dfn></dt>
<dd>The <a class="changed">map</a>,
or array of <a class="changed">maps</a> to perform the expansion upon,
or an <a>IRI</a> referencing the <a>JSON-LD document</a> to expand.</dd>
<dt><dfn data-lt="jsonldprocessor-expand-options" data-lt-noDefault>options</dfn></dt>
<dd>A set of options to configure the used algorithms.
This allows, e.g., to set the input document's <a>base IRI</a>.
<span class="changed">The {{JsonLdOptions}} type defines default option values.</span>
</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="JsonLdProcessor">flatten()</dfn></dt>
<dd class="algorithm">
<p><a href="#flattening">Flattens</a> the given <a data-lt="jsonldprocessor-flatten-input">input</a>
and optionally <a>compacts</a> it using the provided <a data-lt="jsonldprocessor-flatten-context">context</a>
according to the steps in the <a href="#flattening-algorithm">Flattening algorithm</a>:</p>
<ol>
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li class="changed">If the provided <a data-lt="jsonldprocessor-flatten-input">input</a>
is a <a>RemoteDocument</a>,
initialize <var>remote document</var> to <a data-lt="jsonldprocessor-flatten-input">input</a>.</li>
<li>Otherwise, if the provided <a data-lt="jsonldprocessor-flatten-input">input</a>
is a <a>string</a> representing the <a>IRI</a> of a remote document, await and dereference it as <var>remote document</var>
using <a>LoadDocumentCallback</a>, passing <a data-lt="jsonldprocessor-flatten-input">input</a>
for {{LoadDocumentCallback/url}},
and the {{JsonLdOptions/extractAllScripts}} option from <a data-lt="jsonldprocessor-flatten-options">options</a>
for <a data-link-for="LoadDocumentOptions">extractAllScripts</a>.
</li>
<li>Set <var>expanded input</var> to the result of
using the <a data-link-for="JsonLdProcessor">expand()</a> method
using either <var>remote document</var>
or <a data-lt="jsonldprocessor-flatten-input">input</a>
if there is no <var>remote document</var>
for <a data-lt="jsonldprocessor-expand-input">input</a>,
and <a data-lt="jsonldprocessor-flatten-options">options</a>
<span class="changed">with {{JsonLdOptions/ordered}} set to <code>false</code></span>.</li>
<li>Initialize an empty <var>identifier map</var>.</li>
<li>Set <var>flattened output</var> to the result of using the <a href="#flattening-algorithm">Flattening algorithm</a>,
passing <var>expanded input</var> as <var>element</var>,
<span class="changed">and the {{JsonLdOptions/ordered}} flag
from <a data-lt="jsonldprocessor-flatten-options">options</a></span>.
<ol id="api-flatten-post-processing" class="changed">
<li>If <a data-lt="jsonldprocessor-flatten-context">context</a> is not <code>null</code>,
set <var>flattened output</var> to the result of
using the <a data-link-for="JsonLdProcessor">compact()</a> method
using <var>flattened output</var> for <a data-lt="jsonldprocessor-compact-input">input</a>,
<a data-lt="jsonldprocessor-flatten-context">context</a>,
and <a data-lt="jsonldprocessor-flatten-options">options</a>.
Set the <a data-lt="context-base-iri">base IRI</a> in <var>active context</var> to the {{JsonLdOptions/base}} option
from <a data-lt="jsonldprocessor-flatten-options">options</a>, if set;
otherwise, if the <a data-link-for="JsonLdOptions">compactToRelative</a> option is <strong>true</strong>,
to the IRI of the currently being processed document, if available;
otherwise to <code>null</code>.</li>
</ol>
</li>
<li>Resolve the <var>promise</var> with <var>flattened output</var>
<span class="changed">transforming <var>flattened output</var> from the
<a>internal representation</a> to a JSON serialization</span>,
if necessary.</li>
</ol>
<dl class="parameters">
<dt><dfn data-lt="jsonldprocessor-flatten-input" data-lt-noDefault>input</dfn></dt>
<dd>The <a class="changed">map</a>,
or array of <a class="changed">maps</a>,
or an <a>IRI</a> referencing the JSON-LD document to flatten.</dd>
<dt><dfn data-lt="jsonldprocessor-flatten-context" data-lt-noDefault>context</dfn></dt>
<dd>The context to use when <a>compacting</a> the flattened <var>expanded input</var>;
it can be specified by using a <a class="changed">map</a>,
an <a>IRI</a>, or an array consisting of <a class="changed">maps</a>
and <a>IRI</a>s.
If <code>null</code>, the result will not be compacted but kept in expanded form.</dd>
<dt><dfn data-lt="jsonldprocessor-flatten-options" data-lt-noDefault>options</dfn></dt>
<dd>A set of options to configure the used algorithms.
This allows, e.g., to set the input document's <a>base IRI</a>.
<span class="changed">The {{JsonLdOptions}} type defines default option values.</span>
</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="JsonLdProcessor" class="changed">fromRdf()</dfn></dt>
<dd class="algorithm changed">
<p>Transforms the given <a data-lt="jsonldprocessor-fromRdf-input">input</a>
into a <a>JSON-LD document</a> in <a>expanded form</a>
according to the steps in the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>:</p>
<p class="note">This interface does not define a means of creating an <a>RdfDataset</a>
from an arbitrary input, other than the <a data-link-for="JsonLdProcessor">toRdf()</a> method.</p>
<ol>
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li>Set <var>expanded result</var> to the result of invoking the
<a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a> method
using <a data-lt="jsonldprocessor-fromRdf-input">dataset</a>
and <a data-lt="jsonldprocessor-fromRdf-options">options</a>.</li>
<li>Resolve the <var>promise</var> with <var>expanded result</var>
<span class="changed">transforming <var>expanded result</var> from the
<a>internal representation</a> to a JSON serialization</span>.</li>
</ol>
<dl class="parameters">
<dt><dfn data-lt="jsonldprocessor-fromRdf-input" data-lt-noDefault>input</dfn></dt>
<dd>The <a class="changed">map</a>,
or array of <a class="changed">maps</a>,
or an <a>IRI</a> referencing the JSON-LD document to flatten.</dd>
<dt><dfn data-lt="jsonldprocessor-fromRdf-options" data-lt-noDefault>options</dfn></dt>
<dd>A set of options to configure the used algorithms.
This allows, e.g., to set the input document's <a>base IRI</a>.
<span class="changed">The {{JsonLdOptions}} type defines default option values.</span>
</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="JsonLdProcessor" class="changed">toRdf()</dfn></dt>
<dd class="algorithm changed">
<p>Transforms the given <a data-lt="jsonldprocessor-toRdf-input">input</a> into an <a>RdfDataset</a>
according to the steps in the <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>:</p>
<ol>
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li>Set <var>expanded input</var> to the result of using the
<a data-link-for="JsonLdProcessor">expand()</a> method
using <a data-lt="jsonldprocessor-toRdf-input">input</a>
and <a data-lt="jsonldprocessor-toRdf-options">options</a>
<span class="changed">with {{JsonLdOptions/ordered}} set to <code>false</code></span>.</li>
<li>Create a new <a>RdfDataset</a> <var>dataset</var>.</li>
<li>Create a new <a>map</a> <var>node map</var>.</li>
<li>Invoke the <a href="#node-map-generation">Node Map Generation algorithm</a>,
passing <var>expanded input</var> as <var>element</var>
and <var>node map</var>.</li>
<li>Invoke the <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>
passing <var>node map</var>, <var>dataset</var>,
and the {{JsonLdOptions/produceGeneralizedRdf}} flag from <a data-lt="jsonldprocessor-toRdf-options">options</a>.
<div class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD,
as is the support for <a>generalized RDF Datasets</a>
and thus the {{JsonLdOptions/produceGeneralizedRdf}} option may be also be removed.</div>
</li>
<li>Resolve the <var>promise</var> with <var>dataset</var>.</li>
</ol>
<dl class="parameters">
<dt><dfn data-lt="jsonldprocessor-toRdf-input" data-lt-noDefault>input</dfn></dt>
<dd>The <a class="changed">map</a>,
or array of <a class="changed">maps</a>,
or an <a>IRI</a> referencing the JSON-LD document to flatten.</dd>
<dt><dfn data-lt="jsonldprocessor-toRdf-options" data-lt-noDefault>options</dfn></dt>
<dd>A set of options to configure the used algorithms.
This allows, e.g., to set the input document's <a>base IRI</a>.
<span class="changed">The {{JsonLdOptions}} type defines default option values.</span>
</dd>
</dl>
</dd>
</dl>
<pre class="idl changed">
typedef record<USVString, any> JsonLdRecord;
</pre>
<p class="changed">The <dfn>JsonLdRecord</dfn> is the definition of a <a>map</a>
used to contain arbitrary <a>map entries</a>
which are the result of parsing a <a>JSON Object</a>.
<pre class="idl changed">
typedef (JsonLdRecord or sequence<JsonLdRecord> or USVString or RemoteDocument) JsonLdInput;
</pre>
<p class="changed">The <dfn>JsonLdInput</dfn> interface is used to refer to an input value
that that may be a <a>JsonLdRecord</a>,
a `sequence` of <a>JsonLdRecords</a>,
a <a>string</a> representing an <a>IRI</a>,
which can be dereferenced to retrieve a valid JSON document,
<span class="changed">or an already dereferenced <a>RemoteDocument</a></span>.</p>
<p class="changed">When the value is a <a>JsonLdRecord</a> or sequence of <a>JsonLdRecords</a>,
the values are taken as their equivalent internal representation values,
where a <a>JsonLdRecord</a> is equivalent to a <a>map</a>,
and a sequence of <a>JsonLdRecords</a> is equivalent to an <a>array</a>
of <a>maps</a>. The <a>map entries</a> are converted to their equivalents
in [[INFRA]].</p>
<pre class="idl">
typedef (JsonLdRecord or sequence<(JsonLdRecord or USVString)> or USVString) JsonLdContext;
</pre>
<p>The <dfn>JsonLdContext</dfn> interface is used to refer to a value
that may be a <a>JsonLdRecord</a>,
a `sequence` of <a>JsonLdRecords</a>,
or a <a>string</a> representing an <a>IRI</a>,
which can be dereferenced to retrieve a valid JSON document.</p>
<p class="changed">When the value is a <a>JsonLdRecord</a> or sequence of <a>JsonLdRecords</a>,
the values are taken as their equivalent internal representation values,
where a <a>JsonLdRecord</a> is equivalent to a <a>map</a>,
and a sequence of <a>JsonLdRecords</a> is equivalent to an <a>array</a>
of <a>maps</a>. The <a>map entries</a> are converted to their equivalents
in [[INFRA]].</p>
</section>
<section><h3>RDF Dataset Interfaces</h3>
<p>The <dfn>RdfDataset</dfn> interface describes operations on an <a>RDF dataset</a>
used by the <a data-link-for="JsonLdProcessor">fromRdf()</a>
and <a data-link-for="JsonLdProcessor">toRdf()</a> methods
in the <a>JsonLdProcessor</a> interface.
The interface may be used for constructing a new <a>RDF dataset</a>,
which has a <a>default graph</a> accessible via the <a data-link-for="RdfDataset">defaultGraph</a> attribute.</p>
<pre class="idl changed">
[Exposed=JsonLd]
interface RdfDataset {
constructor();
readonly attribute RdfGraph defaultGraph;
undefined add(USVString graphName, RdfGraph graph);
iterable<USVString?, RdfGraph>;
};
</pre>
<dl data-sort>
<dt><dfn data-dfn-for="RdfDataset">defaultGraph</dfn></dt>
<dd>Provides access to the <a>default graph</a> associated with the <a>RDF dataset</a>.</dd>
<dt><dfn data-dfn-for="RdfDataset">add()</dfn></dt>
<dd class="algorithm">
<p>Adds an <a>RdfGraph</a> and its associated <a>graph name</a> to the <a>RdfDataset</a>.
Used by the <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>.</p>
<dl class="parameters">
<dt><dfn data-lt="RdfDataset-add-graphName" data-lt-noDefault>graphName</dfn></dt>
<dd>The <a>graph name</a> associated with <a>graph</a>.
<a href="#dfn-rdfdataset-add-graphname">`graphName`</a> MUST be a
<a>well-formed</a> <a>IRI</a> or <a>blank node identifier</a>.
</dd>
<dt><dfn data-lt="RdfDataset-add-graph" data-lt-noDefault>graph</dfn></dt>
<dd>The <a>RdfGraph</a> to add to the <a>RdfDataset</a>.</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="RdfDataset"><code>iterable</code></dfn></dt>
<dd>The <a data-cite="WEBIDL#dfn-value-pairs-to-iterate-over">value pairs to iterate over</a>
are the list of <var>graph name</var>-<var>graph</var> pairs,
with the <var>graph name</var> being <code>null</code>
(for the <a>default graph</a>),
an <a>IRI</a>,
or <a>blank node identifier</a>
and graph an <a>RdfGraph</a> instance.</dd>
</dl>
<p>The <dfn>RdfGraph</dfn> interface describes operations on an <a>RDF graph</a> used by the <a data-link-for="JsonLdProcessor">fromRdf()</a>
and <a data-link-for="JsonLdProcessor">toRdf()</a> methods
in the <a>JsonLdProcessor</a> interface.
The interface may be used for constructing a new <a>RDF graph</a>,
which is composed of zero or more <a>RdfTriple</a> instances.</p>
<pre class="idl changed">
[Exposed=JsonLd]
interface RdfGraph {
constructor();
undefined add(RdfTriple triple);
iterable<RdfTriple>;
};
</pre>
<dl data-sort>
<dt><dfn data-dfn-for="RdfGraph">add()</dfn></dt>
<dd class="algorithm">
<p>Adds an <a>RdfTriple</a> to the <a>RdfGraph</a>.
Used by the <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>.</p>
<dl class="parameters">
<dt><dfn data-lt="RdfGraph-add-triple" data-lt-noDefault>triple</dfn></dt>
<dd>The <a>RdfTriple</a> to add to the <a>RdfGraph</a>.</dd>
</dl>
</dd>
<dt><dfn data-dfn-for="RdfGraph"><code>iterable</code></dfn></dt>
<dd>A <a data-cite="WEBIDL#dfn-value-iterator">value iterator</a>
over the <a>RdfTriple</a> instances associated with the graph.
Note that a given <a>RdfTriple</a> instance may appear in more than one graph
within a particular <a>RdfDataset</a> instance.</dd>
</dl>
<p>The <dfn>RdfTriple</dfn> interface describes an <a>triple</a>.</p>
<pre class="idl changed">
[Exposed=JsonLd]
interface RdfTriple {
constructor();
readonly attribute USVString subject;
readonly attribute USVString predicate;
readonly attribute (USVString or RdfLiteral) _object;
};
</pre>
<dl>
<dt><dfn data-dfn-for="RdfTriple">subject</dfn></dt>
<dd>An absolute <a>IRI</a> or <a>blank node identifier</a>
denoting the <a>subject</a> of the <a>triple</a>.</dd>
<dt><dfn data-dfn-for="RdfTriple">predicate</dfn></dt>
<dd>An absolute <a>IRI</a> denoting the <a>predicate</a> of the <a>triple</a>.
If used to represent a <a>Generalized RDF Dataset</a>,
it may also be a <a>blank node identifier</a>.
<div class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD, as is the support for <a>generalized RDF Datasets</a>.</div>
</dd>
<dt><dfn data-dfn-for="RdfTriple">object</dfn></dt>
<dd>An absolute <a>IRI</a>, <a>blank node identifier</a>, or <a>literal</a>
denoting the <a>object</a> of the <a>triple</a>.</dd>
</dl>
<p>The <dfn>RdfLiteral</dfn> interface describes an <a>RDF Literal</a>.</p>
<pre class="idl changed">
[Exposed=JsonLd]
interface RdfLiteral {
constructor();
readonly attribute USVString value;
readonly attribute USVString datatype;
readonly attribute USVString? language;
};
</pre>
<dl>
<dt><dfn data-dfn-for="RdfLiteral">value</dfn></dt>
<dd>The lexical value of the <a>literal</a>.</dd>
<dt><dfn data-dfn-for="RdfLiteral">datatype</dfn></dt>
<dd>An absolute <a>IRI</a> denoting the <a data-lt="RDF11-CONCEPTS#dfn-datatype-iri">datatype IRI</a> of the <a>literal</a>.
If the value is <code>rdf:langString</code>,
<a data-link-for="RdfLiteral">language</a> MUST be specified.</dd>
<dt><dfn data-dfn-for="RdfLiteral">language</dfn></dt>
<dd>An optional <a>language tag</a> as defined by [[BCP47]].
If this value is specified, <a data-link-for="RdfLiteral">datatype</a> MUST be <code>rdf:langString</code>.</dd>
</dl>
</section>
<section><h3>The JsonLdOptions Type</h3>
<p>The <dfn>JsonLdOptions</dfn> type is used to pass various options to the
<a>JsonLdProcessor</a> methods.</p>
<pre class="idl">
dictionary JsonLdOptions {
USVString? base = null;
boolean compactArrays = true;
boolean compactToRelative = true;
LoadDocumentCallback? documentLoader = null;
(JsonLdRecord? or USVString) expandContext = null;
boolean extractAllScripts = false;
boolean frameExpansion = false;
boolean ordered = false;
USVString processingMode = "json-ld-1.1";
boolean produceGeneralizedRdf = true;
USVString? rdfDirection = null;
boolean useNativeTypes = false;
boolean useRdfType = false;
};
</pre>
<dl data-sort>
<dt><dfn data-dfn-for="JsonLdOptions">base</dfn></dt>
<dd>The base IRI to use when expanding or <a>compacting</a> the document.
If set, this overrides the input document's IRI.</dd>
<dt><dfn data-dfn-for="JsonLdOptions">compactArrays</dfn></dt>
<dd>If set to <code>true</code>, the JSON-LD processor replaces arrays
with just one element with that element during <a>compaction</a>.
If set to <code>false</code>,
all arrays will remain arrays even if they have just one element.
</dd>
<dt><dfn data-dfn-for="JsonLdOptions">documentLoader</dfn></dt>
<dd>The callback of the loader to be used to retrieve remote documents and contexts,
implementing the <a>LoadDocumentCallback</a>.
If specified, it is used to retrieve remote documents and contexts;
otherwise, if not specified, the processor's built-in loader is used.</dd>
<dt><dfn data-dfn-for="JsonLdOptions">expandContext</dfn></dt>
<dd>A context that is used to initialize the active context when expanding a document.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">extractAllScripts</dfn></dt>
<dd>If set to <code>true</code>,
when extracting <a>JSON-LD script elements</a> from HTML,
unless a specific <a data-cite="RFC3986#section-3.5">fragment identifier</a> is targeted,
extracts all encountered <a>JSON-LD script elements</a> using an <a>array</a> form, if necessary.</dd>
<dt><dfn data-dfn-for="JsonLdOptions">produceGeneralizedRdf</dfn></dt>
<dd>If set to <code>true</code>, the JSON-LD processor may emit
<a>blank nodes</a> for <a>triple</a> <a>predicates</a>,
otherwise they will be omitted.
<dfn data-cite="RDF11-CONCEPTS#dfn-generalized-rdf-dataset" data-lt="generalized rdf dataset">Generalized RDF Datasets</dfn>
are defined in [[RDF11-CONCEPTS]].
<div class="note">The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD,
as is the support for <a>generalized RDF Datasets</a>
and thus the {{JsonLdOptions/produceGeneralizedRdf}} option may be also be removed.</div>
</dd>
<dt><dfn data-dfn-for="JsonLdOptions">processingMode</dfn></dt>
<dd>Sets the <a>processing mode</a>.
If set to `json-ld-1.0` or `json-ld-1.1`,
the implementation must produce exactly the same results as the
algorithms defined in this specification.
If set to another value,
the JSON-LD processor is allowed to extend or modify the algorithms defined in this specification
to enable application-specific optimizations.
The definition of such optimizations is beyond the scope of this specification
and thus not defined.
Consequently, different implementations may implement different optimizations.
Developers must not define modes beginning with <code>json-ld</code>
as they are reserved for future versions of this specification.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">compactToRelative</dfn></dt>
<dd class="changed">Determines if IRIs are compacted
relative to the {{JsonLdOptions/base}} option
or document location when <a>compacting</a>.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">frameExpansion</dfn></dt>
<dd class="changed">Enables special frame processing rules for the <a href="#expansion-algorithm">Expansion Algorithm</a>.</dd>
<dd class="changed">Enables special rules for the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
to use JSON-LD native types as values, where possible.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">useNativeTypes</dfn></dt>
<dd class="changed">Causes the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
to use native JSON values in <a>value objects</a> avoiding the need for an explicitly <code>@type</code>.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">useRdfType</dfn></dt>
<dd class="changed">Enables special rules for the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
causing <code>rdf:type</code> properties to be kept as <a>IRIs</a> in the output, rather than use <code>@type</code>.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">ordered</dfn></dt>
<dd class="changed">If set to <code>true</code>,
certain algorithm processing steps where indicated are ordered lexicographically.
If <code>false</code>, order is not considered in processing.</dd>
<dt class="changed"><dfn data-dfn-for="JsonLdOptions">rdfDirection</dfn></dt>
<dd class="changed">Determines how <a>value objects</a> containing a <a data-cite="JSON-LD11#dfn-base-direction">base direction</a>
are transformed to and from RDF.
<ul>
<li>If set to `i18n-datatype`, an <a>RDF literal</a> is generated using a datatype IRI
based on `https://www.w3.org/ns/i18n#` with both the <a>language tag</a> (if present)
and <a data-cite="JSON-LD11#dfn-base-direction">base direction</a> encoded.
When transforming from RDF, this datatype is decoded to create a <a>value object</a>
containing `@language` (if present) and `@direction`.</li>
<li>If set to `compound-literal`, a <a>blank node</a> is emitted instead of a <a>literal</a>,
where the blank node is the subject of `rdf:value`, `rdf:direction`, and `rdf:language` (if present)
properties.
When transforming from RDF, this object is decoded to create a <a>value object</a>
containing `@language` (if present) and `@direction`.</li>
</ul>
</dd>
</dl>
</section>
<section><h3>Remote Document and Context Retrieval</h3>
<p>Users of an API implementation can utilize a callback to control how
remote documents and contexts are retrieved.
This section details the parameters of that callback
and the data structure used to return the retrieved context.</p>
<section class="algorithm">
<h3>LoadDocumentCallback</h3>
<p>The <dfn>LoadDocumentCallback</dfn> defines a callback that custom document loaders
have to implement to be used to retrieve remote documents and contexts.
The callback returns a {{Promise}} resolving to a <a>RemoteDocument</a>.
On failure, the {{Promise}} with a <a>JsonLdError</a> having an appropriate error <a data-link-for="JsonLdError">code</a>.</p>
<pre class="idl">
callback LoadDocumentCallback = Promise<RemoteDocument> (
USVString url,
optional LoadDocumentOptions? options
);
</pre>
<dl>
<dt><dfn data-dfn-for="LoadDocumentCallback">url</dfn></dt>
<dd>The URL of the remote document or context to load.</dd>
<dt class="changed"><dfn data-lt="LoadDocumentCallback-options" data-lt-noDefault>options</dfn></dt>
<dd class="changed">A set of options to determine
the behavior of the callback. See <a href="#loaddocumentoptions" class="sectionRef"></a>.</dd>
</dl>
<p class="changed">The following algorithm describes the default callback and places
requirements on implementations of the callback.</p>
<ol class="changed">
<li>Create a new {{Promise}} <var>promise</var> and return it.
The following steps are then deferred.</li>
<li id="LoadDocumentCallback-step-2">Set <var>document</var> to the body retrieved from
the resource identified by {{LoadDocumentCallback/url}},
or by otherwise locating a resource associated with {{LoadDocumentCallback/url}}.
When requesting remote documents the request MUST prefer <a>Content-Type</a> <code>application/ld+json</code>
followed by <code>application/json</code>.
<p>If <a data-link-for="LoadDocumentOptions">requestProfile</a> is set,
it MUST be added as a profile on <code>application/ld+json</code>.</p>
<p>Processors MAY include other media types using a <code>+json</code> suffix as defined in [[RFC6839]].</p>
</li>
<li>Set <var>documentUrl</var> to the location of the retrieved resource
considering redirections (exclusive of HTTP status <code>303</code> "See Other" redirects
as discussed in [[?cooluris]]).</li>
<li>If the retrieved resource's <a>Content-Type</a> is not <code>application/json</code>
nor any media type with a <code>+json</code> suffix as defined in [[RFC6839]],
and the response has an HTTP Link Header [[RFC8288]] using the <code>alternate</code> link relation
with type `application/ld+json`,
set <var>url</var> to the associated <code>href</code> relative to the previous <var>url</var>
and restart the algorithm from <a href="#LoadDocumentCallback-step-2">step 2</a>.</li>
<li id="LoadDocumentCallback-step-5">If the retrieved resource's <a>Content-Type</a> is <code>application/json</code>
or any media type with a <code>+json</code> suffix as defined in [[RFC6839]]
except <code>application/ld+json</code>,
and the response has an HTTP Link Header [[RFC8288]] using the <code>http://www.w3.org/ns/json-ld#context</code> link relation,
set <var>contextUrl</var> to the associated <code>href</code>.
<p>If multiple HTTP Link Headers using the <code>http://www.w3.org/ns/json-ld#context</code> link relation are found,
the <var>promise</var> is rejected with a <a>JsonLdError</a> whose {{JsonLdError/code}} is set to <a data-link-for="JsonLdErrorCode">multiple context link headers</a>
and processing is terminated.</p>
<p>Processors MAY transform <var>document</var> to the <a>internal representation</a>.</p>
<p class="note">The HTTP Link Header is ignored for documents served as <code>application/ld+json</code>,
<code>text/html</code>, or <code>application/xhtml+xml</code>.</p>
</li>
<li>Otherwise, the retrieved document's <a>Content-Type</a> is neither
<code>application/json</code>,
<code>application/ld+json</code>,
nor any other media type using a
<code>+json</code> suffix as defined in [[RFC6839]].
Reject the <var>promise</var> passing a <a data-link-for="JsonLdErrorCode">loading document failed</a> error.</li>
<li>Create a new <a>RemoteDocument</a> <var>remote document</var> using
<var>url</var> as {{RemoteDocument/documentUrl}},
<var>document</var> as {{RemoteDocument/document}},
the returned <a>Content-Type</a> (without parameters) as {{RemoteDocument/contentType}},
any returned <code>profile</code> parameter, or `null` as {{RemoteDocument/profile}},
and <var>contextUrl</var>, or `null` as {{RemoteDocument/contextUrl}}.</li>
<li>Resolve the <var>promise</var> with <var>remote document</var>.</li>
</ol>
<p class="note">A custom <a>LoadDocumentCallback</a> set via the
<a data-link-for="JsonLdOptions">documentLoader</a> option might be used
to maintain a local cache of well-known context documents or to implement
application-specific URL protocols.</p>
</section>
<section class="changed">
<h3>LoadDocumentOptions</h3>
<p>The <dfn>LoadDocumentOptions</dfn> type is used to pass various options
to the <a>LoadDocumentCallback</a>.</p>
<pre class="idl">
dictionary LoadDocumentOptions {
boolean extractAllScripts = false;
USVString profile = null;
(USVString or sequence<USVString>) requestProfile = null;
};
</pre>
<dl>
<dt><dfn data-dfn-for="LoadDocumentOptions">extractAllScripts</dfn></dt>
<dd>If set to <code>true</code>,
when extracting <a>JSON-LD script elements</a> from HTML,
unless a specific <a data-cite="RFC3986#section-3.5">fragment identifier</a> is targeted,
extracts all encountered <a>JSON-LD script elements</a> using an <a>array</a> form, if necessary.</dd>
<dt><dfn data-dfn-for="LoadDocumentOptions">profile</dfn></dt>
<dd>When the resulting {{RemoteDocument/contentType}} is <code>text/html</code>
or <code>application/xhtml+xml</code>,
this option determines the profile to use for selecting <a>JSON-LD script elements</a>.</dd>
<dt><dfn data-dfn-for="LoadDocumentOptions">requestProfile</dfn></dt>
<dd>One or more IRIs to use in the request as a <code>profile</code> parameter.
(See <a data-cite="JSON-LD11#iana-considerations">IANA Considerations</a> in [[JSON-LD11]]).</dd>
</dl>
</section>
<section>
<h3>RemoteDocument</h3>
<p>The <dfn>RemoteDocument</dfn> type is used by a <a>LoadDocumentCallback</a>
to return information about a remote document or context.</p>
<pre class="idl">
[Exposed=JsonLd]
interface RemoteDocument {
constructor();
readonly attribute USVString contentType;
readonly attribute USVString contextUrl;
attribute any document;
readonly attribute USVString documentUrl;
readonly attribute USVString profile;
};
</pre>
<dl data-sort>
<dt class="changed"><dfn data-dfn-for="RemoteDocument">contentType</dfn></dt>
<dd class="changed">The <dfn data-cite="RFC2045#section-5">Content-Type</dfn>
of the loaded document, exclusive of any optional parameters.</dd>
<dt><dfn data-dfn-for="RemoteDocument">contextUrl</dfn></dt>
<dd>If available, the value of the HTTP Link Header [[RFC8288]]
using the <code>http://www.w3.org/ns/json-ld#context</code> link relation
in the response.
If the response's <a>Content-Type</a> is <code>application/ld+json</code>,
the HTTP Link Header is ignored.
If multiple HTTP Link Headers using the <code>http://www.w3.org/ns/json-ld#context</code> link relation are found,
the {{Promise}} of the <a>LoadDocumentCallback</a> is rejected
with a <a>JsonLdError</a> whose {{JsonLdError/code}} is set to <a data-link-for="JsonLdErrorCode">multiple context link headers</a>.</dd>
<dt><dfn data-dfn-for="RemoteDocument">documentUrl</dfn></dt>
<dd>The final URL of the loaded document.
This is important to handle HTTP redirects properly.</dd>
<dt><dfn data-dfn-for="RemoteDocument">document</dfn></dt>
<dd>The retrieved document.
This can either be the raw payload or the already parsed document.</dd>
<dt class="changed"><dfn data-dfn-for="RemoteDocument">profile</dfn></dt>
<dd class="changed">The value of any <code>profile</code> parameter
retrieved as part of the original {{RemoteDocument/contentType}}.</dd>
</dl>
</section>
</section>
<section class="changed"><h2>HTML Content Algorithms</h2>
<p class="note">This section describes optional features available
with a <a data-link-for="JsonLdOptions">documentLoader</a> supporting HTML script extraction.</p>
<p>Implementations of a <a data-link-for="JsonLdOptions">documentLoader</a> MAY support extracting JSON-LD from
<a data-cite="HTML/scripting.html#the-script-element">script elements</a> contained within an HTML [[HTML]] document.
This section describes the normative behavior of such processors.
Such a processor supports <dfn>HTML script extraction</dfn>.</p>
<section id="process-html"><h3>Process HTML</h3>
<p>This sections describe an extension to the algorithm specified
in <a>LoadDocumentCallback</a> to support extracting JSON-LD from HTML.</p>
<p><a href="#LoadDocumentCallback-step-2">Step 2</a> is updated to add the following: A processor supporting <a>HTML script extraction</a> MUST include <code>text/html</code> at any preference level
and MAY include <code>application/xhtml+xml</code> at any preference level,
unless <a data-link-for="LoadDocumentOptions">requestProfile</a> is `http://www.w3.org/ns/json-ld#context`.</p>
<p>After <a href="#LoadDocumentCallback-step-5">step 5</a>, add the following processing step:
Otherwise, if the retrieved resource's <a>Content-Type</a> is either <code>text/html</code>
or <code>application/xhtml+xml</code>:</p>
<ol>
<li>Set <var>documentUrl</var> to the <a data-cite="HTML/urls-and-fetching.html#document-base-url">Document Base URL</a>
of {{LoadDocumentCallback/url}}, as defined in [[HTML]],
using the existing <var>documentUrl</var> as the document's URL.
</li>
<li>If the {{LoadDocumentCallback/url}} parameter
contains a <a data-cite="RFC3986#section-3.5">fragment identifier</a>,
set <var>source</var> to the <a data-cite="DOM#dom-node-textcontent">textContent</a>
of the <a data-cite="HTML/scripting.html#the-script-element">script element</a> in <var>document</var>
having an <a data-cite="HTML/dom.html#the-id-attribute">id attribute</a>
that matches the fragment identifier, after decoding <a data-cite="RFC3986#section-2.1">percent encoded sequences</a>.
<p>If no such element is found,
or the located element is not a <a>JSON-LD script element</a>,
the <var>promise</var> is rejected with a <a>JsonLdError</a> whose {{JsonLdError/code}} is set to <a data-link-for="JsonLdErrorCode">loading document failed</a>
and processing is terminated.</p>
</li>
<li>Otherwise, if the <a data-link-for="LoadDocumentOptions">profile</a>
option is specified,
set <var>source</var> to the result of transforming the
<a data-cite="DOM#dom-node-textcontent">textContent</a>
of the first <a data-cite="HTML/scripting.html#the-script-element">script element</a> in <var>document</var>
having an <a data-cite="HTML/semantics.html#attr-link-type">type attribute</a>
of <code>application/ld+json</code> along with the value of the
<a data-link-for="LoadDocumentOptions">profile</a> option, if found.</li>
<li>If <var>source</var> is still undefined and the <a data-link-for="LoadDocumentOptions">extractAllScripts</a> option is not present, or <code>false</code>,
set <var>source</var> to the <a data-cite="DOM#dom-node-textcontent">textContent</a>
of the first <a>JSON-LD script element</a> in <var>document</var>.
<p>If no such element is found,
or the located element is not a <a>JSON-LD script element</a>,
the <var>promise</var> is rejected with a <a>JsonLdError</a> whose {{JsonLdError/code}} is set to <a data-link-for="JsonLdErrorCode">loading document failed</a>
and processing is terminated.</p></li>
<li>If <var>source</var> is defined,
set <var>document</var> to the result of the
<a href="#extract-script-content">Extract Script Content algorithm</a>,
using <var>source</var>, rejecting <var>promise</var>
with a <a>JsonLdError</a> whose code set from the result, if an error is detected
and processing is terminated.
</li>
<li>Otherwise, <var>source</var> is undefined.
<ol>
<li>If the <a data-link-for="LoadDocumentOptions">extractAllScripts</a> option is not present, or <code>false</code>,
the <var>promise</var> is rejected with a <a>JsonLdError</a> whose {{JsonLdError/code}} is set to <a data-link-for="JsonLdErrorCode">loading document failed</a>
and processing is terminated.</li>
<li>Otherwise, the <a data-link-for="LoadDocumentOptions">extractAllScripts</a> option is <code>true</code>.
Set <var>document</var> to a new empty <a>array</a>.
For each <a>JSON-LD script element</a> in <var>input</var>:
<ol>
<li>Set <var>source</var> to its <a data-cite="DOM#dom-node-textcontent">textContent</a>.</li>
<li>Set <var>script content</var> to the result of the <a href="#extract-script-content">Extract Script Content algorithm</a>,
using <var>source</var>, rejecting <var>promise</var>
with a <a>JsonLdError</a> whose code set from the result, if an error is detected
and processing is terminated.</li>
<li>If <var>script content</var> is an <a>array</a>, merge it to the end of <var>document</var>.</li>
<li>Otherwise, append <var>script content</var> to <var>document</var>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</section>
<section id="extract-script-content" class="algorithm">
<h3>Extract Script Content Algorithm</h3>
<p>The algorithm extracts the text content a
<a>JSON-LD script element</a> into a <a>map</a> or <a>array</a> of <a>maps</a>.
A <dfn>JSON-LD script element</dfn> is a <a data-cite="HTML/scripting.html#the-script-element">script element</a>
within an HTML [[HTML]] document with the <a data-cite="HTML/semantics.html#attr-link-type">type attribute</a> set to
<code>application/ld+json</code>.</p>
<p>The algorithm takes a single required input variable: <var>source</var>,
the <a data-cite="DOM#dom-node-textcontent">textContent</a> of an HTML <a data-cite="HTML/scripting.html#the-script-element">script element</a>.</p>
<ol>
<li>If <var>source</var> is not a valid JSON document,
an <a data-link-for="JsonLdErrorCode">invalid script element</a> has been detected, and processing is aborted.</li>
<li>Return the result of transforming <var>source</var> into the <a>internal representation</a>.</li>
</ol>
</section>
</section>
<section><h3>Error Handling</h3>
<p>This section describes the datatype definitions
used within the JSON-LD API for error handling.</p>
<section>
<h4>JsonLdError</h4>
<p>The <dfn>JsonLdError</dfn> type is used to report processing errors.</p>
<pre class="idl">
dictionary JsonLdError {
JsonLdErrorCode code;
USVString? message = null;
};
</pre>
<dl>
<dt><dfn data-dfn-for="JsonLdError">code</dfn></dt>
<dd>A string representing the particular error type,
as described in the various algorithms in this document.</dd>
<dt><dfn data-dfn-for="JsonLdError">message</dfn></dt>
<dd>An optional error message containing additional debugging information.
The specific contents of error messages are outside the scope of this specification.</dd>
</dl>
</section>
<section>
<h4>JsonLdErrorCode</h4>
<p>The <dfn>JsonLdErrorCode</dfn> represents the collection of valid JSON-LD error codes.</p>
<pre class="idl">
enum JsonLdErrorCode {
"colliding keywords",
"conflicting indexes",
"context overflow",
"cyclic IRI mapping",
"invalid @id value",
"invalid @import value",
"invalid @included value",
"invalid @index value",
"invalid @nest value",
"invalid @prefix value",
"invalid @propagate value",
"invalid @protected value",
"invalid @reverse value",
"invalid @version value",
"invalid base direction",
"invalid base IRI",
"invalid container mapping",
"invalid context entry",
"invalid context nullification",
"invalid default language",
"invalid IRI mapping",
"invalid JSON literal",
"invalid keyword alias",
"invalid language map value",
"invalid language mapping",
"invalid language-tagged string",
"invalid language-tagged value",
"invalid local context",
"invalid remote context",
"invalid reverse property map",
"invalid reverse property value",
"invalid reverse property",
"invalid scoped context",
"invalid script element",
"invalid set or list object",
"invalid term definition",
"invalid type mapping",
"invalid type value",
"invalid typed value",
"invalid value object value",
"invalid value object",
"invalid vocab mapping",
"IRI confused with prefix",
"keyword redefinition",
"loading document failed",
"loading remote context failed",
"multiple context link headers",
"processing mode conflict",
"protected term redefinition"
};
</pre>
<dl data-dfn-for="JsonLdErrorCode" data-sort>
<dt><dfn>colliding keywords</dfn></dt>
<dd>Two <a>properties</a> which expand to the same keyword have been detected.
This might occur if a <a>keyword</a>
and an alias thereof
are used at the same time.</dd>
<dt><dfn>conflicting indexes</dfn></dt>
<dd>Multiple conflicting indexes have been found for the same node.</dd>
<dt><dfn>context overflow</dfn></dt>
<dd>Maximum number of <code>@context</code> URLs exceeded.</dd>
<dt><dfn>cyclic IRI mapping</dfn></dt>
<dd>A cycle in <a>IRI mappings</a> has been detected.</dd>
<dt><dfn>invalid @id value</dfn></dt>
<dd>An <code>@id</code> <a>entry</a> was encountered whose value was not a <a>string</a>.</dd>
<dt class="changed"><dfn>invalid @import value</dfn></dt>
<dd class="changed">An invalid value for <code>@import</code> has been found.</dd>
<dt class="changed"><dfn>invalid @included value</dfn></dt>
<dd class="changed">An <a>included block</a> contains an invalid value.</dd>
<dt><dfn>invalid @index value</dfn></dt>
<dd>An <code>@index</code> <a>entry</a> was encountered whose value was not a <a>string</a>.</dd>
<dt class="changed"><dfn>invalid @nest value</dfn></dt>
<dd class="changed">An invalid value for <code>@nest</code> has been found.</dd>
<dt class="changed"><dfn>invalid @prefix value</dfn></dt>
<dd class="changed">An invalid value for <code>@prefix</code> has been found.</dd>
<dt class="changed"><dfn>invalid @propagate value</dfn></dt>
<dd class="changed">An invalid value for <code>@propagate</code> has been found.</dd>
<dt class="changed"><dfn>invalid @protected value</dfn></dt>
<dd class="changed">An invalid value for `@protected` has been found.</dd>
<dt><dfn>invalid @reverse value</dfn></dt>
<dd>An invalid value for an <code>@reverse</code> <a>entry</a> has been detected,
i.e., the value was not a <a class="changed">map</a>.</dd>
<dt><dfn>invalid @version value</dfn></dt>
<dd>The <code>@version</code> <a>entry</a> was used in a <a>context</a>
with an out of range value.</dd>
<dt class="changed"><dfn>invalid base direction</dfn></dt>
<dd class="changed">The value of `@direction` is not `"ltr"`, `"rtl"`,
or <code>null</code> and thus invalid.</dd>
<dt><dfn>invalid base IRI</dfn></dt>
<dd>An invalid <a>base IRI</a> has been detected, i.e.,
it is neither an <a>IRI</a> nor <code>null</code>.</dd>
<dt><dfn>invalid container mapping</dfn></dt>
<dd>An <code>@container</code> <a>entry</a> was encountered
whose value was not one of the following <a>strings</a>:
<code>@list</code>,
<code>@set</code>,
<code>@language</code>,
<code>@index</code>,
<span class="changed"><code>@id</code></span>,
<span class="changed"><code>@graph</code></span>, or
<span class="changed"><code>@type</code></span>.</dd>
<dt class="changed"><dfn>invalid context entry</dfn></dt>
<dd class="changed">An <a>entry</a> in a context is invalid due to processing mode incompatibility.</dd>
<dt class="changed"><dfn>invalid context nullification</dfn></dt>
<dd class="changed">An attempt was made to nullify a context
containing <a>protected</a> <a>term definitions</a>.</dd>
<dt><dfn>invalid default language</dfn></dt>
<dd>The value of the <a>default language</a> is not a <a>string</a>
or <code>null</code> and thus invalid.</dd>
<dt><dfn>invalid IRI mapping</dfn></dt>
<dd>A <a>local context</a> contains a <a>term</a>
that has an invalid or missing <a>IRI mapping</a>.</dd>
<dt class="changed"><dfn>invalid JSON literal</dfn></dt>
<dd class="changed">An invalid JSON literal was detected.</dd>
<dt><dfn>invalid keyword alias</dfn></dt>
<dd>An invalid <a>keyword</a> alias definition has been encountered.</dd>
<dt><dfn>invalid language map value</dfn></dt>
<dd>An invalid value in a <a>language map</a> has been detected.
It MUST be a <a>string</a> or an <a>array</a> of <a>strings</a>.</dd>
<dt><dfn>invalid language mapping</dfn></dt>
<dd>An <code>@language</code> <a>entry</a> in a <a>term definition</a>
was encountered whose value was neither a <a>string</a>
nor <code>null</code> and thus invalid.</dd>
<dt><dfn>invalid language-tagged string</dfn></dt>
<dd>A <a>language-tagged string</a> with an invalid language value was detected.</dd>
<dt><dfn>invalid language-tagged value</dfn></dt>
<dd>A <a>number</a>, <code>true</code>, or <code>false</code>
with an associated <a>language tag</a> was detected.</dd>
<dt><dfn>invalid local context</dfn></dt>
<dd>In invalid <a>local context</a> was detected.</dd>
<dt><dfn>invalid remote context</dfn></dt>
<dd>No valid context document has been found for a referenced remote context.</dd>
<dt><dfn>invalid reverse property</dfn></dt>
<dd>An invalid reverse property definition has been detected.</dd>
<dt><dfn>invalid reverse property map</dfn></dt>
<dd>An invalid reverse property map has been detected.
No <a>keywords</a> apart from <code>@context</code>
are allowed in reverse property maps.</dd>
<dt><dfn>invalid reverse property value</dfn></dt>
<dd>An invalid value for a reverse property has been detected.
The value of an inverse property must be a <a>node object</a>.</dd>
<dt class="changed"><dfn>invalid scoped context</dfn></dt>
<dd class="changed">The <a>local context</a>
defined within a <a>term definition</a>
is invalid.</dd>
<dt class="changed"><dfn>invalid script element</dfn></dt>
<dd class="changed">A <a data-cite="HTML/scripting.html#the-script-element">script element</a> in HTML input
which is the target of a <a data-cite="RFC3986#section-3.5">fragment identifier</a>
does not have an appropriate <a data-cite="HTML/semantics.html#attr-link-type">type attribute</a>.</dd>
<dt><dfn>invalid set or list object</dfn></dt>
<dd>A <a>set object</a> or <a>list object</a>
with disallowed <a>entries</a>
has been detected.</dd>
<dt><dfn>invalid term definition</dfn></dt>
<dd>An invalid <a>term definition</a> has been detected.</dd>
<dt><dfn>invalid type mapping</dfn></dt>
<dd>An <code>@type</code> <a>entry</a> in a <a>term definition</a>
was encountered whose value could not be expanded to an <a>IRI</a>.</dd>
<dt><dfn>invalid type value</dfn></dt>
<dd>An invalid value for an <code>@type</code> <a>entry</a> has been detected,
i.e., the value was neither a <a>string</a> nor an <a>array</a> of <a>strings</a>.</dd>
<dt><dfn>invalid typed value</dfn></dt>
<dd>A <a>typed value</a> with an invalid type was detected.</dd>
<dt><dfn>invalid value object</dfn></dt>
<dd>A <a>value object</a> with disallowed <a>entries</a> has been detected.</dd>
<dt><dfn>invalid value object value</dfn></dt>
<dd>An invalid value for the <code>@value</code> <a>entry</a> of a <a>value object</a>
has been detected,
i.e., it is neither a <a>scalar</a> nor <code>null</code>.</dd>
<dt><dfn>invalid vocab mapping</dfn></dt>
<dd>An invalid <a>vocabulary mapping</a> has been detected,
i.e., it is neither an <a>IRI</a> nor <code>null</code>.</dd>
<dt class="changed"><dfn>IRI confused with prefix</dfn></dt>
<dd>When compacting an <a>IRI</a> would result in an <a>IRI</a>
which could be confused with a <a>compact IRI</a>
(because its <a data-cite="RFC3986#section-3.1">IRI scheme</a> matches a <a>term definition</a> and it has no <a data-cite="RFC3986#section-3.1">IRI authority</a>).</dd>
<dt><dfn>keyword redefinition</dfn></dt>
<dd>A <a>keyword</a> redefinition has been detected.</dd>
<dt><dfn>loading document failed</dfn></dt>
<dd>The document could not be loaded or parsed as JSON.</dd>
<dt><dfn>loading remote context failed</dfn></dt>
<dd>There was a problem encountered loading a remote context.</dd>
<dt><dfn>multiple context link headers</dfn></dt>
<dd>Multiple HTTP Link Headers [[RFC8288]]
using the <code>http://www.w3.org/ns/json-ld#context</code> link relation
have been detected.</dd>
<dt><dfn>processing mode conflict</dfn></dt>
<dd>An attempt was made to change the <a>processing mode</a>
which is incompatible with the previous specified version.</dd>
<dt class="changed"><dfn>protected term redefinition</dfn></dt>
<dd class="changed">An attempt was made to redefine a <a>protected</a> term.</dd>
</dl>
</section>
</section>
</section>
<section id="security"><h3>Security Considerations</h3>
<p>See, <a data-cite="JSON-LD11#security">Security Considerations</a> in [[JSON-LD11]].</p>
</section>
<section id="privacy"><h3>Privacy Considerations</h3>
<p>See, <a data-cite="JSON-LD11#privacy">Privacy Considerations</a> in [[JSON-LD11]].</p>
</section>
<section id="internationalization"><h3>Internationalization Considerations</h3>
<p>See, <a data-cite="JSON-LD11#internationalization">Internationalization Considerations</a> in [[JSON-LD11]].</p>
</section>
<section id="idl-index" class="appendix informative">
</section>
<section class="appendix informative preserve"><h2>Open Issues</h2>
<p>The following is a list of issues open at the time of publication.</p>
<p class="issue" data-number="76">More compact @prefix.</p>
<p class="issue" data-number="94">Expansion concept "key's term definition" is unclear with compact IRI keys.</p>
<p class="issue" data-number="166">Relationship to the RDF/JS Dataset interface(s).</p>
<p class="issue" data-number="380">Expansion does not take property-scoped contexts for nested properties into account.</p>
<p class="issue" data-number="391">Recursively nested properties and compaction.</p>
<p class="issue" data-number="435">relative iri compaction.</p>
</section>
<section class="appendix informative"><h2>Changes since 1.0 Recommendation of 16 January 2014</h2>
<ul>
<li>The <a href="#expansion-algorithm">Expansion Algorithm</a>
has a special <a>processing mode</a>, based on
the {{JsonLdOptions/frameExpansion}} flag, to enable content associated with JSON-LD
frames, which may not otherwise be valid <a>JSON-LD documents</a>.</li>
<li>An <a>expanded term definition</a> can now have an
<code>@context</code> <a>entry</a>, which defines a context used for values of
a <a>property</a> identified with such a <a>term</a>. This context is used
in both the <a href="#expansion-algorithm">Expansion Algorithm</a> and
<a href="#compaction-algorithm">Compaction Algorithm</a>.</li>
<li>A new <a href="#merge-node-maps" class="sectionRef"></a> is required
for framing, to create a single graph from the <a data-lt="default graph">default</a>
and <a>named graphs</a>.</li>
<li>An <a>expanded term definition</a> can now have an
<code>@nest</code> <a>entry</a>, which identifies a term expanding to
<code>@nest</code> which is used for containing <a>properties</a> using the same
<code>@nest</code> mapping. When expanding, the values of an <a>entry</a>
expanding to <code>@nest</code> are treated as if they were contained
within the enclosing <a>node object</a> directly.</li>
<li><code>@container</code> values within an <a>expanded term definition</a> may now
include <code>@id</code> and <code>@type</code>, corresponding to <a>id maps</a> and <a>type maps</a>.</li>
<li>Both <a>language maps</a> and <a>index maps</a> may legitimately have an <code>@none</code> value, but
JSON-LD 1.0 only allowed <a>string</a> values. This has been updated
to allow (and ignore) <code>@none</code> values.</li>
<li>The JSON syntax has been abstracted into an <a>internal representation</a>
to allow for other serialization formats that are functionally equivalent
to JSON.</li>
<li>Preserved values are compacted using the <a>properties</a> of the referencing term.</li>
<li>The value for <code>@container</code> in an <a>expanded term definition</a>
can also be an <a>array</a> containing any appropriate container
keyword along with <code>@set</code> (other than <code>@list</code>).
This allows a way to ensure that such <a>entry</a> values will always
be expressed in <a>array</a> form.</li>
<li>Added support for the <a data-link-for="JsonLdOptions">compactToRelative</a> option to allow IRI compaction (<a href="#iri-compaction" class="sectionRef"></a>)
to document-relative IRIs to be disabled.</li>
<li>In JSON-LD 1.1, terms will be used as <a>compact IRI</a> prefixes
when compacting only if
a <a>simple term definition</a> is used where the value ends with a URI <a data-cite="RFC3986#section-2.2">gen-delim</a> character,
or if their <a>expanded term definition</a> contains
an <code>@prefix</code> <a>entry</a> with the value <code>true</code>. The 1.0 algorithm has
been updated to only consider terms that map to a value that ends with a URI
<a data-cite="RFC3986#section-2.2">gen-delim</a> character.</li>
<li>Term definitions now allow <code>@container</code> to include <code>@graph</code>,
along with <code>@id</code>, <code>@index</code> and <code>@set</code>.
In the <a href="#expansion-algorithm">Expansion Algorithm</a>, this is
used to create a <a>named graph</a> from either a <a>node object</a>, or
objects which are values of <a>entries</a> in an <a>id map</a> or <a>index map</a>.
The <a href="#compaction-algorithm">Compaction Algorithm</a> allows
specific forms of graph objects to be compacted back to a set of <a>node objects</a>,
or maps of <a>node objects</a>.</li>
<li><a href="#value-expansion">Value Expansion</a> will not turn native values
into <a>node objects</a>.</li>
<li>The <a href="#term-selection">Term Selection algorithm</a> has been
updated to allow uses of containers for values which would otherwise not
match. This is used in the <a href="#expansion-algorithm">Compaction
Algorithm</a> to use the <code>@none</code> keyword, or an alias, for
values of maps for which there is no natural index. The <a
href="#expansion-algorithm">Expansion Algorithm</a> removes this indexing
transparently.</li>
</ul>
<p>Additionally, see <a href="#changes-from-cg" class="sectionRef"></a>.</p>
</section>
<section class="appendix informative" id="changes-from-cg"><h2>Changes since JSON-LD Community Group Final Report</h2>
<ul>
<li><a>Lists</a> may now have items which are themselves <a>lists</a>.</li>
<li>The <a href="#deserialize-json-ld-to-rdf-algorithm">Deserialize JSON-LD to RDF Algorithm</a>
has been updated to ensure that only <a>well-formed</a> <a>triples</a>
are emitted; previously, it only ensured that <a>triples</a> containing
<a>relative IRI references</a> were excluded.</li>
<li>The API now adds an {{JsonLdOptions/ordered}}
option, defaulting to <code>false</code> This is used in algorithms to
control iteration of <a>map entry</a> keys. Previously, the
algorithms always required such an order. The instructions for
evaluating test results have been updated accordingly.</li>
<li>The <a href="#generate-blank-node-identifier">Generate Blank Node Identifier algorithm</a>
has been updated to remove the specifics of how new blank node
identifiers are created.</li>
<li>Values of <code>@type</code>, or an alias of <code>@type</code>, may now have their <code>@container</code> set to <code>@set</code>
to ensure that <code>@type</code> entries are always represented as an array. This
also allows a term to be defined for <code>@type</code>, where the value MUST be a <a>map</a>
with <code>@container</code> set to <code>@set</code>.</li>
<li>Updated the <a href="#iri-expansion">IRI Expansion algorithm</a> so that
if <var>value</var> contains a colon (<code>:</code>), but
<var>prefix</var> is not a <a>term</a>, to only return <var>value</var>
if it has the <a href="https://tools.ietf.org/html/rfc3987#section-2.2">form</a> of an <a>IRI</a>, otherwise fall through to
the rest of the algorithm.</li>
<li>The use of <a>blank node identifiers</a> to label properties is obsolete,
and may be removed in a future version of JSON-LD,
as is the support for <a>generalized RDF Datasets</a>
and thus the {{JsonLdOptions/produceGeneralizedRdf}} option may be also be removed.</li>
<li>Added API steps to accept <code>text/html</code> as input,
extracting either a specifically targeted <a data-cite="HTML/scripting.html#the-script-element">script element</a>,
the first found <a>JSON-LD script element</a>,
or all <a>JSON-LD script elements</a>.</li>
<li>Added {{RemoteDocument/contentType}} field to <a>RemoteDocument</a>.</li>
<li>Added support for protected <a>contexts</a> and <a>term definitions</a>.</li>
<li>Because scoped contexts can lead to contexts being reloaded, replace the
<strong>recursive context inclusion</strong> error with a <a data-link-for="JsonLdErrorCode">context overflow</a> error.</li>
<li>Added support for <code>"@type": "@none"</code> in a <a>term definition</a> to prevent value compaction.</li>
<li>Added support for <a>JSON literals</a>.</li>
<li><a>Term definitions</a> with keys which are of the <a href="https://tools.ietf.org/html/rfc3987#section-2.2">form</a> of an <a>IRI</a> or a <a>compact IRI</a> MUST NOT
expand to an <a>IRI</a> other than the expansion of the key itself.</li>
<li>Consolidate <a>RemoteDocument</a> processing into the <a>LoadDocumentCallback</a>
including variations on HTML processing.</li>
<li>The <a href="#iri-compaction">IRI Compaction algorithm</a> may generate an error if the result is an
<a>IRI</a> which could be confused with a <a>compact IRI</a> in the
<a>active context</a>.</li>
<li>By default, all contexts are propagated when traversing <a>node objects</a>, other than
<a>type-scoped contexts</a>. This can be controlled using the <code>@propagate</code>
<a>entry</a> in a <a>local context</a>.</li>
<li>A context may contain a <code>@import</code> <a>entry</a> used to reference a remote context
within a context, allowing <code>JSON-LD 1.1</code> features to be added to contexts originally
authored for <code>JSON-LD 1.0</code>.</li>
<li>The <a data-link-for="JsonLdErrorCode">colliding keywords</a> error is not issued for `@type`;
instead, previous values of `@type` are prepended to any new values, when expanding.</li>
<li>A <a>node object</a> may include an <a>included block</a>,
which is used to contain a set of <a>node objects</a> which are treated
exactly as if they were <a>node objects</a> defined in an <a>array</a> including the containing
<a>node object</a>.
This allows the use of the object form of a JSON-LD document when there is more
than one <a>node object</a> being defined, and where those <a>node objects</a>
are not embedded as values of the containing <a>node object</a>.</li>
<li>A <a>relative IRI reference</a> has been added as a possible value for <code>@vocab</code> in
a context. When this is set, vocabulary-relative IRI references, such as the
<a>entries</a> of <a>node objects</a>, are expanded or compacted relative
to the <a>base IRI</a> and the <a>vocabulary mapping</a> using string concatenation.</li>
<li>In the <a>LoadDocumentCallback</a>, if the retrieved content is not any JSON media type
and there is a link header with `rel=alternate` and `type=application/ld+json`, redirect
to that content.</li>
<li><a>Value objects</a>, and associated <a>context</a> and <a>term definitions</a> have been updated to
support `@direction` for setting the <a>base direction</a> of strings.</li>
<li>It is no longer required that language tags be normalized to lower case,
other than for testing considerations.
Language tags that are not valid according to [[BCP47]] are rejected.</li>
<li>The <a>processing mode</a> is now implicitly `json-ld-1.1`, unless set
explicitly to `json-ld-1.0`.</li>
<li>Improve notation using <a>IRI</a>, <a>IRI reference</a>, and <a>relative IRI reference</a>.</li>
<li>Ignore terms and IRIs that have the form of a keyword (`"@"1*ALPHA`).</li>
</ul>
</section>
<section class="appendix informative" id="changes-from-cr">
<h2>Changes since Candidate Release of 12 December 2019</h2>
<p class="note">All changes are editorial and do not affect the observable
behavior of the API nor the expected test results.</p>
<ul>
<li>Add `application/xhtml+xml` as an allowed media type in <a href="#process-html" class="sectionRef"></a>,
in the note in <a href="#loaddocumentcallback" class="sectionRef"></a>,
and as a use of the {{LoadDocumentOptions/profile}} API option.</li>
<li>Added <a>add value</a>, <a>IRI expanding</a>, and <a>IRI compacting</a>
macros to reduce boilerplate in algorithmic language.</li>
<li>Improved algorithms in
<a href="#context-processing-algorithm" class="sectionRef"></a>,
<a href="#create-term-definition" class="sectionRef"></a>,
<a href="#expansion" class="sectionRef"></a>,
<a href="#compaction" class="sectionRef"></a>,
<a href="#value-compaction" class="sectionRef"></a>,
<a href="#node-map-generation" class="sectionRef"></a>,
and <a href="#deserialize-json-ld-to-rdf-algorithm" class="sectionRef"></a>.
</li>
<li>When creating an `i18n` datatype or `rdf:CompoundLiteral`, <a>language tags</a> are
normalized to lower case to improve interoperability between implementations.</li>
<li>Moved non-recursive portions algorithms
into the {{JsonLdProcessor}} processing steps.</li>
<li>Fix some {{JsonLdOption}} initializers where defaults are `null`.
Set default value for <a data-link-for="JsonLdOptions">processingMode</a> to `json-ld-1.1`.</li>
<li>Remove normative text for canonicalizing `rdf:JSON` literals and
reference the `rdf:JSON` datatype of the syntax document
for the conversion of the <a>JSON Literals</a> in <a href="#data-round-tripping" class="sectionRef"></a>.</li>
<li>Updated interfaces in <a href="#the-application-programming-interface" class="sectionRef"></a>
to use <a data-cite="WEBIDL#idl-record">record</a>,
instead of <a data-cite="WEBIDL#dfn-dictionary">dictionary</a>,
and to allow <a>RemoteDocument</a> to be used
as a direct input, which resolves a {{Promise}} boundary issue.</li>
</ul>
</section>
<section class="appendix informative" id="changes-from-cr2">
<h2>Changes since Candidate Release of 05 March 2020</h2>
<p class="note">All changes are editorial and do not affect the observable
behavior of the API nor the expected test results.</p>
<ul>
<li>The <a>inverse context</a> is not passed explicitly as a parameter
to the <a href="#term-selection">Term Selection</a>,
<a href="#iri-compaction">IRI compaction</a>,
and <a href="#value-compaction">Value Compaction</a> algorithms,
but is retrieved from the <a data-lt="context-inverse">inverse context</a> field
within an <a>active context</a>, and initialized as necessary.
This simplifies calling sequences and better represents actual implementation experience.</li>
<li>Updated step <a href="#alg-context-validate-scoped">5.13</a> of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>
to pass <var>override protected</var>
and not pass <var>validate scoped context</var>
to the <a href="#create-term-definition">Create Term Definition algorithm</a>.</li>
<li>Move step <a href="#alg-context-create-defns">5.2.2</a> of the
<a href="#context-processing-algorithm">Context Processing algorithm</a>
to run before the subsequent step for checking <var>remote contexts</var>.</li>
<li>Updated step <a href="#alg-ctd-protected">11</a> of the
<a href="#create-term-definition">Create Term Definition algorithm</a>
to use any boolean value of `@protected`, not just `true`.</li>
<li>Updated step <a href="#alg-iric-value-map">4.5</a> of the <a href="#iri-compaction">IRI Compaction algorithm</a>
to use `@index` for any value with an `@index` entry.</li>
<li>Update step <a href="#alg-expand-included">13.4.6.2</a> of the
<a href="#expansion-algorithm">Expansion algorithm</a> to pass
`null` for <var>active property</var>, as <a>included blocks</a>
do not define a relationship to a referencing node.</li>
<li>Update step <a href="#alg-expand-index-value">13.8.3.6</a> of the
<a href="#expansion-algorithm">Expansion algorithm</a> to pass
`true` for the <var>from map</var> parameter to properly manage reverting
<a>active contexts</a>.</li>
<li>Update step <a href="#alg-compact-11_1">11.1</a> of the
<a href="#compaction-algorithm">Compaction Algorithm</a>
to pass `false` for <var>propagate</var> when calling the
<a href="#context-processing-algorithm">Context Processing algorithm</a>.</li>
<li>Updated step <a href="#alg-compact-12_2_4">12.2.4</a> of the
<a href="#compaction-algorithm">Compaction Algorithm</a>
to only look for `@set` if <a>processing mode</a> is json-ld-1.1.</li>
<li>Update step <a href="#alg-compact-12_8_6">12.8.6</a> of the
<a href="#compaction-algorithm">Compaction Algorithm</a>
to clarify the value passed for <var>element</var>.</li>
<li>Update steps <a href="#alg-compact-12_8_9_6_3">12.8.9.6.3</a>
and <a href="#alg-compact-12_8_9_8_2">12.8.9.2.2</a> of the
<a href="#compaction-algorithm">Compaction Algorithm</a>
to invoke the <a>add value</a> macro for adding remaining values back to <var>compacted item</var>.</li>
<li>Update step <a href="#alg-compact-12_8_10">12.8.10</a> of the
<a href="#compaction-algorithm">Compaction Algorithm</a>
to add values to <var>nest result</var> instead of <var>result</var>
as was originally intended.</li>
<li>Update step <a href="#alg-merge-node-maps-2_2_1">2.2.1</a>
of <a href="#merge-node-maps" class="sectionRef"></a> to
exclude `@type`, leaving it to the next step.
This could cause type values from a node to be left out of the merge.</li>
<li>Added step <a href="#alg-context-validate-scoped">5.2.3</a>
to the <a href="#context-processing-algorithm">Context Processing algorithm</a>,
which is added <var>validate scoped context</var> as a new
optional argument, and passed to the
<a href="#create-term-definition">Create Term Definition algorithm</a>,
which in turn uses it with the value `false` when recursively calling
the <a href="#context-processing-algorithm">Context Processing algorithm</a>
when validating a <a>scoped context</a>.</li>
<li>Added missing values for `@container` in the description of
<a data-link-for="JsonLdErrorCode">invalid container mapping</a>.</li>
<li>Clarified step <a href="#alg-inv-lang-dir">3.13</a> in the
<a href="#inverse-context-creation">Inverse Context Creation algorithm</a>
by moving the preceding step to <a href=#alg-inv-lang-map>3.9</a>.</li>
<li>Update substeps of <a href="#alg-serialize-rdf-cl-reference">6.1.6</a>
in the <a href="#serialize-rdf-as-json-ld-algorithm">Serialize RDF as JSON-LD Algorithm</a>
to update <var>cl reference</var> and not <var>node</var>.</li>
<li>Added <a href="#api-keywords" class="sectionRef"></a> to describe
the `preserve` keyword, which is only used for framing.</li>
</ul>
</section>
<section class="appendix informative" id="changes-from-pr">
<h2>Changes since Proposed Recommendation Release of 7 May 2020</h2>
<ul>
<li>Removed remaining "at-risk" notes.</li>
<li>Update bibliographic reference for JCS to [[RFC8785]].</li>
<li>Changed `[Exposed=(Window,Worker)]` to `[Exposed=JsonLd]`,
which is declared as a global interface in order to expose the {{JsonLdProcessor}} interface
for non-browser usage to address review suggestions.</li>
</ul>
</section>
<section class="appendix informative" id="changes-from-rec1">
<h2>Changes since Recommendation of 16 July 2020</h2>
<ul>
<li>Regenerated definition list, which does not attempt to filter out unused definitions.</li>
<li>Changed obsolete use of `void` in WebIDL to `undefined`.</li>
<li>Added some clarifications to the algorithm of <a href="#node-map-generation"></a>.</li>
<li>Added some clarifications to the algorithm of <a href="#iri-compaction"></a>.</li>
<li>Added additional language to the
<a href="#compaction-algorithm">Compaction Algorithm</a>
step <a href="#alg-compact-12_8_9_6_1">12.8.9.6.1</a> to first expand
<var>container key</var> before compacting it.</li>
</ul>
</section>
<section id="ack"
class="appendix informative"
data-include="ack-script/acknowledgements.html"
data-include-replace="true">
</section>
</body>
</html>