--- a/spec/latest/json-ld-api/index.html Wed Feb 27 09:17:19 2013 -0800
+++ b/spec/latest/json-ld-api/index.html Wed Feb 27 18:25:41 2013 +0100
@@ -82,7 +82,7 @@
// document unless you know what you're doing. If in doubt ask your friendly neighbourhood
// Team Contact.
wgPatentURI: "http://www.w3.org/2004/01/pp-impl/46168/status",
- maxTocLevel: 3,
+ maxTocLevel: 2,
preProcess: [ preProc ],
alternateFormats: [ {uri: "diff-20120930.html", label: "diff to previous version"} ],
};
@@ -163,6 +163,7 @@
</ul>
</section>
+
<section class="informative">
<h1>Introduction</h1>
@@ -185,29 +186,8 @@
knowledge of the JavaScript programming language [[ECMA-262]] and
WebIDL [[!WEBIDL]]. To understand how JSON-LD maps to RDF, it is helpful to be
familiar with the basic RDF concepts [[!RDF-CONCEPTS]].</p>
-
- <p>Throughout this document, <tref title="compact iri">compact IRIs</tref>
- are used without prefix definitions.
- The examples throughout this document assume that the following
- vocabulary <tref title="prefix">prefixes</tref> have been defined:</p>
- <table>
- <tbody>
- <tr>
- <td rowspan="1" colspan="1">rdf:</td>
- <td rowspan="1" colspan="1">
- http://www.w3.org/1999/02/22-rdf-syntax-ns#</td>
- </tr>
- <tr>
- <td rowspan="1" colspan="1">rdfs:</td>
- <td rowspan="1" colspan="1"> http://www.w3.org/2000/01/rdf-schema#</td>
- </tr>
- <tr>
- <td rowspan="1" colspan="1">xsd:</td>
- <td rowspan="1" colspan="1">http://www.w3.org/2001/XMLSchema#</td>
- </tr>
- </tbody>
- </table>
-</section>
+</section> <!-- end of Introduction -->
+
<section class="informative">
<h1>Features</h1>
@@ -333,7 +313,7 @@
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> <!-- end of Expansion -->
<section class="informative">
<h2>Compaction</h2>
@@ -421,7 +401,7 @@
into an application-specific compacted document. While the context provided
above mapped <code>http://xmlns.com/foaf/0.1/nam</code> to <code>name</code>, it
could also have been mapped to any other term provided by the developer.</p>
- </section>
+ </section> <!-- end of Compaction -->
<section class="informative">
<h2>Flattening</h2>
@@ -522,7 +502,7 @@
<p>Please note that the flattened and compacted result always explicitly
designates the default graph by the <code>@graph</code> member in the
top-level <tref>JSON object</tref>.</p>
- </section>
+ </section> <!-- end of Flattening -->
<section class="informative">
<h2>RDF Conversion</h2>
@@ -568,8 +548,9 @@
<p>Note that the output above could easily be compacted using the technique outlined
in the previous section. It is also possible to transform the JSON-LD document back
to RDF using the <a href="#convert-to-rdf-algorithm">Convert to RDF Algorithm</a>.</p>
- </section>
-</section>
+ </section> <!-- end of RDF Conversion -->
+</section> <!-- end of Features section -->
+
<section>
<h1>Conformance</h1>
@@ -609,7 +590,8 @@
suite [[JSON-LD-TESTS]]. Note, however, that passing all the tests in the test
suite does not imply complete conformance to this specification. It only implies
that the implementation conforms to aspects tested by the test suite.</p>
-</section>
+</section> <!-- end of Conformance section -->
+
<section>
<h1>General Terminology</h1>
@@ -715,19 +697,11 @@
<tref title="blank node">blank nodes</tref>, and
<tref title="JSON-LD value">JSON-LD values</tref>.</dd>
</dl>
-
-</section>
+</section> <!-- end of General Terminology section -->
+
<section>
- <h1>Algorithms</h1>
-
- <p>All algorithms described in this section are intended to operate on
- language-native data structures. That is, the serialization to a text-based
- JSON document isn't required as input or output to any of these algorithms and
- language-native data structures MUST be used where applicable.</p>
-
-<section>
- <h2>Algorithm Terms</h2>
+ <h1>Algorithm Terms</h1>
<dl>
<dt><tdef>active graph</tdef></dt>
@@ -789,803 +763,2319 @@
<dd>A <tref href="http://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset">dataset</tref> as specified by [[RDF-CONCEPTS]] representing a collection of
<tref href="http://www.w3.org/TR/rdf11-concepts/#dfn-rdf-graph">RDF graphs</tref>.</dd>
</dl>
-
-</section>
-
-<section>
- <h2>Remote Context Resolution</h2>
-
-<section class="informative">
- <h3>Purpose</h3>
-
- <p>A JSON-LD document may contain remote <tref title="context">contexts</tref>.
- These <tref title="context">contexts</tref> must be dereferenced before they
- can be processed.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>Dereferencing remote <tref title="context">contexts</tref> can be performed
- either inline with the other JSON-LD algorithms or as a separate, prior step.
- This solution opts to dereference them first, in a prior step, to both
- separate concerns and to better enable <tref>active context</tref> caching.
- By separating concerns, the other JSON-LD algorithms can be described more
- simply. Implementations may also be either simplified or made more efficient
- because there is no need to block or respond to events when remote
- <tref title="context">contexts</tref> are dereferenced over the network. This
- is particularly important for simplifying implementations in asynchronous
- programming environments. Of course, choosing this approach is not a
- requirement.</p>
-
- <p>The JSON-LD document is searched for remote <tref title="context">contexts</tref>
- recursively, starting with its root <em>element</em>. If the <em>element</em>
- contains an <code>@context</code> key, its value is searched for
- <tref title="string">strings</tref>. The result represents a remote
- <tref>context</tref>, which we add to a map that will ensure we don't
- dereference an already dereferenced remote <tref>context</tref> for a given
- <tref>IRI</tref>.</p>
-
- <p>When we have finished searching, we dereference each remote
- <tref>context</tref> (or get its already-dereferenced value from our map).
- Each time we dereference a remote <tref>context</tref>, we store its result
- in our map and then recursively search it for more remote
- <tref title="IRI">contexts</tref> as above, checking to ensure there is no
- cyclical reference, which is a
- <code class="error">recursive context inclusion</code> error.</p>
-
- <p>Once all of the remote <tref title="IRI">contexts</tref> have been
- dereferenced, we replace all of their associated <tref>context</tref>
- <tref title="IRI">IRIs</tref> in the JSON-LD document with the
- results from our map.</p>
-</section>
-
-<!-- end of Remote Context Resolution -->
-</section>
-
-<section>
-<h2>Context Processing</h2>
-
-<p>
-When processing a JSON-LD data structure, each processing rule is applied
-using information provided by the <tref>active context</tref>. This
-section describes how to produce an <tref>active context</tref>.
-</p>
-
-<p>
-The <tref>active context</tref> contains the active
-<tdef title="term definition">term definitions</tdef> which specify how
-properties and values have to be interpreted as well as the current
-<tdef>vocabulary mapping</tdef> and the <tdef>default language</tdef>. Each
-<tref>term definition</tref> consists of an <tdef>IRI mapping</tdef> and
-optionally a <tdef>type mapping</tdef> from terms to datatypes or
-<tdef>language mapping</tdef> from terms to language codes, and a
-<tdef>container mapping</tdef>. If an <tref>IRI mapping</tref> maps a term
-to multiple <tref title="IRI">IRIs</tref> it is said to be a
-<tdef>property generator</tdef>. The <tref>active context</tref> also
-keeps track of <tref>keyword</tref> aliases.
-</p>
-
-<p>
-When processing, the <tref>active context</tref> is initialized
-without any <tref title="term definition">term definitions</tref>,
-<tref>vocabulary mapping</tref>, or <tref>default language</tref>.
-If a <tref>local context</tref> is encountered during processing, a new
-<tref>active context</tref> is created by cloning the existing
-<tref>active context</tref>. Then the information from the
-<tref>local context</tref> is merged into the new <tref>active context</tref>.
-A <tref>local context</tref> is identified within a <tref>JSON object</tref>
-by the value of the <code>@context</code> key, which MUST be a
-<tref>string</tref>, an <tref>array</tref>, or a <tref>JSON object</tref>.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-<p>
-A <tref>local context</tref> needs to be transformed into an
-<tref>active context</tref> so that the <tref>active context</tref> can be
-used when executing other JSON-LD algorithms such as
-<a href="#expansion-algorithm">Expansion</a> or
-<a href="#compaction-algorithm">Compaction</a>. Any remote
-<tref title="context">contexts</tref> in the <tref>local context</tref>
-have already been dereferenced.
-</p>
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-First we prepare a new <tref>active context</tref> <em>result</em> by cloning
-the current <tref>active context</tref>. Next we update the
-<tref>vocabulary mapping</tref> and <tref>default language</tref> by
-processing two specific keywords: <code>@vocab</code> and <code>@language</code>.
-These are handled before any other keys in the <tref>local context</tref> because
-they affect how the other keys are processed.
-</p>
-
-<p>
-Then, for every other key in <tref>local context</tref>, we update
-the <tref>term definition</tref> in <em>result</em>.
-</p>
-
-<p>
-Since <tref title="context">context</tref> values in a
-<tref>local context</tref> may themselves contain
-<tref title="compact IRI">compact IRIs</tref>, we may need to recurse to
-define a <tref>prefix</tref>. When doing so, we must ensure that there is
-no cyclical dependency, which is an error. After we have processed any
-<tref title="term definition">term definition</tref> dependencies, we update
-the current <tref title="term definition">term definition</tref>, which may be
-a keyword alias or consist of <code>@id</code>, <code>@language</code>,
-<code>@type</code>, or <code>@container</code> mappings.
-</p>
-
-<p>
-Finally, we return <em>result</em> as the new <tref>active context</tref>.
-</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>
-This algorithm specifies how a new <tref>active context</tref> is updated
-with a <tref>local context</tref>. The algorithm takes two input variables:
-an <tref>active context</tref> and a <tref>local context</tref>.</p>
-
-<ol class="algorithm">
- <li>
- Initialize <em>result</em> to the result of cloning
- <tref>active context</tref>.
- </li>
- <li>
- If <tref>local context</tref> is not an <tref>array</tref>, then
- set it to an <tref>array</tref> containing only
- <tref>local context</tref>.
- </li>
- <li>
- For each item <em>context</em> in <tref>local context</tref>:
- <ol class="algorithm">
- <li>
- If <em>context</em> is <tref>null</tref>, then set <em>result</em>
- to a newly-initialized <tref>active context</tref> and continue to the
- next <em>context</em>.
- </li>
- <li>
- At this point, <em>context</em> MUST be a <tref>JSON object</tref>
- because all remote <tref title="context">contexts</tref> have already
- been dereferenced. Otherwise, an
- <code class="error">invalid local context</code> error has been
- detected.
- </li>
- <li>
- If <em>context</em> has an <code>@vocab</code> key:
- <ol class="algorithm">
- <li>
- Initialize <em>value</em> to the value associated with the
- <code>@vocab</code> key.
- </li>
- <li>
- If <em>value</em> is <tref>null</tref>, then remove
- any <tref>vocabulary mapping</tref> from <em>result</em>.
- </li>
- <li>
- Otherwise, <em>value</em> MUST be an <tref>absolute IRI</tref>,
- if not, an <code class="error">invalid vocab mapping</code>
- error has been detected. Set <em>result</em>'s
- <tref>vocabulary mapping</tref> to <em>value</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>context</em> has an <code>@language</code> key:
- <ol class="algorithm">
- <li>
- Initialize <em>value</em> to the value associated with the
- <code>@language</code> key.
- </li>
- <li>
- If <em>value</em> is <tref>null</tref>, then remove
- any <tref>default language</tref> from <em>result</em>.
- </li>
- <li>
- Otherwise, <em>value</em> MUST be a <tref>string</tref>, if not,
- an <code class="error">invalid default language</code> error
- has been detected. Set <em>result</em>'s
- <tref>default language</tref> to lowercased <em>value</em>.
- </li>
- </ol>
- </li>
- <li>
- Create a <tref>JSON object</tref> <em>defined</em> to use to keep
- track of whether or not a <tref>term</tref> has already been defined
- or currently being defined during recursion.
- </li>
- <li>
- For each <em>key</em>-<em>value</em> pair in <em>context</em> where
- <em>key</em> is not <code>@vocab</code> or <code>@language</code>,
- invoke the <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
- subalgorithm, passing <em>result</em> for <tref>active context</tref>,
- <em>context</em> for <tref>local context</tref>, <em>key</em>,
- and <em>defined</em>.
- </li>
- </ol>
- </li>
- <li>
- Return <em>result</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Context Processing algorithm -->
-</section>
-
-<section>
-<h2>Create Term Definition Subalgorithm</h2>
-
-<p>
-This algorithm is called from the
-<a href="#context-processing">Context Processing</a> algorithm to create
-<tref title="term definition">term definitions</tref> in a new
-<tref>active context</tref>.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-A <tref>term definition</tref> must be created for the given
-<tref>term</tref>.
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-<tref title="term definition">Term definitions</tref> are created by
-parsing the information in the given <tref>local context</tref> for the
-given <tref>term</tref>. If the given <tref>term</tref> is a
-<tref>compact IRI</tref>, it may omit an <tref>IRI mapping</tref> by
-depending on its <tref>prefix</tref> having its own
-<tref>term definition</tref>. If the <tref>prefix</tref> is
-a key in the <tref>local context</tref>, then its <tref>term definition</tref>
-must first be created, through recursion, before continuing. Because a
-<tref>term definition</tref> can depend on other
-<tref title="term definition">term definitions</tref>, a mechanism must
-be used to detect cyclical dependencies. The solution employed here
-uses a map, <em>defined</em>, that keeps track of whether or not a
-<tref>term</tref> 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 <tref>term</tref> have been defined, the rest of
-the information in the <tref>local context</tref> for the given
-<tref>term</tref> is taken into account, creating the appropriate
-<tref>IRI mapping</tref>, <tref>container mapping</tref>, and
-<tref>type mapping</tref> or <tref>language mapping</tref> for the
-<tref>term</tref>.
-</p>
-
-</section>
+</section> <!-- end of Algorithm Terms section -->
+
<section>
-<h3>Algorithm</h3>
-
-<p>
-The algorithm has four required inputs which are:
-an <tref>active context</tref>, a <tref>local context</tref>,
-a <em>term</em>, and a map <em>defined</em>.
-</p>
-
-<ol class="algorithm">
- <li>
- If <em>defined</em> contains the key <em>term</em>, then the associated
- value MUST be <tref>true</tref>, indicating that the
- <tref>term definition</tref> has already been created, so return.
- Otherwise, a <code class="error">cyclic IRI mapping</code> error has been
- detected.
- </li>
- <li>
- Set the value associated with <em>defined</em>'s <em>term</em> key to
- <tref>false</tref>. This indicates that the <tref>term definition</tref>
- is now being created but is not yet complete.
- </li>
- <li>
- Since <tref title="keyword">keywords</tref> cannot be overridden,
- <em>term</em> MUST NOT be a <tref>keyword</tref>. Otherwise, a
- <code class="error">keyword redefinition</code> error has been detected.
- </li>
- <li>
- Remove any existing <tref>term definition</tref> for <em>term</em> in
- <tref>active context</tref>.
- </li>
- <li>
- Initialize <em>value</em> to the value associated with the key
- <em>term</em> in <tref>local context</tref>.
- </li>
- <li>
- If <em>value</em> is <tref>null</tref> or <em>value</em>
- is a <tref>JSON object</tref> containing the key-value pair
- (<code>@id</code>-<tref>null</tref>), then set the
- <tref>term definition</tref> in <tref>active context</tref> to
- <tref>null</tref>, set the value associated with <em>defined</em>'s
- key <em>term</em> to <tref>true</tref>, and return.
- </li>
- <li>
- Otherwise, if <em>value</em> is a <tref>string</tref>:
- <ol class="algorithm">
- <li>
- Expand <em>value</em> by setting it to the result of
- using the <a href="#iri-expansion">IRI Expansion</a> algorithm,
- passing <tref>active context</tref>, <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>,
- <tref>true</tref> for <em>documentRelative</em>,
- <tref>local context</tref>, and <em>defined</em>.
- </li>
- <li>
- If <em>value</em> is a <tref>keyword</tref>, then <em>value</em>
- MUST NOT be <code>@context</code>, if it is, an
- <code class="error">invalid keyword alias</code> error has been
- detected. Add <em>term</em> to <tref>active context</tref> as a
- <tref>keyword</tref> alias for <em>value</em>. If there is more than
- one <tref>keyword</tref> alias for <em>value</em>, then store its
- aliases as an <tref>array</tref>, sorted by length, breaking ties
- lexicographically.
- </li>
- <li>
- Set the <tref>IRI mapping</tref> for the <tref>term definition</tref>
- for <em>term</em> in <tref>active context</tref> to <em>value</em>,
- set the value associated with <em>defined</em>'s key <em>term</em> to
- <tref>true</tref>, and return.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, <em>value</em> MUST be a <tref>JSON object</tref>, if not,
- an <code>invalid term definition</code> error has been detected.
- </li>
- <li>
- Create a new <tref>JSON object</tref>, <em>definition</em>.
- </li>
- <li>
- If <em>value</em> contains the key <code>@id</code>:
+ <h1>Context Processing Algorithms</h1>
+
+ <section>
+ <h2>Remote Context Resolution</h2>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A JSON-LD document may contain remote <tref title="context">contexts</tref>.
+ These <tref title="context">contexts</tref> must be dereferenced before they
+ can be processed.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Dereferencing remote <tref title="context">contexts</tref> can be performed
+ either inline with the other JSON-LD algorithms or as a separate, prior step.
+ This solution opts to dereference them first, in a prior step, to both
+ separate concerns and to better enable <tref>active context</tref> caching.
+ By separating concerns, the other JSON-LD algorithms can be described more
+ simply. Implementations may also be either simplified or made more efficient
+ because there is no need to block or respond to events when remote
+ <tref title="context">contexts</tref> are dereferenced over the network. This
+ is particularly important for simplifying implementations in asynchronous
+ programming environments. Of course, choosing this approach is not a
+ requirement.</p>
+
+ <p>The JSON-LD document is searched for remote <tref title="context">contexts</tref>
+ recursively, starting with its root <em>element</em>. If the <em>element</em>
+ contains an <code>@context</code> key, its value is searched for
+ <tref title="string">strings</tref>. The result represents a remote
+ <tref>context</tref>, which we add to a map that will ensure we don't
+ dereference an already dereferenced remote <tref>context</tref> for a given
+ <tref>IRI</tref>.</p>
+
+ <p>When we have finished searching, we dereference each remote
+ <tref>context</tref> (or get its already-dereferenced value from our map).
+ Each time we dereference a remote <tref>context</tref>, we store its result
+ in our map and then recursively search it for more remote
+ <tref title="IRI">contexts</tref> as above, checking to ensure there is no
+ cyclical reference, which is a
+ <code class="error">recursive context inclusion</code> error.</p>
+
+ <p>Once all of the remote <tref title="IRI">contexts</tref> have been
+ dereferenced, we replace all of their associated <tref>context</tref>
+ <tref title="IRI">IRIs</tref> in the JSON-LD document with the
+ results from our map.</p>
+ </section>
+ </section> <!-- end of Remote Context Resolution -->
+
+ <section>
+ <h2>Context Processing</h2>
+
+ <p>When processing a JSON-LD data structure, each processing rule is applied
+ using information provided by the <tref>active context</tref>. This
+ section describes how to produce an <tref>active context</tref>.</p>
+
+ <p>The <tref>active context</tref> contains the active
+ <tdef title="term definition">term definitions</tdef> which specify how
+ properties and values have to be interpreted as well as the current
+ <tdef>vocabulary mapping</tdef> and the <tdef>default language</tdef>. Each
+ <tref>term definition</tref> consists of an <tdef>IRI mapping</tdef> and
+ optionally a <tdef>type mapping</tdef> from terms to datatypes or
+ <tdef>language mapping</tdef> from terms to language codes, and a
+ <tdef>container mapping</tdef>. If an <tref>IRI mapping</tref> maps a term
+ to multiple <tref title="IRI">IRIs</tref> it is said to be a
+ <tdef>property generator</tdef>. The <tref>active context</tref> also
+ keeps track of <tref>keyword</tref> aliases.</p>
+
+ <p>When processing, the <tref>active context</tref> is initialized
+ without any <tref title="term definition">term definitions</tref>,
+ <tref>vocabulary mapping</tref>, or <tref>default language</tref>.
+ If a <tref>local context</tref> is encountered during processing, a new
+ <tref>active context</tref> is created by cloning the existing
+ <tref>active context</tref>. Then the information from the
+ <tref>local context</tref> is merged into the new <tref>active context</tref>.
+ A <tref>local context</tref> is identified within a <tref>JSON object</tref>
+ by the value of the <code>@context</code> key, which MUST be a
+ <tref>string</tref>, an <tref>array</tref>, or a <tref>JSON object</tref>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A <tref>local context</tref> needs to be transformed into an
+ <tref>active context</tref> so that the <tref>active context</tref> can be
+ used when executing other JSON-LD algorithms such as
+ <a href="#expansion-algorithm">Expansion</a> or
+ <a href="#compaction-algorithm">Compaction</a>. Any remote
+ <tref title="context">contexts</tref> in the <tref>local context</tref>
+ have already been dereferenced.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>First we prepare a new <tref>active context</tref> <em>result</em> by cloning
+ the current <tref>active context</tref>. Next we update the
+ <tref>vocabulary mapping</tref> and <tref>default language</tref> by
+ processing two specific keywords: <code>@vocab</code> and <code>@language</code>.
+ These are handled before any other keys in the <tref>local context</tref> because
+ they affect how the other keys are processed.</p>
+
+ <p>Then, for every other key in <tref>local context</tref>, we update
+ the <tref>term definition</tref> in <em>result</em>.</p>
+
+ <p>Since <tref title="context">context</tref> values in a
+ <tref>local context</tref> may themselves contain
+ <tref title="compact IRI">compact IRIs</tref>, we may need to recurse to
+ define a <tref>prefix</tref>. When doing so, we must ensure that there is
+ no cyclical dependency, which is an error. After we have processed any
+ <tref title="term definition">term definition</tref> dependencies, we update
+ the current <tref title="term definition">term definition</tref>, which may be
+ a keyword alias or consist of <code>@id</code>, <code>@language</code>,
+ <code>@type</code>, or <code>@container</code> mappings.</p>
+
+ <p>Finally, we return <em>result</em> as the new <tref>active context</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>This algorithm specifies how a new <tref>active context</tref> is updated
+ with a <tref>local context</tref>. The algorithm takes two input variables:
+ an <tref>active context</tref> and a <tref>local context</tref>.</p>
+
+ <ol class="algorithm">
+ <li>Initialize <em>result</em> to the result of cloning
+ <tref>active context</tref>.</li>
+ <li>If <tref>local context</tref> is not an <tref>array</tref>, then
+ set it to an <tref>array</tref> containing only
+ <tref>local context</tref>.</li>
+ <li>
+ For each item <em>context</em> in <tref>local context</tref>:
+ <ol class="algorithm">
+ <li>If <em>context</em> is <tref>null</tref>, then set <em>result</em>
+ to a newly-initialized <tref>active context</tref> and continue to the
+ next <em>context</em>.</li>
+ <li>At this point, <em>context</em> MUST be a <tref>JSON object</tref>
+ because all remote <tref title="context">contexts</tref> have already
+ been dereferenced. Otherwise, an
+ <code class="error">invalid local context</code> error has been
+ detected.</li>
+ <li>
+ If <em>context</em> has an <code>@vocab</code> key:
+ <ol class="algorithm">
+ <li>Initialize <em>value</em> to the value associated with the
+ <code>@vocab</code> key.</li>
+ <li>If <em>value</em> is <tref>null</tref>, then remove
+ any <tref>vocabulary mapping</tref> from <em>result</em>.</li>
+ <li>Otherwise, <em>value</em> MUST be an <tref>absolute IRI</tref>,
+ if not, an <code class="error">invalid vocab mapping</code>
+ error has been detected. Set <em>result</em>'s
+ <tref>vocabulary mapping</tref> to <em>value</em>.</li>
+ </ol>
+ </li>
+ <li>
+ If <em>context</em> has an <code>@language</code> key:
+ <ol class="algorithm">
+ <li>Initialize <em>value</em> to the value associated with the
+ <code>@language</code> key.</li>
+ <li>If <em>value</em> is <tref>null</tref>, then remove
+ any <tref>default language</tref> from <em>result</em>.</li>
+ <li>Otherwise, <em>value</em> MUST be a <tref>string</tref>, if not,
+ an <code class="error">invalid default language</code> error
+ has been detected. Set <em>result</em>'s
+ <tref>default language</tref> to lowercased <em>value</em>.</li>
+ </ol>
+ </li>
+ <li>Create a <tref>JSON object</tref> <em>defined</em> to use to keep
+ track of whether or not a <tref>term</tref> has already been defined
+ or currently being defined during recursion.</li>
+ <li>For each <em>key</em>-<em>value</em> pair in <em>context</em> where
+ <em>key</em> is not <code>@vocab</code> or <code>@language</code>,
+ invoke the <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
+ subalgorithm, passing <em>result</em> for <tref>active context</tref>,
+ <em>context</em> for <tref>local context</tref>, <em>key</em>,
+ and <em>defined</em>.</li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Context Processing -->
+
+ <section>
+ <h2>Create Term Definition Subalgorithm</h2>
+
+ <p>This algorithm is called from the
+ <a href="#context-processing">Context Processing</a> algorithm to create
+ <tref title="term definition">term definitions</tref> in a new
+ <tref>active context</tref>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A <tref>term definition</tref> must be created for the given
+ <tref>term</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p><tref title="term definition">Term definitions</tref> are created by
+ parsing the information in the given <tref>local context</tref> for the
+ given <tref>term</tref>. If the given <tref>term</tref> is a
+ <tref>compact IRI</tref>, it may omit an <tref>IRI mapping</tref> by
+ depending on its <tref>prefix</tref> having its own
+ <tref>term definition</tref>. If the <tref>prefix</tref> is
+ a key in the <tref>local context</tref>, then its <tref>term definition</tref>
+ must first be created, through recursion, before continuing. Because a
+ <tref>term definition</tref> can depend on other
+ <tref title="term definition">term definitions</tref>, a mechanism must
+ be used to detect cyclical dependencies. The solution employed here
+ uses a map, <em>defined</em>, that keeps track of whether or not a
+ <tref>term</tref> 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 <tref>term</tref> have been defined, the rest of
+ the information in the <tref>local context</tref> for the given
+ <tref>term</tref> is taken into account, creating the appropriate
+ <tref>IRI mapping</tref>, <tref>container mapping</tref>, and
+ <tref>type mapping</tref> or <tref>language mapping</tref> for the
+ <tref>term</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm has four required inputs which are:
+ an <tref>active context</tref>, a <tref>local context</tref>,
+ a <em>term</em>, and a map <em>defined</em>.</p>
+
+ <ol class="algorithm">
+ <li>If <em>defined</em> contains the key <em>term</em>, then the associated
+ value MUST be <tref>true</tref>, indicating that the
+ <tref>term definition</tref> has already been created, so return.
+ Otherwise, a <code class="error">cyclic IRI mapping</code> error has been
+ detected.</li>
+ <li>Set the value associated with <em>defined</em>'s <em>term</em> key to
+ <tref>false</tref>. This indicates that the <tref>term definition</tref>
+ is now being created but is not yet complete.</li>
+ <li>Since <tref title="keyword">keywords</tref> cannot be overridden,
+ <em>term</em> MUST NOT be a <tref>keyword</tref>. Otherwise, a
+ <code class="error">keyword redefinition</code> error has been detected.</li>
+ <li>Remove any existing <tref>term definition</tref> for <em>term</em> in
+ <tref>active context</tref>.</li>
+ <li>Initialize <em>value</em> to the value associated with the key
+ <em>term</em> in <tref>local context</tref>.</li>
+ <li>If <em>value</em> is <tref>null</tref> or <em>value</em>
+ is a <tref>JSON object</tref> containing the key-value pair
+ (<code>@id</code>-<tref>null</tref>), then set the
+ <tref>term definition</tref> in <tref>active context</tref> to
+ <tref>null</tref>, set the value associated with <em>defined</em>'s
+ key <em>term</em> to <tref>true</tref>, and return.</li>
+ <li>Otherwise, if <em>value</em> is a <tref>string</tref>:
+ <ol class="algorithm">
+ <li>Expand <em>value</em> by setting it to the result of
+ using the <a href="#iri-expansion">IRI Expansion</a> algorithm,
+ passing <tref>active context</tref>, <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>,
+ <tref>true</tref> for <em>documentRelative</em>,
+ <tref>local context</tref>, and <em>defined</em>.</li>
+ <li>If <em>value</em> is a <tref>keyword</tref>, then <em>value</em>
+ MUST NOT be <code>@context</code>, if it is, an
+ <code class="error">invalid keyword alias</code> error has been
+ detected. Add <em>term</em> to <tref>active context</tref> as a
+ <tref>keyword</tref> alias for <em>value</em>. If there is more than
+ one <tref>keyword</tref> alias for <em>value</em>, then store its
+ aliases as an <tref>array</tref>, sorted by length, breaking ties
+ lexicographically.</li>
+ <li>Set the <tref>IRI mapping</tref> for the <tref>term definition</tref>
+ for <em>term</em> in <tref>active context</tref> to <em>value</em>,
+ set the value associated with <em>defined</em>'s key <em>term</em> to
+ <tref>true</tref>, and return.</li>
+ </ol>
+ </li>
+ <li>Otherwise, <em>value</em> MUST be a <tref>JSON object</tref>, if not,
+ an <code>invalid term definition</code> error has been detected.</li>
+ <li>Create a new <tref>JSON object</tref>, <em>definition</em>.</li>
+ <li>If <em>value</em> contains the key <code>@id</code>:
+ <ol class="algorithm">
+ <li>Initialize <em>id</em> to the value associated with the
+ <code>@id</code> key.</li>
+ <li>If <em>id</em> is an <tref>array</tref>, then the
+ <tref>term definition</tref> is for a <tref>property generator</tref>:
+ <ol class="algorithm">
+ <li>Create an empty <tref>array</tref> <em>property generator</em>.</li>
+ <li>For each item <em>iri</em> in <em>id</em>:
+ <ol class="algorithm">
+ <li>If <em>iri</em> is a <tref>string</tref>, then
+ set <em>iri</em> to the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>iri</em> for <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>,
+ <tref>true</tref> for <em>documentRelative</em>,
+ <tref>local context</tref>, and <em>defined</em>.</li>
+ <li><em>iri</em> MUST be a <tref>string</tref> and MUST not be
+ a <tref>keyword</tref>, otherwise an
+ <code class="error">invalid property generator</code>
+ error has been detected.</li>
+ <li>Append <em>iri</em> to <em>property generator</em>.</li>
+ </ol>
+ </li>
+ <li>Set the <tref>property generator</tref> <tref>IRI mapping</tref>
+ for <em>definition</em> to the result of sorting
+ <em>property generator</em> lexicographically.</li>
+ </ol>
+ </li>
+ <li>Otherwise <em>id</em> MUST be a <tref>string</tref>, if not,
+ an <code class="error">invalid IRI mapping</code> error has been
+ detected. Set the <tref>IRI mapping</tref> for <em>definition</em>
+ to the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>id</em> for <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>,
+ <tref>true</tref> for <em>documentRelative</em>,
+ <tref>local context</tref>, and <em>defined</em>.</li>
+ </ol>
+ </li>
+ <li>
+ Otherwise if the <em>term</em> contains a colon (<code>:</code>):
+ <ol class="algorithm">
+ <li>If <em>term</em> is a <tref>compact IRI</tref> with a
+ <tref>prefix</tref> that is a key in <tref>local context</tref> then
+ a dependency has been found. Use this algorithm recursively passing
+ <tref>active context</tref>, <tref>local context</tref>, the
+ <tref>prefix</tref> as <em>term</em>, and <em>defined</em>.</li>
+ <li>If <em>term</em>'s <tref>prefix</tref> has a
+ <tref>term definition</tref> in <tref>active context</tref>, set
+ the <tref>IRI mapping</tref> for <em>definition</em> to the result of
+ concatenating the value associated with the <tref>prefix</tref>'s
+ <tref>IRI mapping</tref> and the <em>term</em>'s <em>suffix</em>.</li>
+ <li>Otherwise, <em>term</em> is an <tref>absolute IRI</tref>. Set the
+ <tref>IRI mapping</tref> for <em>definition</em> to <em>term</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, <tref>active context</tref> MUST have a
+ <tref>vocabulary mapping</tref>, if not, an
+ <code class="error">invalid IRI mapping</code> error
+ been detected. Set the <tref>IRI mapping</tref>
+ for <em>definition</em> to the result of concatenating the value
+ associated with the <tref>vocabulary mapping</tref> and <em>term</em>.</li>
+ <li>If <em>value</em> contains the key <code>@type</code>:
+ <ol class="algorithm">
+ <li>Initialize <em>type</em> to the value associated with the
+ <code>@type</code> key, which MUST be a <tref>string</tref>.
+ Otherwise, an <code class="error">invalid type mapping</code> error
+ has been detected.</li>
+ <li>If <em>type</em> is not <code>@id</code> then set it to
+ the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>type</em> for <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>,
+ <tref>true</tref> for <em>documentRelative</em>,
+ <tref>local context</tref>, and <em>defined</em>. Set the
+ <tref>type mapping</tref> for <em>definition</em> to <em>type</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>value</em> contains the key <code>@container</code>:
+ <ol class="algorithm">
+ <li>Initialize <em>container</em> to the value associated with the
+ <code>@container</code> key, which MUST be either:
+ <code>@list</code>, <code>@set</code>, <code>@index</code>,
+ or <code>@language</code>. Otherwise, an
+ <code class="error">invalid container mapping</code> error
+ has been detected.</li>
+ <li>Set the <tref>container mapping</tref> for <em>definition</em> to
+ <em>container</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>value</em> contains the key <code>@language</code> and
+ does not contain the key <code>@type</code>:
+ <ol class="algorithm">
+ <li>Initialize <em>language</em> to the value associated with the
+ <code>@language</code> key, which MUST be either <tref>null</tref>
+ or a <tref>string</tref>. Otherwise, an
+ <code class="error">invalid language mapping</code> error has been
+ detected.</li>
+ <li>If <em>language</em> is a <tref>string</tref> set it to
+ lowercased <em>language</em>. Set the <tref>language mapping</tref>
+ for <em>definition</em> to <em>language</em>.</li>
+ </ol>
+ </li>
+ <li>Set the <tref>term definition</tref> for <em>term</em> in
+ <tref>active context</tref> to <em>definition</em> and set the value
+ associated with <em>defined</em>'s key <em>term</em> to
+ <tref>true</tref>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Term Creation subalgorithm -->
+
+ <section>
+ <h2>IRI Expansion</h2>
+
+ <p>In JSON-LD documents, some keys and values may represent
+ <tref title="IRI">IRIs</tref>. This section defines an algorithm for
+ transforming a <tref>string</tref> that represents an <tref>IRI</tref> into
+ an <tref>absolute IRI</tref>. It also covers transforming <tref>keyword</tref>
+ aliases into <tref title="keyword">keywords</tref>.</p>
+
+ <p><tref>IRI</tref> expansion may occur during context processing or during
+ any of the other JSON-LD algorithms. If IRI expansion occurs during context
+ processing, then the <tref>local context</tref> and its related
+ <em>defined</em> map from the
+ <a href="#context-processing">Context Processing</a> algorithm are passed
+ to this algorithm. This allows for <tref>term definition</tref> dependencies
+ to be processed via the context processing subalgorithm,
+ <a href="#create-term-definition-subalgorithm">Create Term Definition</a>.</p>
+
+ <p>After application of this algorithm, values processed by this algorithm are
+ said to be in <tdef>expanded IRI form</tdef> (Advanced note: this form
+ may also include
+ <tref title="blank node identifier">blank node identifiers</tref> and
+ JSON-LD <tref title="keyword">keywords</tref>).</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>We have a value that needs to be expanded to an <tref>absolute IRI</tref>
+ or a <tref>keyword</tref>. The given value may be <tref>null</tref>, a
+ <tref>term</tref>, a <tref>keyword</tref> alias, a <tref>compact IRI</tref>,
+ a <tref>relative IRI</tref>, or an <tref>absolute IRI</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>In order to expand <em>value</em> to an <tref>absolute IRI</tref>, we must
+ first determine if it is <tref>null</tref>, a <tref>term</tref>, a
+ <tref>keyword</tref> alias, or some form of <tref>IRI</tref>. Based on what
+ we find, we handle the specific kind of expansion; for example, we expand
+ a <tref>keyword</tref> alias to a <tref>keyword</tref> and a <tref>term</tref>
+ to an <tref>absolute IRI</tref> according to its <tref>IRI mapping</tref>
+ in the <tref>active context</tref>. While inspecting <em>value</em> we
+ may also find that we need to create <tref>term definition</tref>
+ dependencies because we're running this
+ algorithm during <a href="#context-processing">Context Processing</a>. We can
+ tell whether or not we're running during
+ <a href="#context-processing">Context Processing</a> by checking
+ <tref>local context</tref> against <tref>null</tref>.
+ We know we need to create a <tref>term definition</tref> in the
+ <tref>active context</tref> when <em>value</em> is
+ a key in the <tref>local context</tref> and the <em>defined</em> map
+ does not have a key for <em>value</em> with an associated value of
+ <tref>true</tref>. The <em>defined</em> map is used during
+ <a href="#context-processing">Context Processing</a> to keep track of
+ which <tref title="term">terms</tref> have already been defined or are
+ in the process of being defined. We create a
+ <tref>term definition</tref> by using the
+ <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
+ subalgorithm.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes two required and four optional input variables. The
+ required inputs are an <tref>active context</tref> and a <em>value</em>
+ to be expanded. The optional inputs are two flags,
+ <em>documentRelative</em> and <em>vocabRelative</em>, that specifying
+ whether <em>value</em> can be interpreted as a <tref>relative IRI</tref>
+ against the document's base <tref>IRI</tref> or the
+ <tref title="active context">active context's</tref>
+ <tref>vocabulary mapping</tref>, respectively, and
+ a <tref>local context</tref> and a map <em>defined</em> to be used when
+ this algorithm is used during
+ <a href="#context-processing">Context Processing</a>. If not passed, the
+ two flags are set to <code>false</code> and <tref>local context</tref> and
+ <em>defined</em> are initialized to <tref>null</tref>.</p>
+
+ <ol class="algorithm">
+ <li>If <em>value</em> is a <tref>keyword</tref> or is <tref>null</tref>,
+ return <em>value</em> as is.</li>
+ <li>If <tref>local context</tref> is not <tref>null</tref>, it contains
+ a key that equals <em>value</em>, and the value associated with the key
+ that equals <em>value</em> in <em>defined</em> is not <tref>true</tref>,
+ then invoke the <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
+ subalgorithm, passing <tref>active context</tref>, <tref>local context</tref>,
+ <em>value</em> as <em>term</em>, and <em>defined</em>. This will ensure that
+ a <tref>term definition</tref> is created for <em>value</em> in
+ <tref>active context</tref> during <a href="#context-processing">Context Processing</a>.
+ </li>
+ <li>Initialize <em>result</em> to <tref>null</tref>.</li>
+ <li>If <em>vocabRelative</em> is <tref>true</tref>:
+ <ol class="algorithm">
+ <li>If <tref>local context</tref> is not <tref>null</tref> then
+ <tref>active context</tref> MUST NOT have a <tref>term definition</tref>
+ for <em>value</em> that is a <tref>property generator</tref>.
+ Otherwise, a
+ <code class="error">property generator in term definition</code>
+ error has been detected.</li>
+ <li>If <em>value</em> has a <tref>null</tref> mapping in
+ <tref>active context</tref>, then return <tref>null</tref> which
+ has the effect of explicitly dropping <em>value</em>.</li>
+ <li>If <tref>active context</tref> has a <tref>term definition</tref> for
+ <em>value</em>, then set <em>result</em> to the associated
+ <tref>IRI mapping</tref>.</li>
+ </ol>
+ </li>
+ <li>If <em>result</em> is <tref>null</tref> and <em>value</em> contains a
+ colon (<code>:</code>), then it is either an <tref>absolute IRI</tref> or
+ a <tref>compact IRI</tref>:
+ <ol class="algorithm">
+ <li>Split <em>value</em> into a <tref>prefix</tref> and <em>suffix</em>
+ at the first occurrence of a colon (<code>:</code>).</li>
+ <li>If <tref>prefix</tref> is not underscore (<code>_</code>)
+ and <em>suffix</em> does not begin with double-forward-slash
+ (<code>//</code>), then it may be a <tref>compact IRI</tref>:
+ <ol class="algorithm">
+ <li>If <tref>local context</tref> is not <tref>null</tref> and it
+ contains a key that equals <tref>prefix</tref>, then invoke the
+ <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
+ subalgorithm, passing <tref>active context</tref>,
+ <tref>local context</tref>, <em>prefix</em> as <em>term</em>,
+ and <em>defined</em>. This will ensure that a
+ <tref>term definition</tref> is created for <tref>prefix</tref>
+ in <tref>active context</tref> during
+ <a href="#context-processing">Context Processing</a>.</li>
+ <li>If <tref>active context</tref> contains a
+ <tref>term definition</tref> for <tref>prefix</tref> that is
+ not a <tref>property generator</tref> then set <em>result</em>
+ to the result of concatenating the value associated with the
+ <tref>prefix</tref>'s <tref>IRI mapping</tref> and
+ <em>suffix</em>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>If <em>result</em> is <tref>null</tref>, set it to <em>value</em>.</li>
+ <li>If <tref>active context</tref> indicates that <em>value</em> is a
+ <tref>keyword</tref> alias then return the associated <tref>keyword</tref>.</li>
+ <li>If <tref>local context</tref> is <tref>null</tref> and <em>result</em>
+ begins with an underscore and colon (<code>_:</code>) then <em>result</em> is a
+ <tref>blank node identifier</tref>. Set <em>result</em> to the
+ result of the
+ <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
+ algorithm, passing <tref>active context</tref> and <em>result</em>
+ for <em>identifier</em>.</li>
+ <li>Otherwise, if <em>result</em> does not contain a colon (<code>:</code>),
+ <em>vocabRelative</em> is <tref>true</tref>, and
+ <tref>active context</tref> has a <tref>vocabulary mapping</tref>,
+ then set <em>result</em> to the result of concatenating the
+ <tref>vocabulary mapping</tref> with <em>result</em>.</li>
+ <li>Otherwise, if <em>documentRelative</em> is <tref>true</tref>,
+ set <em>result</em> to the result of resolving <em>result</em> against
+ the document base as per [[RFC3986]]. Only the basic algorithm in
+ section 5.2 of [[RFC3986]] is used; neither Syntax-Based Normalization
+ nor Scheme-Based Normalization (as described in sections 6.2.2 and
+ 6.2.3 of [[RFC3986]]) are performed. Characters additionally allowed in
+ IRI references are treated in the same way that unreserved characters
+ are treated in URI references, per section 6.5 of [[RFC3987]].</li>
+ <li>If <tref>local context</tref> is not <tref>null</tref> then
+ <em>result</em> MUST be an <tref>absolute IRI</tref>, if not,
+ an <code class="error">invalid IRI mapping</code> error has been
+ detected.</li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of IRI Expansion -->
+
+ <section>
+ <h2>Generate Blank Node Identifier</h2>
+
+ <p>This algorithm is used to generate new
+ <tref title="blank node identifier">blank node identifiers</tref> or to
+ relabel an existing <tref>blank node identifier</tref> to avoid collision
+ by the introduction of new ones. Between its executions, the algorithm
+ needs to keep an <em>identifier map</em> to relabel existing
+ <tref title="blank node identifier">blank node identifiers</tref> consistently
+ and a <em>counter</em> to generate new
+ <tref title="blank node identifier">blank node identifiers</tref>. The
+ <em>counter</em> is initialized to <code>0</code> by default.</p>
+
+ <p>The algorithm takes a single input variable <em>identifier</em> which may
+ be <tref>null</tref>.</p>
+
<ol class="algorithm">
- <li>
- Initialize <em>id</em> to the value associated with the
- <code>@id</code> key.
- </li>
- <li>
- If <em>id</em> is an <tref>array</tref>, then the
- <tref>term definition</tref> is for a <tref>property generator</tref>:
- <ol class="algorithm">
- <li>Create an empty <tref>array</tref> <em>property generator</em>.</li>
- <li>
- For each item <em>iri</em> in <em>id</em>:
- <ol class="algorithm">
- <li>
- If <em>iri</em> is a <tref>string</tref>, then
- set <em>iri</em> to the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>iri</em> for <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>,
- <tref>true</tref> for <em>documentRelative</em>,
- <tref>local context</tref>, and <em>defined</em>.
- </li>
- <li>
- <em>iri</em> MUST be a <tref>string</tref> and MUST not be
- a <tref>keyword</tref>, otherwise an
- <code class="error">invalid property generator</code>
- error has been detected.
- </li>
- <li>
- Append <em>iri</em> to <em>property generator</em>.
- </li>
- </ol>
- </li>
- <li>
- Set the <tref>property generator</tref> <tref>IRI mapping</tref>
- for <em>definition</em> to the result of sorting
- <em>property generator</em> lexicographically.
- </li>
- </ol>
- </li>
- <li>
- Otherwise <em>id</em> MUST be a <tref>string</tref>, if not,
- an <code class="error">invalid IRI mapping</code> error has been
- detected. Set the <tref>IRI mapping</tref> for <em>definition</em>
- to the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>id</em> for <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>,
- <tref>true</tref> for <em>documentRelative</em>,
- <tref>local context</tref>, and <em>defined</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise if the <em>term</em> contains a colon (<code>:</code>):
- <ol class="algorithm">
- <li>
- If <em>term</em> is a <tref>compact IRI</tref> with a
- <tref>prefix</tref> that is a key in <tref>local context</tref> then
- a dependency has been found. Use this algorithm recursively passing
- <tref>active context</tref>, <tref>local context</tref>, the
- <tref>prefix</tref> as <em>term</em>, and <em>defined</em>.
- </li>
- <li>
- If <em>term</em>'s <tref>prefix</tref> has a
- <tref>term definition</tref> in <tref>active context</tref>, set
- the <tref>IRI mapping</tref> for <em>definition</em> to the result of
- concatenating the value associated with the <tref>prefix</tref>'s
- <tref>IRI mapping</tref> and the <em>term</em>'s <em>suffix</em>.
- </li>
- <li>
- Otherwise, <em>term</em> is an <tref>absolute IRI</tref>. Set the
- <tref>IRI mapping</tref> for <em>definition</em> to <em>term</em>.
- </li>
+ <li>If the <em>identifier</em> is not <tref>null</tref> and is in the
+ <em>identifier map</em>, return the mapped identifier.</li>
+ <li>Otherwise, generate a new <em>blankNodeIdentifier</em> by concatenating
+ the string <code>_:b</code> and <em>counter</em>.</li>
+ <li>Increment <em>counter</em> by <code>1</code>.</li>
+ <li>If <em>identifier</em> is not <tref>null</tref>, create a new entry
+ for <em>identifier</em> in <em>identifier map</em> and set its value
+ to <em>blankNodeIdentifer</em>.</li>
+ <li>Return <em>blankNodeIdentifier</em>.</li>
</ol>
- </li>
- <li>
- Otherwise, <tref>active context</tref> MUST have a
- <tref>vocabulary mapping</tref>, if not, an
- <code class="error">invalid IRI mapping</code> error
- been detected. Set the <tref>IRI mapping</tref>
- for <em>definition</em> to the result of concatenating the value
- associated with the <tref>vocabulary mapping</tref> and <em>term</em>.
- </li>
- <li>
- If <em>value</em> contains the key <code>@type</code>:
- <ol class="algorithm">
- <li>
- Initialize <em>type</em> to the value associated with the
- <code>@type</code> key, which MUST be a <tref>string</tref>.
- Otherwise, an <code class="error">invalid type mapping</code> error
- has been detected.
- </li>
- <li>
- If <em>type</em> is not <code>@id</code> then set it to
- the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>type</em> for <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>,
- <tref>true</tref> for <em>documentRelative</em>,
- <tref>local context</tref>, and <em>defined</em>. Set the
- <tref>type mapping</tref> for <em>definition</em> to <em>type</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>value</em> contains the key <code>@container</code>:
- <ol class="algorithm">
- <li>
- Initialize <em>container</em> to the value associated with the
- <code>@container</code> key, which MUST be either:
- <code>@list</code>, <code>@set</code>, <code>@index</code>,
- or <code>@language</code>. Otherwise, an
- <code class="error">invalid container mapping</code> error
- has been detected.
- </li>
- <li>
- Set the <tref>container mapping</tref> for <em>definition</em> to
- <em>container</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>value</em> contains the key <code>@language</code> and
- does not contain the key <code>@type</code>:
- <ol class="algorithm">
- <li>
- Initialize <em>language</em> to the value associated with the
- <code>@language</code> key, which MUST be either <tref>null</tref>
- or a <tref>string</tref>. Otherwise, an
- <code class="error">invalid language mapping</code> error has been
- detected.
- </li>
- <li>
- If <em>language</em> is a <tref>string</tref> set it to
- lowercased <em>language</em>. Set the <tref>language mapping</tref>
- for <em>definition</em> to <em>language</em>.
- </li>
- </ol>
- </li>
- <li>
- Set the <tref>term definition</tref> for <em>term</em> in
- <tref>active context</tref> to <em>definition</em> and set the value
- associated with <em>defined</em>'s key <em>term</em> to
- <tref>true</tref>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Term Creation subalgorithm -->
-</section>
+ </section> <!-- end of Generate Blank Node Identifier -->
+</section> <!-- end of Context Processing section -->
+
<section>
-<h2>Expansion Algorithm</h2>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-<p>
-A JSON-LD document needs to be expanded, such that all <tref>context</tref>
-definitions have been removed, all <tref title="term">terms</tref> and
-<tref title="compact IRI">compact IRIs</tref> have been expanded to absolute
-<tref title="IRI">IRIs</tref>, and all
-<tref title="JSON-LD value">JSON-LD values</tref> are expressed in
-<tref title="array">arrays</tref> in <tref>expanded form</tref>.
-</p>
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>Starting with its root <em>element</em>, we can process the
- JSON-LD document recursively, until we have a fully
- <tref title="expansion">expanded</tref> <em>result</em>. When
- <tref title="expansion">expanding</tref> an <em>element</em>, we can treat
- each one differently according to its type, in order to break down the
- problem:</p>
-
-<ol>
- <li>If the <em>element</em> is <tref>null</tref>, there is nothing
- to expand.</li>
- <li>Otherwise, if <em>element</em> is a <tref>scalar</tref>, we expand it
- according to the <a href="#value-expansion">Value Expansion</a> subalgorithm.</li>
- <li>Otherwise, if the <em>element</em> is an <tref>array</tref>, then we expand
- each of its items recursively and return them in a new
- <tref>array</tref>.</li>
- <li>Otherwise, <em>element</em> is a <tref>JSON object</tref>. We expand
- each of its keys, adding them to our <em>result</em>, and then we expand
- each value for each key recursively. Some of the keys will be
- <tref title="term">terms</tref> or
- <tref title="compact IRI">compact IRIs</tref> and others will be
- <tref title="keyword">keywords</tref> or simply ignored because
- they do not have definitions in the <tref>context</tref>. Any
- <tref title="IRI">IRIs</tref> will be expanded using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm.
- </li>
-</ol>
-
-<p>Finally, after ensuring <em>result</em> is in an <tref>array</tref>,
- we return <em>result</em>.</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>The algorithm takes four input variables: an <tref>active context</tref>,
- an <tref>active property</tref>, an <em>element</em> to be expanded, and
- an <em>insideList</em> flag. To begin, the <tref>active context</tref> is set
- to the result of performing, <a
- href="#context-processing">Context Processing</a> on the passed
- <code class="idlMemberName"><a href="#widl-JsonLdOptions-expandContext">expandContext</a></code>,
- or empty if <code class="idlMemberName"><a href="#widl-JsonLdOptions-expandContext">expandContext</a></code>
- is <tref>null</tref>, <tref>active property</tref> is set to <tref>null</tref>,
- <em>element</em> is set to the <tref>JSON-LD input</tref>, and <em>insideList</em>
- is set to <tref>false</tref>. This algorithm expects the
- <tref>JSON-LD input</tref> to be a well-formed JSON-LD document as defined in [[!JSON-LD]].</p>
-
-<ol class="algorithm">
- <li>If <em>element</em> is <tref>null</tref>, return <tref>null</tref>.</li>
- <li>If <em>element</em> is a <tref>scalar</tref>,
+ <h1>Expansion Algorithms</h1>
+
+ <section>
+ <h2>Expansion Algorithm</h2>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A JSON-LD document needs to be expanded, such that all <tref>context</tref>
+ definitions have been removed, all <tref title="term">terms</tref> and
+ <tref title="compact IRI">compact IRIs</tref> have been expanded to absolute
+ <tref title="IRI">IRIs</tref>, and all
+ <tref title="JSON-LD value">JSON-LD values</tref> are expressed in
+ <tref title="array">arrays</tref> in <tref>expanded form</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Starting with its root <em>element</em>, we can process the
+ JSON-LD document recursively, until we have a fully
+ <tref title="expansion">expanded</tref> <em>result</em>. When
+ <tref title="expansion">expanding</tref> an <em>element</em>, we can treat
+ each one differently according to its type, in order to break down the
+ problem:</p>
+
+ <ol>
+ <li>If the <em>element</em> is <tref>null</tref>, there is nothing
+ to expand.</li>
+ <li>Otherwise, if <em>element</em> is a <tref>scalar</tref>, we expand it
+ according to the <a href="#value-expansion">Value Expansion</a> subalgorithm.</li>
+ <li>Otherwise, if the <em>element</em> is an <tref>array</tref>, then we expand
+ each of its items recursively and return them in a new
+ <tref>array</tref>.</li>
+ <li>Otherwise, <em>element</em> is a <tref>JSON object</tref>. We expand
+ each of its keys, adding them to our <em>result</em>, and then we expand
+ each value for each key recursively. Some of the keys will be
+ <tref title="term">terms</tref> or
+ <tref title="compact IRI">compact IRIs</tref> and others will be
+ <tref title="keyword">keywords</tref> or simply ignored because
+ they do not have definitions in the <tref>context</tref>. Any
+ <tref title="IRI">IRIs</tref> will be expanded using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm.
+ </li>
+ </ol>
+
+ <p>Finally, after ensuring <em>result</em> is in an <tref>array</tref>,
+ we return <em>result</em>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes four input variables: an <tref>active context</tref>,
+ an <tref>active property</tref>, an <em>element</em> to be expanded, and
+ an <em>insideList</em> flag. To begin, the <tref>active context</tref> is set
+ to the result of performing, <a
+ href="#context-processing">Context Processing</a> on the passed
+ <code class="idlMemberName"><a href="#widl-JsonLdOptions-expandContext">expandContext</a></code>,
+ or empty if <code class="idlMemberName"><a href="#widl-JsonLdOptions-expandContext">expandContext</a></code>
+ is <tref>null</tref>, <tref>active property</tref> is set to <tref>null</tref>,
+ <em>element</em> is set to the <tref>JSON-LD input</tref>, and <em>insideList</em>
+ is set to <tref>false</tref>. This algorithm expects the
+ <tref>JSON-LD input</tref> to be a well-formed JSON-LD document as defined
+ in [[!JSON-LD]].</p>
+
+ <ol class="algorithm">
+ <li>If <em>element</em> is <tref>null</tref>, return <tref>null</tref>.</li>
+ <li>If <em>element</em> is a <tref>scalar</tref>,
+ <ol class="algorithm">
+ <li>If <em>insideList</em> is <tref>false</tref> and
+ either <tref>active property</tref> is <tref>null</tref> or
+ the result of expanding <tref>active property</tref> using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm is
+ <code>@graph</code>, then drop the top-level
+ <tref>scalar</tref> by returning <tref>null</tref>.</li>
+ <li>Return the result of the
+ <a href="#value-expansion">Value Expansion</a> algorithm, passing the
+ <tref>active context</tref>, <tref>active property</tref>, and
+ <em>element</em> as <em>value</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>element</em> is an <tref>array</tref>,
+ <ol class="algorithm">
+ <li>Initialize an empty array, <em>result</em>.</li>
+ <li>For each <em>item</em> in <em>element</em>:
+ <ol class="algorithm">
+ <li>Initialize <em>expanded item</em> to the result of using this
+ algorithm recursively, passing <tref>active context</tref>,
+ <tref>active property</tref>, <em>item</em> as <em>element</em>,
+ and <em>insideList</em>.</li>
+ <li>If <em>insideList</em> is <tref>true</tref> then
+ <em>expanded item</em> MUST NOT be an <tref>array</tref> or a
+ <tref>list object</tref>, otherwise a
+ <code class="error">list of lists</code> error has been detected.</li>
+ <li>If <em>expanded item</em> is an <tref>array</tref>, append each
+ of its items to <em>result</em>. Otherwise, if
+ <em>expanded item</em> is not null, append it to <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.</li>
+ <li>If <em>element</em> contains the key <code>@context</code>, set
+ <tref>active context</tref> to the result of the
+ <a href="#context-processing">Context Processing</a> algorithm,
+ passing <tref>active context</tref> and the value of the
+ <code>@context</code> key as <tref>local context</tref>.</li>
+ <li>Initialize <em>expanded active property</em> to the result of the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <tref>active property</tref> for
+ <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.</li>
+ <li>Initialize an empty <tref>JSON object</tref>, <em>result</em>.</li>
+ <li>For each <em>key</em> and <em>value</em> in <em>element</em>,
+ ordered lexicographically by <em>key</em>:
+ <ol class="algorithm">
+ <li>If <em>key</em> is <code>@context</code>, continue to
+ the next <em>key</em>.</li>
+ <li>If <em>key</em> is mapped to a <tref>property generator</tref>
+ in <tref>active context</tref>, set <em>expanded property</em>
+ to an array containing its <tref title="IRI">IRIs</tref>.
+ Otherwise, set <em>expanded property</em> to the result of
+ using the <a href="#iri-expansion">IRI Expansion</a> algorithm,
+ passing <tref>active context</tref>, <em>key</em> for
+ <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.</li>
+ <li>If <em>expanded property</em> is either <tref>null</tref> or
+ is: not an <tref>array</tref>, an <tref>absolute IRI</tref> or
+ a <tref>keyword</tref>, then drop <em>key</em> by
+ continuing to the next <em>key</em>.</li>
+ <li>Validate <em>expanded property</em> against <em>value</em>
+ as follows:
+ <ol class="algorithm">
+ <li>If <em>expanded property</em> is <code>@id</code> then
+ <em>value</em> MUST be a <tref>string</tref>, otherwise
+ an <code class="error">invalid @id value</code> error has been
+ detected.</li>
+ <li>If <em>expanded property</em> is <code>@type</code> then
+ <em>value</em> MUST be a <tref>string</tref> or an <tref>array</tref>
+ of strings, otherwise an
+ <code class="error">invalid type value</code> error has been
+ detected.</li>
+ <li>If <em>expanded property</em> is <code>@graph</code> then
+ <em>value</em> MUST be a <tref>JSON object</tref> or an
+ <tref>array</tref>, otherwise an
+ <code class="error">invalid @graph value</code> error has been
+ detected.</li>
+ <li>If <em>expanded property</em> is <code>@value</code> then
+ <em>value</em> MUST NOT be a <tref>JSON object</tref> or
+ an <tref>array</tref>, otherwise an
+ <code class="error">invalid value object value</code> error
+ has been detected.</li>
+ <li>If <em>expanded property</em> is <code>@language</code> then
+ <em>value</em> MUST be a <tref>string</tref>, otherwise an
+ <code class="error">invalid language tagged string</code> error
+ has been detected. Set <em>expanded value</em> to lowercased
+ <em>value</em>.</li>
+ <li>If <em>expanded property</em> is <code>@index</code>
+ then <em>value</em> MUST be a <tref>string</tref>, otherwise an
+ <code class="error">invalid @index value</code> error has been
+ detected.</li>
+ </ol>
+ </li>
+ <li>If <em>key</em>'s <tref>container mapping</tref> in
+ <tref>active context</tref> is <code>@language</code> and
+ <em>value</em> is a <tref>JSON object</tref> then <em>value</em>
+ is expanded from a <tref>language map</tref> as follows:
+ <ol class="algorithm">
+ <li>Initialize <em>expanded value</em> to an empty
+ <tref>array</tref>.</li>
+ <li>For each key <em>language</em> and value <em>language value</em>
+ in <em>value</em>, ordered lexicographically by
+ <em>language</em>:
+ <ol class="algorithm">
+ <li>If <em>language value</em> is not an <tref>array</tref>
+ set it to an <tref>array</tref> containing only
+ <em>language value</em>.</li>
+ <li>For each <em>item</em> in <em>language value</em>:
+ <ol class="algorithm">
+ <li><em>item</em> MUST be a <tref>string</tref>,
+ otherwise an
+ <code class="error">invalid language map value</code>
+ error has been detected.</li>
+ <li>Append a <tref>JSON object</tref> to
+ <em>expanded value</em> that consists of two
+ key-value pairs: (<code>@value</code>-<em>item</em>)
+ and (<code>@language</code>-lowercased
+ <em>language</em>).</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>If <em>key</em>'s <tref>container mapping</tref> in
+ <tref>active context</tref> is <code>@index</code> and
+ <em>value</em> is a <tref>JSON object</tref> then <em>value</em>
+ is expanded from an index map as follows:
+ <ol class="algorithm">
+ <li>Initialize <em>expanded value</em> to an empty
+ <tref>array</tref>.</li>
+ <li>For each key <em>index</em> and value
+ <em>index value</em> in <em>value</em>, ordered
+ lexicographically by <em>index</em>:
+ <ol class="algorithm">
+ <li>If <em>index value</em> is not an <tref>array</tref>
+ set it to an <tref>array</tref> containing only
+ <em>index value</em>.</li>
+ <li>Initialize <em>index value</em> to the result of
+ using this algorithm recursively, passing
+ <tref>active context</tref>, <tref>active property</tref>,
+ <em>index value</em> as <em>element</em>, and
+ <tref>false</tref> for <em>insideList</em>.</li>
+ <li>For each <em>item</em> in <em>index value</em>:
+ <ol class="algorithm">
+ <li>If <em>item</em> does not have the key
+ <code>@index</code>, add the key-value pair
+ (<code>@index</code>-<em>index</em>) to
+ <em>item</em>.</li>
+ <li>Append <em>item</em> to <em>expanded value</em>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>expanded property</em> is <code>@list</code>
+ or <code>@set</code>, initialize <em>expanded value</em> to the
+ result of using this algorithm recursively passing
+ <tref>active context</tref>, <tref>null</tref> for
+ <tref>active property</tref> if <em>expanded property</em> is
+ <code>@list</code> and <em>expanded active property</em> is
+ <code>@graph</code> otherwise <tref>active property</tref>,
+ <em>value</em> for <em>element</em>, and <tref>true</tref>
+ for <em>insideList</em> if <em>expanded property</em> is
+ <code>@list</code> otherwise <tref>false</tref>.
+ If <em>expanded property</em> is <code>@list</code>
+ then <em>expanded value</em> MUST NOT be a
+ <tref>list object</tref>, otherwise a
+ <code class="error">list of lists</code> error has been detected.</li>
+ <li>Otherwise, initialize <em>expanded value</em> to the result of
+ using this algorithm recursively, passing
+ <tref>active context</tref>, <em>key</em> for
+ <tref>active property</tref>, <em>value</em>
+ for <em>element</em>, and <tref>false</tref> for
+ <em>insideList</em>.</li>
+ <li>If <em>expanded value</em> is <tref>null</tref> and
+ <em>expanded property</em> is not <code>@value</code> then
+ drop <em>key</em> by continuing to the next key.</li>
+ <li>If <em>expanded property</em> is not <code>@list</code> and
+ <em>expanded value</em> is not a <tref>list object</tref> and
+ <em>key</em>'s <tref>container mapping</tref> in
+ <tref>active context</tref> is <code>@list</code> then convert
+ <em>expanded value</em> to a <tref>list object</tref> by first
+ setting it to an <tref>array</tref> containing only
+ <em>expanded value</em> if it is not already an
+ <tref>array</tref>, and then by setting it to a
+ <tref>JSON object</tref> containing the key-value pair
+ (<code>@list</code>-<em>expanded value</em>).</li>
+ <li>If <em>expanded property</em> is an <tref>array</tref>:
+ <ol class="algorithm">
+ <li>Set <em>expanded value</em> to the result of the
+ <a href="#label-blank-nodes-subalgorithm">Label Blank Nodes</a>
+ subalgorithm, passing <tref>active context</tref> and
+ <em>expanded value</em> as <em>element</em>.</li>
+ <li>For each item <em>iri</em> in <em>expanded property</em>:
+ <ol class="algorithm">
+ <li>If <em>result</em> does not have the key <em>iri</em>,
+ set this key's value in <em>result</em> to an empty
+ <tref>array</tref>. Append a copy of
+ <em>expanded value</em> to the <tref>array</tref> value
+ associated with <em>result</em>'s <em>iri</em> key.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>expanded property</em> is
+ <code>@index</code>, <code>@id</code>, <code>@type</code>,
+ <code>@value</code>, or <code>@language</code>, then
+ set key <em>expanded property</em>'s value to
+ <em>expanded value</em> in <em>result</em>.</li>
+ <li>Otherwise, if <em>result</em> does not have the key
+ <em>expanded property</em>, set this key's value in <em>result</em>
+ to an empty <tref>array</tref>. Append <em>expanded value</em>
+ to the <tref>array</tref> value associated with <em>result</em>'s
+ <em>expanded property</em> key.</li>
+ </ol>
+ </li>
+ <li>If <em>result</em> contains the key <code>@value</code>:
+ <ol class="algorithm">
+ <li>The <em>result</em> MUST NOT contain any keys other than
+ <code>@value</code>, <code>@language</code>, <code>@type</code>,
+ and <code>@index</code>. It MUST NOT contain both the
+ <code>@language</code> key and the <code>@type</code> key.
+ Otherwise, an <code class="error">invalid value object</code> error
+ has been detected.</li>
+ <li>If the value of <em>result</em>'s <code>@value</code> key is
+ <tref>null</tref>, then set <em>result</em> to <tref>null</tref>.</li>
+ <li>Otherwise, if <em>result</em> contains the key
+ <code>@language</code> and the value of <em>result</em>'s
+ <code>@value</code> key is not a <tref>string</tref>, then remove
+ the <code>@language</code> key from <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>result</em> contains the key <code>@type</code>
+ and its associated value is not an <tref>array</tref>, set it to
+ an <tref>array</tref> containing only the associated value.</li>
+ <li>Otherwise, if <em>result</em> contains the key <code>@set</code>
+ or <code>@list</code>:
+ <ol class="algorithm">
+ <li>The <em>result</em> MUST contain at most one other key and that
+ key MUST be <code>@index</code>. Otherwise, an
+ <code class="error">invalid set or list object</code> error
+ has been detected.</li>
+ <li>If <em>result</em> contains the key <code>@set</code>, then
+ set <em>result</em> to the key's associated value.</li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>result</em> contains only the key
+ <code>@language</code>, set <em>result</em> to <tref>null</tref>.</li>
+ <li>If <em>insideList</em> is <tref>false</tref> and either
+ <tref>active property</tref> is <tref>null</tref> or
+ <em>expanded active property</em> is <code>@graph</code>, then
+ drop free-floating values as follows:
+ <ol class="algorithm">
+ <li>If <em>result</em> contains no keys or contains the key
+ <code>@value</code>, setting <em>result</em> to
+ <tref>null</tref>.</li><li>
+ Otherwise, if <em>result</em>'s keys are only keywords and none
+ of the keys are <code>@graph</code> or <code>@type</code> then
+ set <em>result</em> to <tref>null</tref>.</li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+
+ <p>If, after the above algorithm is run, the result is a
+ <tref>JSON object</tref> that contains only an <code>@graph</code> key, set the
+ result to the value of <code>@graph</code>'s value. Otherwise, if the result
+ is <tref>null</tref>, set it to an empty <tref>array</tref>. Finally, if
+ the result is not an <tref>array</tref>, then set the result to an
+ <tref>array</tref> containing only the result.</p>
+ </section>
+ </section> <!-- end of Expansion Algorithm -->
+
+
+ <section>
+ <h2>Value Expansion</h2>
+
+ <p>Some values in JSON-LD can be expressed in a <tref>compacted form</tref>.
+ These values are required to be <tref title="expansion">expanded</tref> at
+ times when processing JSON-LD documents. A value is said to be in
+ <tdef>expanded form</tdef> after the application of this algorithm.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A <em>value</em> associated with an <tref>active property</tref> must
+ be <tref title="expansion">expanded</tref> to <tref>expanded form</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Other than the simple case where <em>value</em> is <tref>null</tref>, for
+ which we return <tref>null</tref>, we must primarily look at <em>value</em>'s
+ associated <tref>active property</tref> to determine how to expand it.</p>
+
+ <p>First we <tref title="expansion">expand</tref> the
+ <tref>active property</tref> itself, so that we can resolve
+ <tref>keyword</tref> aliases. Then, for certain
+ <tref title="keyword">keywords</tref> like <code>@id</code> and
+ <code>@type</code>, we simply expand <em>value</em>
+ using the <a href="#iri-expansion">IRI Expansion</a> algorithm and return
+ the result.</p>
+
+ <p>Next, we check to see if <tref>active property</tref> has a
+ <tref>type mapping</tref> in the <tref>active context</tref> that would alter
+ what we return. If it has one that is <code>@vocab</code> or
+ <code>@type</code> or if the <em>expanded property</em> is <code>@graph</code>
+ then we return a <tref>JSON object</tref> with a single key-pair of
+ <code>@id</code> and the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm on <em>value</em>.</p>
+
+ <p>If we haven't returned yet and the <em>expanded property</em> is a
+ <tref>keyword</tref>, then there is no special <tref>expansion</tref> to be
+ performed on the <em>value</em>, so we return it as is.</p>
+
+ <p>Otherwise, we'll our result will be a <tref>JSON object</tref> containing
+ the key <code>@value</code> with the value the <em>value</em>. Additionally,
+ a <code>@type</code> key-value pair will be included if there is a
+ <tref>type mapping</tref> associated with the <tref>active property</tref>
+ or a <code>@language</code> key-value pair if <em>value</em> is a
+ <tref>string</tref> and there is <tref>language mapping</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes three required inputs: an <tref>active context</tref>,
+ an <tref>active property</tref>, and a <em>value</em> to expand.</p>
+
+ <ol class="algorithm">
+ <li>If <em>value</em> is <tref>null</tref>, then return <tref>null</tref>.</li>
+ <li>Initialize <em>expanded property</em> to the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <tref>active property</tref> for
+ <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.</li>
+ <li>If <em>expanded property</em> is <code>@id</code> then return
+ the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>value</em>, and <tref>true</tref>
+ for <em>documentRelative</em>.</li>
+ <li>If <em>expanded property</em> is <code>@type</code> then
+ return the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>value</em>, <tref>true</tref> for
+ <em>vocabRelative</em>, and <tref>true</tref> for
+ <em>documentRelative</em>.</li>
+ <li>If <tref>active property</tref> has a <tref>type mapping</tref> in
+ <tref>active context</tref> that is <code>@id</code> or if
+ <em>expanded property</em> is <code>@graph</code> and <em>value</em>
+ is a <tref>string</tref>, then return a new <tref>JSON object</tref>
+ containing a single key-value pair where the key is <code>@id</code> and
+ the value is the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>value</em>, and <tref>true</tref> for
+ <em>documentRelative</em>.</li>
+ <li>If <tref>active property</tref> has a <tref>type mapping</tref> in
+ <tref>active context</tref> that is <code>@vocab</code>, then return
+ a new <tref>JSON object</tref> containing a single key-value pair
+ where the key is <code>@id</code> and the value is the result of
+ using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>value</em>, <tref>true</tref> for
+ <em>vocabRelative</em>, and <tref>true</tref> for
+ <em>documentRelative</em>.</li>
+ <li>If <em>expanded property</em> is a <tref>keyword</tref> return
+ <em>value</em> as is.</li>
+ <li>Otherwise, initialize <em>result</em> to an empty
+ <tref>JSON object</tref>.</li>
+ <li>If <tref>active property</tref> has a <tref>type mapping</tref> in
+ <tref>active context</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>type</em> to the value associated with the
+ <tref>type mapping</tref>.</li>
+ <li>If <em>type</em> is a <tref>blank node identifier</tref> (it
+ begins with <code>_:</code>), then set it to the result of the
+ <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
+ algorithm, passing <tref>active context</tref> and <em>type</em> for
+ <em>identifier</em>.</li>
+ <li>Add the key-value pair, (<code>@type</code>-<em>type</em>), to
+ <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>value</em> is a <tref>string</tref>:
+ <ol class="algorithm">
+ <li>If <em>value</em> has a <tref>language mapping</tref> in
+ <tref>active context</tref> that is not <tref>null</tref>, then
+ add a key-value pair to <em>result</em> where the key is
+ <code>@language</code> and the value is the value associated with
+ the <tref>language mapping</tref>.</li>
+ <li>Otherwise, if <em>value</em> has no <tref>language mapping</tref> in
+ <tref>active context</tref> and <tref>active context</tref> has a
+ <tref>default language</tref>, then add a key-value pair to
+ <em>result</em> where the key is <code>@language</code> and the value
+ is the <tref>default language</tref>.</li>
+ </ol>
+ </li>
+ <li>Finally, add the key-value pair, (<code>@value</code>-<em>value</em>), to
+ <em>result</em> and return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Value Expansion -->
+
+ <section>
+ <h2>Label Blank Nodes Subalgorithm</h2>
+
+ <p>During <tref>expansion</tref>, it is sometimes necessary to ensure
+ all <tref title="blank node">blank nodes</tref> have been labeled. This
+ occurs when a <tref>property generator</tref> is used to copy a single
+ property's values across multiple properties. This step is necessary to
+ ensure that these duplicated values can be later
+ <tref title="compaction">recompacted</tref>. Because new labels will
+ be assigned to <tref title="blank node">blank nodes</tref>, it is
+ important to relabel any existing <tref title="blank node">blank nodes</tref>
+ to avoid conflicting names.</p>
+
+ <p>The algorithm takes two required inputs: an <tref>active context</tref>,
+ and an <em>element</em> to be labeled with
+ <tref title="blank node identifier">blank node identifiers</tref>.</p>
+
<ol class="algorithm">
- <li>If <em>insideList</em> is <tref>false</tref> and
- either <tref>active property</tref> is <tref>null</tref> or
- the result of expanding <tref>active property</tref> using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm is
- <code>@graph</code>, then drop the top-level
- <tref>scalar</tref> by returning <tref>null</tref>.</li>
- <li>Return the result of the
- <a href="#value-expansion">Value Expansion</a> algorithm, passing the
- <tref>active context</tref>, <tref>active property</tref>, and
- <em>element</em> as <em>value</em>.</li>
- </ol>
- </li>
- <li>If <em>element</em> is an <tref>array</tref>,
- <ol class="algorithm">
- <li>
- Initialize an empty array, <em>result</em>.
- </li>
- <li>For each <em>item</em> in <em>element</em>:
+ <li>If <em>element</em> is an <tref>array</tref>, then for each
+ <em>item</em> in <em>element</em>:
<ol class="algorithm">
- <li>
- Initialize <em>expanded item</em> to the result of using this
- algorithm recursively, passing <tref>active context</tref>,
- <tref>active property</tref>, <em>item</em> as <em>element</em>,
- and <em>insideList</em>.
- </li>
- <li>
- If <em>insideList</em> is <tref>true</tref> then
- <em>expanded item</em> MUST NOT be an <tref>array</tref> or a
- <tref>list object</tref>, otherwise a
- <code class="error">list of lists</code> error has been detected.
- </li>
- <li>
- If <em>expanded item</em> is an <tref>array</tref>, append each
- of its items to <em>result</em>. Otherwise, if
- <em>expanded item</em> is not null, append it to <em>result</em>.
- </li>
+ <li>Replace <em>item</em> with the result of using this algorithm
+ recursively, passing <tref>active context</tref> and <em>item</em>
+ for <em>element</em>.</li>
</ol>
</li>
- <li>
- Return <em>result</em>.
- </li>
- </ol>
- </li>
- <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.</li>
- <li>
- If <em>element</em> contains the key <code>@context</code>, set
- <tref>active context</tref> to the result of the
- <a href="#context-processing">Context Processing</a> algorithm,
- passing <tref>active context</tref> and the value of the
- <code>@context</code> key as <tref>local context</tref>.
- </li>
- <li>
- Initialize <em>expanded active property</em> to the result of the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <tref>active property</tref> for
- <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.</li>
- <li>
- Initialize an empty <tref>JSON object</tref>, <em>result</em>.
- </li>
- <li>
- For each <em>key</em> and <em>value</em> in <em>element</em>,
- ordered lexicographically by <em>key</em>:
- <ol class="algorithm">
- <li>
- If <em>key</em> is <code>@context</code>, continue to
- the next <em>key</em>.
- </li>
- <li>
- If <em>key</em> is mapped to a <tref>property generator</tref>
- in <tref>active context</tref>, set <em>expanded property</em>
- to an array containing its <tref title="IRI">IRIs</tref>.
- Otherwise, set <em>expanded property</em> to the result of
- using the <a href="#iri-expansion">IRI Expansion</a> algorithm,
- passing <tref>active context</tref>, <em>key</em> for
- <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.
- </li>
- <li>
- If <em>expanded property</em> is either <tref>null</tref> or
- is: not an <tref>array</tref>, an <tref>absolute IRI</tref> or
- a <tref>keyword</tref>, then drop <em>key</em> by
- continuing to the next <em>key</em>.
- </li>
- <li>
- Validate <em>expanded property</em> against <em>value</em>
- as follows:
+ <li>Otherwise, if <em>element</em> is a <tref>list object</tref>, then
+ replace the value of the <code>@list</code> key in <em>element</em>
+ with the result of using this algorithm recursively, passing
+ <tref>active context</tref> and the value of the <code>@list</code> key
+ for <em>element</em>.</li>
+ <li>Otherwise, if <em>element</em> is a <tref>node object</tref>:
<ol class="algorithm">
- <li>
- If <em>expanded property</em> is <code>@id</code> then
- <em>value</em> MUST be a <tref>string</tref>, otherwise
- an <code class="error">invalid @id value</code> error has been
- detected.
- </li>
- <li>
- If <em>expanded property</em> is <code>@type</code> then
- <em>value</em> MUST be a <tref>string</tref> or an <tref>array</tref>
- of strings, otherwise an
- <code class="error">invalid type value</code> error has been
- detected.
- </li>
- <li>
- If <em>expanded property</em> is <code>@graph</code> then
- <em>value</em> MUST be a <tref>JSON object</tref> or an
- <tref>array</tref>, otherwise an
- <code class="error">invalid @graph value</code> error has been
- detected.
- </li>
- <li>
- If <em>expanded property</em> is <code>@value</code> then
- <em>value</em> MUST NOT be a <tref>JSON object</tref> or
- an <tref>array</tref>, otherwise an
- <code class="error">invalid value object value</code> error
- has been detected.
- </li>
- <li>
- If <em>expanded property</em> is <code>@language</code> then
- <em>value</em> MUST be a <tref>string</tref>, otherwise an
- <code class="error">invalid language tagged string</code> error
- has been detected. Set <em>expanded value</em> to lowercased
- <em>value</em>.
- </li>
- <li>
- If <em>expanded property</em> is <code>@index</code>
- then <em>value</em> MUST be a <tref>string</tref>, otherwise an
- <code class="error">invalid @index value</code> error has been
- detected.
- </li>
- </ol>
- </li>
- <li>
- If <em>key</em>'s <tref>container mapping</tref> in
- <tref>active context</tref> is <code>@language</code> and
- <em>value</em> is a <tref>JSON object</tref> then <em>value</em>
- is expanded from a <tref>language map</tref> as follows:
- <ol class="algorithm">
- <li>
- Initialize <em>expanded value</em> to an empty
- <tref>array</tref>.
- </li>
- <li>
- For each key <em>language</em> and value <em>language value</em>
- in <em>value</em>, ordered lexicographically by
- <em>language</em>:
+ <li>If <em>element</em> has no <code>@id</code> member, i.e., it
+ represents an unlabeled <em>blank node</em>, add an <code>@id</code>
+ member to element and set its value to the result of using the
+ <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
+ algorithm.</li>
+ <li>For each <em>key</em>-<em>value</em> pair ordered lexicographically
+ by <em>key</em>:
<ol class="algorithm">
- <li>
- If <em>language value</em> is not an <tref>array</tref>
- set it to an <tref>array</tref> containing only
- <em>language value</em>.
- </li>
- <li>
- For each <em>item</em> in <em>language value</em>:
- <ol class="algorithm">
- <li>
- <em>item</em> MUST be a <tref>string</tref>,
- otherwise an
- <code class="error">invalid language map value</code>
- error has been detected.
- </li>
- <li>
- Append a <tref>JSON object</tref> to
- <em>expanded value</em> that consists of two
- key-value pairs: (<code>@value</code>-<em>item</em>)
- and (<code>@language</code>-lowercased
- <em>language</em>).
- </li>
- </ol>
- </li>
+ <li>If <em>key</em> is not <code>@id</code>, then replace
+ <em>value</em> in <em>element</em> with the result of using
+ this algorithm recursively, passing <tref>active context</tref>
+ and <em>value</em> for <em>element</em>.</li>
</ol>
</li>
</ol>
</li>
- <li>
- If <em>key</em>'s <tref>container mapping</tref> in
- <tref>active context</tref> is <code>@index</code> and
- <em>value</em> is a <tref>JSON object</tref> then <em>value</em>
- is expanded from an index map as follows:
+ <li>Return <em>element</em>.</li>
+ </ol>
+ </section> <!-- end of Label Blank Nodes Subalgorithm -->
+
+</section> <!-- end of Expansion section -->
+
+
+<section>
+ <h1>Compaction Algorithms</h1>
+
+ <section>
+ <h2>Compaction Algorithm</h2>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A JSON-LD document needs to be compacted, such that the given
+ <tref>context</tref> is applied. This must result in shortening
+ any applicable <tref title="IRI">IRIs</tref> to
+ <tref title="term">terms</tref> or
+ <tref title="compact IRI">compact IRIs</tref> and
+ any applicable <tref title="JSON-LD value">JSON-LD values</tref>
+ expressed in <tref>expanded form</tref> to simple values such as
+ <tref title="string">strings</tref> or
+ <tref title="number">numbers</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Starting with its root <em>element</em>, we can process the
+ JSON-LD document recursively, until we have a fully
+ <tref title="compaction">compacted</tref> <em>result</em>. When
+ <tref title="compaction">compacting</tref> an <em>element</em>, we can treat
+ each one differently according to its type, in order to break down the
+ problem:</p>
+
+ <ol>
+ <li>If the <em>element</em> is a <tref>scalar</tref>, it is
+ already in <tref>compacted form</tref>, so we simply return it.</li>
+ <li>If the <em>element</em> is an <tref>array</tref>, we compact
+ each of its items recursively and return them in a new
+ <tref>array</tref>.</li>
+ <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.
+ We start by creating a shallow copy of it and each of its
+ key's <tref>array</tref> values. This is done so that if any key
+ is compacted to a <tref>property generator</tref> <tref>term</tref>,
+ we can remove duplicate values without modifying the original
+ <em>element</em>. Then, we compact each value in the shallow copy
+ for each key recursively. Some of the keys will be
+ compacted, using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm,
+ to <tref title="term">terms</tref> or
+ <tref title="compact IRI">compact IRIs</tref> and others will be
+ compacted from <tref title="keyword">keywords</tref> to
+ <tref>keyword</tref> aliases or simply left unchanged because
+ they do not have definitions in the <tref>context</tref>. Values will
+ be converted to <tref>compacted form</tref> via the
+ <a href="#value-compaction">Value Compaction</a> algorithm. Some data
+ will be reshaped based on
+ <tref title="container mapping">container mappings</tref> specified
+ in the context such as <code>@index</code> or <code>@language</code>
+ maps.</li>
+ </ol>
+
+ <p>The final output is a <tref>JSON object</tref> with a <code>@context</code>
+ key, if a <tref>context</tref> was given, where the <tref>JSON object</tref>
+ is either <em>result</em> or a wrapper for it where <em>result</em> appears
+ as the value of an aliased <code>@graph</code> key because <em>result</em>
+ contained two or more items in an <tref>array</tref>. If no
+ <tref>context</tref> was given, the <em>result</em> is only simplified
+ from an <tref>array</tref> to a <tref>JSON object</tref> if it has one or
+ fewer items.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes four required input variables: an
+ <tref>active context</tref>, an <tref>active property</tref>, and an
+ <em>element</em> to be compacted. To begin, the <tref>active context</tref>
+ is set to the result of performing
+ <a href="#context-processing">Context Processing</a> on the passed
+ <em>context</em>, the <tref>active property</tref> is set to
+ <tref>null</tref>, and <em>element</em> is set to the result of performing
+ the <a href="#expansion-algorithm">Expansion Algorithm</a> on the
+ <tref>JSON-LD input</tref>.</p>
+
+ <ol class="algorithm">
+ <li>If <em>element</em> is a <tref>scalar</tref>, it is already in its most
+ compact form, so simply return <em>element</em>.</li>
+ <li>If <em>element</em> is an <tref>array</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>result</em> to an empty <tref>array</tref>.</li>
+ <li>For each <em>item</em> in <em>element</em>:
+ <ol class="algorithm">
+ <li>Initialize <em>compacted item</em> to the result of using this
+ algorithm recursively, passing <tref>active context</tref>,
+ <tref>active property</tref>, and <em>item</em> for
+ <em>element</em>.</li>
+ <li>If <em>compacted item</em> is not <tref>null</tref>, then append
+ it to <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>result</em> contains only one item (it has a length of
+ <code>1</code>) and <tref>active property</tref> has no
+ <tref>container mapping</tref> in <tref>active context</tref>,
+ then set <em>result</em> to its only item.</li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.</li>
+ <li>If <em>element</em> contains the key <code>@value</code> or
+ if it contains only one key and that key is <code>@id</code>,
+ then return the result of using the
+ <a href="#value-compaction">Value Compaction</a> algorithm,
+ passing <tref>active context</tref>, <tref>active property</tref>,
+ and <em>element</em> as <em>value</em>.</li>
+ <li>Create a shallow copy of <em>element</em> and each <tref>array</tref>
+ associated with its keys so that duplicate values can be removed
+ during <tref>property generator</tref> <tref>compaction</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>shallow</em> to an empty <tref>JSON object</tref>.</li>
+ <li>For each <em>key</em>-<em>value</em> pair in <em>element</em>:
+ <ol class="algorithm">
+ <li>If <em>value</em> is an <tref>array</tref>, then add
+ a key-value pair to <em>shallow</em> where the key
+ is <em>key</em> and the value is a shallow copy of
+ <em>value</em>.</li>
+ <li>Otherwise, add the key-value pair, <em>key</em>-<em>value</em>
+ to <em>shallow</em>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Initialize <em>result</em> to an empty <tref>JSON object</tref>.</li>
+ <li>Initialize <em>keys</em> to an <tref>array</tref> containing
+ all of the keys in <em>shallow</em>, ordered lexicographically.</li>
+ <li>For each key <em>expanded property</em> in <em>keys</em>:
+ <ol class="algorithm">
+ <li>If <em>shallow</em> does not contain a key that equals
+ <em>expanded property</em>, then continue to the next
+ <em>expanded property</em>.</li>
+ <li>Initialize <em>expanded value</em> to the value associated
+ with the key that equals <em>expanded property</em> in
+ <em>shallow</em>.</li>
+ <li>If <em>expanded property</em> is <code>@id</code> or
+ <code>@type</code>:
+ <ol class="algorithm">
+ <li>If <em>expanded value</em> is a <tref>string</tref>,
+ then initialize <em>compacted value</em> to the result
+ of using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>expanded value</em> for <em>iri</em>,
+ and <tref>true</tref> for <em>vocabRelative</em> if
+ <em>expanded property</em> is <code>@type</code>,
+ <tref>false</tref> otherwise.</li>
+ <li>Otherwise, <em>expanded value</em> must be a
+ <code>@type</code> <tref>array</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>compacted value</em> to an empty
+ <tref>array</tref>.</li>
+ <li>For each item <em>expanded type</em> in
+ <em>expanded value</em>, append the result of
+ of using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>expanded type</em> for <em>iri</em>, and
+ <tref>true</tref> for <em>vocabRelative</em>,
+ to <em>compacted value</em>.</li>
+ <li>If <em>compacted value</em> contains only one
+ item (it has a length of <code>1</code>), then
+ set <em>compacted value</em> to its only item.</li>
+ </ol>
+ </li>
+ <li>Initialize <em>alias</em> to the result of using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <em>expanded property</em> for <em>iri</em>.</li>
+ <li>Add the key-value pair,
+ (<em>alias</em>-<em>compacted value</em>) to
+ <em>result</em> and continue to the next
+ <em>expanded property</em>.</li>
+ </ol>
+ </li>
+ <li>
+ If <em>expanded property</em> is <code>@index</code>:
+ <ol class="algorithm">
+ <li>If <tref>active property</tref> has a
+ <tref>container mapping</tref> in <tref>active context</tref>
+ that is <code>@index</code>, then the compacted
+ result will be inside of an <code>@index</code>
+ container, so simply drop the <code>@index</code>
+ property by continuing to the next
+ <em>expanded property</em>.</li>
+ <li>Otherwise, initialize <em>alias</em> to the result of using
+ the <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <em>expanded property</em> for <em>iri</em>.</li>
+ <li>Add the key-value pair,
+ (<em>alias</em>-<em>expanded value</em>) to
+ <em>result</em> and continue to the next
+ <em>expanded property</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>expanded value</em> is an empty <tref>array</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>item active property</em> to the result of
+ using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>expanded property</em> for <em>iri</em>,
+ <em>expanded value</em> for <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>, and
+ <em>shallow</em> for <em>parent</em>.</li>
+ <li>If <em>result</em> does not have the key that equals
+ <em>item active property</em>, set this key's value in
+ <em>result</em> to an empty <tref>array</tref>. Otherwise, if
+ the key's value is not an <tref>array</tref>, then set it
+ to one containing only the value.</li>
+ </ol>
+ </li>
+ <li>
+ At this point, <em>expanded value</em> must be an
+ <tref>array</tref> due to the
+ <a href="#expansion-algorithm">Expansion algorithm</a>.
+ For each item <em>expanded item</em> in <em>expanded value</em>:
+ <ol class="algorithm">
+ <li>Initialize <em>item active property</em> to the result of using
+ the <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>expanded property</em> for <em>iri</em>,
+ <em>expanded item</em> for <em>value</em>,
+ <tref>true</tref> for <em>vocabRelative</em>, and
+ <em>shallow</em> for <em>parent</em>.</li>
+ <li>Initialize <em>container</em> to <tref>null</tref>. If there
+ is a <tref>container mapping</tref> for
+ <em>item active property</em> in <tref>active context</tref>,
+ set <em>container</em> to its value.</li>
+ <li>If there is a <tref>term definition</tref> for
+ <em>item active property</em> in <tref>active context</tref>
+ that is a <tref>property generator</tref>, then invoke the
+ <a href="#find-property-generator-duplicates-subalgorithm">Find Property Generator Duplicates</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>shallow</em> for <em>element</em>,
+ <em>expanded property</em>, <em>expanded item</em> for
+ <em>value</em>, <em>item active property</em> for
+ <tref>active property</tref>, and
+ <tref>true</tref> for <em>remove</em>.</li>
+ <li>Initialize <em>compacted item</em> to the result of using
+ this algorithm recursively, passing
+ <tref>active context</tref>, <em>item active property</em>
+ for <tref>active property</tref>,
+ <em>expanded item</em> for <em>element</em> if it does
+ not contain the key <code>@list</code>, otherwise pass
+ the key's associated value for <em>element</em>.</li>
+ <li>
+ If <em>expanded item</em> is a <tref>list object</tref>:
+ <ol class="algorithm">
+ <li>If <em>compacted item</em> is not an <tref>array</tref>,
+ then set it to an <tref>array</tref> containing only
+ <em>compacted item</em>.</li>
+ <li>If <em>container</em> is not <code>@list</code>:
+ <ol class="algorithm">
+ <li>Convert <em>compacted item</em> to a
+ <tref>list object</tref> by setting it to a
+ <tref>JSON object</tref> containing key-value pair
+ where the key is the result of the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@list</code> for <em>iri</em>, and the
+ value is <em>compacted item</em>.</li>
+ <li>If <em>expanded item</em> contains the key
+ <code>@index</code>, then add a key-value pair
+ to <em>compacted item</em> where the key is the
+ result of the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@index</code> for <em>iri</em>, and the
+ value is the value associated with the
+ <code>@index</code> key in
+ <em>expanded item</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, <em>item active property</em> MUST NOT be a key
+ in <em>result</em> because there cannot be two
+ <tref title="list object">list objects</tref> associated
+ with an <tref>active property</tref> that has a
+ <tref>container mapping</tref>; a
+ <code class="error">compaction to list of lists</code> error
+ has been detected.</li>
+ </ol>
+ </li>
+ <li>
+ If <em>container</em> is <code>@language</code> or
+ <code>@index</code>:
+ <ol class="algorithm">
+ <li>If <em>item active property</em> is a key in
+ <em>result</em>, then initialize <em>map object</em> to
+ its associated value, otherwise initialize it to an empty
+ <tref>JSON object</tref>.</li>
+ <li>If <em>container</em> is <code>@language</code> and
+ <em>compacted item</em> contains the key
+ <code>@value</code>, then set <em>compacted item</em>
+ to the value associated with its <code>@value</code> key.</li>
+ <li>Initialize <em>map key</em> to the value associated with
+ with the key that equals <em>container</em> in
+ <em>expanded item</em>.</li>
+ <li>If <em>map key</em> is not a key in <em>map object</em>,
+ then set this key's value in <em>map object</em>
+ to <em>compacted item</em>. Otherwise, if the value
+ is not an <tref>array</tref>, then set it to one
+ containing only the value and then append
+ <em>compacted item</em> to it.</li>
+ </ol>
+ </li>
+ <li>
+ Otherwise,
+ <ol class="algorithm">
+ <li>Initialize <em>useArray</em> to <tref>false</tref>. If
+ <em>container</em> is <code>@set</code> or
+ <code>@list</code>, or <em>compacted item</em> is
+ an empty <tref>array</tref>, or
+ <em>expanded property</em> is <code>@list</code> or
+ <code>@graph</code>, then set <em>useArray</em>
+ to <tref>true</tref>.</li>
+ <li>If <em>useArray</em> is <tref>true</tref> and
+ <em>compacted item</em> is not an <tref>array</tref>,
+ then set it to a new <tref>array</tref>
+ containing only <em>compacted item</em>.</li>
+ <li>If <em>item active property</em> is not a key in
+ <em>result</em> then add the key-value pair,
+ (<em>item active property</em>-<em>compacted item</em>),
+ to <em>result</em>.</li>
+ <li>Otherwise, if the value associated with the key that
+ equals <em>item active property</em> in <em>result</em>
+ is not an <tref>array</tref>, set it to a new
+ <tref>array</tref> containing only the value. Then
+ append <em>compacted item</em> to the value if
+ <em>compacted item</em> is not an <tref>array</tref>,
+ otherwise, concatenate it.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+
+ <p>If, after the algorithm outlined above is run, the result <em>result</em> is
+ an <tref>array</tref> with two or more items and a <em>context</em> has
+ been passed, replace it with a new <tref>JSON object</tref> with a single
+ key-value pair where the key is the result of using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, passing
+ <tref>active context</tref> and <code>@graph</code> for <em>iri</em>, and
+ the value is <em>result</em>. Otherwise, if <em>result</em> is an
+ <tref>array</tref> with only one item, set <em>result</em> to that item.
+ Otherwise, if <em>result</em> is an <tref>array</tref> with zero items,
+ replace it with an empty <tref>JSON object</tref>. Finally, if a
+ <em>context</em> has been passed, add an <code>@context</code> property to
+ <em>result</em> and set its value to the initially passed
+ <em>context</em>.</p>
+ </section>
+ </section> <!-- end of Compaction -->
+
+ <section>
+ <h2>Inverse Context Creation Subalgorithm</h2>
+
+ <p>When there is more than one <tref>term</tref> that could be chosen
+ to compact an <tref>IRI</tref>, we want to ensure that our <tref>term</tref>
+ selection is both deterministic and not unexpected, representing the most
+ context-appropriate choice whilst taking into consideration algorithmic
+ complexity.</p>
+
+ <p>In order to make <tref>term</tref> selections the concept of an
+ <tref>inverse context</tref> is introduced. An <tdef>inverse context</tdef>
+ is essentially a reverse lookup table that maps
+ <tref title="container mapping">container mappings</tref>,
+ <tref title="type mapping">type mappings</tref>, and
+ <tref title="language mapping">language mappings</tref> to a simple
+ <tref>term</tref> and, if applicable, an <tref>array</tref> of potential
+ <tref>property generator</tref> <tref title="term">terms</tref> for
+ a given <tref>active context</tref>. A <tref>inverse context</tref> only
+ needs to be generated for an <tref>active context</tref> if it is being
+ used for <tref>compaction</tref>.</p>
+
+ <p>To make use of an <tref>inverse context</tref>, a list of preferred
+ <tref title="container mapping">container mappings</tref> and the
+ <tref>type mapping</tref> or <tref>language mapping</tref> are gathered
+ for a particular value associated with an <tref>IRI</tref>. These parameters
+ are then fed to the <a href="#term-selection-subalgorithm">Term Selection</a>
+ subalgorithm, which will find the <tref>term</tref> that most appropriately
+ matches the value's mappings.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>An <tref>inverse context</tref> must be created for the given
+ <tref>active context</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>To create an <tref>inverse context</tref> for a given
+ <tref>active context</tref>, each <tref>term</tref> in the
+ <tref>active context</tref> is visited, ordered by length, shortest
+ first (ties are broken by choosing the lexicographically least
+ <tref>term</tref>). For each <tref>term</tref>, an entry is added to
+ the <tref>inverse context</tref> for each possible combination of
+ <tref>container mapping</tref> and <tref>type mapping</tref>
+ or <tref>language mapping</tref> that would legally match the
+ <tref>term</tref>. Illegal matches include differences between a
+ value's <tref>type mapping</tref> or <tref>language mapping</tref> and
+ that of the <tref>term</tref>. If a <tref>term</tref> has no
+ <tref>container mapping</tref>, <tref>type mapping</tref>, or
+ <tref>language mapping</tref> (or some combination of these), then it
+ will have an entry in the <tref>inverse context</tref> using the special
+ key <code>@none</code>. This allows the
+ <a href="#term-selection-subalgorithm">Term Selection</a> subalgorithm to fall back
+ to choosing more generic <tref title="term">terms</tref> when a more
+ specifically-matching <tref>term</tref> is not available for a particular
+ <tref>IRI</tref> and value combination.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes one required input: the <tref>active context</tref> that
+ the <tref>inverse context</tref> is being created for.</p>
+
+ <ol class="algorithm">
+ <li>Initialize <em>result</em> to an empty <tref>JSON object</tref>.</li>
+ <li>Initialize <em>defaultLanguage</em> to <code>@none</code>. If the
+ <tref>active context</tref> has a <tref>default language</tref>, then
+ set <em>defaultLanguage</em> to it.</li>
+ <li>For each key <tref>term</tref> and value <tref>term definition</tref> in
+ the <tref>active context</tref>, ordered by shortest <tref>term</tref>
+ first (breaking ties by choosing the lexicographically least
+ <tref>term</tref>):
+ <ol class="algorithm">
+ <li>If the <tref>term definition</tref> is <tref>null</tref>, then
+ <tref>term</tref> cannot be selected during <tref>compaction</tref>,
+ so continue to the next <tref>term</tref>.</li>
+ <li>Initialize <em>container</em> to <code>@none</code>. If there
+ is a <tref>container mapping</tref> in
+ <tref>term definition</tref>, then set <em>container</em> to
+ its associated value.</li>
+ <li>Initialize <em>iris</em> to the value of the <tref>IRI mapping</tref>
+ for the <tref>term definition</tref>. If <em>iris</em> is not an
+ <tref>array</tref>, then set it to an <tref>array</tref> containing
+ only <em>iris</em>.</li>
+ <li>
+ For each item <em>iri</em> in <em>iris</em>:
+ <ol class="algorithm">
+ <li>If <em>iri</em> is not a key in <em>result</em>, then add
+ a key-value pair where the key is <em>iri</em> and the value
+ is an empty <tref>JSON object</tref> to <em>result</em>.</li>
+ <li>Initialize <em>container map</em> to the value associated with
+ the <em>iri</em> key in <em>result</em>.</li>
+ <li>If <em>container</em> is not a key in <em>container map</em>,
+ then initialize <em>typeOrLanguage map</em> to a new
+ <tref>JSON object</tref>. Add two key-value pairs to
+ <em>typeOrLanguage map</em>, where the first's key is
+ <code>@language</code> and its value is a new
+ <tref>JSON object</tref> and where the second's key is
+ <code>@type</code> and its value is a new
+ <tref>JSON object</tref>.</li>
+ <li>Set <em>typeOrLanguage map</em> to the value associated with
+ the key <em>container</em> in <em>container map</em>.</li>
+ <li>If there is no <tref>type mapping</tref> in the
+ <tref>term definition</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>language map</em> to the value associated
+ with the key <code>@language</code> in
+ <em>typeOrLanguage map</em>.</li>
+ <li>If there is a <tref>language mapping</tref> in the
+ <tref>term definition</tref>:
+ <ol class="algorithm">
+ <li>If the value of the <tref>language mapping</tref>
+ is <tref>null</tref> initialize <em>language</em>
+ to <code>@null</code>, otherwise initialize it to the
+ value.</li>
+ <li>If <em>language</em> is not a key in
+ <em>language map</em>, then add a key-value
+ pair to <em>language map</em> where the key is
+ <em>language</em> and the value is a new
+ <tref>JSON object</tref> with two key-value
+ pairs, where the first's key is <code>term</code>
+ and its value is <tref>null</tref>, and the second's
+ key is <code>propertyGenerators</code> and the
+ value is an empty <tref>array</tref>.</li>
+ <li>Initialize <em>entry</em> to the value associated with
+ the key <em>language</em> in <em>language map</em>.</li>
+ <li>If <tref>term definition</tref> is a
+ <tref>property generator</tref>, append the
+ <tref>term</tref> to the <tref>array</tref> associated
+ with the <code>propertyGenerators</code> key in
+ <em>entry</em>.</li>
+ <li>Otherwise, if the value associated with the key
+ <code>term</code> in <em>entry</em> is <tref>null</tref>,
+ set it to the <tref>term</tref>.</li>
+ </ol>
+ </li>
+ <li>Otherwise:
+ <ol class="algorithm">
+ <li>If <em>defaultLanguage</em> is not a key in
+ <em>language map</em>, then add a key-value
+ pair to <em>language map</em> where the key is
+ <em>defaultLanguage</em> and the value is a new
+ <tref>JSON object</tref> with two key-value
+ pairs, where the first's key is <code>term</code>
+ and its value is <tref>null</tref>, and the second's
+ key is <code>propertyGenerators</code> and the
+ value is an empty <tref>array</tref>.</li>
+ <li>Initialize <em>entry</em> to the value associated with
+ the key <em>defaultLanguage</em> in <em>language map</em>.</li>
+ <li>If <tref>term definition</tref> is a
+ <tref>property generator</tref>, append the
+ <tref>term</tref> to the <tref>array</tref> associated
+ with the <code>propertyGenerators</code> key in
+ <em>entry</em>.</li>
+ <li>Otherwise, if the value associated with the key
+ <code>term</code> in <em>entry</em> is <tref>null</tref>,
+ set it to the <tref>term</tref>.</li>
+ <li>If <code>@none</code> is not a key in
+ <em>language map</em>, then add a key-value
+ pair to <em>language map</em> where the key is
+ <code>@none</code> and the value is a new
+ <tref>JSON object</tref> with two key-value
+ pairs, where the first's key is <code>term</code>
+ and its value is <tref>null</tref>, and the second's
+ key is <code>propertyGenerators</code> and the
+ value is an empty <tref>array</tref>.</li>
+ <li>Set <em>entry</em> to the value associated with
+ the key <code>@none</code> in <em>language map</em>.</li>
+ <li>If <tref>term definition</tref> is a
+ <tref>property generator</tref>, append the
+ <tref>term</tref> to the <tref>array</tref> associated
+ with the <code>propertyGenerators</code> key in
+ <em>entry</em>.</li>
+ <li>Otherwise, if the value associated with the key
+ <code>term</code> in <em>entry</em> is <tref>null</tref>,
+ set it to the <tref>term</tref>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>If there is no <tref>language mapping</tref> in the
+ <tref>term definition</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>type map</em> to the value associated
+ with the key <code>@type</code> in
+ <em>typeOrLanguage map</em>.</li>
+ <li>If there is a <tref>type mapping</tref> in the
+ <tref>term definition</tref> then initialize <em>type</em>
+ to its value, otherwise initialize it to
+ to <code>@none</code>.</li>
+ <li>If <em>type</em> is not a key in <em>type map</em>, then
+ add a key-value pair to <em>type map</em> where the key is
+ <em>type</em> and the value is a new <tref>JSON object</tref>
+ with two key-value pairs, where the first's key is
+ <code>term</code> and its value is <tref>null</tref>, and the
+ second's key is <code>propertyGenerators</code> and the
+ value is an empty <tref>array</tref>.</li>
+ <li>Initialize <em>entry</em> to the value associated with
+ the key <em>type</em> in <em>type map</em>.</li>
+ <li>If <tref>term definition</tref> is a
+ <tref>property generator</tref>, append the
+ <tref>term</tref> to the <tref>array</tref> associated
+ with the <code>propertyGenerators</code> key in
+ <em>entry</em>.</li>
+ <li>Otherwise, if the value associated with the key
+ <code>term</code> in <em>entry</em> is <tref>null</tref>,
+ set it to the <tref>term</tref>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Inverse Context Creation subalgorithm -->
+
+ <section>
+ <h2>IRI Compaction Algorithm</h2>
+
+ <p>This section defines an algorithm for transforming an <tref>IRI</tref>
+ to a <tref>term</tref> or <tref>compact IRI</tref>, or a <tref>keyword</tref>
+ alias to a <tref>keyword</tref>. A value that is associated with the
+ <tref>IRI</tref> may be passed in order to assist in selecting the most
+ context-appropriate <tref>term</tref>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>We have an <tref>IRI</tref> (or <tref>keyword</tref>) that we may
+ be able to compact to <tref>term</tref>, <tref>compact IRI</tref>, or
+ <tref>keyword</tref> alias.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>First, we handle the simple cases: if the value given as an <tref>IRI</tref>
+ is <tref>null</tref>, we simply return <tref>null</tref> and if it is a
+ <tref>keyword</tref> we return its associated alias.</p>
+
+ <p>Otherwise, we first try to find a <tref>term</tref> that the
+ <tref>IRI</tref> can be <tref title="compaction">compacted</tref> to if
+ it is relative to <tref title="active context">active context's</tref>'s
+ <tref>vocabulary mapping</tref>. In order to select a <tref>term</tref>, we
+ have to collect information about the <tref title="IRI">IRI's</tref>
+ associated value. This information includes which
+ <tref title="container mapping">container mappings</tref>
+ would be preferred for expressing the value, and what its
+ <tref>type mapping</tref> or <tref>language mapping</tref> is. For
+ JSON-LD lists, the <tref>type mapping</tref> or <tref>language mapping</tref>
+ 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-subalgorithm">Term Selection</a> subalgorithm, which will
+ return the most appropriate <tref>term</tref> to use.</p>
+
+ <p>If no <tref>term</tref> was found that could be used to compact the
+ <tref>IRI</tref>, then an attempt is made to find a <tref>compact IRI</tref>
+ to use. If there is no appropriate <tref>compact IRI</tref>, then, if
+ the <tref>IRI</tref> is relative to
+ <tref title="active context">active context's</tref>
+ <tref>vocabulary mapping</tref>, then it is used. Otherwise, transform it to
+ a <tref>relative IRI</tref> using the document's base <tref>IRI</tref>.
+ Finally, if the <tref>IRI</tref> still could not be compacted, return it
+ as is.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>This algorithm takes three required inputs and three optional inputs.
+ The required inputs an <tref>active context</tref> and the <em>iri</em> to
+ be compacted. The optional inputs are: a <em>value</em> associated with
+ the <em>iri</em>, a <em>vocabRelative</em> flag which specifies whether the
+ passed <em>iri</em> should be compacted using the
+ <tref title="active context">active context's</tref>
+ <tref>vocabulary mapping</tref>, and the <em>parent</em> element for
+ the <em>value</em>. If not passed, <em>value</em> is set to
+ <tref>null</tref>, <em>vocabRelative</em> is set to <code>false</code>, and
+ <em>parent</em> is set to <tref>null</tref>.</p>
+
+ <ol class="algorithm">
+ <li>If <em>iri</em> is <tref>null</tref>, return <tref>null</tref>.</li>
+ <li>If <em>iri</em> is a <tref>keyword</tref> and does not have a
+ <tref>keyword</tref> alias, return <em>iri</em>, otherwise return
+ its first associated <tref>keyword</tref> alias from
+ <tref>active context</tref>.</li>
+ <li>If <em>vocabRelative</em> is <tref>true</tref> and
+ <tref>active context</tref> has no associated
+ <tref>inverse context</tref>, then generate it using the
+ <a href="#inverse-context-creation-subalgorithm">Inverse Context Creation</a>
+ algorithm. Set <em>inverse context</em> to the
+ <tref>inverse context</tref> associated with <tref>active context</tref>.</li>
+ <li>If <em>vocabRelative</em> is <tref>true</tref> and <em>iri</em> is a
+ key in <em>inverse context</em>:
+ <ol class="algorithm">
+ <li>Initialize <em>defaultLanguage</em> to
+ <tref title="active context">active context's</tref>
+ <tref>default language</tref>, if it has one, otherwise to
+ <code>@none</code>.</li>
+ <li>Initialize <em>containers</em> to an empty <tref>array</tref>. This
+ <tref>array</tref> will be used to keep track of an ordered list of
+ preferred <tref title="container mapping">container mappings</tref>
+ for a <tref>term</tref>, based on what is compatible with
+ <em>value</em>.</li>
+ <li>If <em>value</em> is a <tref>JSON object</tref> that contains the
+ key <code>@index</code>, then append the value <code>@index</code>
+ to <em>containers</em>.</li>
+ <li>Initialize <em>typeOrLanguage</em> to <code>@language</code>,
+ and <em>typeOrLanguageValue</em> to <code>@null</code>. These two
+ variables will keep track of the preferred
+ <tref>type mapping</tref> or <tref>language mapping</tref> for
+ a <tref>term</tref>, based on what is compatible with <em>value</em>.</li>
+ <li>If <em>value</em> is a <tref>list object</tref>, then set
+ <em>typeOrLanguage</em> and <em>typeOrLanguageValue</em>
+ to the most specific values that work for all items in
+ the list as follows:
+ <ol class="algorithm">
+ <li>If <code>@index</code> is a not key in <em>value</em>, then
+ append <code>@list</code> to <em>containers</em>.</li>
+ <li>Initialize <em>list</em> to the <tref>array</tref> associated
+ with the key <code>@list</code> in <em>value</em>.</li>
+ <li>Initialize <em>commonLanguage</em> to <tref>null</tref>. If
+ <em>list</em> is empty, set <em>commonLanguage</em> to
+ <em>defaultLanguage</em>.</li>
+ <li>For each <em>item</em> in <em>list</em>:
+ <ol class="algorithm">
+ <li>Initialize <em>itemLanguage</em> to <code>@none</code> and
+ <em>itemType</em> to <code>@none</code>.</li>
+ <li>If <em>item</em> contains the key <code>@value</code>:
+ <ol class="algorithm">
+ <li>If <em>item</em> contains the key <code>@language</code>,
+ then set <em>itemLanguage</em> to its associated
+ value.</li>
+ <li>Otherwise, if <em>item</em> contains the key
+ <code>@type</code>, set <em>itemType</em> to its
+ associated value.</li>
+ <li>Otherwise, set <em>itemLanguage</em> to
+ <code>@null</code>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, set <em>itemType</em> to <code>@id</code>.</li>
+ <li>If <em>commonLanguage</em> is <tref>null</tref>, set it
+ to <em>itemLanguage</em>.</li>
+ <li>Otherwise, if <em>itemLanguage</em> does not equal
+ <em>commonLanguage</em> and <em>item</em> contains the
+ key <code>@value</code>, then set <em>commonLanguage</em>
+ to <code>@none</code> because list items have conflicting
+ languages.</li>
+ <li>If <em>commonType</em> is <tref>null</tref>, set it
+ to <em>itemType</em>.</li>
+ <li>Otherwise, if <em>itemType</em> does not equal
+ <em>commonType</em>, then set <em>commonType</em>
+ to <code>@none</code> because list items have conflicting
+ types.</li>
+ <li>If <em>commonLanguage</em> is <code>@none</code> and
+ <em>commonType</em> 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 <em>commonLanguage</em> is <tref>null</tref>, set it to
+ <code>@none</code>.</li>
+ <li>If <em>commonType</em> is <tref>null</tref>, set it to
+ <code>@none</code>.</li>
+ <li>If <em>commonType</em> is not <code>@none</code> then set
+ <em>typeOrLanguage</em> to <code>@type</code> and
+ <em>typeOrLanguageValue</em> to <em>commonType</em>.</li>
+ <li>Otherwise, set <em>typeOrLanguageValue</em> to
+ <em>commonLanguage</em>.</li>
+ </ol>
+ </li>
+ <li>
+ Otherwise:
+ <ol class="algorithm">
+ <li>If <em>value</em> contains the key <code>@value</code>:
+ <ol class="algorithm">
+ <li>If <em>value</em> contains the key <code>@language</code>
+ and does not contain the key <code>@index</code>,
+ then set <em>typeOrLanguageValue</em> to its associated
+ value and append <code>@language</code> to
+ <em>containers</em>.</li>
+ <li>Otherwise, if <em>value</em> contains the key
+ <code>@type</code>, then set <em>typeOrLanguageValue</em> to
+ its associated value and set <em>typeOrLanguage</em> to
+ <code>@type</code>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, set <em>typeOrLanguage</em> to <code>@type</code>
+ and set <em>typeOrLanguageValue</em> to <code>@id</code>.</li>
+ <li>Append <code>@set</code> to <em>containers</em>.</li>
+ </ol>
+ </li>
+ <li>Initialize <em>term</em> to the result of the
+ <a href="#term-selection-subalgorithm">Term Selection</a> subalgorithm, passing
+ <tref>active context</tref>, <em>inverse context</em>, <em>iri</em>,
+ <em>value</em>, <em>parent</em>, <em>containers</em>,
+ <em>typeOrLanguage</em>, and <em>typeOrLanguageValue</em>.</li>
+ <li>If <em>term</em> is not <tref>null</tref>, return <em>term</em>.</li>
+ </ol>
+ </li>
+ <li>At this point, there is no simple <tref>term</tref> that <em>iri</em>
+ can be compacted to. Instead, try to choose a <tref>compact IRI</tref>,
+ starting by initializing <em>choice</em> to <tref>null</tref>. This
+ variable will be used to store the chosen <tref>compact IRI</tref> to
+ use, if any.</li>
+ <li>For each key <tref>term</tref> and value <tref>term definition</tref> in
+ the <tref>active context</tref>:
+ <ol class="algorithm">
+ <li>If the <tref>term</tref> contains a colon (<code>:</code>),
+ then continue to the next <tref>term</tref> because
+ <tref title="term">terms</tref> with colons can't be
+ used as <tref title="prefix">prefixes</tref>.</li>
+ <li>If the <tref>term definition</tref> is <tref>null</tref>
+ or for a <tref>property generator</tref> or its
+ <tref>IRI mapping</tref> equals <em>iri</em> or is not
+ a substring at the beginning of <em>iri</em>, then the
+ <tref>term</tref> cannot be used as a <tref>prefix</tref>
+ because it is not a partial match with <em>iri</em>. So
+ continue to the next <tref>term</tref>.</li>
+ <li>Initialize <em>curie</em> by concatenating <tref>term</tref>,
+ a colon (<code>:</code>), and the substring of <em>iri</em>
+ that follows after the value of the
+ <tref title="term definition">term definition's</tref>
+ <tref>IRI mapping</tref>.</li>
+ <li>If either <em>choice</em> is <tref>null</tref> or <em>curie</em> is
+ shorter or the same length but lexicographically less than
+ <em>choice</em> and <em>curie</em> does not have a
+ <tref>term definition</tref> in <tref>active context</tref> or if the
+ <tref>term definition</tref> has an <tref>IRI mapping</tref>
+ that equals <em>iri</em> and <em>value</em> is <tref>null</tref>,
+ set <em>choice</em> to <em>curie</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>choice</em> is not <tref>null</tref>, return <em>choice</em>.</li>
+ <li>At this point, there is no <tref>compact IRI</tref> that <em>iri</em>
+ can be compacted to, so if <em>vocabRelative</em> is
+ <tref>true</tref> and <tref>active context</tref> has a
+ <tref>vocabulary mapping</tref>:
+ <ol class="algorithm">
+ <li>If <em>iri</em> begins with the
+ <tref title="vocabulary mapping">vocabulary mapping's</tref> value
+ but is longer, then initialize <em>suffix</em> to the substring
+ of <em>iri</em> that does not match. If <em>suffix</em> does not
+ have a <tref>term definition</tref> in <tref>active context</tref>,
+ then return <em>suffix</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>vocabRelative</em> is <tref>false</tref> then
+ transform <em>iri</em> to a <tref>relative IRI</tref> using
+ the document's base <tref>IRI</tref>.</li>
+ <li>Finally, return <em>iri</em> as is.</li>
+ </ol>
+ </section>
+ </section> <!-- end of IRI Compaction -->
+
+ <section>
+ <h2>Term Selection Subalgorithm</h2>
+
+ <p>This subalgorithm, invoked via the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, makes use
+ of an <tref title="active context">active context's</tref>
+ <tref>inverse context</tref> to find the <tref>term</tref> that is best
+ used to <tref title="compaction">compact</tref> an <tref>IRI</tref>. Other
+ information about a value associated with the <tref>IRI</tref> is given,
+ including which <tref title="container mapping">container mappings</tref>
+ and which <tref>type mapping</tref> or <tref>language mapping</tref> would
+ be best used to express the value.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>An <tref>IRI</tref> with an associated <em>value</em> should be compacted
+ to the most appropriate <tref>term</tref> in the <tref>active context</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>The <tref title="inverse context">inverse context's</tref> entry for
+ the <tref>IRI</tref> will be first searched according to the preferred
+ <tref title="container mapping">container mappings</tref>, in the order
+ that they are given. Amongst <tref title="term">terms</tref> with a matching
+ <tref>container mapping</tref>, preference will be given to those
+ with a matching <tref>type mapping</tref> or <tref>language mapping</tref>,
+ over those without a <tref>type mapping</tref> or
+ <tref>language mapping</tref>. If there is no <tref>term</tref>
+ with a matching <tref>container mapping</tref> then the <tref>term</tref>
+ without a <tref>container mapping</tref> that matches the given
+ <tref>type mapping</tref> or <tref>language mapping</tref> is selected. If
+ there is still no selected <tref>term</tref>, then a <tref>term</tref>
+ with no <tref>type mapping</tref> or <tref>language mapping</tref> will
+ be selected if available. No <tref>term</tref> will be selected that
+ has a conflicting <tref>type mapping</tref> or <tref>language mapping</tref>.
+ Ties between <tref title="term">terms</tref> 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-subalgorithm">Inverse Context Creation algorithm</a>
+ was used to create the <tref>inverse context</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>This subalgorithm has eight required inputs. They are:
+ an <tref>active context</tref>, an <tref>inverse context</tref>, an
+ <tref>IRI</tref> <em>iri</em>, a <em>value</em> associated with the
+ <tref>IRI</tref>, the expanded <em>parent</em> element for <em>value</em>
+ (which may be a <tref>JSON object</tref>, an <tref>array</tref>, or
+ <tref>null</tref>), an <tref>array</tref> <em>containers</em> that
+ represents ordered list of preferred
+ <tref title="container mapping">container mappings</tref>, a
+ <tref>string</tref> <em>typeOrLanguage</em> that indicates whether
+ to look for a <tref>term</tref> with a matching <tref>type mapping</tref>
+ or <tref>language mapping</tref>, and a <tref>string</tref>
+ <em>typeOrLanguageValue</em> with the associated value for the
+ <tref>type mapping</tref> or <tref>language mapping</tref> to look for.</p>
+
+ <ol class="algorithm">
+ <li>Append <code>@none</code> to <em>containers</em>. This represents
+ the non-existence of a <tref>container mapping</tref>, and it will
+ be the last <tref>container mapping</tref> value to be checked as it
+ is the most generic.</li>
+ <li>Initialize <em>container map</em> to the value associated with
+ <em>iri</em> in the <tref>inverse context</tref>.</li>
+ <li>If <em>typeOrLanguageValue</em> is <tref>null</tref>, set it to
+ <code>@null</code>. This is the key under which <tref>null</tref> values
+ are stored in the <tref>inverse context</tref> <em>entry</em>.</li>
+ <li>Initialize <em>preferred values</em> to an empty <tref>array</tref>.
+ This <tref>array</tref> will indicate, in order, the preferred values for
+ a <tref title="term">term's</tref> <tref>type mapping</tref> or
+ <tref>language mapping</tref>.</li>
+ <li>If <em>typeOrLanguageValue</em> is <code>@id</code> and
+ <em>value</em> is a <tref>JSON object</tref> containing the key
+ <code>@id</code>:
+ <ol class="algorithm">
+ <li>If the result of using the
+ <a href="#iri-compaction-algorithm">IRI compaction</a> algorithm,
+ passing <tref>active context</tref>, the value associated with the
+ <code>@id</code> key in <em>value</em> for
+ <em>iri</em>, <tref>true</tref> for <em>vocabRelative</em>, and
+ <tref>true</tref> for <em>documentRelative</em> has a
+ <tref>term definition</tref> in the <tref>active context</tref>
+ with an <tref>IRI mapping</tref> that equals the value associated
+ with the <code>@id</code> key in <em>value</em>,
+ then append <code>@vocab</code>, <code>@id</code>, and
+ <code>@none</code>, in that order, to <em>preferred values</em>.</li>
+ <li>Otherwise, append <code>@id</code>, <code>@vocab</code>, and
+ <code>@none</code>, in that order, to <em>preferred values</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, append <em>typeOrLanguageValue</em> and <code>@none</code>, in
+ that order, to <em>preferred values</em>.</li>
+ <li>Initialize <em>selected term</em> to <tref>null</tref>.</li>
+ <li>For each item <em>container</em> in <em>containers</em> while
+ <em>selected term</em> is <tref>null</tref>:
+ <ol class="algorithm">
+ <li>If <em>container</em> is not a key in <em>container map</em>, then
+ there is no <tref>term</tref> with a matching
+ <tref>container mapping</tref> for it, so continue to the next
+ <em>container</em>.</li>
+ <li>Initialize <em>typeOrLanguage map</em> to the value associated
+ with <em>container</em> in <em>container map</em>.</li>
+ <li>Initialize <em>typeOrLanguageValue map</em> to the value associated
+ with <em>typeOrLanguage</em> in <em>typeOrLanguage map</em>.</li>
+ <li>For each <em>item</em> in <em>preferred values</em> while
+ <em>selected term</em> is <tref>null</tref>:
+ <ol class="algorithm">
+ <li>If <em>item</em> is not a key in <em>typeOrLanguageValue map</em>,
+ then there is no <tref>term</tref> with a matching
+ <tref>type mapping</tref> or <tref>language mapping</tref>,
+ so continue to the next <em>item</em>.</li>
+ <li>Initialize <em>termInfo</em> to the value associated with
+ <em>item</em> in <em>typeOrLanguageValue map</em>.</li>
+ <li>If <em>parent</em> is a <tref>JSON object</tref>,
+ then for each <tref>property generator</tref> <tref>term</tref>
+ <em>propertyGeneratorTerm</em> in <em>termInfo</em> while
+ <em>selected term</em> is <tref>null</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>match</em> to the result of using the
+ <a href="#find-property-generator-duplicates-subalgorithm">Find Property Generator Duplicates</a>
+ algorithm, passing <tref>active context</tref>,
+ <em>parent</em> for <em>element</em>, <em>iri</em> for
+ <em>expanded property</em>, <em>value</em>,
+ <em>propertyGeneratorTerm</em> for <em>activeProperty</em>,
+ and <tref>false</tref> for <em>remove</em>.</li>
+ <li>If <em>match</em> is <tref>true</tref>, then set
+ <em>selected term</em> to <em>propertyGeneratorTerm</em>.</li>
+ </ol>
+ </li>
+ <li>If <em>selected term</em> is <tref>null</tref>, then no
+ <tref>property generator</tref> match was found, so set
+ <em>selected term</em> to the non-<tref>property generator</tref>
+ <tref>term</tref> in <em>termInfo</em>, which may be
+ <tref>null</tref>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Return <em>selected term</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Term Selection subalgorithm -->
+
+ <section>
+ <h2>Value Compaction</h2>
+
+ <p><tref>Expansion</tref> transforms all values into <tref>expanded form</tref>
+ in JSON-LD. This algorithm performs the opposite operation, transforming
+ a value into <tdef>compacted form</tdef>. This algorithm compacts a
+ value according to the <tref>term definition</tref> in the given
+ <tref>active context</tref> that is associated with the value's associated
+ <tref>active property</tref>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>A <em>value</em> associated with an <tref>active property</tref> must
+ be <tref title="compaction">compacted</tref> to <tref>compacted form</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>The <em>value</em> to compact either contains the key <code>@value</code>
+ or the key <code>@id</code>.</p>
+
+ <p>We start with the former case, first trying to compact the
+ <em>value</em> into just the value associated with its
+ <code>@value</code> key. This can be done if the <em>value</em> is not
+ going to be contained by an <code>@index</code> container and if the
+ <tref>active property</tref> has a matching <tref>type mapping</tref> or
+ <tref>language mapping</tref>. It can also be done if <code>@value</code>
+ is the only key in <em>value</em> and either its associated value is
+ not a <tref>string</tref>, there's no <tref>default language</tref>, or
+ there's an explicit <tref>null</tref> <tref>language mapping</tref> for
+ the <tref>active property</tref>.</p>
+
+ <p>If we couldn't do the above optimal compaction, then we simply replace
+ <tref title="keyword">keywords</tref> with aliases and compact any
+ <tref title="IRI">IRIs</tref>.</p>
+
+ <p>For the latter case, where the key <code>@id</code> appears in <em>value</em>,
+ we compact the associated value using the
+ <a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, and
+ use its value if the <tref>type mapping</tref> associated with the
+ <tref>active property</tref> is <code>@id</code> or the expanded value for
+ the <tref>active property</tref> is <code>@graph</code>. Otherwise, we
+ replace the <code>@id</code> key with its alias and its associated value
+ with its compacted version.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>This algorithm has three required inputs: an <tref>active context</tref>, an
+ an <tref>active property</tref>, and a <em>value</em> to be compacted.</p>
+
+ <ol class="algorithm">
+ <li>If <em>value</em> contains the key <code>@value</code>:
+ <ol class="algorithm">
+ <li>Initialize <em>preserveIndex</em> to <tref>false</tref>. If
+ <code>@index</code> is a key in <em>value</em> and
+ <tref>active property</tref> does not have a
+ <tref>container mapping</tref> in <tref>active context</tref> that
+ is <code>@index</code>, set <em>preserveIndex</em> to
+ <tref>true</tref>.</li>
+ <li>If <em>preserveIndex</em> is <tref>false</tref> and either
+ <em>value</em> has a <code>@type</code> key with a value that
+ matches <tref title="active property">active property's</tref>
+ <tref>type mapping</tref> in <tref>active context</tref> or
+ <em>value</em> has a <code>@language</code> key with a value that
+ matches <tref title="active property">active property's</tref>
+ <tref>language mapping</tref> in <tref>active context</tref>, then
+ return the value associated with the <code>@value</code> key in
+ <em>value</em>.</li>
+ <li>If <code>@value</code> is the only key in <em>value</em> or
+ <em>preserveIndex</em> is <tref>false</tref> and either
+ there is no <tref>default language</tref> in
+ <tref>active context</tref>, the value associated with the
+ <code>@value</code> key in <em>value</em> is not a
+ <tref>string</tref>, or <tref>active property</tref>
+ has a <tref>null</tref> <tref>language mapping</tref> in
+ <tref>active context</tref>, then return the value
+ associated with the <code>@value</code> key in <em>value</em>.</li>
+ <li>Initialize <em>result</em> to an empty <tref>JSON object</tref>.</li>
+ <li>If <em>preserveIndex</em> is <tref>true</tref>, then add
+ a key-value pair to <em>result</em> where the key is the result
+ using the <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@index</code> for <em>iri</em>, and the value is
+ the value associated with the <code>@index</code> key in
+ <em>value</em>.</li>
+ <li>If <em>value</em> contains the key <code>@type</code>, then add
+ a key-value pair to <em>result</em> where the key is the result
+ using the <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@type</code> for <em>iri</em>, and the value is the result
+ of using the <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref>, the value associated
+ with the <code>@type</code> key in <em>value</em> for <em>iri</em>,
+ and <tref>true</tref> for <em>vocabRelative</em>.</li>
+ <li>Otherwise, if <em>value</em> contains the key <code>@language</code>,
+ then add a key-value pair to <em>result</em> where the key is the
+ result using the
+ <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@language</code> for <em>iri</em>, and the value is the
+ value associated with the <code>@language</code> key in
+ <em>value</em>.</li>
+ <li>Add a key-value pair to <em>result</em> where the key is the result
+ using the <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref> and
+ <code>@value</code> for <em>iri</em>, and the value is the value
+ associated with the <code>@value</code> key in <em>value</em>.</li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, <em>value</em> must contain the single key <code>@id</code>.
+ Initialize <em>expanded property</em> to the result of using the
+ <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
+ <tref>active context</tref>, <em>value</em>, and
+ <tref>true</tref> for <em>vocabRelative</em>.</li>
+ <li>Initialize <em>term</em> to the result of using the
+ <a href="#iri-compaction-algorithm">IRI compaction</a> algorithm,
+ passing <tref>active context</tref>, the value associated with
+ the key <code>@id</code> in <em>value</em> for <em>iri</em>, and
+ <tref>true</tref> for <em>vocabRelative</em> if
+ <tref>active property</tref> has a <tref>type mapping</tref> in the
+ <tref>active context</tref> that is <code>@vocab</code>.</li>
+ <li>If <tref>active property</tref> has a <tref>type mapping</tref> in
+ the <tref>active context</tref> that is <code>@id</code> or
+ <code>@vocab</code> or if <em>expanded property</em> is
+ <code>@graph</code>, then return <em>term</em>.</li>
+ <li>Initialize <em>result</em> to an empty <tref>JSON object</tref>. Add
+ a key-value pair to <em>result</em> where the key is the result of
+ using the <a href="#iri-compaction-algorithm">IRI compaction</a>
+ algorithm, passing <tref>active context</tref>, and <code>@id</code> for
+ <em>iri</em>, and the value is <em>term</em>.</li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Value Compaction algorithm -->
+
+ <section>
+ <h2>Find Property Generator Duplicates Subalgorithm</h2>
+
+ <p>This algorithm checks if a specific value exists for all
+ <tref title="IRI">IRIs</tref> associated with a
+ <tref>property generator</tref> and, if specified, it removes them.
+ The algorithm takes six required inputs: an <tref>active context</tref>,
+ <em>element</em>, <em>expanded property</em>, <em>value</em>,
+ <tref>active property</tref>, and a flag <em>remove</em>, that indicates
+ whether or not to remove the duplicate values. It returns <tref>true</tref>
+ if the required duplicate values were found and <tref>false</tref> if not.</p>
+
+ <ol class="algorithm">
+ <li>Initialize <em>result</em> to <tref>true</tref>.</li>
+ <li>Initialize <em>iris</em> to the <tref>array</tref> associated with the
+ <tref>IRI mapping</tref> for <tref>active property</tref> in
+ <tref>active context</tref>.</li>
+ <li>For each <em>iri</em> in <em>iris</em>:
<ol class="algorithm">
- <li>
- Initialize <em>expanded value</em> to an empty
- <tref>array</tref>.
- </li>
- <li>
- For each key <em>index</em> and value
- <em>index value</em> in <em>value</em>, ordered
- lexicographically by <em>index</em>:
+ <li>If <em>iri</em> equals <em>expanded property</em>, then this
+ is the <em>iri</em> that is to be preserved, so continue to the next
+ <em>iri</em>.</li>
+ <li>Set <em>result</em> to <tref>false</tref>.</li>
+ <li>If <em>element</em> contains a key that equals <em>iri</em>:
<ol class="algorithm">
- <li>
- If <em>index value</em> is not an <tref>array</tref>
- set it to an <tref>array</tref> containing only
- <em>index value</em>.
+ <li>Initialize <em>prospects</em> to the value associated with the
+ key that equals <em>iri</em> in <em>element</em>. This
+ <tref>array</tref> will be checked for a value that matches
+ the <tref>property generator</tref> <em>value</em>.</li>
+ <li>If <em>value</em> is an empty <tref>array</tref>:
+ <ol class="algorithm">
+ <li>Set <em>result</em> to <tref>true</tref>.</li>
+ <li>If <em>remove</em> is <tref>true</tref>, remove <em>iri</em>
+ from <em>element</em>.</li>
+ <li>Continue to the next <em>iri</em>.</li>
+ </ol>
</li>
- <li>
- Initialize <em>index value</em> to the result of
- using this algorithm recursively, passing
- <tref>active context</tref>, <tref>active property</tref>,
- <em>index value</em> as <em>element</em>, and
- <tref>false</tref> for <em>insideList</em>.</li>
- <li>
- For each <em>item</em> in <em>index value</em>:
+ <li>For each item <em>prospect</em> in <em>prospects</em>, until
+ a <tref>property generator</tref> duplicate is found for
+ <em>value</em>:
<ol class="algorithm">
- <li>
- If <em>item</em> does not have the key
- <code>@index</code>, add the key-value pair
- (<code>@index</code>-<em>index</em>) to
- <em>item</em>.
+ <li>Check to see if <em>prospect</em> and <em>value</em> are
+ <tref>property generator</tref> duplicates:
+ <ol class="algorithm">
+ <li>If their types and values are equal, then they are
+ duplicates.</li>
+ <li>Otherwise, if they are both
+ <tref title="JSON object">JSON objects</tref> that contain
+ the key <code>@value</code> and they both have the same
+ key-value pairs for the keys <code>@value</code>,
+ <code>@type</code>, <code>@language</code>, and
+ <code>@index</code>, then they are duplicates.</li>
+ <li>Otherwise, if they are both
+ <tref title="list object">list objects</tref> with the same
+ key-value pairs for the key <code>@index</code>, and the
+ <tref title="array">arrays</tref> associated with their
+ <code>@list</code> keys have the same length and their
+ corresponding items, by index, are duplicates, then they
+ are duplicates.</li>
+ <li>Otherwise, if they are both
+ <tref title="JSON object">JSON objects</tref> that contain
+ the key <code>@id</code> and the values associated with
+ those keys are equal, then they are duplicates.</li>
+ <li>Otherwise, they are not duplicates.</li>
+ </ol>
</li>
- <li>
- Append <em>item</em> to <em>expanded value</em>.
+ <li>If <em>prospect</em> and <em>value</em> are
+ <tref>property generator</tref> duplicates:
+ <ol class="algorithm">
+ <li>Set <em>result</em> to <tref>true</tref>.</li>
+ <li>If <em>remove</em> is <tref>true</tref>, then remove
+ <em>prospect</em> from <em>prospects</em> and, if
+ <em>prospects</em> is now empty, remove <em>iri</em>
+ from <em>element</em>.</li>
+ </ol>
</li>
</ol>
</li>
@@ -1593,2861 +3083,725 @@
</li>
</ol>
</li>
- <li>
- Otherwise, if <em>expanded property</em> is <code>@list</code>
- or <code>@set</code>, initialize <em>expanded value</em> to the
- result of using this algorithm recursively passing
- <tref>active context</tref>, <tref>null</tref> for
- <tref>active property</tref> if <em>expanded property</em> is
- <code>@list</code> and <em>expanded active property</em> is
- <code>@graph</code> otherwise <tref>active property</tref>,
- <em>value</em> for <em>element</em>, and <tref>true</tref>
- for <em>insideList</em> if <em>expanded property</em> is
- <code>@list</code> otherwise <tref>false</tref>.
- If <em>expanded property</em> is <code>@list</code>
- then <em>expanded value</em> MUST NOT be a
- <tref>list object</tref>, otherwise a
- <code class="error">list of lists</code> error has been detected.
- </li>
- <li>
- Otherwise, initialize <em>expanded value</em> to the result of
- using this algorithm recursively, passing
- <tref>active context</tref>, <em>key</em> for
- <tref>active property</tref>, <em>value</em>
- for <em>element</em>, and <tref>false</tref> for
- <em>insideList</em>.
- </li>
- <li>
- If <em>expanded value</em> is <tref>null</tref> and
- <em>expanded property</em> is not <code>@value</code> then
- drop <em>key</em> by continuing to the next key.
- </li>
- <li>
- If <em>expanded property</em> is not <code>@list</code> and
- <em>expanded value</em> is not a <tref>list object</tref> and
- <em>key</em>'s <tref>container mapping</tref> in
- <tref>active context</tref> is <code>@list</code> then convert
- <em>expanded value</em> to a <tref>list object</tref> by first
- setting it to an <tref>array</tref> containing only
- <em>expanded value</em> if it is not already an
- <tref>array</tref>, and then by setting it to a
- <tref>JSON object</tref> containing the key-value pair
- (<code>@list</code>-<em>expanded value</em>).
- </li>
- <li>
- If <em>expanded property</em> is an <tref>array</tref>:
- <ol class="algorithm">
- <li>
- Set <em>expanded value</em> to the result of the
- <a href="#label-blank-nodes-subalgorithm">Label Blank Nodes</a>
- subalgorithm, passing <tref>active context</tref> and
- <em>expanded value</em> as <em>element</em>.
- </li>
- <li>
- For each item <em>iri</em> in <em>expanded property</em>:
- <ol class="algorithm">
- <li>
- If <em>result</em> does not have the key <em>iri</em>,
- set this key's value in <em>result</em> to an empty
- <tref>array</tref>. Append a copy of
- <em>expanded value</em> to the <tref>array</tref> value
- associated with <em>result</em>'s <em>iri</em> key.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- Otherwise, if <em>expanded property</em> is
- <code>@index</code>, <code>@id</code>, <code>@type</code>,
- <code>@value</code>, or <code>@language</code>, then
- set key <em>expanded property</em>'s value to
- <em>expanded value</em> in <em>result</em>.
- </li>
- <li>
- Otherwise, if <em>result</em> does not have the key
- <em>expanded property</em>, set this key's value in <em>result</em>
- to an empty <tref>array</tref>. Append <em>expanded value</em>
- to the <tref>array</tref> value associated with <em>result</em>'s
- <em>expanded property</em> key.
- </li>
- </ol>
- </li>
- <li>
- If <em>result</em> contains the key <code>@value</code>:
- <ol class="algorithm">
- <li>
- The <em>result</em> MUST NOT contain any keys other than
- <code>@value</code>, <code>@language</code>, <code>@type</code>,
- and <code>@index</code>. It MUST NOT contain both the
- <code>@language</code> key and the <code>@type</code> key.
- Otherwise, an <code class="error">invalid value object</code> error
- has been detected.
- </li>
- <li>
- If the value of <em>result</em>'s <code>@value</code> key is
- <tref>null</tref>, then set <em>result</em> to <tref>null</tref>.
- </li>
- <li>
- Otherwise, if <em>result</em> contains the key
- <code>@language</code> and the value of <em>result</em>'s
- <code>@value</code> key is not a <tref>string</tref>, then remove
- the <code>@language</code> key from <em>result</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, if <em>result</em> contains the key <code>@type</code>
- and its associated value is not an <tref>array</tref>, set it to
- an <tref>array</tref> containing only the associated value.
- </li>
- <li>
- Otherwise, if <em>result</em> contains the key <code>@set</code>
- or <code>@list</code>:
- <ol class="algorithm">
- <li>
- The <em>result</em> MUST contain at most one other key and that
- key MUST be <code>@index</code>. Otherwise, an
- <code class="error">invalid set or list object</code> error
- has been detected.
- </li>
- <li>
- If <em>result</em> contains the key <code>@set</code>, then
- set <em>result</em> to the key's associated value.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, if <em>result</em> contains only the key
- <code>@language</code>, set <em>result</em> to <tref>null</tref>.
- </li>
- <li>
- If <em>insideList</em> is <tref>false</tref> and either
- <tref>active property</tref> is <tref>null</tref> or
- <em>expanded active property</em> is <code>@graph</code>, then
- drop free-floating values as follows:
- <ol class="algorithm">
- <li>
- If <em>result</em> contains no keys or contains the key
- <code>@value</code>, setting <em>result</em> to
- <tref>null</tref>.</li>
- <li>
- Otherwise, if <em>result</em>'s keys are only keywords and none
- of the keys are <code>@graph</code> or <code>@type</code> then
- set <em>result</em> to <tref>null</tref>.
- </li>
- </ol>
- </li>
- <li>Return <em>result</em>.</li>
-</ol>
-
-<p>
-If, after the above algorithm is run, the result is a
-<tref>JSON object</tref> that contains only an <code>@graph</code> key, set the
-result to the value of <code>@graph</code>'s value. Otherwise, if the result
-is <tref>null</tref>, set it to an empty <tref>array</tref>. Finally, if
-the result is not an <tref>array</tref>, then set the result to an
-<tref>array</tref> containing only the result.
-</p>
-
-</section>
-
-</section> <!-- end of Expansion Algorithm -->
-
-<section>
- <h2>IRI Expansion</h2>
-
- <p>In JSON-LD documents, some keys and values may represent
- <tref title="IRI">IRIs</tref>. This section defines an algorithm for
- transforming a <tref>string</tref> that represents an <tref>IRI</tref> into
- an <tref>absolute IRI</tref>. It also covers transforming <tref>keyword</tref>
- aliases into <tref title="keyword">keywords</tref>.</p>
-
- <p><tref>IRI</tref> expansion may occur during context processing or during
- any of the other JSON-LD algorithms. If IRI expansion occurs during context
- processing, then the <tref>local context</tref> and its related
- <em>defined</em> map from the
- <a href="#context-processing">Context Processing</a> algorithm are passed
- to this algorithm. This allows for <tref>term definition</tref> dependencies
- to be processed via the context processing subalgorithm,
- <a href="#create-term-definition-subalgorithm">Create Term Definition</a>.</p>
-
- <p>After application of this algorithm, values processed by this algorithm are
- said to be in <tdef>expanded IRI form</tdef> (Advanced note: this form
- may also include
- <tref title="blank node identifier">blank node identifiers</tref> and
- JSON-LD <tref title="keyword">keywords</tref>).</p>
-
- <section class="informative">
- <h3>Purpose</h3>
-
- <p>We have a value that needs to be expanded to an <tref>absolute IRI</tref>
- or a <tref>keyword</tref>. The given value may be <tref>null</tref>, a
- <tref>term</tref>, a <tref>keyword</tref> alias, a <tref>compact IRI</tref>,
- a <tref>relative IRI</tref>, or an <tref>absolute IRI</tref>.</p>
- </section>
-
- <section class="informative">
- <h3>General Solution</h3>
-
- <p>In order to expand <em>value</em> to an <tref>absolute IRI</tref>, we must
- first determine if it is <tref>null</tref>, a <tref>term</tref>, a
- <tref>keyword</tref> alias, or some form of <tref>IRI</tref>. Based on what
- we find, we handle the specific kind of expansion; for example, we expand
- a <tref>keyword</tref> alias to a <tref>keyword</tref> and a <tref>term</tref>
- to an <tref>absolute IRI</tref> according to its <tref>IRI mapping</tref>
- in the <tref>active context</tref>. While inspecting <em>value</em> we
- may also find that we need to create <tref>term definition</tref>
- dependencies because we're running this
- algorithm during <a href="#context-processing">Context Processing</a>. We can
- tell whether or not we're running during
- <a href="#context-processing">Context Processing</a> by checking
- <tref>local context</tref> against <tref>null</tref>.
- We know we need to create a <tref>term definition</tref> in the
- <tref>active context</tref> when <em>value</em> is
- a key in the <tref>local context</tref> and the <em>defined</em> map
- does not have a key for <em>value</em> with an associated value of
- <tref>true</tref>. The <em>defined</em> map is used during
- <a href="#context-processing">Context Processing</a> to keep track of
- which <tref title="term">terms</tref> have already been defined or are
- in the process of being defined. We create a
- <tref>term definition</tref> by using the
- <a href="#create-term-definition-subalgorithm">Create Term Definition</a> subalgorithm.</p>
- </section>
-
- <section>
- <h3>Algorithm</h3>
-
- <p>The algorithm takes two required and four optional input variables. The
- required inputs are an <tref>active context</tref> and a <em>value</em>
- to be expanded. The optional inputs are two flags,
- <em>documentRelative</em> and <em>vocabRelative</em>, that specifying
- whether <em>value</em> can be interpreted as a <tref>relative IRI</tref>
- against the document's base <tref>IRI</tref> or the
- <tref title="active context">active context's</tref>
- <tref>vocabulary mapping</tref>, respectively, and
- a <tref>local context</tref> and a map <em>defined</em> to be used when
- this algorithm is used during
- <a href="#context-processing">Context Processing</a>. If not passed, the
- two flags are set to <code>false</code> and <tref>local context</tref> and
- <em>defined</em> are initialized to <tref>null</tref>.</p>
-
- <ol class="algorithm">
- <li>If <em>value</em> is a <tref>keyword</tref> or is <tref>null</tref>,
- return <em>value</em> as is.</li>
- <li>If <tref>local context</tref> is not <tref>null</tref>, it contains
- a key that equals <em>value</em>, and the value associated with the key
- that equals <em>value</em> in <em>defined</em> is not <tref>true</tref>,
- then invoke the <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
- subalgorithm, passing <tref>active context</tref>, <tref>local context</tref>,
- <em>value</em> as <em>term</em>, and <em>defined</em>. This will ensure that
- a <tref>term definition</tref> is created for <em>value</em> in
- <tref>active context</tref> during <a href="#context-processing">Context Processing</a>.
- </li>
- <li>Initialize <em>result</em> to <tref>null</tref>.</li>
- <li>If <em>vocabRelative</em> is <tref>true</tref>:
- <ol class="algorithm">
- <li>If <tref>local context</tref> is not <tref>null</tref> then
- <tref>active context</tref> MUST NOT have a <tref>term definition</tref>
- for <em>value</em> that is a <tref>property generator</tref>.
- Otherwise, a
- <code class="error">property generator in term definition</code>
- error has been detected.</li>
- <li>If <em>value</em> has a <tref>null</tref> mapping in
- <tref>active context</tref>, then return <tref>null</tref> which
- has the effect of explicitly dropping <em>value</em>.</li>
- <li>If <tref>active context</tref> has a <tref>term definition</tref> for
- <em>value</em>, then set <em>result</em> to the associated
- <tref>IRI mapping</tref>.</li>
- </ol>
- </li>
- <li>If <em>result</em> is <tref>null</tref> and <em>value</em> contains a
- colon (<code>:</code>), then it is either an <tref>absolute IRI</tref> or
- a <tref>compact IRI</tref>:
- <ol class="algorithm">
- <li>Split <em>value</em> into a <tref>prefix</tref> and <em>suffix</em>
- at the first occurrence of a colon (<code>:</code>).</li>
- <li>If <tref>prefix</tref> is not underscore (<code>_</code>)
- and <em>suffix</em> does not begin with double-forward-slash
- (<code>//</code>), then it may be a <tref>compact IRI</tref>:
- <ol class="algorithm">
- <li>If <tref>local context</tref> is not <tref>null</tref> and it
- contains a key that equals <tref>prefix</tref>, then invoke the
- <a href="#create-term-definition-subalgorithm">Create Term Definition</a>
- subalgorithm, passing <tref>active context</tref>,
- <tref>local context</tref>, <em>prefix</em> as <em>term</em>,
- and <em>defined</em>. This will ensure that a
- <tref>term definition</tref> is created for <tref>prefix</tref>
- in <tref>active context</tref> during
- <a href="#context-processing">Context Processing</a>.</li>
- <li>If <tref>active context</tref> contains a
- <tref>term definition</tref> for <tref>prefix</tref> that is
- not a <tref>property generator</tref> then set <em>result</em>
- to the result of concatenating the value associated with the
- <tref>prefix</tref>'s <tref>IRI mapping</tref> and
- <em>suffix</em>.</li>
- </ol>
- </li>
- </ol>
- </li>
- <li>If <em>result</em> is <tref>null</tref>, set it to <em>value</em>.</li>
- <li>If <tref>active context</tref> indicates that <em>value</em> is a
- <tref>keyword</tref> alias then return the associated <tref>keyword</tref>.</li>
- <li>If <tref>local context</tref> is <tref>null</tref> and <em>result</em>
- begins with an underscore and colon (<code>_:</code>) then <em>result</em> is a
- <tref>blank node identifier</tref>. Set <em>result</em> to the
- result of the
- <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
- algorithm, passing <tref>active context</tref> and <em>result</em>
- for <em>identifier</em>.</li>
- <li>Otherwise, if <em>result</em> does not contain a colon (<code>:</code>),
- <em>vocabRelative</em> is <tref>true</tref>, and
- <tref>active context</tref> has a <tref>vocabulary mapping</tref>,
- then set <em>result</em> to the result of concatenating the
- <tref>vocabulary mapping</tref> with <em>result</em>.</li>
- <li>Otherwise, if <em>documentRelative</em> is <tref>true</tref>,
- set <em>result</em> to the result of resolving <em>result</em> against
- the document base as per [[RFC3986]]. Only the basic algorithm in
- section 5.2 of [[RFC3986]] is used; neither Syntax-Based Normalization
- nor Scheme-Based Normalization (as described in sections 6.2.2 and
- 6.2.3 of [[RFC3986]]) are performed. Characters additionally allowed in
- IRI references are treated in the same way that unreserved characters
- are treated in URI references, per section 6.5 of [[RFC3987]].</li>
- <li>If <tref>local context</tref> is not <tref>null</tref> then
- <em>result</em> MUST be an <tref>absolute IRI</tref>, if not,
- an <code class="error">invalid IRI mapping</code> error has been
- detected.</li>
<li>Return <em>result</em>.</li>
</ol>
- </section>
-</section> <!-- end of IRI Expansion -->
-
-<section>
-<h2>Value Expansion</h2>
-
-<p>
-Some values in JSON-LD can be expressed in a <tref>compacted form</tref>.
-These values are required to be <tref title="expansion">expanded</tref> at
-times when processing JSON-LD documents. A value is said to be in
-<tdef>expanded form</tdef> after the application of this algorithm.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-A <em>value</em> associated with an <tref>active property</tref> must
-be <tref title="expansion">expanded</tref> to <tref>expanded form</tref>.
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-Other than the simple case where <em>value</em> is <tref>null</tref>, for
-which we return <tref>null</tref>, we must primarily look at <em>value</em>'s
-associated <tref>active property</tref> to determine how to expand it.
-</p>
-
-<p>
-First we <tref title="expansion">expand</tref> the
-<tref>active property</tref> itself, so that we can resolve
-<tref>keyword</tref> aliases. Then, for certain
-<tref title="keyword">keywords</tref> like <code>@id</code> and
-<code>@type</code>, we simply expand <em>value</em>
-using the <a href="#iri-expansion">IRI Expansion</a> algorithm and return
-the result.
-</p>
-
-<p>
-Next, we check to see if <tref>active property</tref> has a
-<tref>type mapping</tref> in the <tref>active context</tref> that would alter
-what we return. If it has one that is <code>@vocab</code> or
-<code>@type</code> or if the <em>expanded property</em> is <code>@graph</code>
-then we return a <tref>JSON object</tref> with a single key-pair of
-<code>@id</code> and the result of using the
-<a href="#iri-expansion">IRI Expansion</a> algorithm on <em>value</em>.
-</p>
-
-<p>
-If we haven't returned yet and the <em>expanded property</em> is a
-<tref>keyword</tref>, then there is no special <tref>expansion</tref> to be
-performed on the <em>value</em>, so we return it as is.
-</p>
-
-<p>
-Otherwise, we'll our result will be a <tref>JSON object</tref> containing
-the key <code>@value</code> with the value the <em>value</em>. Additionally,
-a <code>@type</code> key-value pair will be included if there is a
-<tref>type mapping</tref> associated with the <tref>active property</tref>
-or a <code>@language</code> key-value pair if <em>value</em> is a
-<tref>string</tref> and there is <tref>language mapping</tref>.
-</p>
-
-</section>
+ </section> <!-- end of Find Property Generator Duplicates Subalgorithm -->
+</section> <!-- end of Compaction section -->
+
<section>
-<h3>Algorithm</h3>
-
-<p>
-The algorithm takes three required inputs: an <tref>active context</tref>,
-an <tref>active property</tref>, and a <em>value</em> to expand.
-</p>
-
-<ol class="algorithm">
- <li>
- If <em>value</em> is <tref>null</tref>, then return <tref>null</tref>.
- </li>
- <li>
- Initialize <em>expanded property</em> to the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <tref>active property</tref> for
- <em>value</em>, and <tref>true</tref> for <em>vocabRelative</em>.
- </li>
- <li>
- If <em>expanded property</em> is <code>@id</code> then return
- the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>value</em>, and <tref>true</tref>
- for <em>documentRelative</em>.
- </li>
- <li>
- If <em>expanded property</em> is <code>@type</code> then
- return the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>value</em>, <tref>true</tref> for
- <em>vocabRelative</em>, and <tref>true</tref> for
- <em>documentRelative</em>.
- </li>
- <li>
- If <tref>active property</tref> has a <tref>type mapping</tref> in
- <tref>active context</tref> that is <code>@id</code> or if
- <em>expanded property</em> is <code>@graph</code> and <em>value</em>
- is a <tref>string</tref>, then return a new <tref>JSON object</tref>
- containing a single key-value pair where the key is <code>@id</code> and
- the value is the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>value</em>, and <tref>true</tref> for
- <em>documentRelative</em>.
- </li>
- <li>
- If <tref>active property</tref> has a <tref>type mapping</tref> in
- <tref>active context</tref> that is <code>@vocab</code>, then return
- a new <tref>JSON object</tref> containing a single key-value pair
- where the key is <code>@id</code> and the value is the result of
- using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>value</em>, <tref>true</tref> for
- <em>vocabRelative</em>, and <tref>true</tref> for
- <em>documentRelative</em>.
- </li>
- <li>
- If <em>expanded property</em> is a <tref>keyword</tref> return
- <em>value</em> as is.
- </li>
- <li>
- Otherwise, initialize <em>result</em> to an empty
- <tref>JSON object</tref>.
- </li>
- <li>
- If <tref>active property</tref> has a <tref>type mapping</tref> in
- <tref>active context</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>type</em> to the value associated with the
- <tref>type mapping</tref>.
- </li>
- <li>
- If <em>type</em> is a <tref>blank node identifier</tref> (it
- begins with <code>_:</code>), then set it to the result of the
- <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
- algorithm, passing <tref>active context</tref> and <em>type</em> for
- <em>identifier</em>.
- </li>
- <li>
- Add the key-value pair, (<code>@type</code>-<em>type</em>), to
- <em>result</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, if <em>value</em> is a <tref>string</tref>:
+ <h1>Flattening Algorithms</h1>
+
+ <section>
+ <h2>Flattening Algorithm</h2>
+
+ <p>The algorithm takes two input variables, an <em>element</em> to flatten and a
+ <em>context</em> used to compact the flattened document.</p>
+
<ol class="algorithm">
- <li>
- If <em>value</em> has a <tref>language mapping</tref> in
- <tref>active context</tref> that is not <tref>null</tref>, then
- add a key-value pair to <em>result</em> where the key is
- <code>@language</code> and the value is the value associated with
- the <tref>language mapping</tref>.
- </li>
- <li>
- Otherwise, if <em>value</em> has no <tref>language mapping</tref> in
- <tref>active context</tref> and <tref>active context</tref> has a
- <tref>default language</tref>, then add a key-value pair to
- <em>result</em> where the key is <code>@language</code> and the value
- is the <tref>default language</tref>.
- </li>
- </ol>
- </li>
- <li>
- Finally, add the key-value pair, (<code>@value</code>-<em>value</em>), to
- <em>result</em> and return <em>result</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Value Expansion -->
-</section>
-
-<section>
- <h2>Label Blank Nodes Subalgorithm</h2>
-
- <p>During <tref>expansion</tref>, it is sometimes necessary to ensure
- all <tref title="blank node">blank nodes</tref> have been labeled. This
- occurs when a <tref>property generator</tref> is used to copy a single
- property's values across multiple properties. This step is necessary to
- ensure that these duplicated values can be later
- <tref title="compaction">recompacted</tref>. Because new labels will
- be assigned to <tref title="blank node">blank nodes</tref>, it is
- important to relabel any existing <tref title="blank node">blank nodes</tref>
- to avoid conflicting names.</p>
-
- <p>The algorithm takes two required inputs: an <tref>active context</tref>,
- and an <em>element</em> to be labeled with
- <tref title="blank node identifier">blank node identifiers</tref>.</p>
-
- <ol class="algorithm">
- <li>If <em>element</em> is an <tref>array</tref>, then for each
- <em>item</em> in <em>element</em>:
- <ol class="algorithm">
- <li>Replace <em>item</em> with the result of using this algorithm
- recursively, passing <tref>active context</tref> and <em>item</em>
- for <em>element</em>.</li>
- </ol>
- </li>
- <li>Otherwise, if <em>element</em> is a <tref>list object</tref>, then
- replace the value of the <code>@list</code> key in <em>element</em>
- with the result of using this algorithm recursively, passing
- <tref>active context</tref> and the value of the <code>@list</code> key
- for <em>element</em>.</li>
- <li>Otherwise, if <em>element</em> is a <tref>node object</tref>:
- <ol class="algorithm">
- <li>If <em>element</em> has no <code>@id</code> member, i.e., it
- represents an unlabeled <em>blank node</em>, add an <code>@id</code>
- member to element and set its value to the result of using the
- <a href="#generate-blank-node-identifier">Generate Blank Node Identifier</a>
- algorithm.</li>
- <li>For each <em>key</em>-<em>value</em> pair ordered lexicographically
- by <em>key</em>:
- <ol class="algorithm">
- <li>If <em>key</em> is not <code>@id</code>, then replace
- <em>value</em> in <em>element</em> with the result of using
- this algorithm recursively, passing <tref>active context</tref>
- and <em>value</em> for <em>element</em>.</li>
- </ol>
- </li>
- </ol>
- </li>
- <li>Return <em>element</em>.</li>
- </ol>
-</section>
-
-<section>
- <h2>Generate Blank Node Identifier</h2>
-
- <p>This algorithm is used to generate new
- <tref title="blank node identifier">blank node identifiers</tref> or to
- relabel an existing <tref>blank node identifier</tref> to avoid collision
- by the introduction of new ones. Between its executions, the algorithm
- needs to keep an <em>identifier map</em> to relabel existing
- <tref title="blank node identifier">blank node identifiers</tref> consistently
- and a <em>counter</em> to generate new
- <tref title="blank node identifier">blank node identifiers</tref>. The
- <em>counter</em> is initialized to <code>0</code> by default.</p>
-
- <p>The algorithm takes a single input variable <em>identifier</em> which may
- be <tref>null</tref>.</p>
-
- <ol class="algorithm">
- <li>If the <em>identifier</em> is not <tref>null</tref> and is in the
- <em>identifier map</em>, return the mapped identifier.</li>
- <li>Otherwise, generate a new <em>blankNodeIdentifier</em> by concatenating
- the string <code>_:b</code> and <em>counter</em>.</li>
- <li>Increment <em>counter</em> by <code>1</code>.</li>
- <li>If <em>identifier</em> is not <tref>null</tref>, create a new entry
- for <em>identifier</em> in <em>identifier map</em> and set its value
- to <em>blankNodeIdentifer</em>.</li>
- <li>Return <em>blankNodeIdentifier</em>.</li>
- </ol>
-</section>
-
-<section>
-<h2>Compaction Algorithm</h2>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-<p>A JSON-LD document needs to be compacted, such that the given
- <tref>context</tref> is applied. This must result in shortening
- any applicable <tref title="IRI">IRIs</tref> to
- <tref title="term">terms</tref> or
- <tref title="compact IRI">compact IRIs</tref> and
- any applicable <tref title="JSON-LD value">JSON-LD values</tref>
- expressed in <tref>expanded form</tref> to simple values such as
- <tref title="string">strings</tref> or
- <tref title="number">numbers</tref>.</p>
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>Starting with its root <em>element</em>, we can process the
- JSON-LD document recursively, until we have a fully
- <tref title="compaction">compacted</tref> <em>result</em>. When
- <tref title="compaction">compacting</tref> an <em>element</em>, we can treat
- each one differently according to its type, in order to break down the
- problem:</p>
-
-<ol>
- <li>If the <em>element</em> is a <tref>scalar</tref>, it is
- already in <tref>compacted form</tref>, so we simply return it.</li>
- <li>If the <em>element</em> is an <tref>array</tref>, we compact
- each of its items recursively and return them in a new
- <tref>array</tref>.</li>
- <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.
- We start by creating a shallow copy of it and each of its
- key's <tref>array</tref> values. This is done so that if any key
- is compacted to a <tref>property generator</tref> <tref>term</tref>,
- we can remove duplicate values without modifying the original
- <em>element</em>. Then, we compact each value in the shallow copy
- for each key recursively. Some of the keys will be
- compacted, using the
- <a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm,
- to <tref title="term">terms</tref> or
- <tref title="compact IRI">compact IRIs</tref> and others will be
- compacted from <tref title="keyword">keywords</tref> to
- <tref>keyword</tref> aliases or simply left unchanged because
- they do not have definitions in the <tref>context</tref>. Values will
- be converted to <tref>compacted form</tref> via the
- <a href="#value-compaction">Value Compaction</a> algorithm. Some data
- will be reshaped based on
- <tref title="container mapping">container mappings</tref> specified
- in the context such as <code>@index</code> or <code>@language</code>
- maps.</li>
-</ol>
-
-<p>The final output is a <tref>JSON object</tref> with a <code>@context</code>
- key, if a <tref>context</tref> was given, where the <tref>JSON object</tref>
- is either <em>result</em> or a wrapper for it where <em>result</em> appears
- as the value of an aliased <code>@graph</code> key because <em>result</em>
- contained two or more items in an <tref>array</tref>. If no
- <tref>context</tref> was given, the <em>result</em> is only simplified
- from an <tref>array</tref> to a <tref>JSON object</tref> if it has one or
- fewer items.</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>The algorithm takes four required input variables: an
- <tref>active context</tref>, an <tref>active property</tref>, and an
- <em>element</em> to be compacted. To begin, the <tref>active context</tref>
- is set to the result of performing
- <a href="#context-processing">Context Processing</a> on the passed
- <em>context</em>, the <tref>active property</tref> is set to
- <tref>null</tref>, and <em>element</em> is set to the result of performing
- the <a href="#expansion-algorithm">Expansion Algorithm</a> on the
- <tref>JSON-LD input</tref>.</p>
-
-<ol class="algorithm">
- <li>If <em>element</em> is a <tref>scalar</tref>, it is already in its most
- compact form, so simply return <em>element</em>.</li>
- <li>
- If <em>element</em> is an <tref>array</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>result</em> to an empty <tref>array</tref>.
- </li>
- <li>
- For each <em>item</em> in <em>element</em>:
+ <li>Expand <em>element</em> according the
+ <a href="#expansion-algorithm">Expansion algorithm</a>.</li>
+ <li>Generate a <em>nodeMap</em> according the
+ <a href="#node-map-generation">Node Map Generation algorithm</a>.</li>
+ <li>Let <em>defaultGraph</em> be the value of the <code>@default</code> member of
+ <em>nodeMap</em>; a <tref>JSON object</tref> representing the <tref>default graph</tref>.</li>
+ <li>For each other <em>graphName</em>-<em>graph</em> pair in <em>nodeMap</em>
+ perform the following steps:
<ol class="algorithm">
- <li>
- Initialize <em>compacted item</em> to the result of using this
- algorithm recursively, passing <tref>active context</tref>,
- <tref>active property</tref>, and <em>item</em> for
- <em>element</em>.
- </li>
- <li>
- If <em>compacted item</em> is not <tref>null</tref>, then append
- it to <em>result</em>.
- </li>
+ <li>If <em>defaultGraph</em> does not have a <em>graphName</em> member, create
+ one and initialize its value to a <tref>JSON object</tref> consisting of an
+ <code>@id</code> member whose value is set to <em>graphName</em>.</li>
+ <li>Add an <code>@graph</code> member set to an empty <tref>array</tref>
+ (referred to as <em>nodes</em>) to the <tref>JSON object</tref> which is the
+ value of the <em>graphName</em> member of <em>nodeMap</em>.</li>
+ <li>For each <em>id</em>-<em>node</em> pair in <em>graph</em> ordered by <em>id</em>,
+ add <em>node</em> to the <em>nodes</em> <tref>array</tref>.</li>
</ol>
</li>
- <li>
- If <em>result</em> contains only one item (it has a length of
- <code>1</code>) and <tref>active property</tref> has no
- <tref>container mapping</tref> in <tref>active context</tref>,
- then set <em>result</em> to its only item.
- </li>
- <li>
- Return <em>result</em>.
- </li>
+ <li>Initialize an empty <tref>array</tref> flattened.</li>
+ <li>For each <em>id</em>-<em>node</em> pair in <em>defaultGraph</em> ordered by <em>id</em>,
+ add <em>node</em> to <em>flattened</em>.</li>
+ <li>If <em>context</em> is <tref>null</tref>, return <em>flattened</em>.</li>
+ <li>Otherwise, return the result of compacting <em>flattened</em> according the
+ <a href="#compaction-algorithm">Compaction algorithm</a> passing <em>context</em>
+ ensuring that the compaction result uses the <code>@graph</code> keyword (or its alias)
+ at the top-level, even if the context is empty or if there is only one element to
+ put in the <code>@graph</code> <tref>array</tref>. This ensures that the returned
+ document has a deterministic structure.</li>
</ol>
- </li>
- <li>Otherwise <em>element</em> is a <tref>JSON object</tref>.</li>
- <li>
- If <em>element</em> contains the key <code>@value</code> or
- if it contains only one key and that key is <code>@id</code>,
- then return the result of using the
- <a href="#value-compaction">Value Compaction</a> algorithm,
- passing <tref>active context</tref>, <tref>active property</tref>,
- and <em>element</em> as <em>value</em>.
- </li>
- <li>
- Create a shallow copy of <em>element</em> and each <tref>array</tref>
- associated with its keys so that duplicate values can be removed
- during <tref>property generator</tref> <tref>compaction</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>shallow</em> to an empty <tref>JSON object</tref>.
- </li>
- <li>
- For each <em>key</em>-<em>value</em> pair in <em>element</em>:
- <ol class="algorithm">
- <li>
- If <em>value</em> is an <tref>array</tref>, then add
- a key-value pair to <em>shallow</em> where the key
- is <em>key</em> and the value is a shallow copy of
- <em>value</em>.
- </li>
- <li>
- Otherwise, add the key-value pair, <em>key</em>-<em>value</em>
- to <em>shallow</em>.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- Initialize <em>result</em> to an empty <tref>JSON object</tref>.
- </li>
- <li>
- Initialize <em>keys</em> to an <tref>array</tref> containing
- all of the keys in <em>shallow</em>, ordered lexicographically.
- </li>
- <li>
- For each key <em>expanded property</em> in <em>keys</em>:
+ </section> <!-- end of Flattening Algorithm -->
+
+ <section>
+ <h2>Node Map Generation</h2>
+
+ <p>This algorithm creates a <tref>JSON object</tref> <em>nodeMap</em> holding an indexed
+ representation of the <tref title="JSON-LD graph">graphs</tref> and <tref title="node">nodes</tref>
+ represented in the passed, expanded document. All <tref title="node">nodes</tref> that are not
+ uniquely identified by an IRI get assigned a (new) <tref>blank node identifier</tref>.
+ The resulting <em>nodeMap</em> will have a member for every graph in the document whose
+ value is another object with a member for every <tref>node</tref> represented in the document.
+ The default graph is stored under the <code>@default</code> member, all other graphs are
+ stored under their <tref>graph name</tref>.</p>
+
+ <p>The algorithm takes as input an expanded JSON-LD document <em>element</em> and a reference to
+ a <tref>JSON object</tref> <em>nodeMap</em>. Furthermore it has the optional parameters
+ <tref>active graph</tref> (which defaults to <code>@default</code>), an <tref>active subject</tref>,
+ <tref>active property</tref>, and a reference to a <tref>JSON object</tref> <em>list</em>. The
+ <em>nodeMap</em> must be initialized to a <tref>JSON object</tref> consisting of a single member
+ whose name corresponds with <tref>active graph</tref> and whose value is an empty <tref>JSON object</tref>.</p>
+
<ol class="algorithm">
- <li>
- If <em>shallow</em> does not contain a key that equals
- <em>expanded property</em>, then continue to the next
- <em>expanded property</em>.
- </li>
- <li>
- Initialize <em>expanded value</em> to the value associated
- with the key that equals <em>expanded property</em> in
- <em>shallow</em>.
- </li>
- <li>
- If <em>expanded property</em> is <code>@id</code> or
- <code>@type</code>:
- <ol class="algorithm">
- <li>
- If <em>expanded value</em> is a <tref>string</tref>,
- then initialize <em>compacted value</em> to the result
- of using the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref>,
- <em>expanded value</em> for <em>iri</em>,
- and <tref>true</tref> for <em>vocabRelative</em> if
- <em>expanded property</em> is <code>@type</code>,
- <tref>false</tref> otherwise.
- </li>
- <li>
- Otherwise, <em>expanded value</em> must be a
- <code>@type</code> <tref>array</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>compacted value</em> to an empty
- <tref>array</tref>.
- </li>
- <li>
- For each item <em>expanded type</em> in
- <em>expanded value</em>, append the result of
- of using the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref>,
- <em>expanded type</em> for <em>iri</em>, and
- <tref>true</tref> for <em>vocabRelative</em>,
- to <em>compacted value</em>.
- </li>
- <li>
- If <em>compacted value</em> contains only one
- item (it has a length of <code>1</code>), then
- set <em>compacted value</em> to its only item.
- </li>
- </ol>
- </li>
- <li>
- Initialize <em>alias</em> to the result of using the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref> and
- <em>expanded property</em> for <em>iri</em>.
- </li>
- <li>
- Add the key-value pair,
- (<em>alias</em>-<em>compacted value</em>) to
- <em>result</em> and continue to the next
- <em>expanded property</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>expanded property</em> is <code>@index</code>:
+ <li>If <em>element</em> is an array, process each entry in <em>element</em> recursively, using this algorithm
+ and return.</li>
+ <li>Otherwise <em>element</em> is a <tref>JSON object</tref>. Let <em>activeGraph</em> be the
+ <tref>JSON object</tref> which is the value of the <tref>active graph</tref> member of
+ <em>nodeMap</em>.</li>
+ <li>If it has an <code>@type</code> member, perform for each <em>item</em> the following
+ steps:
<ol class="algorithm">
- <li>
- If <tref>active property</tref> has a
- <tref>container mapping</tref> in <tref>active context</tref>
- that is <code>@index</code>, then the compacted
- result will be inside of an <code>@index</code>
- container, so simply drop the <code>@index</code>
- property by continuing to the next
- <em>expanded property</em>.
- </li>
- <li>
- Otherwise, initialize <em>alias</em> to the result of using
- the <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref> and
- <em>expanded property</em> for <em>iri</em>.
- </li>
- <li>
- Add the key-value pair,
- (<em>alias</em>-<em>expanded value</em>) to
- <em>result</em> and continue to the next
- <em>expanded property</em>.
- </li>
+ <li>If <em>item</em> is a <tref>blank node identifier</tref>, replace it with a
+ <a href="#generate-blank-node-identifier">new blank node identifier</a>.</li>
+ <li>If <em>activeGraph</em> has no member <em>item</em>, create it and initialize its
+ value to a <tref>JSON object</tref> consisting of a single member <code>@id</code>
+ with the value <em>item</em>.</li>
</ol>
</li>
- <li>
- If <em>expanded value</em> is an empty <tref>array</tref>:
+ <li>If <em>element</em> has an <code>@value</code> member, perform the following steps:
<ol class="algorithm">
- <li>
- Initialize <em>item active property</em> to the result of
- using the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref>,
- <em>expanded property</em> for <em>iri</em>,
- <em>expanded value</em> for <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>, and
- <em>shallow</em> for <em>parent</em>.
- </li>
- <li>
- If <em>result</em> does not have the key that equals
- <em>item active property</em>, set this key's value in
- <em>result</em> to an empty <tref>array</tref>. Otherwise, if
- the key's value is not an <tref>array</tref>, then set it
- to one containing only the value.
- </li>
+ <li>If no <em>list</em> has been passed, merge <em>element</em> into the
+ <tref>active property</tref> member of the <tref>active subject</tref> in
+ <em>activeGraph</em>.</li>
+ <li>Otherwise, append <em>element</em> to the <code>@list</code> member of <em>list</em>.</li>
</ol>
</li>
- <li>
- At this point, <em>expanded value</em> must be an
- <tref>array</tref> due to the
- <a href="#expansion-algorithm">Expansion algorithm</a>.
- For each item <em>expanded item</em> in <em>expanded value</em>:
+ <li>Otherwise, if <em>element</em> has an <code>@list</code> member, perform
+ the following steps:
<ol class="algorithm">
- <li>
- Initialize <em>item active property</em> to the result of using
- the <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref>,
- <em>expanded property</em> for <em>iri</em>,
- <em>expanded item</em> for <em>value</em>,
- <tref>true</tref> for <em>vocabRelative</em>, and
- <em>shallow</em> for <em>parent</em>.
- </li>
- <li>
- Initialize <em>container</em> to <tref>null</tref>. If there
- is a <tref>container mapping</tref> for
- <em>item active property</em> in <tref>active context</tref>,
- set <em>container</em> to its value.
- </li>
- <li>
- If there is a <tref>term definition</tref> for
- <em>item active property</em> in <tref>active context</tref>
- that is a <tref>property generator</tref>, then invoke the
- <a href="#find-property-generator-duplicates-subalgorithm">Find Property Generator Duplicates</a>
- algorithm, passing <tref>active context</tref>,
- <em>shallow</em> for <em>element</em>,
- <em>expanded property</em>, <em>expanded item</em> for
- <em>value</em>, <em>item active property</em> for
- <tref>active property</tref>, and
- <tref>true</tref> for <em>remove</em>.
- </li>
- <li>
- Initialize <em>compacted item</em> to the result of using
- this algorithm recursively, passing
- <tref>active context</tref>, <em>item active property</em>
- for <tref>active property</tref>,
- <em>expanded item</em> for <em>element</em> if it does
- not contain the key <code>@list</code>, otherwise pass
- the key's associated value for <em>element</em>.
- </li>
- <li>
- If <em>expanded item</em> is a <tref>list object</tref>:
+ <li>Initialize a new <tref>JSON object</tref> <em>result</em> having a single member
+ <code>@list</code> whose value is initialized to an empty <tref>array</tref>.</li>
+ <li>Recursively call this algorithm passing the value of <em>element's</em>
+ <code>@list</code> member as new <em>element</em> and <em>result</em> as <em>list</em>.</li>
+ <li>If <tref>active property</tref> is <tref>null</tref> or <code>@graph</code>,
+ <a href="#generate-blank-node-identifier">generate a blank node identifier</a> <em>id</em>
+ and store <em>result</em> as value of the member <em>id</em> in <em>activeGraph</em>.</li>
+ <li>Otherwise, add <em>result</em> to the the value of the <tref>active property</tref> member
+ of the <tref>active subject</tref> in <em>activeGraph</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise <em>element</em> is a <tref>node object</tref>, perform the following
+ steps:
+ <ol class="algorithm">
+ <li>If <em>element</em> has an <code>@id</code> member, store its value in <em>id</em> and remove
+ the member from <em>element</em>. If <em>id</em> is a <tref>blank node identifier</tref>, replace it with
+ <a href="#generate-blank-node-identifier">a new blank node identifier</a>.</li>
+ <li>Otherwise <a href="#generate-blank-node-identifier">generate a new blank node identifier</a>
+ and store it as <em>id</em>.</li>
+ <li>If <em>activeGraph</em> does not contain a member <em>id</em>, create one and initialize
+ it to a <tref>JSON object</tref> consisting of a single member <code>@id</code> whose
+ value is set to <em>id</em>.</li>
+ <li>If <tref>active property</tref> is not <tref>null</tref>, perform the following steps:
<ol class="algorithm">
- <li>
- If <em>compacted item</em> is not an <tref>array</tref>,
- then set it to an <tref>array</tref> containing only
- <em>compacted item</em>.
- </li>
- <li>
- If <em>container</em> is not <code>@list</code>:
- <ol class="algorithm">
- <li>
- Convert <em>compacted item</em> to a
- <tref>list object</tref> by setting it to a
- <tref>JSON object</tref> containing key-value pair
- where the key is the result of the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@list</code> for <em>iri</em>, and the
- value is <em>compacted item</em>.
- </li>
- <li>
- If <em>expanded item</em> contains the key
- <code>@index</code>, then add a key-value pair
- to <em>compacted item</em> where the key is the
- result of the
- <a href="#iri-compaction-algorithm">IRI Compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@index</code> for <em>iri</em>, and the
- value is the value associated with the
- <code>@index</code> key in
- <em>expanded item</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, <em>item active property</em> MUST NOT be a key
- in <em>result</em> because there cannot be two
- <tref title="list object">list objects</tref> associated
- with an <tref>active property</tref> that has a
- <tref>container mapping</tref>; a
- <code class="error">compaction to list of lists</code> error
- has been detecetd.
- </li>
+ <li>Create a new <tref>JSON object</tref> <em>reference</em> consisting of a single member
+ <code>@id</code> whose value is <em>id</em>.</li>
+ <li>If no <em>list</em> has been passed, merge <em>element</em> into the
+ <tref>active property</tref> member of the <tref>active subject</tref> in
+ <em>activeGraph</em>.</li>
+ <li>Otherwise, append <em>element</em> to the <code>@list</code> member of <em>list</em>.</li>
</ol>
</li>
- <li>
- If <em>container</em> is <code>@language</code> or
- <code>@index</code>:
+ <li>If <em>element</em> has an <code>@type</code> member, merge each value into the <code>@type</code>
+ of <tref>active subject</tref> in <em>activeGraph</em>. Then remove the <code>@type</code> member
+ from <em>element</em>.</li>
+ <li>If <em>element</em> has an <code>@index</code> member, set the <code>@index</code>
+ of <tref>active subject</tref> in <em>activeGraph</em> to its value. There MUST be no
+ existing member already in <tref>active subject</tref> with a different value, if there
+ is, then a <code class="error">conflicting indexes</code> error has been detected. Continue and remove the
+ <code>@index</code> from <em>element</em>.</li>
+ <li>If <em>element</em> has an <code>@graph</code> member, recursively invoke this algorithm passing
+ the value of the <code>@graph</code> member as new <em>element</em> and <em>id</em> as new
+ <tref>active subject</tref>. Then remove the <code>@graph</code> member from <em>element</em>.</li>
+ <li>Finally for each <em>property</em>-<em>value</em> pair in <em>element</em> ordered by
+ <em>property</em> perform the following steps:
<ol class="algorithm">
- <li>
- If <em>item active property</em> is a key in
- <em>result</em>, then initialize <em>map object</em> to
- its associated value, otherwise initialize it to an empty
- <tref>JSON object</tref>.
- </li>
- <li>
- If <em>container</em> is <code>@language</code> and
- <em>compacted item</em> contains the key
- <code>@value</code>, then set <em>compacted item</em>
- to the value associated with its <code>@value</code> key.
- </li>
- <li>
- Initialize <em>map key</em> to the value associated with
- with the key that equals <em>container</em> in
- <em>expanded item</em>.
- </li>
- <li>
- If <em>map key</em> is not a key in <em>map object</em>,
- then set this key's value in <em>map object</em>
- to <em>compacted item</em>. Otherwise, if the value
- is not an <tref>array</tref>, then set it to one
- containing only the value and then append
- <em>compacted item</em> to it.
- </li>
- </ol>
- </li>
- <li>
- Otherwise,
- <ol class="algorithm">
- <li>
- Initialize <em>useArray</em> to <tref>false</tref>. If
- <em>container</em> is <code>@set</code> or
- <code>@list</code>, or <em>compacted item</em> is
- an empty <tref>array</tref>, or
- <em>expanded property</em> is <code>@list</code> or
- <code>@graph</code>, then set <em>useArray</em>
- to <tref>true</tref>.
- </li>
- <li>
- If <em>useArray</em> is <tref>true</tref> and
- <em>compacted item</em> is not an <tref>array</tref>,
- then set it to a new <tref>array</tref>
- containing only <em>compacted item</em>.
- </li>
- <li>
- If <em>item active property</em> is not a key in
- <em>result</em> then add the key-value pair,
- (<em>item active property</em>-<em>compacted item</em>),
- to <em>result</em>.
- </li>
- <li>
- Otherwise, if the value associated with the key that
- equals <em>item active property</em> in <em>result</em>
- is not an <tref>array</tref>, set it to a new
- <tref>array</tref> containing only the value. Then
- append <em>compacted item</em> to the value if
- <em>compacted item</em> is not an <tref>array</tref>,
- otherwise, concatenate it.
- </li>
+ <li>If no <em>property</em> member exists in the <tref>JSON object</tref> which is the
+ value of the <em>id</em> member of <em>activeGraph</em> create the member and initialize
+ its value to an empty <tref>array</tref>.</li>
+ <li>Recursively invoke this algorithm passing <em>value</em> as new <em>element</em>, <em>id</em>
+ as new <tref>active subject</tref>, and <em>property</em> as new <tref>active property</tref>.</li>
</ol>
</li>
</ol>
</li>
</ol>
- </li>
- <li>Return <em>result</em>.</li>
-</ol>
-
-<p>
-If, after the algorithm outlined above is run, the result <em>result</em> is
-an <tref>array</tref> with two or more items and a <em>context</em> has
-been passed, replace it with a new <tref>JSON object</tref> with a single
-key-value pair where the key is the result of using the
-<a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, passing
-<tref>active context</tref> and <code>@graph</code> for <em>iri</em>, and
-the value is <em>result</em>. Otherwise, if <em>result</em> is an
-<tref>array</tref> with only one item, set <em>result</em> to that item.
-Otherwise, if <em>result</em> is an <tref>array</tref> with zero items,
-replace it with an empty <tref>JSON object</tref>. Finally, if a
-<em>context</em> has been passed, add an <code>@context</code> property to
-<em>result</em> and set its value to the initially passed
-<em>context</em>.
-</p>
-
-</section>
-
-<!-- end of Compaction -->
-</section>
-
-<section>
-<h2>IRI Compaction Algorithm</h2>
-
-<p>This section defines an algorithm for transforming an <tref>IRI</tref>
- to a <tref>term</tref> or <tref>compact IRI</tref>, or a <tref>keyword</tref>
- alias to a <tref>keyword</tref>. A value that is associated with the
- <tref>IRI</tref> may be passed in order to assist in selecting the most
- context-appropriate <tref>term</tref>.</p>
-
-<section class="informative">
- <h3>Purpose</h3>
-
- <p>We have an <tref>IRI</tref> (or <tref>keyword</tref>) that we may
- be able to compact to <tref>term</tref>, <tref>compact IRI</tref>, or
- <tref>keyword</tref> alias.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>First, we handle the simple cases: if the value given as an <tref>IRI</tref>
- is <tref>null</tref>, we simply return <tref>null</tref> and if it is a
- <tref>keyword</tref> we return its associated alias.</p>
-
- <p>Otherwise, we first try to find a <tref>term</tref> that the
- <tref>IRI</tref> can be <tref title="compaction">compacted</tref> to if
- it is relative to <tref title="active context">active context's</tref>'s
- <tref>vocabulary mapping</tref>. In order to select a <tref>term</tref>, we
- have to collect information about the <tref title="IRI">IRI's</tref>
- associated value. This information includes which
- <tref title="container mapping">container mappings</tref>
- would be preferred for expressing the value, and what its
- <tref>type mapping</tref> or <tref>language mapping</tref> is. For
- JSON-LD lists, the <tref>type mapping</tref> or <tref>language mapping</tref>
- 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-subalgorithm">Term Selection</a> subalgorithm, which will
- return the most appropriate <tref>term</tref> to use.</p>
-
- <p>If no <tref>term</tref> was found that could be used to compact the
- <tref>IRI</tref>, then an attempt is made to find a <tref>compact IRI</tref>
- to use. If there is no appropriate <tref>compact IRI</tref>, then, if
- the <tref>IRI</tref> is relative to
- <tref title="active context">active context's</tref>
- <tref>vocabulary mapping</tref>, then it is used. Otherwise, transform it to
- a <tref>relative IRI</tref> using the document's base <tref>IRI</tref>.
- Finally, if the <tref>IRI</tref> still could not be compacted, return it
- as is.</p>
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>This algorithm takes three required inputs and three optional inputs.
- The required inputs an <tref>active context</tref> and the <em>iri</em> to
- be compacted. The optional inputs are: a <em>value</em> associated with
- the <em>iri</em>, a <em>vocabRelative</em> flag which specifies whether the
- passed <em>iri</em> should be compacted using the
- <tref title="active context">active context's</tref>
- <tref>vocabulary mapping</tref>, and the <em>parent</em> element for
- the <em>value</em>. If not passed, <em>value</em> is set to
- <tref>null</tref>, <em>vocabRelative</em> is set to <code>false</code>, and
- <em>parent</em> is set to <tref>null</tref>.</p>
-
-<ol class="algorithm">
- <li>
- If <em>iri</em> is <tref>null</tref>, return <tref>null</tref>.
- </li>
- <li>
- If <em>iri</em> is a <tref>keyword</tref> and does not have a
- <tref>keyword</tref> alias, return <em>iri</em>, otherwise return
- its first associated <tref>keyword</tref> alias from
- <tref>active context</tref>.
- </li>
- <li>
- If <em>vocabRelative</em> is <tref>true</tref> and
- <tref>active context</tref> has no associated
- <tref>inverse context</tref>, then generate it using the
- <a href="#inverse-context-creation-subalgorithm">Inverse Context Creation</a>
- algorithm. Set <em>inverse context</em> to the
- <tref>inverse context</tref> associated with <tref>active context</tref>.
- </li>
- <li>
- If <em>vocabRelative</em> is <tref>true</tref> and <em>iri</em> is a
- key in <em>inverse context</em>:
- <ol class="algorithm">
- <li>
- Initialize <em>defaultLanguage</em> to
- <tref title="active context">active context's</tref>
- <tref>default language</tref>, if it has one, otherwise to
- <code>@none</code>.
- </li>
- <li>
- Initialize <em>containers</em> to an empty <tref>array</tref>. This
- <tref>array</tref> will be used to keep track of an ordered list of
- preferred <tref title="container mapping">container mappings</tref>
- for a <tref>term</tref>, based on what is compatible with
- <em>value</em>.
- </li>
- <li>
- If <em>value</em> is a <tref>JSON object</tref> that contains the
- key <code>@index</code>, then append the value <code>@index</code>
- to <em>containers</em>.
- </li>
- <li>
- Initialize <em>typeOrLanguage</em> to <code>@language</code>,
- and <em>typeOrLanguageValue</em> to <code>@null</code>. These two
- variables will keep track of the preferred
- <tref>type mapping</tref> or <tref>language mapping</tref> for
- a <tref>term</tref>, based on what is compatible with <em>value</em>.
- </li>
- <li>
- If <em>value</em> is a <tref>list object</tref>, then set
- <em>typeOrLanguage</em> and <em>typeOrLanguageValue</em>
- to the most specific values that work for all items in
- the list as follows:
- <ol class="algorithm">
- <li>
- If <code>@index</code> is a not key in <em>value</em>, then
- append <code>@list</code> to <em>containers</em>.
- </li>
- <li>
- Initialize <em>list</em> to the <tref>array</tref> associated
- with the key <code>@list</code> in <em>value</em>.
- </li>
- <li>
- Initialize <em>commonLanguage</em> to <tref>null</tref>. If
- <em>list</em> is empty, set <em>commonLanguage</em> to
- <em>defaultLanguage</em>.
- </li>
- <li>
- For each <em>item</em> in <em>list</em>:
- <ol class="algorithm">
- <li>
- Initialize <em>itemLanguage</em> to <code>@none</code> and
- <em>itemType</em> to <code>@none</code>.
- </li>
- <li>
- If <em>item</em> contains the key <code>@value</code>:
- <ol class="algorithm">
- <li>
- If <em>item</em> contains the key <code>@language</code>,
- then set <em>itemLanguage</em> to its associated
- value.
- </li>
- <li>
- Otherwise, if <em>item</em> contains the key
- <code>@type</code>, set <em>itemType</em> to its
- associated value.
- </li>
- <li>
- Otherwise, set <em>itemLanguage</em> to
- <code>@null</code>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, set <em>itemType</em> to <code>@id</code>.
- </li>
- <li>
- If <em>commonLanguage</em> is <tref>null</tref>, set it
- to <em>itemLanguage</em>.
- </li>
- <li>
- Otherwise, if <em>itemLanguage</em> does not equal
- <em>commonLanguage</em> and <em>item</em> contains the
- key <code>@value</code>, then set <em>commonLanguage</em>
- to <code>@none</code> because list items have conflicting
- languages.
- </li>
- <li>
- If <em>commonType</em> is <tref>null</tref>, set it
- to <em>itemType</em>.
- </li>
- <li>
- Otherwise, if <em>itemType</em> does not equal
- <em>commonType</em>, then set <em>commonType</em>
- to <code>@none</code> because list items have conflicting
- types.
- </li>
- <li>
- If <em>commonLanguage</em> is <code>@none</code> and
- <em>commonType</em> 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 <em>commonLanguage</em> is <tref>null</tref>, set it to
- <code>@none</code>.
- </li>
- <li>
- If <em>commonType</em> is <tref>null</tref>, set it to
- <code>@none</code>.
- </li>
- <li>
- If <em>commonType</em> is not <code>@none</code> then set
- <em>typeOrLanguage</em> to <code>@type</code> and
- <em>typeOrLanguageValue</em> to <em>commonType</em>.
- </li>
- <li>
- Otherwise, set <em>typeOrLanguageValue</em> to
- <em>commonLanguage</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise:
- <ol class="algorithm">
- <li>
- If <em>value</em> contains the key <code>@value</code>:
- <ol class="algorithm">
- <li>
- If <em>value</em> contains the key <code>@language</code>
- and does not contain the key <code>@index</code>,
- then set <em>typeOrLanguageValue</em> to its associated
- value and append <code>@language</code> to
- <em>containers</em>.
- </li>
- <li>
- Otherwise, if <em>value</em> contains the key
- <code>@type</code>, then set <em>typeOrLanguageValue</em> to
- its associated value and set <em>typeOrLanguage</em> to
- <code>@type</code>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, set <em>typeOrLanguage</em> to <code>@type</code>
- and set <em>typeOrLanguageValue</em> to <code>@id</code>.
- </li>
- <li>
- Append <code>@set</code> to <em>containers</em>.
- </li>
- </ol>
- </li>
- <li>
- Initialize <em>term</em> to the result of the
- <a href="#term-selection-subalgorithm">Term Selection</a> subalgorithm, passing
- <tref>active context</tref>, <em>inverse context</em>, <em>iri</em>,
- <em>value</em>, <em>parent</em>, <em>containers</em>,
- <em>typeOrLanguage</em>, and <em>typeOrLanguageValue</em>.
- </li>
- <li>
- If <em>term</em> is not <tref>null</tref>, return <em>term</em>.
- </li>
- </ol>
- </li>
- <li>
- At this point, there is no simple <tref>term</tref> that <em>iri</em>
- can be compacted to. Instead, try to choose a <tref>compact IRI</tref>,
- starting by initializing <em>choice</em> to <tref>null</tref>. This
- variable will be used to store the chosen <tref>compact IRI</tref> to
- use, if any.
- </li>
- <li>
- For each key <tref>term</tref> and value <tref>term definition</tref> in
- the <tref>active context</tref>:
- <ol class="algorithm">
- <li>
- If the <tref>term</tref> contains a colon (<code>:</code>),
- then continue to the next <tref>term</tref> because
- <tref title="term">terms</tref> with colons can't be
- used as <tref title="prefix">prefixes</tref>.
- </li>
- <li>
- If the <tref>term definition</tref> is <tref>null</tref>
- or for a <tref>property generator</tref> or its
- <tref>IRI mapping</tref> equals <em>iri</em> or is not
- a substring at the beginning of <em>iri</em>, then the
- <tref>term</tref> cannot be used as a <tref>prefix</tref>
- because it is not a partial match with <em>iri</em>. So
- continue to the next <tref>term</tref>.
- </li>
- <li>
- Initialize <em>curie</em> by concatenating <tref>term</tref>,
- a colon (<code>:</code>), and the substring of <em>iri</em>
- that follows after the value of the
- <tref title="term definition">term definition's</tref>
- <tref>IRI mapping</tref>.
- </li>
- <li>
- If either <em>choice</em> is <tref>null</tref> or <em>curie</em> is
- shorter or the same length but lexicographically less than
- <em>choice</em> and <em>curie</em> does not have a
- <tref>term definition</tref> in <tref>active context</tref> or if the
- <tref>term definition</tref> has an <tref>IRI mapping</tref>
- that equals <em>iri</em> and <em>value</em> is <tref>null</tref>,
- set <em>choice</em> to <em>curie</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>choice</em> is not <tref>null</tref>, return <em>choice</em>.
- </li>
- <li>
- At this point, there is no <tref>compact IRI</tref> that <em>iri</em>
- can be compacted to, so if <em>vocabRelative</em> is
- <tref>true</tref> and <tref>active context</tref> has a
- <tref>vocabulary mapping</tref>:
- <ol class="algorithm">
- <li>
- If <em>iri</em> begins with the
- <tref title="vocabulary mapping">vocabulary mapping's</tref> value
- but is longer, then initialize <em>suffix</em> to the substring
- of <em>iri</em> that does not match. If <em>suffix</em> does not
- have a <tref>term definition</tref> in <tref>active context</tref>,
- then return <em>suffix</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>vocabRelative</em> is <tref>false</tref> then
- transform <em>iri</em> to a <tref>relative IRI</tref> using
- the document's base <tref>IRI</tref>.
- </li>
- <li>
- Finally, return <em>iri</em> as is.
- </li>
-</ol>
-
-</section>
-
-<!-- end of IRI Compaction -->
-</section>
-
-<section>
-<h2>Inverse Context Creation Subalgorithm</h2>
-
-<p>
-When there is more than one <tref>term</tref> that could be chosen
-to compact an <tref>IRI</tref>, we want to ensure that our <tref>term</tref>
-selection is both deterministic and not unexpected, representing the most
-context-appropriate choice whilst taking into consideration algorithmic
-complexity.
-</p>
-
-<p>
-In order to make <tref>term</tref> selections the concept of an
-<tref>inverse context</tref> is introduced. An <tdef>inverse context</tdef>
-is essentially a reverse lookup table that maps
-<tref title="container mapping">container mappings</tref>,
-<tref title="type mapping">type mappings</tref>, and
-<tref title="language mapping">language mappings</tref> to a simple
-<tref>term</tref> and, if applicable, an <tref>array</tref> of potential
-<tref>property generator</tref> <tref title="term">terms</tref> for
-a given <tref>active context</tref>. A <tref>inverse context</tref> only
-needs to be generated for an <tref>active context</tref> if it is being
-used for <tref>compaction</tref>.
-</p>
-
-<p>
-To make use of an <tref>inverse context</tref>, a list of preferred
-<tref title="container mapping">container mappings</tref> and the
-<tref>type mapping</tref> or <tref>language mapping</tref> are gathered
-for a particular value associated with an <tref>IRI</tref>. These parameters
-are then fed to the <a href="#term-selection-subalgorithm">Term Selection</a>
-subalgorithm, which will find the <tref>term</tref> that most appropriately
-matches the value's mappings.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-An <tref>inverse context</tref> must be created for the given
-<tref>active context</tref>.
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-To create an <tref>inverse context</tref> for a given
-<tref>active context</tref>, each <tref>term</tref> in the
-<tref>active context</tref> is visited, ordered by length, shortest
-first (ties are broken by choosing the lexicographically least
-<tref>term</tref>). For each <tref>term</tref>, an entry is added to
-the <tref>inverse context</tref> for each possible combination of
-<tref>container mapping</tref> and <tref>type mapping</tref>
-or <tref>language mapping</tref> that would legally match the
-<tref>term</tref>. Illegal matches include differences between a
-value's <tref>type mapping</tref> or <tref>language mapping</tref> and
-that of the <tref>term</tref>. If a <tref>term</tref> has no
-<tref>container mapping</tref>, <tref>type mapping</tref>, or
-<tref>language mapping</tref> (or some combination of these), then it
-will have an entry in the <tref>inverse context</tref> using the special
-key <code>@none</code>. This allows the
-<a href="#term-selection-subalgorithm">Term Selection</a> subalgorithm to fall back
-to choosing more generic <tref title="term">terms</tref> when a more
-specifically-matching <tref>term</tref> is not available for a particular
-<tref>IRI</tref> and value combination.
-</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>
-The algorithm takes one required input: the <tref>active context</tref> that
-the <tref>inverse context</tref> is being created for.
-</p>
-
-<ol class="algorithm">
- <li>
- Initialize <em>result</em> to an empty <tref>JSON object</tref>.
- </li>
- <li>
- Initialize <em>defaultLanguage</em> to <code>@none</code>. If the
- <tref>active context</tref> has a <tref>default language</tref>, then
- set <em>defaultLanguage</em> to it.
- </li>
- <li>
- For each key <tref>term</tref> and value <tref>term definition</tref> in
- the <tref>active context</tref>, ordered by shortest <tref>term</tref>
- first (breaking ties by choosing the lexicographically least
- <tref>term</tref>):
- <ol class="algorithm">
- <li>
- If the <tref>term definition</tref> is <tref>null</tref>, then
- <tref>term</tref> cannot be selected during <tref>compaction</tref>,
- so continue to the next <tref>term</tref>.
- </li>
- <li>
- Initialize <em>container</em> to <code>@none</code>. If there
- is a <tref>container mapping</tref> in
- <tref>term definition</tref>, then set <em>container</em> to
- its associated value.
- </li>
- <li>
- Initialize <em>iris</em> to the value of the <tref>IRI mapping</tref>
- for the <tref>term definition</tref>. If <em>iris</em> is not an
- <tref>array</tref>, then set it to an <tref>array</tref> containing
- only <em>iris</em>.
- </li>
- <li>
- For each item <em>iri</em> in <em>iris</em>:
- <ol class="algorithm">
- <li>
- If <em>iri</em> is not a key in <em>result</em>, then add
- a key-value pair where the key is <em>iri</em> and the value
- is an empty <tref>JSON object</tref> to <em>result</em>.
- </li>
- <li>
- Initialize <em>container map</em> to the value associated with
- the <em>iri</em> key in <em>result</em>.
- </li>
- <li>
- If <em>container</em> is not a key in <em>container map</em>,
- then initialize <em>typeOrLanguage map</em> to a new
- <tref>JSON object</tref>. Add two key-value pairs to
- <em>typeOrLanguage map</em>, where the first's key is
- <code>@language</code> and its value is a new
- <tref>JSON object</tref> and where the second's key is
- <code>@type</code> and its value is a new
- <tref>JSON object</tref>.
- </li>
- <li>
- Set <em>typeOrLanguage map</em> to the value associated with
- the key <em>container</em> in <em>container map</em>.
- </li>
- <li>
- If there is no <tref>type mapping</tref> in the
- <tref>term definition</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>language map</em> to the value associated
- with the key <code>@language</code> in
- <em>typeOrLanguage map</em>.
- </li>
- <li>
- If there is a <tref>language mapping</tref> in the
- <tref>term definition</tref>:
- <ol class="algorithm">
- <li>
- If the value of the <tref>language mapping</tref>
- is <tref>null</tref> initialize <em>language</em>
- to <code>@null</code>, otherwise initialize it to the
- value.
- </li>
- <li>
- If <em>language</em> is not a key in
- <em>language map</em>, then add a key-value
- pair to <em>language map</em> where the key is
- <em>language</em> and the value is a new
- <tref>JSON object</tref> with two key-value
- pairs, where the first's key is <code>term</code>
- and its value is <tref>null</tref>, and the second's
- key is <code>propertyGenerators</code> and the
- value is an empty <tref>array</tref>.
- </li>
- <li>
- Initialize <em>entry</em> to the value associated with
- the key <em>language</em> in <em>language map</em>.
- </li>
- <li>
- If <tref>term definition</tref> is a
- <tref>property generator</tref>, append the
- <tref>term</tref> to the <tref>array</tref> associated
- with the <code>propertyGenerators</code> key in
- <em>entry</em>.
- </li>
- <li>
- Otherwise, if the value associated with the key
- <code>term</code> in <em>entry</em> is <tref>null</tref>,
- set it to the <tref>term</tref>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise:
- <ol class="algorithm">
- <li>
- If <em>defaultLanguage</em> is not a key in
- <em>language map</em>, then add a key-value
- pair to <em>language map</em> where the key is
- <em>defaultLanguage</em> and the value is a new
- <tref>JSON object</tref> with two key-value
- pairs, where the first's key is <code>term</code>
- and its value is <tref>null</tref>, and the second's
- key is <code>propertyGenerators</code> and the
- value is an empty <tref>array</tref>.
- </li>
- <li>
- Initialize <em>entry</em> to the value associated with
- the key <em>defaultLanguage</em> in <em>language map</em>.
- </li>
- <li>
- If <tref>term definition</tref> is a
- <tref>property generator</tref>, append the
- <tref>term</tref> to the <tref>array</tref> associated
- with the <code>propertyGenerators</code> key in
- <em>entry</em>.
- </li>
- <li>
- Otherwise, if the value associated with the key
- <code>term</code> in <em>entry</em> is <tref>null</tref>,
- set it to the <tref>term</tref>.
- </li>
- <li>
- If <code>@none</code> is not a key in
- <em>language map</em>, then add a key-value
- pair to <em>language map</em> where the key is
- <code>@none</code> and the value is a new
- <tref>JSON object</tref> with two key-value
- pairs, where the first's key is <code>term</code>
- and its value is <tref>null</tref>, and the second's
- key is <code>propertyGenerators</code> and the
- value is an empty <tref>array</tref>.
- </li>
- <li>
- Set <em>entry</em> to the value associated with
- the key <code>@none</code> in <em>language map</em>.
- </li>
- <li>
- If <tref>term definition</tref> is a
- <tref>property generator</tref>, append the
- <tref>term</tref> to the <tref>array</tref> associated
- with the <code>propertyGenerators</code> key in
- <em>entry</em>.
- </li>
- <li>
- Otherwise, if the value associated with the key
- <code>term</code> in <em>entry</em> is <tref>null</tref>,
- set it to the <tref>term</tref>.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- If there is no <tref>language mapping</tref> in the
- <tref>term definition</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>type map</em> to the value associated
- with the key <code>@type</code> in
- <em>typeOrLanguage map</em>.
- </li>
- <li>
- If there is a <tref>type mapping</tref> in the
- <tref>term definition</tref> then initialize <em>type</em>
- to its value, otherwise initialize it to
- to <code>@none</code>.
- </li>
- <li>
- If <em>type</em> is not a key in <em>type map</em>, then
- add a key-value pair to <em>type map</em> where the key is
- <em>type</em> and the value is a new <tref>JSON object</tref>
- with two key-value pairs, where the first's key is
- <code>term</code> and its value is <tref>null</tref>, and the
- second's key is <code>propertyGenerators</code> and the
- value is an empty <tref>array</tref>.
- </li>
- <li>
- Initialize <em>entry</em> to the value associated with
- the key <em>type</em> in <em>type map</em>.
- </li>
- <li>
- If <tref>term definition</tref> is a
- <tref>property generator</tref>, append the
- <tref>term</tref> to the <tref>array</tref> associated
- with the <code>propertyGenerators</code> key in
- <em>entry</em>.
- </li>
- <li>
- Otherwise, if the value associated with the key
- <code>term</code> in <em>entry</em> is <tref>null</tref>,
- set it to the <tref>term</tref>.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- Return <em>result</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Inverse Context Creation subalgorithm -->
-</section>
-
-<section>
-<h2>Term Selection Subalgorithm</h2>
-
-<p>
-This subalgorithm, invoked via the
-<a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, makes use
-of an <tref title="active context">active context's</tref>
-<tref>inverse context</tref> to find the <tref>term</tref> that is best
-used to <tref title="compaction">compact</tref> an <tref>IRI</tref>. Other
-information about a value associated with the <tref>IRI</tref> is given,
-including which <tref title="container mapping">container mappings</tref>
-and which <tref>type mapping</tref> or <tref>language mapping</tref> would
-be best used to express the value.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-An <tref>IRI</tref> with an associated <em>value</em> should be compacted
-to the most appropriate <tref>term</tref> in the <tref>active context</tref>.
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-The <tref title="inverse context">inverse context's</tref> entry for
-the <tref>IRI</tref> will be first searched according to the preferred
-<tref title="container mapping">container mappings</tref>, in the order
-that they are given. Amongst <tref title="term">terms</tref> with a matching
-<tref>container mapping</tref>, preference will be given to those
-with a matching <tref>type mapping</tref> or <tref>language mapping</tref>,
-over those without a <tref>type mapping</tref> or
-<tref>language mapping</tref>. If there is no <tref>term</tref>
-with a matching <tref>container mapping</tref> then the <tref>term</tref>
-without a <tref>container mapping</tref> that matches the given
-<tref>type mapping</tref> or <tref>language mapping</tref> is selected. If
-there is still no selected <tref>term</tref>, then a <tref>term</tref>
-with no <tref>type mapping</tref> or <tref>language mapping</tref> will
-be selected if available. No <tref>term</tref> will be selected that
-has a conflicting <tref>type mapping</tref> or <tref>language mapping</tref>.
-Ties between <tref title="term">terms</tref> 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-subalgorithm">Inverse Context Creation algorithm</a>
-was used to create the <tref>inverse context</tref>.
-</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>
-This subalgorithm has eight required inputs. They are:
-an <tref>active context</tref>, an <tref>inverse context</tref>, an
-<tref>IRI</tref> <em>iri</em>, a <em>value</em> associated with the
-<tref>IRI</tref>, the expanded <em>parent</em> element for <em>value</em>
-(which may be a <tref>JSON object</tref>, an <tref>array</tref>, or
-<tref>null</tref>), an <tref>array</tref> <em>containers</em> that
-represents ordered list of preferred
-<tref title="container mapping">container mappings</tref>, a
-<tref>string</tref> <em>typeOrLanguage</em> that indicates whether
-to look for a <tref>term</tref> with a matching <tref>type mapping</tref>
-or <tref>language mapping</tref>, and a <tref>string</tref>
-<em>typeOrLanguageValue</em> with the associated value for the
-<tref>type mapping</tref> or <tref>language mapping</tref> to look for.
-</p>
-
-<ol class="algorithm">
- <li>
- Append <code>@none</code> to <em>containers</em>. This represents
- the non-existence of a <tref>container mapping</tref>, and it will
- be the last <tref>container mapping</tref> value to be checked as it
- is the most generic.
- </li>
- <li>
- Initialize <em>container map</em> to the value associated with
- <em>iri</em> in the <tref>inverse context</tref>.
- </li>
- <li>
- If <em>typeOrLanguageValue</em> is <tref>null</tref>, set it to
- <code>@null</code>. This is the key under which <tref>null</tref> values
- are stored in the <tref>inverse context</tref> <em>entry</em>.
- </li>
- <li>
- Initialize <em>preferred values</em> to an empty <tref>array</tref>.
- This <tref>array</tref> will indicate, in order, the preferred values for
- a <tref title="term">term's</tref> <tref>type mapping</tref> or
- <tref>language mapping</tref>.
- </li>
- <li>
- If <em>typeOrLanguageValue</em> is <code>@id</code> and
- <em>value</em> is a <tref>JSON object</tref> containing the key
- <code>@id</code>:
- <ol class="algorithm">
- <li>
- If the result of using the
- <a href="#iri-compaction-algorithm">IRI compaction</a> algorithm,
- passing <tref>active context</tref>, the value associated with the
- <code>@id</code> key in <em>value</em> for
- <em>iri</em>, <tref>true</tref> for <em>vocabRelative</em>, and
- <tref>true</tref> for <em>documentRelative</em> has a
- <tref>term definition</tref> in the <tref>active context</tref>
- with an <tref>IRI mapping</tref> that equals the value associated
- with the <code>@id</code> key in <em>value</em>,
- then append <code>@vocab</code>, <code>@id</code>, and
- <code>@none</code>, in that order, to <em>preferred values</em>.
- </li>
- <li>
- Otherwise, append <code>@id</code>, <code>@vocab</code>, and
- <code>@none</code>, in that order, to <em>preferred values</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, append <em>typeOrLanguageValue</em> and <code>@none</code>, in
- that order, to <em>preferred values</em>.
- </li>
- <li>
- Initialize <em>selected term</em> to <tref>null</tref>.
- </li>
- <li>
- For each item <em>container</em> in <em>containers</em> while
- <em>selected term</em> is <tref>null</tref>:
- <ol class="algorithm">
- <li>
- If <em>container</em> is not a key in <em>container map</em>, then
- there is no <tref>term</tref> with a matching
- <tref>container mapping</tref> for it, so continue to the next
- <em>container</em>.
- </li>
- <li>
- Initialize <em>typeOrLanguage map</em> to the value associated
- with <em>container</em> in <em>container map</em>.
- </li>
- <li>
- Initialize <em>typeOrLanguageValue map</em> to the value associated
- with <em>typeOrLanguage</em> in <em>typeOrLanguage map</em>.
- </li>
- <li>
- For each <em>item</em> in <em>preferred values</em> while
- <em>selected term</em> is <tref>null</tref>:
- <ol class="algorithm">
- <li>
- If <em>item</em> is not a key in <em>typeOrLanguageValue map</em>,
- then there is no <tref>term</tref> with a matching
- <tref>type mapping</tref> or <tref>language mapping</tref>,
- so continue to the next <em>item</em>.
- </li>
- <li>
- Initialize <em>termInfo</em> to the value associated with
- <em>item</em> in <em>typeOrLanguageValue map</em>.
- </li>
- <li>
- If <em>parent</em> is a <tref>JSON object</tref>,
- then for each <tref>property generator</tref> <tref>term</tref>
- <em>propertyGeneratorTerm</em> in <em>termInfo</em> while
- <em>selected term</em> is <tref>null</tref>:
- <ol class="algorithm">
- <li>
- Initialize <em>match</em> to the result of using the
- <a href="#find-property-generator-duplicates-subalgorithm">Find Property Generator Duplicates</a>
- algorithm, passing <tref>active context</tref>,
- <em>parent</em> for <em>element</em>, <em>iri</em> for
- <em>expanded property</em>, <em>value</em>,
- <em>propertyGeneratorTerm</em> for <em>activeProperty</em>,
- and <tref>false</tref> for <em>remove</em>.
- </li>
- <li>
- If <em>match</em> is <tref>true</tref>, then set
- <em>selected term</em> to <em>propertyGeneratorTerm</em>.
- </li>
- </ol>
- </li>
- <li>
- If <em>selected term</em> is <tref>null</tref>, then no
- <tref>property generator</tref> match was found, so set
- <em>selected term</em> to the non-<tref>property generator</tref>
- <tref>term</tref> in <em>termInfo</em>, which may be
- <tref>null</tref>.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- Return <em>selected term</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Term Selection subalgorithm -->
-</section>
-
-<section>
-<h2>Value Compaction</h2>
-
-<p>
-<tref>Expansion</tref> transforms all values into <tref>expanded form</tref>
-in JSON-LD. This algorithm performs the opposite operation, transforming
-a value into <tdef>compacted form</tdef>. This algorithm compacts a
-value according to the <tref>term definition</tref> in the given
-<tref>active context</tref> that is associated with the value's associated
-<tref>active property</tref>.
-</p>
-
-<section class="informative">
-<h3>Purpose</h3>
-
-A <em>value</em> associated with an <tref>active property</tref> must
-be <tref title="compaction">compacted</tref> to <tref>compacted form</tref>.
-
-</section>
-
-<section class="informative">
-<h3>General Solution</h3>
-
-<p>
-The <em>value</em> to compact either contains the key <code>@value</code>
-or the key <code>@id</code>.
-</p>
-
-<p>
-We start with the former case, first trying to compact the
-<em>value</em> into just the value associated with its
-<code>@value</code> key. This can be done if the <em>value</em> is not
-going to be contained by an <code>@index</code> container and if the
-<tref>active property</tref> has a matching <tref>type mapping</tref> or
-<tref>language mapping</tref>. It can also be done if <code>@value</code>
-is the only key in <em>value</em> and either its associated value is
-not a <tref>string</tref>, there's no <tref>default language</tref>, or
-there's an explicit <tref>null</tref> <tref>language mapping</tref> for
-the <tref>active property</tref>.
-</p>
-
-<p>
-If we couldn't do the above optimal compaction, then we simply replace
-<tref title="keyword">keywords</tref> with aliases and compact any
-<tref title="IRI">IRIs</tref>.
-</p>
-
-<p>
-For the latter case, where the key <code>@id</code> appears in <em>value</em>,
-we compact the associated value using the
-<a href="#iri-compaction-algorithm">IRI Compaction</a> algorithm, and
-use its value if the <tref>type mapping</tref> associated with the
-<tref>active property</tref> is <code>@id</code> or the expanded value for
-the <tref>active property</tref> is <code>@graph</code>. Otherwise, we
-replace the <code>@id</code> key with its alias and its associated value
-with its compacted version.
-</p>
-
-</section>
-
-<section>
-<h3>Algorithm</h3>
-
-<p>
-This algorithm has three required inputs: an <tref>active context</tref>, an
-an <tref>active property</tref>, and a <em>value</em> to be compacted.
-</p>
-
-<ol class="algorithm">
- <li>
- If <em>value</em> contains the key <code>@value</code>:
- <ol class="algorithm">
- <li>
- Initialize <em>preserveIndex</em> to <tref>false</tref>. If
- <code>@index</code> is a key in <em>value</em> and
- <tref>active property</tref> does not have a
- <tref>container mapping</tref> in <tref>active context</tref> that
- is <code>@index</code>, set <em>preserveIndex</em> to
- <tref>true</tref>.
- </li>
- <li>
- If <em>preserveIndex</em> is <tref>false</tref> and either
- <em>value</em> has a <code>@type</code> key with a value that
- matches <tref title="active property">active property's</tref>
- <tref>type mapping</tref> in <tref>active context</tref> or
- <em>value</em> has a <code>@language</code> key with a value that
- matches <tref title="active property">active property's</tref>
- <tref>language mapping</tref> in <tref>active context</tref>, then
- return the value associated with the <code>@value</code> key in
- <em>value</em>.
- </li>
- <li>
- If <code>@value</code> is the only key in <em>value</em> or
- <em>preserveIndex</em> is <tref>false</tref> and either
- there is no <tref>default language</tref> in
- <tref>active context</tref>, the value associated with the
- <code>@value</code> key in <em>value</em> is not a
- <tref>string</tref>, or <tref>active property</tref>
- has a <tref>null</tref> <tref>language mapping</tref> in
- <tref>active context</tref>, then return the value
- associated with the <code>@value</code> key in <em>value</em>.
- </li>
- <li>
- Initialize <em>result</em> to an empty <tref>JSON object</tref>.
- </li>
- <li>
- If <em>preserveIndex</em> is <tref>true</tref>, then add
- a key-value pair to <em>result</em> where the key is the result
- using the <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@index</code> for <em>iri</em>, and the value is
- the value associated with the <code>@index</code> key in
- <em>value</em>.
- </li>
- <li>
- If <em>value</em> contains the key <code>@type</code>, then add
- a key-value pair to <em>result</em> where the key is the result
- using the <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@type</code> for <em>iri</em>, and the value is the result
- of using the <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref>, the value associated
- with the <code>@type</code> key in <em>value</em> for <em>iri</em>,
- and <tref>true</tref> for <em>vocabRelative</em>.
- </li>
- <li>
- Otherwise, if <em>value</em> contains the key <code>@language</code>,
- then add a key-value pair to <em>result</em> where the key is the
- result using the
- <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@language</code> for <em>iri</em>, and the value is the
- value associated with the <code>@language</code> key in
- <em>value</em>.
- </li>
- <li>
- Add a key-value pair to <em>result</em> where the key is the result
- using the <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref> and
- <code>@value</code> for <em>iri</em>, and the value is the value
- associated with the <code>@value</code> key in <em>value</em>.
- </li>
- <li>
- Return <em>result</em>.
- </li>
- </ol>
- </li>
- <li>
- Otherwise, <em>value</em> must contain the single key <code>@id</code>.
- Initialize <em>expanded property</em> to the result of using the
- <a href="#iri-expansion">IRI Expansion</a> algorithm, passing
- <tref>active context</tref>, <em>value</em>, and
- <tref>true</tref> for <em>vocabRelative</em>.
- </li>
- <li>
- Initialize <em>term</em> to the result of using the
- <a href="#iri-compaction-algorithm">IRI compaction</a> algorithm,
- passing <tref>active context</tref>, the value associated with
- the key <code>@id</code> in <em>value</em> for <em>iri</em>, and
- <tref>true</tref> for <em>vocabRelative</em> if
- <tref>active property</tref> has a <tref>type mapping</tref> in the
- <tref>active context</tref> that is <code>@vocab</code>.
- </li>
- <li>
- If <tref>active property</tref> has a <tref>type mapping</tref> in
- the <tref>active context</tref> that is <code>@id</code> or
- <code>@vocab</code> or if <em>expanded property</em> is
- <code>@graph</code>, then return <em>term</em>.
- </li>
- <li>
- Initialize <em>result</em> to an empty <tref>JSON object</tref>. Add
- a key-value pair to <em>result</em> where the key is the result of
- using the <a href="#iri-compaction-algorithm">IRI compaction</a>
- algorithm, passing <tref>active context</tref>, and <code>@id</code> for
- <em>iri</em>, and the value is <em>term</em>.
- </li>
- <li>
- Return <em>result</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- end of Value Compaction algorithm -->
-</section>
-
-<section>
-<h2>Find Property Generator Duplicates Subalgorithm</h2>
-
-<p>
-This algorithm checks if a specific value exists for all
-<tref title="IRI">IRIs</tref> associated with a
-<tref>property generator</tref> and, if specified, it removes them.
-The algorithm takes six required inputs: an <tref>active context</tref>,
-<em>element</em>, <em>expanded property</em>, <em>value</em>,
-<tref>active property</tref>, and a flag <em>remove</em>, that indicates
-whether or not to remove the duplicate values. It returns <tref>true</tref>
-if the required duplicate values were found and <tref>false</tref> if not.
-</p>
-
-<ol class="algorithm">
- <li>
- Initialize <em>result</em> to <tref>true</tref>.
- </li>
- <li>
- Initialize <em>iris</em> to the <tref>array</tref> associated with the
- <tref>IRI mapping</tref> for <tref>active property</tref> in
- <tref>active context</tref>.
- </li>
- <li>
- For each <em>iri</em> in <em>iris</em>:
- <ol class="algorithm">
- <li>
- If <em>iri</em> equals <em>expanded property</em>, then this
- is the <em>iri</em> that is to be preserved, so continue to the next
- <em>iri</em>.
- </li>
- <li>
- Set <em>result</em> to <tref>false</tref>.
- </li>
- <li>
- If <em>element</em> contains a key that equals <em>iri</em>:
- <ol class="algorithm">
- <li>
- Initialize <em>prospects</em> to the value associated with the
- key that equals <em>iri</em> in <em>element</em>. This
- <tref>array</tref> will be checked for a value that matches
- the <tref>property generator</tref> <em>value</em>.
- </li>
- <li>
- If <em>value</em> is an empty <tref>array</tref>:
- <ol class="algorithm">
- <li>
- Set <em>result</em> to <tref>true</tref>.
- </li>
- <li>
- If <em>remove</em> is <tref>true</tref>, remove <em>iri</em>
- from <em>element</em>.
- </li>
- <li>
- Continue to the next <em>iri</em>.
- </li>
- </ol>
- </li>
- <li>
- For each item <em>prospect</em> in <em>prospects</em>, until
- a <tref>property generator</tref> duplicate is found for
- <em>value</em>:
- <ol class="algorithm">
- <li>
- Check to see if <em>prospect</em> and <em>value</em> are
- <tref>property generator</tref> duplicates:
- <ol class="algorithm">
- <li>
- If their types and values are equal, then they are
- duplicates.
- </li>
- <li>
- Otherwise, if they are both
- <tref title="JSON object">JSON objects</tref> that contain
- the key <code>@value</code> and they both have the same
- key-value pairs for the keys <code>@value</code>,
- <code>@type</code>, <code>@language</code>, and
- <code>@index</code>, then they are duplicates.
- </li>
- <li>
- Otherwise, if they are both
- <tref title="list object">list objects</tref> with the same
- key-value pairs for the key <code>@index</code>, and the
- <tref title="array">arrays</tref> associated with their
- <code>@list</code> keys have the same length and their
- corresponding items, by index, are duplicates, then they
- are duplicates.
- </li>
- <li>
- Otherwise, if they are both
- <tref title="JSON object">JSON objects</tref> that contain
- the key <code>@id</code> and the values associated with
- those keys are equal, then they are duplicates.
- </li>
- <li>
- Otherwise, they are not duplicates.
- </li>
- </ol>
- </li>
- <li>
- If <em>prospect</em> and <em>value</em> are
- <tref>property generator</tref> duplicates:
- <ol class="algorithm">
- <li>
- Set <em>result</em> to <tref>true</tref>.
- </li>
- <li>
- If <em>remove</em> is <tref>true</tref>, then remove
- <em>prospect</em> from <em>prospects</em> and, if
- <em>prospects</em> is now empty, remove <em>iri</em>
- from <em>element</em>.
- </li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>
- Return <em>result</em>.
- </li>
-</ol>
-
-</section>
-
-<!-- FIXME -->
-<section>
- <h2>Flattening Algorithm</h2>
-
- <p>The algorithm takes two input variables, an <em>element</em> to flatten and a
- <em>context</em> used to compact the flattened document.</p>
-
- <ol class="algorithm">
- <li>Expand <em>element</em> according the
- <a href="#expansion-algorithm">Expansion algorithm</a>.</li>
- <li>Generate a <em>nodeMap</em> according the
- <a href="#node-map-generation">Node Map Generation algorithm</a>.</li>
- <li>Let <em>defaultGraph</em> be the value of the <code>@default</code> member of
- <em>nodeMap</em>; a <tref>JSON object</tref> representing the <tref>default graph</tref>.</li>
- <li>For each other <em>graphName</em>-<em>graph</em> pair in <em>nodeMap</em>
- perform the following steps:
- <ol class="algorithm">
- <li>If <em>defaultGraph</em> does not have a <em>graphName</em> member, create
- one and initialize its value to a <tref>JSON object</tref> consisting of an
- <code>@id</code> member whose value is set to <em>graphName</em>.</li>
- <li>Add an <code>@graph</code> member set to an empty <tref>array</tref>
- (referred to as <em>nodes</em>) to the <tref>JSON object</tref> which is the
- value of the <em>graphName</em> member of <em>nodeMap</em>.</li>
- <li>For each <em>id</em>-<em>node</em> pair in <em>graph</em> ordered by <em>id</em>,
- add <em>node</em> to the <em>nodes</em> <tref>array</tref>.</li>
- </ol>
- </li>
- <li>Initialize an empty <tref>array</tref> flattened.</li>
- <li>For each <em>id</em>-<em>node</em> pair in <em>defaultGraph</em> ordered by <em>id</em>,
- add <em>node</em> to <em>flattened</em>.</li>
- <li>If <em>context</em> is <tref>null</tref>, return <em>flattened</em>.</li>
- <li>Otherwise, return the result of compacting <em>flattened</em> according the
- <a href="#compaction-algorithm">Compaction algorithm</a> passing <em>context</em>
- ensuring that the compaction result uses the <code>@graph</code> keyword (or its alias)
- at the top-level, even if the context is empty or if there is only one element to
- put in the <code>@graph</code> <tref>array</tref>. This ensures that the returned
- document has a deterministic structure.</li>
- </ol>
-</section>
-
-<!-- FIXME -->
-<section>
- <h2>Node Map Generation</h2>
-
- <p>This algorithm creates a <tref>JSON object</tref> <em>nodeMap</em> holding an indexed
- representation of the <tref title="JSON-LD graph">graphs</tref> and <tref title="node">nodes</tref>
- represented in the passed, expanded document. All <tref title="node">nodes</tref> that are not
- uniquely identified by an IRI get assigned a (new) <tref>blank node identifier</tref>.
- The resulting <em>nodeMap</em> will have a member for every graph in the document whose
- value is another object with a member for every <tref>node</tref> represented in the document.
- The default graph is stored under the <code>@default</code> member, all other graphs are
- stored under their <tref>graph name</tref>.</p>
-
- <p>The algorithm takes as input an expanded JSON-LD document <em>element</em> and a reference to
- a <tref>JSON object</tref> <em>nodeMap</em>. Furthermore it has the optional parameters
- <tref>active graph</tref> (which defaults to <code>@default</code>), an <tref>active subject</tref>,
- <tref>active property</tref>, and a reference to a <tref>JSON object</tref> <em>list</em>. The
- <em>nodeMap</em> must be initialized to a <tref>JSON object</tref> consisting of a single member
- whose name corresponds with <tref>active graph</tref> and whose value is an empty <tref>JSON object</tref>.</p>
-
- <ol class="algorithm">
- <li>If <em>element</em> is an array, process each entry in <em>element</em> recursively, using this algorithm
- and return.</li>
- <li>Otherwise <em>element</em> is a <tref>JSON object</tref>. Let <em>activeGraph</em> be the
- <tref>JSON object</tref> which is the value of the <tref>active graph</tref> member of
- <em>nodeMap</em>.</li>
- <li>If it has an <code>@type</code> member, perform for each <em>item</em> the following
- steps:
- <ol class="algorithm">
- <li>If <em>item</em> is a <tref>blank node identifier</tref>, replace it with a
- <a href="#generate-blank-node-identifier">new blank node identifier</a>.</li>
- <li>If <em>activeGraph</em> has no member <em>item</em>, create it and initialize its
- value to a <tref>JSON object</tref> consisting of a single member <code>@id</code>
- with the value <em>item</em>.</li>
- </ol>
- </li>
- <li>If <em>element</em> has an <code>@value</code> member, perform the following steps:
- <ol class="algorithm">
- <li>If no <em>list</em> has been passed, merge <em>element</em> into the
- <tref>active property</tref> member of the <tref>active subject</tref> in
- <em>activeGraph</em>.</li>
- <li>Otherwise, append <em>element</em> to the <code>@list</code> member of <em>list</em>.</li>
- </ol>
- </li>
- <li>Otherwise, if <em>element</em> has an <code>@list</code> member, perform
- the following steps:
- <ol class="algorithm">
- <li>Initialize a new <tref>JSON object</tref> <em>result</em> having a single member
- <code>@list</code> whose value is initialized to an empty <tref>array</tref>.</li>
- <li>Recursively call this algorithm passing the value of <em>element's</em>
- <code>@list</code> member as new <em>element</em> and <em>result</em> as <em>list</em>.</li>
- <li>If <tref>active property</tref> is <tref>null</tref> or <code>@graph</code>,
- <a href="#generate-blank-node-identifier">generate a blank node identifier</a> <em>id</em>
- and store <em>result</em> as value of the member <em>id</em> in <em>activeGraph</em>.</li>
- <li>Otherwise, add <em>result</em> to the the value of the <tref>active property</tref> member
- of the <tref>active subject</tref> in <em>activeGraph</em>.</li>
- </ol>
- </li>
- <li>Otherwise <em>element</em> is a <tref>node object</tref>, perform the following
- steps:
- <ol class="algorithm">
- <li>If <em>element</em> has an <code>@id</code> member, store its value in <em>id</em> and remove
- the member from <em>element</em>. If <em>id</em> is a <tref>blank node identifier</tref>, replace it with
- <a href="#generate-blank-node-identifier">a new blank node identifier</a>.</li>
- <li>Otherwise <a href="#generate-blank-node-identifier">generate a new blank node identifier</a>
- and store it as <em>id</em>.</li>
- <li>If <em>activeGraph</em> does not contain a member <em>id</em>, create one and initialize
- it to a <tref>JSON object</tref> consisting of a single member <code>@id</code> whose
- value is set to <em>id</em>.</li>
- <li>If <tref>active property</tref> is not <tref>null</tref>, perform the following steps:
- <ol class="algorithm">
- <li>Create a new <tref>JSON object</tref> <em>reference</em> consisting of a single member
- <code>@id</code> whose value is <em>id</em>.</li>
- <li>If no <em>list</em> has been passed, merge <em>element</em> into the
- <tref>active property</tref> member of the <tref>active subject</tref> in
- <em>activeGraph</em>.</li>
- <li>Otherwise, append <em>element</em> to the <code>@list</code> member of <em>list</em>.</li>
- </ol>
- </li>
- <li>If <em>element</em> has an <code>@type</code> member, merge each value into the <code>@type</code>
- of <tref>active subject</tref> in <em>activeGraph</em>. Then remove the <code>@type</code> member
- from <em>element</em>.</li>
- <li>If <em>element</em> has an <code>@index</code> member, set the <code>@index</code>
- of <tref>active subject</tref> in <em>activeGraph</em> to its value. There MUST be no
- existing member already in <tref>active subject</tref> with a different value, if there
- is, then a <code class="error">conflicting indexes</code> error has been detected. Continue and remove the
- <code>@index</code> from <em>element</em>.</li>
- <li>If <em>element</em> has an <code>@graph</code> member, recursively invoke this algorithm passing
- the value of the <code>@graph</code> member as new <em>element</em> and <em>id</em> as new
- <tref>active subject</tref>. Then remove the <code>@graph</code> member from <em>element</em>.</li>
- <li>Finally for each <em>property</em>-<em>value</em> pair in <em>element</em> ordered by
- <em>property</em> perform the following steps:
- <ol class="algorithm">
- <li>If no <em>property</em> member exists in the <tref>JSON object</tref> which is the
- value of the <em>id</em> member of <em>activeGraph</em> create the member and initialize
- its value to an empty <tref>array</tref>.</li>
- <li>Recursively invoke this algorithm passing <em>value</em> as new <em>element</em>, <em>id</em>
- as new <tref>active subject</tref>, and <em>property</em> as new <tref>active property</tref>.</li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
-</section>
+ </section> <!-- end of Node Map Generation -->
+</section> <!-- end of Flattening section -->
<section>
-<h2>Convert to RDF Algorithm</h2>
-
-<p>
-This section describes algorithms to transform a JSON-LD document to an <tref>RDF dataset</tref>.
-The algorithm below is designed for in-memory implementations with random
-access to <tref>JSON object</tref> elements.
-</p>
-
-<p>
-A conforming JSON-LD processor implementing RDF conversion MUST implement a
-processing algorithm that results in the same <tref>RDF dataset</tref> that the following algorithm generates. Conformant
-implementations are only required to produce the same <tref>RDF dataset</tref> but are not required to implement the algorithm exactly as described.
-</p>
-
-<section class="informative">
- <h3>Purpose</h3>
- <p>A JSON-LD document needs to be converted to an <tref>RDF dataset</tref>.</p>
-<p class="issue" data-number="217">RDF does not currently allow a <tref>blank node identifier</tref> to be used as a <tref>graph name</tref>.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>The JSON-LD document is expanded converted to a <em>node map</em> 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
- <tref>node object</tref>. Each graph from the <em>node map</em>
- is processed to extract <tref title="rdf triple">RDF triples</tref>, to which any (non-default) graph name
- is applied to create an <tref>RDF dataset</tref>.
- </p>
-</section>
-
-<section>
-<h3>Algorithm</h3>
-<p>
-The algorithm takes a JSON-LD document <em>element</em> and creates an <tref>RDF dataset</tref>.
-</p>
-
-<ol class="algorithm">
- <li>Expand <em>element</em> according the
- <a href="#expansion-algorithm">Expansion algorithm</a>.</li>
- <li>Generate a <em>nodeMap</em> according the
- <a href="#node-map-generation">Node Map Generation Subalgorithm</a>.</li>
- <li>Initialize an empty <tref>RDF dataset</tref> <em>dataset</em>.</li>
- <li>For each <em>graph name</em> and <em>graph</em> in <em>nodeMap</em>:
- <ol class="algorithm">
- <li>Retrieve <em>triples</em> using the <a href="#nodemap-rdf">Node Map to RDF Subalgorithm</a>.</li>
- <li>If <em>graph name</em> is <code>@default</code>, add
- <em>triples</em> to the <tref>default graph</tref> in <em>dataset</em>.</li>
- <li>Otherwise, create a <tref>named graph</tref> in <em>dataset</em>
- composed of <em>graph name</em> and <em>triples</em>.</li>
- </ol>
- </li>
- <li>Return <em>dataset</em>.</li>
-</ol>
-</section>
-</section> <!-- Convert to RDF Algorithm -->
-
-<section id="nodemap-rdf">
-<h3>Node Map to RDF Subalgorithm</h3>
-<p>This algorithm takes the a <em>Node Map</em> for a particular graph
- as generated by the
- <a href="#node-map-generation">Node Map Generation Subalgorithm</a>
- and returns a set of <em>RDF triples</em>.</p>
-
-<section class="informative">
- <h3>Purpose</h3>
- <p>Given a set of <tref title="node">nodes</tref> associated with a
- <tref>JSON-LD graph</tref> as obtained from the <a href="">Node Map Generation</a>
- algorithm, transform each <tref>node</tref> into one or more <tref
- title="RDF triple">RDF triples</tref>.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>Identify <tref title="RDF subject">RDF subjects</tref> and
- <tref title="RDF predicate">RDF predicates</tref> from the
- <tref>node</tref> identifier and properties. Transform each property value
- into an <tref>IRI</tref> or
- <tref
- href="http://www.w3.org/TR/rdf11-concepts/#dfn-literal">RDF literal</tref>
- to generate an <tref>RDF triple</tref>.
- <tref title="list">Lists</tref> are transformed into an
- <tref
- href="http://www.w3.org/TR/rdf-schema/#ch_collectionvocab">RDF Collection</tref>
- using the <a href="#list-conversion">List to RDF Conversion Subalgorithm.</a></p>
-</section>
-
-<section>
-<h3>Algorithm</h3>
-<p>The <em>nodeMap</em> is represented as an <tref>JSON object</tref>
- having keys which are node identifiers (<tref title="iri">IRIs</tref> or
- <tref title="blank node identifier">blank node identifiers</tref>)
- and values are <tref title="node object">Node objects</tref>.</p>
-<ol class="algorithm">
- <li>Initialize <em>result</em> as an empty <tref>array</tref>.</li>
- <li>For each <em>subject</em> and <em>node</em> in <em>nodeMap</em>:
- <ol class="algorithm">
- <li>For each <em>property</em> and <em>values</em> in <em>node</em>:
- <ol class="algorithm">
- <li>If <em>property</em> is <code>@type</code>, then for each
- <em>type</em> in <em>values</em>, append a <tref>triple</tref>
- composed of <em>subject</em>, <code>rdf:type</code>,
- and <em>type</em> to <em>result</em>.</li>
- <li>Otherwise, if <em>property</em> is a <tref>keyword</tref>
- continue to the next <em>property</em>-<em>values</em> pair.</li>
- <li>Otherwise, <em>property</em> is an <tref>IRI</tref> or
- <tref>blank node identifier</tref>.</li>
- <li>For each <em>item</em> in <em>values</em>:
- <ol class="algorithm">
- <li>If <em>item</em> is a <tref>list object</tref>, initialize
- <em>list result</em> as an empty <tref>array</tref>, and
- <em>object</em> to the result of the <a
- href="#list-conversion">List Conversion algorithm</a>, passing
- the value associated with the <code>@list</code> key from
- <em>item</em> and <em>list result</em>. Append a
- <tref>triple</tref> composed of <em>subject</em>,
- <em>property</em>, and <em>object</em> to <em>result</em> and
- add all <tref title="triple">triples</tref> from <em>list
- result</em> to <em>result</em>.</li>
- <li>Otherwise, <em>item</em> is a <tref>value object</tref>
- or a <tref>node object</tref>. Generate <em>object</em> as
- the result of the <a href="#rdf-object-conversion">Object to
- RDF Conversion Subalgorithm</a> passing <em>item</em>. Append a
- <tref>triple</tref> composed of <em>subject</em>,
- <em>property</em>, and <em>object</em> to <em>result</em>.</li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>Return <em>result</em>.</li>
-</ol>
-</section>
-</section> <!-- Node Map to RDF Subalgorithm -->
-
-<section id="rdf-object-conversion">
-<h3>Object to RDF Conversion Subalgorithm</h3>
-<p>This algorithm takes a <tref>node</tref> or <tref>value object</tref>
- and transforms it into an <tref
- href="http://www.w3.org/TR/rdf11-concepts/#dfn-resource">RDF resource</tref>
- to be used as the <tref>object</tref> or an <tref>RDF triple</tref>.</p>
-
-<section class="informative">
- <h3>Purpose</h3>
- <p>Create an <tref>RDF resource</tref> from a <tref>node</tref> or <tref>value object</tref>.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>Transform <tref title="value object">value objects</tref> to their
- <tref>RDF literal</tref> form and
- <tref title="node object">node objects</tref> to an
- <tref>RDF resource</tref>.</p>
-</section>
-
-<section>
-<h3>Algorithm</h3>
-<p>The algorithm takes as its sole argument <em>item</em> which MUST be either a <tref>value object</tref> or <tref>node object</tref>.</p>
-<ol class="algorithm">
- <li>If <em>item</em> is a <tref>value object</tref>:
- <ol class="algorithm">
- <li>Initialize <em>value</em> to the value associated with the
- <code>@value</code> key in <em>item</em>. Initialize <em>datatype</em>
- to the value associated with the <code>@type</code> key in
- <em>item</em>, or <code>null</code> if <em>item</em> does not contain
- that key.</li>
- <li>If <em>value</em> is <tref>true</tref> or
- <tref>false</tref>, then set <em>value</em> to its
- <tref>canonical lexical form</tref> as defined
- in the section <a href="#data-round-tripping">Data Round Tripping</a>.
- If <em>datatype</em> is <tref>null</tref>, set it to
- <code>xsd:boolean</code>.</li>
- <li>Otherwise, if <em>value</em> is a <tref>number</tref>, then set
- <em>value</em> to its <tref>canonical lexical form</tref> as defined
- in the section <a href="#data-round-tripping">Data Round Tripping</a>.
- If <em>datatype</em> is <tref>null</tref>, set it to either
- <code>xsd:integer</code> or <code>xsd:double</code>, depending
- on if the value contains a fractional and/or an exponential
- component.</li>
- <li>Otherwise, if <em>datatype</em> is <tref>null</tref>, set it to
- <code>xsd:string</code> or <code>rdf:langString</code>, depending on if
- item has a <code>@language</code> key.</li>
- <li>Initialize <em>literal</em> as an <tref>RDF literal</tref> using
- <em>value</em> and <em>datatype</em>. If <em>item</em> has the key
- <code>@language</code> and <em>datatype</em> is
- <code>rdf:langString</code>, then add the value associated with the
- <code>@language</code> key as the language of <em>literal</em>.</li>
- <li>Return <em>literal</em>.</li>
- </ol>
- </li>
- <li>Otherwise, <em>item</em> MUST be a <tref>node object</tref> containing only <code>@id</code> having an <tref>IRI</tref> or <tref>blank node identifier</tref> value. Return that value.</li>
-</ol>
-</section>
-</section> <!-- Object to RDF Conversion Subalgorithm -->
-
-<section id="list-conversion">
-<h3>List to RDF Conversion Subalgorithm</h3>
-
-<p>
- List Conversion is the process of taking a <tref>list</tref> <tref>node</tref>
- and transforming it into an
- <tref href="http://www.w3.org/TR/rdf-schema/#ch_collectionvocab">
- RDF Collection
- </tref> as defined in [[!RDF-MT]].</p>
-<div class="note">This algorithm does not support lists containing lists.</div>
-
-
-<section class="informative">
- <h3>Purpose</h3>
- <p>Transform a sequential set of <tref title="node">nodes</tref> in a <tref>list</tref> into the equivalent <tref>RDF Collection</tref>.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>Allocate a new <tref>blank node</tref> for each element of the
- <tref>list</tref> and generate <code>rdf:first</code> and
- <code>rdf:rest</code> <tref title="RDF triple">triples</tref> for each,
- returning the first <tref>blank node</tref> or <code>rdf:nil</code> if the
- list is empty.</p>
-</section>
-
-<section>
-<h3>Algorithm</h3>
-<p>The algorithm takes two inputs: an <tref>array</tref> of
- <tref title="node">nodes</tref> <em>list</em> and an empty <tref>array</tref>
- <em>list triples</em> used for returning the generated <tref title="RDF
- triple">triples</tref>.</p>
-
-<ol class="algorithm">
- <li>Create a new <tref>array</tref> <em>array</em> composed of a
- <a href="#generate-blank-node-identifier">new blank node identifier</a>
- for each entry in <em>list</em>.</li>
- <li>For each pair of <em>subject</em> from <em>array</em> and <em>item</em> from <em>list</em>:
- <ol class="algorithm">
- <li>Generate <em>object</em> as
- the result of the <a href="#rdf-object-conversion">Object to
- RDF Conversion Subalgorithm</a> passing <em>item</em>. Append a
- <tref>triple</tref> composed of <em>subject</em>,
- <code>rdf:first</code>, and <em>object</em> to <em>list triples</em>.</li>
- <li>Set <em>rest</em> as the next entry in <em>array</em>, or if that
- does not exist, <code>rdf:nil</code>. Append a
- <tref>triple</tref> composed of <em>subject</em>,
- <code>rdf:rest</code>, and <em>rest</em> to <em>list triples</em>.</li>
- </ol>
- </li>
- <li>Return the first <tref>blank node</tref> from <em>array</em> or
- <code>rdf:nil</code> if <em>array</em> is empty.</li>
-</ol>
+ <h1>RDF Conversion Algorithms</h1>
+
+ <p>Throughout this section, the following vocabulary
+ <tref title="prefix">prefixes</tref> are used in
+ <tref title="compact iri">compact IRIs</tref>:</p>
+
+ <table rules="all">
+ <thead>
+ <th>Prefix</th>
+ <th>IRI</th>
+ </thead>
+ <tbody>
+ <tr>
+ <td>rdf</td>
+ <td>http://www.w3.org/1999/02/22-rdf-syntax-ns#</td>
+ </tr>
+ <tr>
+ <td>rdfs</td>
+ <td> http://www.w3.org/2000/01/rdf-schema#</td>
+ </tr>
+ <tr>
+ <td>xsd</td>
+ <td>http://www.w3.org/2001/XMLSchema#</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <section>
+ <h2>Convert to RDF Algorithm</h2>
+
+ <p>This section describes algorithms to transform a JSON-LD document to an
+ <tref>RDF dataset</tref>. The algorithm below is designed for in-memory
+ implementations with random access to <tref>JSON object</tref> elements.</p>
+
+ <p>A conforming JSON-LD processor implementing RDF conversion MUST implement a
+ processing algorithm that results in the same <tref>RDF dataset</tref> that the
+ following algorithm generates. Conformant implementations are only required to
+ produce the same <tref>RDF dataset</tref> but are not required to implement the
+ algorithm exactly as described.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+ <p>A JSON-LD document needs to be converted to an <tref>RDF dataset</tref>.</p>
+
+ <p class="issue" data-number="217">RDF does not currently allow a
+ <tref>blank node identifier</tref> to be used as a <tref>graph name</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>The JSON-LD document is expanded converted to a <em>node map</em> 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
+ <tref>node object</tref>. Each graph from the <em>node map</em>
+ is processed to extract <tref title="rdf triple">RDF triples</tref>, to which any (non-default) graph name
+ is applied to create an <tref>RDF dataset</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+ <p>The algorithm takes a JSON-LD document <em>element</em> and creates an
+ <tref>RDF dataset</tref>.</p>
+
+ <ol class="algorithm">
+ <li>Expand <em>element</em> according the
+ <a href="#expansion-algorithm">Expansion algorithm</a>.</li>
+ <li>Generate a <em>nodeMap</em> according the
+ <a href="#node-map-generation">Node Map Generation Subalgorithm</a>.</li>
+ <li>Initialize an empty <tref>RDF dataset</tref> <em>dataset</em>.</li>
+ <li>For each <em>graph name</em> and <em>graph</em> in <em>nodeMap</em>:
+ <ol class="algorithm">
+ <li>Retrieve <em>triples</em> using the
+ <a href="#nodemap-rdf">Node Map to RDF Subalgorithm</a>.</li>
+ <li>If <em>graph name</em> is <code>@default</code>, add
+ <em>triples</em> to the <tref>default graph</tref> in <em>dataset</em>.</li>
+ <li>Otherwise, create a <tref>named graph</tref> in <em>dataset</em>
+ composed of <em>graph name</em> and <em>triples</em>.</li>
+ </ol>
+ </li>
+ <li>Return <em>dataset</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Convert to RDF Algorithm -->
+
+ <section id="nodemap-rdf">
+ <h3>Node Map to RDF Subalgorithm</h3>
+
+ <p>This algorithm takes the a <em>Node Map</em> for a particular graph as generated
+ by the <a href="#node-map-generation">Node Map Generation Subalgorithm</a>
+ and returns a set of <em>RDF triples</em>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+ <p>Given a set of <tref title="node">nodes</tref> associated with a
+ <tref>JSON-LD graph</tref> as obtained from the <a href="">Node Map Generation</a>
+ algorithm, transform each <tref>node</tref> into one or more <tref
+ title="RDF triple">RDF triples</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Identify <tref title="RDF subject">RDF subjects</tref> and
+ <tref title="RDF predicate">RDF predicates</tref> from the
+ <tref>node</tref> identifier and properties. Transform each property value
+ into an <tref>IRI</tref> or
+ <tref
+ href="http://www.w3.org/TR/rdf11-concepts/#dfn-literal">RDF literal</tref>
+ to generate an <tref>RDF triple</tref>.
+ <tref title="list">Lists</tref> are transformed into an
+ <tref
+ href="http://www.w3.org/TR/rdf-schema/#ch_collectionvocab">RDF Collection</tref>
+ using the <a href="#list-conversion">List to RDF Conversion Subalgorithm.</a></p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+ <p>The <em>nodeMap</em> is represented as an <tref>JSON object</tref>
+ having keys which are node identifiers (<tref title="iri">IRIs</tref> or
+ <tref title="blank node identifier">blank node identifiers</tref>)
+ and values are <tref title="node object">Node objects</tref>.</p>
+ <ol class="algorithm">
+ <li>Initialize <em>result</em> as an empty <tref>array</tref>.</li>
+ <li>For each <em>subject</em> and <em>node</em> in <em>nodeMap</em>:
+ <ol class="algorithm">
+ <li>For each <em>property</em> and <em>values</em> in <em>node</em>:
+ <ol class="algorithm">
+ <li>If <em>property</em> is <code>@type</code>, then for each
+ <em>type</em> in <em>values</em>, append a <tref>triple</tref>
+ composed of <em>subject</em>, <code>rdf:type</code>,
+ and <em>type</em> to <em>result</em>.</li>
+ <li>Otherwise, if <em>property</em> is a <tref>keyword</tref>
+ continue to the next <em>property</em>-<em>values</em> pair.</li>
+ <li>Otherwise, <em>property</em> is an <tref>IRI</tref> or
+ <tref>blank node identifier</tref>.</li>
+ <li>For each <em>item</em> in <em>values</em>:
+ <ol class="algorithm">
+ <li>If <em>item</em> is a <tref>list object</tref>, initialize
+ <em>list result</em> as an empty <tref>array</tref>, and
+ <em>object</em> to the result of the <a
+ href="#list-conversion">List Conversion algorithm</a>, passing
+ the value associated with the <code>@list</code> key from
+ <em>item</em> and <em>list result</em>. Append a
+ <tref>triple</tref> composed of <em>subject</em>,
+ <em>property</em>, and <em>object</em> to <em>result</em> and
+ add all <tref title="triple">triples</tref> from <em>list
+ result</em> to <em>result</em>.</li>
+ <li>Otherwise, <em>item</em> is a <tref>value object</tref>
+ or a <tref>node object</tref>. Generate <em>object</em> as
+ the result of the
+ <a href="#rdf-object-conversion">Object to RDF Conversion Subalgorithm</a>
+ passing <em>item</em>. Append a <tref>triple</tref> composed of
+ <em>subject</em>, <em>property</em>, and <em>object</em> to
+ <em>result</em>.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Return <em>result</em>.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Node Map to RDF Subalgorithm -->
+
+ <section id="rdf-object-conversion">
+ <h3>Object to RDF Conversion Subalgorithm</h3>
+
+ <p>This algorithm takes a <tref>node</tref> or <tref>value object</tref>
+ and transforms it into an <tref
+ href="http://www.w3.org/TR/rdf11-concepts/#dfn-resource">RDF resource</tref>
+ to be used as the <tref>object</tref> or an <tref>RDF triple</tref>.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>Create an <tref>RDF resource</tref> from a <tref>node</tref> or
+ <tref>value object</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Transform <tref title="value object">value objects</tref> to their
+ <tref>RDF literal</tref> form and
+ <tref title="node object">node objects</tref> to an
+ <tref>RDF resource</tref>.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+ <p>The algorithm takes as its sole argument <em>item</em> which MUST be
+ either a <tref>value object</tref> or <tref>node object</tref>.</p>
+ <ol class="algorithm">
+ <li>If <em>item</em> is a <tref>value object</tref>:
+ <ol class="algorithm">
+ <li>Initialize <em>value</em> to the value associated with the
+ <code>@value</code> key in <em>item</em>. Initialize <em>datatype</em>
+ to the value associated with the <code>@type</code> key in
+ <em>item</em>, or <code>null</code> if <em>item</em> does not contain
+ that key.</li>
+ <li>If <em>value</em> is <tref>true</tref> or
+ <tref>false</tref>, then set <em>value</em> to its
+ <tref>canonical lexical form</tref> as defined
+ in the section <a href="#data-round-tripping">Data Round Tripping</a>.
+ If <em>datatype</em> is <tref>null</tref>, set it to
+ <code>xsd:boolean</code>.</li>
+ <li>Otherwise, if <em>value</em> is a <tref>number</tref>, then set
+ <em>value</em> to its <tref>canonical lexical form</tref> as defined
+ in the section <a href="#data-round-tripping">Data Round Tripping</a>.
+ If <em>datatype</em> is <tref>null</tref>, set it to either
+ <code>xsd:integer</code> or <code>xsd:double</code>, depending
+ on if the value contains a fractional and/or an exponential
+ component.</li>
+ <li>Otherwise, if <em>datatype</em> is <tref>null</tref>, set it to
+ <code>xsd:string</code> or <code>rdf:langString</code>, depending on if
+ item has a <code>@language</code> key.</li>
+ <li>Initialize <em>literal</em> as an <tref>RDF literal</tref> using
+ <em>value</em> and <em>datatype</em>. If <em>item</em> has the key
+ <code>@language</code> and <em>datatype</em> is
+ <code>rdf:langString</code>, then add the value associated with the
+ <code>@language</code> key as the language of <em>literal</em>.</li>
+ <li>Return <em>literal</em>.</li>
+ </ol>
+ </li>
+ <li>Otherwise, <em>item</em> MUST be a <tref>node object</tref> containing
+ only <code>@id</code> having an <tref>IRI</tref> or
+ <tref>blank node identifier</tref> value. Return that value.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Object to RDF Conversion Subalgorithm -->
+
+ <section id="list-conversion">
+ <h3>List to RDF Conversion Subalgorithm</h3>
+
+ <p>List Conversion is the process of taking a <tref>list</tref> <tref>node</tref>
+ and transforming it into an
+ <tref href="http://www.w3.org/TR/rdf-schema/#ch_collectionvocab">RDF Collection</tref>
+ as defined in [[!RDF-MT]].</p>
+
+ <p class="note">This algorithm does not support lists containing lists.</p>
+
+
+ <section class="informative">
+ <h3>Purpose</h3>
+ <p>Transform a sequential set of <tref title="node">nodes</tref> in a
+ <tref>list</tref> into the equivalent <tref>RDF Collection</tref>.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Allocate a new <tref>blank node</tref> for each element of the
+ <tref>list</tref> and generate <code>rdf:first</code> and
+ <code>rdf:rest</code> <tref title="RDF triple">triples</tref> for each,
+ returning the first <tref>blank node</tref> or <code>rdf:nil</code> if the
+ list is empty.</p>
+ </section>
+
+ <section>
+ <h3>Algorithm</h3>
+
+ <p>The algorithm takes two inputs: an <tref>array</tref> of
+ <tref title="node">nodes</tref> <em>list</em> and an empty <tref>array</tref>
+ <em>list triples</em> used for returning the generated <tref title="RDF
+ triple">triples</tref>.</p>
+
+ <ol class="algorithm">
+ <li>Create a new <tref>array</tref> <em>array</em> composed of a
+ <a href="#generate-blank-node-identifier">new blank node identifier</a>
+ for each entry in <em>list</em>.</li>
+ <li>For each pair of <em>subject</em> from <em>array</em> and <em>item</em> from <em>list</em>:
+ <ol class="algorithm">
+ <li>Generate <em>object</em> as
+ the result of the <a href="#rdf-object-conversion">Object to
+ RDF Conversion Subalgorithm</a> passing <em>item</em>. Append a
+ <tref>triple</tref> composed of <em>subject</em>,
+ <code>rdf:first</code>, and <em>object</em> to <em>list triples</em>.</li>
+ <li>Set <em>rest</em> as the next entry in <em>array</em>, or if that
+ does not exist, <code>rdf:nil</code>. Append a
+ <tref>triple</tref> composed of <em>subject</em>,
+ <code>rdf:rest</code>, and <em>rest</em> to <em>list triples</em>.</li>
+ </ol>
+ </li>
+ <li>Return the first <tref>blank node</tref> from <em>array</em> or
+ <code>rdf:nil</code> if <em>array</em> is empty.</li>
+ </ol>
+ </section>
+ </section> <!-- end of List to RDF Subalgorithm -->
+
+ <section>
+ <h2>Convert from RDF Algorithm</h2>
+
+ <p>This section describes algorithms to transform an <tref>RDF dataset</tref>
+ into a JSON-LD document.</p>
+
+ <p>A conforming JSON-LD processor implementing RDF conversion MUST implement a
+ processing algorithm that results in the same JSON-LD document that the following
+ algorithm generates. Conformant implementations are only required to produce
+ the same JSON-LD document but are not required to implement the algorithm exactly
+ as described.</p>
+
+ <section class="informative">
+ <h3>Purpose</h3>
+
+ <p>An <tref>RDF dataset</tref> including a <tref>default graph</tref> and zero or more
+ <tref title="named graph">named graphs</tref> needs to be converted to JSON-LD document.</p>
+
+ <p>In some cases, data exists natively in the form of triples or
+ <tref title="triple">triples</tref>; for example, if the data was
+ originally represented in an <tref>RDF dataset</tref>. This algorithm is
+ designed to simply translate an array of <tref title="triple">triples</tref>
+ into a JSON-LD document.</p>
+ <p>When expanding <tref title="typed value">typed values</tref> having a datatype
+ of <code>xsd:string</code>, the <code>@type</code> MUST NOT be set to
+ <code>xsd:string</code> and the resulting value MUST have only an
+ <code>@value</code> property.</p>
+ </section>
+
+ <section class="informative">
+ <h3>General Solution</h3>
+
+ <p>Iterate through each graph in the dataset, converting
+ <tref title="rdf collection">RDF Collections</tref> into a <tref>list</tref>
+ and generating an JSON-LD document in expanded form for all
+ <tref title="RDF literal">RDF literals</tref>, <tref title="IRI">IRIs</tref>
+ and <tref title="blank node identifier">blank node identifiers</tref>.</p>
+ </section>
+
+ <section>
+ <h2>Algorithm</h2>
+
+ <p>The algorithm takes a single parameter <em>dataSet</em> in the form of
+ an array of an <tref>RDF dataset</tref>.</p>
+
+ <ol class="algorithm">
+ <li id="new_graph">Construct <em>defaultGraph</em> as a
+ <tref>JSON object</tref> containing <em>nodes</em> and <em>listMap</em>,
+ each an empty <tref>JSON object</tref>.</li>
+ <li>Construct <em>graphs</em> as a <tref>JSON object</tref>
+ containing <em>defaultGraph</em> identified by <code>@default</code>.</li>
+ <li>For each <em>graph</em> in <em>dataSet</em>:
+ <ol class="algorithm">
+ <li>If <em>graph</em> is the <tref>default graph</tref>,
+ set <em>name</em> to <code>@default</code>, otherwise to the
+ <tref>graph name</tref> associated with <em>graph</em>.</li>
+ <li>Set <em>graph object</em> to the entry in <em>graphs</em>
+ identified by <em>name</em>, initializing it to a new entry as an empty
+ <tref>JSON object</tref> containing <em>nodes</em> and
+ <em>listMap</em>, each an empty <tref>JSON object</tref>.</li>
+ <li>For each <tref>RDF triple</tref> <em>triple</em> in <em>graph</em>
+ having <em>subject</em>, <em>predicate</em> and <em>object</em>:
+ <ol class="algorithm">
+ <li>If <em>predicate</em> is <code>rdf:first</code>,
+ use the entry in <em>graph.listMap</em> identified by
+ <em>subject</em>, initializing it to a new <tref>JSON object</tref>
+ if necessary. Represent <em>object</em> in <tref>expanded
+ form</tref>, as described in <a href="#value-expansion">Value
+ Expansion</a>. Add the resulting <em>object representation</em> to
+ the entry indexed by <em>first</em>, and skip to the next
+ <tref>triple</tref>.</li>
+ <li>If <em>predicate</em> is <code>rdf:rest</code>:
+ <ol class="algorithm">
+ <li>If <em>object</em> is a <tref>blank node</tref>,
+ use the entry in <em>graph.listMap</em> identified by
+ <em>subject</em>, initializing it to a new <tref>JSON
+ object</tref> if necessary. Add the <em>nominalValue</em> of
+ <em>object</em> to the entry indexed by <em>rest</em>.
+ <p class="issue">What is <em>nominalValue</em>? Presumably
+ this references the object in <em>graph.listMap</em>
+ identified by <em>object</em>.</p></li>
+ <li>Skip to the next <tref>triple</tref>.</li>
+ </ol>
+ </li>
+ <li>If <em>name</em> is not <code>@default</code>,
+ and <em>defaultGraph.nodes</em> does not contain an entry for
+ <em>name</em>, create a new entry for <em>name</em> from a new
+ <tref>JSON object</tref> with key/value pair of <code>@id</code>
+ and <em>name</em> represented in <tref>expanded IRI
+ form</tref>.</li>
+ <li>Set <em>value</em> as the entry from <em>graph.nodes</em> for
+ <em>subject</em>, initializing it to a new <tref>JSON object</tref>
+ with key/value pair of <code>@id</code> and <em>subject</em>
+ represented in <tref>expanded IRI form</tref> if necessary.</li>
+ <li>If <em>predicate</em> is <code>rdf:type</code>, <em>object</em>
+ is not a <tref>JSON-LD value</tref>, and the <code
+ class="idlMemberName"><a
+ href="#widl-JsonLdOptions-useRdfType">useRdfType</a></code> option
+ is not present or <tref>false</tref>:
+ <ol class="algorithm">
+ <li>Append <em>object</em> represented in
+ <tref>expanded IRI form</tref> to the array value for the key
+ <code>@type</code>, creating an entry in <em>value</em> if
+ necessary.</li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>object</em> is a <tref>typed value</tref>
+ and the <code class="idlMemberName"><a
+ href="#widl-JsonLdOptions-useNativeTypes">useNativeTypes</a></code>
+ option is set to <tref>true</tref>:
+ <ol class="algorithm">
+ <li>Generate a <em>converted value</em>:
+ <ol class="algorithm">
+ <li>If the literal's type is <code>xsd:boolean</code>, the
+ <em>converted value</em> is <tref>true</tref> if the literal
+ matches the value <code>true</code> or <code>false</code> if
+ the literal matches the value <code>false</code>.</li>
+ <li>If the literal's type is <code>xsd:integer</code> or
+ <code>xsd:double</code>, try to convert the literal to a
+ JSON <tref>number</tref>. If the conversion is successful,
+ store the result in <em>converted value</em>, otherwise
+ set <em>converted value</em> to <em>value</em>.</li>
+ <li>Otherwise, do not perform a conversion. Set
+ the <em>converted value</em> to the <em>value</em>.</li>
+ </ol>
+ </li>
+ <li>Append the <em>converted value</em> to the array value for the
+ key, creating an entry in <em>value</em> if necessary.</li>
+ </ol>
+ </li>
+ <li>Otherwise, if <em>object</em> is <code>rdf:nil</code>:
+ <ol class="algorithm">
+ <li>Let <em>key</em> be <em>predicate</em>
+ expressed in <tref>expanded IRI form</tref>.</li>
+ <li>Append an empty <code>@list</code> representation
+ to the array value for <em>key</em>, creating an entry in
+ <em>value</em> if necessary.</li>
+ </ol>
+ </li>
+ <li>Otherwise,
+ <ol class="algorithm">
+ <li>Let <em>key</em> be <em>predicate</em>
+ expressed in <tref>expanded IRI form</tref> and let <em>object
+ representation</em> be <em>object</em> represented in
+ <tref>expanded form</tref> as described in <a
+ href="#value-expansion">Value Expansion</a>.</li>
+ <li>If <em>object</em> is a <tref>blank node</tref>,
+ use the entry in <em>graph.listMap</em> indexed by
+ <em>object</em>, initializing it to a new <tref>JSON
+ object</tref> if necessary. Add an entry for <em>head</em> with
+ <em>object representation</em>.</li>
+ <li>Append <em>object representation</em> to the array value for
+ <em>key</em>, creating an entry in <em>value</em> if
+ necessary.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>For each <em>name</em> and <em>graph object</em> in <em>graphs</em>:
+ <ol class="algorithm">
+ <li>For each <em>subject</em> and <em>entry</em> in <em>graph object</em>
+ where <em>entry</em> has both <em>head</em> and <em>first</em> keys:
+ <ol class="algorithm">
+ <li>Set <em>value</em> to the value of <em>head</em> in <em>entry</em>.</li>
+ <li>Remove the entry for <code>@id</code> in <em>value</em>.</li>
+ <li>Add an entry to <em>value</em> for <code>@list</code> initialized to a new array
+ containing the value of <em>first</em> from <em>entry</em>.</li>
+ <li>While <em>entry</em> has a key for <em>rest</em>:
+ <ol class="algorithm">
+ <li>Set <em>entry</em> to the value of <em>graph.listMap</em> for <em>entry.rest</em>.</li>
+ <li>Add the value for <em>entry.first</em> to the list array.</li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li>Create <em>array</em> as an empty <tref>array</tref>.</li>
+ <li>For each <em>subject</em> and <em>entry</em> in <em>defaultGraph.nodes</em>
+ ordered by <em>subject</em>:
+ <ol class="algorithm">
+ <li>Add <em>entry</em> to <em>array</em>.</li>
+ <li>If <em>graphs</em> has an entry for <em>subject</em>, add a property
+ <code>@graph</code> in <em>entry</em> containing the ordered entries
+ from <em>graphs[subject].nodes</em>.</li>
+ </ol>
+ </li>
+ <li>Return <em>array</em> as the result.</li>
+ </ol>
+ </section>
+ </section> <!-- end of Convert from RDF algorithm -->
+
+ <section>
+ <h2>Data Round Tripping</h2>
+
+ <p>When <a href="#rdf-conversion">converting JSON-LD to RDF</a> JSON-native types such as
+ <em>numbers</em> and <em>booleans</em> are automatically coerced to
+ <strong>xsd:integer</strong>, <strong>xsd:double</strong>, or <strong>xsd:boolean</strong>.
+ Implementers MUST ensure that the result is in <tref>canonical lexical form</tref>. A
+ <tdef>canonical lexical form</tdef> is a set of literals from among the valid set of literals for
+ a datatype such that there is a one-to-one mapping between the <tref>canonical lexical form</tref>
+ and a value in the value space as defined in [[!XMLSCHEMA11-2]]. In other words, every
+ value MUST be converted to a deterministic <tref>string</tref> representation.</p>
+
+ <p>The canonical lexical form of an <em>integer</em>, i.e., a number without fractions
+ or a number coerced to <strong>xsd:integer</strong>, is a finite-length sequence of decimal
+ digits (<code>0-9</code>) with an optional leading minus sign; leading zeros are prohibited.
+ To convert the number in JavaScript, implementers can use the following snippet of code:</p>
+
+ <pre class="example" data-transform="updateExample"
+ title="Sample integer serialization implementation in JavaScript">
+ <!--
+ (value).toFixed(0).toString()
+ -->
+ </pre>
+
+ <p>The canonical lexical form of a <em>double</em>, i.e., a number with fractions
+ or a number coerced to <strong>xsd:double</strong>, consists of a mantissa followed by the
+ character "E", followed by an exponent. The mantissa MUST be a decimal number. The exponent
+ MUST be an integer. Leading zeros and a preceding plus sign (<code>+</code>) are prohibited
+ in the exponent. If the exponent is zero, it must be 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>.
+ <strong>xsd:double</strong>'s value space is defined by the IEEE double-precision 64-bit
+ floating point type [[!IEEE-754-1985]]; in JSON-LD the mantissa is rounded to 15 digits after the
+ decimal point.</p>
+
+ <p>To convert the number in JavaScript, implementers can use the following snippet of code:</p>
+
+ <pre class="example" data-transform="updateExample"
+ title="Sample floating point number serialization implementation in JavaScript">
+ <!--
+ (value).toExponential(15).replace(/(\d)0*e\+?/,'$1E')
+ -->
+ </pre>
+
+ <p class="note">When data such as decimals need to be normalized, JSON-LD authors should
+ not use values that are going to undergo automatic conversion. This is due to the lossy nature
+ of <strong>xsd:double</strong> values. Authors should instead use the expanded object form to
+ set the canonical lexical form directly.</p>
+
+ <p>The canonical lexical form of the <em>boolean</em> values <code>true</code> and <code>false</code>
+ are the strings <strong>true</strong> and <strong>false</strong>.</p>
+
+ <p>When JSON-native <tref>number</tref>s, are type coerced, lossless data round-tripping can not
+ be guaranteed as rounding errors might occur. Additionally, only literals typed as
+ <strong>xsd:integer</strong>, <strong>xsd:double</strong>, and <strong>xsd:boolean</strong> are
+ automatically converted back to their JSON-native counterparts in when
+ <a href="#rdf-conversion">converting from RDF</a>.</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, a JSON-LD serializer MUST NOT backslash-escape forward slashes.</p>
+ </section> <!-- end of Data Round Tripping -->
</section>
-</section> <!-- List to RDF Subalgorithm -->
-
-<section>
- <h2>Convert from RDF Algorithm</h2>
-<p>
-This section describes algorithms to transform an <tref>RDF dataset</tref> into a JSON-LD document.
-</p>
-
-<p>
-A conforming JSON-LD processor implementing RDF conversion MUST implement a
-processing algorithm that results in the same JSON-LD document that the following algorithm generates. Conformant
-implementations are only required to produce the same JSON-LD document but are not required to implement the algorithm exactly as described.
-</p>
-
-<section class="informative">
- <h3>Purpose</h3>
- <p>An <tref>RDF dataset</tref> including a <tref>default graph</tref> and zero or more <tref title="named graph">named graphs</tref> needs to be converted to JSON-LD document.</p>
-
- <p>In some cases, data exists natively in the form of triples or
- <tref title="triple">triples</tref>; for example, if the data was
- originally represented in an <tref>RDF dataset</tref>. This algorithm is
- designed to simply translate an array of <tref
- title="triple">triples</tref> into a JSON-LD document.</p> <p>When
- expanding <tref title="typed value">typed values</tref> having a datatype
- of <code>xsd:string</code>, the <code>@type</code> MUST NOT be set to
- <code>xsd:string</code> and the resulting value MUST have only an
- <code>@value</code> property.</p>
-</section>
-
-<section class="informative">
- <h3>General Solution</h3>
-
- <p>Iterate through each graph in the dataset, converting <tref title="rdf collection">RDF Collections</tref> into a <tref>list</tref> and generating an JSON-LD document in expanded form for all <tref title="RDF literal">RDF literals</tref>, <tref title="IRI">IRIs</tref> and <tref title="blank node identifier">blank node identifiers</tref>.</p>
-</section>
-
-<section>
-<h2>Algorithm</h2>
-
-<p>The algorithm takes a single parameter <em>dataSet</em> in the form of an
- array of an <tref>RDF dataset</tref>.</p>
-
-<ol class="algorithm">
- <li id="new_graph">Construct <em>defaultGraph</em> as a
- <tref>JSON object</tref> containing <em>nodes</em> and <em>listMap</em>,
- each an empty <tref>JSON object</tref>.</li>
- <li>Construct <em>graphs</em> as a <tref>JSON object</tref>
- containing <em>defaultGraph</em> identified by <code>@default</code>.</li>
- <li>For each <em>graph</em> in <em>dataSet</em>:
- <ol class="algorithm">
- <li>If <em>graph</em> is the <tref>default graph</tref>,
- set <em>name</em> to <code>@default</code>, otherwise to the
- <tref>graph name</tref> associated with <em>graph</em>.</li>
- <li>Set <em>graph object</em> to the entry in <em>graphs</em>
- identified by <em>name</em>, initializing it to a new entry as an empty
- <tref>JSON object</tref> containing <em>nodes</em> and
- <em>listMap</em>, each an empty <tref>JSON object</tref>.</li>
- <li>For each <tref>RDF triple</tref> <em>triple</em> in <em>graph</em>
- having <em>subject</em>, <em>predicate</em> and <em>object</em>:
- <ol class="algorithm">
- <li>If <em>predicate</em> is <code>rdf:first</code>,
- use the entry in <em>graph.listMap</em> identified by
- <em>subject</em>, initializing it to a new <tref>JSON object</tref>
- if necessary. Represent <em>object</em> in <tref>expanded
- form</tref>, as described in <a href="#value-expansion">Value
- Expansion</a>. Add the resulting <em>object representation</em> to
- the entry indexed by <em>first</em>, and skip to the next
- <tref>triple</tref>.</li>
- <li>If <em>predicate</em> is <code>rdf:rest</code>:
- <ol class="algorithm">
- <li>If <em>object</em> is a <tref>blank node</tref>,
- use the entry in <em>graph.listMap</em> identified by
- <em>subject</em>, initializing it to a new <tref>JSON
- object</tref> if necessary. Add the <em>nominalValue</em> of
- <em>object</em> to the entry indexed by <em>rest</em>.
- <span class="issue">What is <em>nominalValue</em>? Presumably
- this references the object in <em>graph.listMap</em>
- identified by <em>object</em>.</span></li>
- <li>Skip to the next <tref>triple</tref>.</li>
- </ol>
- </li>
- <li>If <em>name</em> is not <code>@default</code>,
- and <em>defaultGraph.nodes</em> does not contain an entry for
- <em>name</em>, create a new entry for <em>name</em> from a new
- <tref>JSON object</tref> with key/value pair of <code>@id</code>
- and <em>name</em> represented in <tref>expanded IRI
- form</tref>.</li>
- <li>Set <em>value</em> as the entry from <em>graph.nodes</em> for
- <em>subject</em>, initializing it to a new <tref>JSON object</tref>
- with key/value pair of <code>@id</code> and <em>subject</em>
- represented in <tref>expanded IRI form</tref> if necessary.</li>
- <li>If <em>predicate</em> is <code>rdf:type</code>, <em>object</em>
- is not a <tref>JSON-LD value</tref>, and the <code
- class="idlMemberName"><a
- href="#widl-JsonLdOptions-useRdfType">useRdfType</a></code> option
- is not present or <tref>false</tref>:
- <ol class="algorithm">
- <li>Append <em>object</em> represented in
- <tref>expanded IRI form</tref> to the array value for the key
- <code>@type</code>, creating an entry in <em>value</em> if
- necessary.</li>
- </ol>
- </li>
-
- <li>Otherwise, if <em>object</em> is a <tref>typed value</tref>
- and the <code class="idlMemberName"><a
- href="#widl-JsonLdOptions-useNativeTypes">useNativeTypes</a></code>
- option is set to <tref>true</tref>:
- <ol class="algorithm">
- <li>Generate a <em>converted value</em>:
- <ol class="algorithm">
- <li>If the literal's type is <code>xsd:boolean</code>, the
- <em>converted value</em> is <tref>true</tref> if the literal
- matches the value <code>true</code> or <code>false</code> if
- the literal matches the value <code>false</code>.</li>
- <li>If the literal's type is <code>xsd:integer</code> or
- <code>xsd:double</code>, try to convert the literal to a
- JSON <tref>number</tref>. If the conversion is successful,
- store the result in <em>converted value</em>, otherwise
- set <em>converted value</em> to <em>value</em>.</li>
- <li>Otherwise, do not perform a conversion. Set
- the <em>converted value</em> to the <em>value</em>.</li>
- </ol>
- </li>
- <li>Append the <em>converted value</em> to the array value for the
- key, creating an entry in <em>value</em> if necessary.</li>
- </ol>
- </li>
-
- <li>Otherwise, if <em>object</em> is <code>rdf:nil</code>:
- <ol class="algorithm">
- <li>Let <em>key</em> be <em>predicate</em>
- expressed in <tref>expanded IRI form</tref>.</li>
- <li>Append an empty <code>@list</code> representation
- to the array value for <em>key</em>, creating an entry in
- <em>value</em> if necessary.</li>
- </ol>
- </li>
- <li>Otherwise,
- <ol class="algorithm">
- <li>Let <em>key</em> be <em>predicate</em>
- expressed in <tref>expanded IRI form</tref> and let <em>object
- representation</em> be <em>object</em> represented in
- <tref>expanded form</tref> as described in <a
- href="#value-expansion">Value Expansion</a>.</li>
- <li>If <em>object</em> is a <tref>blank node</tref>,
- use the entry in <em>graph.listMap</em> indexed by
- <em>object</em>, initializing it to a new <tref>JSON
- object</tref> if necessary. Add an entry for <em>head</em> with
- <em>object representation</em>.</li>
- <li>Append <em>object representation</em> to the array value for
- <em>key</em>, creating an entry in <em>value</em> if
- necessary.</li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>For each <em>name</em> and <em>graph object</em> in <em>graphs</em>:
- <ol class="algorithm">
- <li>For each <em>subject</em> and <em>entry</em> in <em>graph object</em>
- where <em>entry</em> has both <em>head</em> and <em>first</em> keys:
- <ol class="algorithm">
- <li>Set <em>value</em> to the value of <em>head</em> in <em>entry</em>.</li>
- <li>Remove the entry for <code>@id</code> in <em>value</em>.</li>
- <li>Add an entry to <em>value</em> for <code>@list</code> initialized to a new array
- containing the value of <em>first</em> from <em>entry</em>.</li>
- <li>While <em>entry</em> has a key for <em>rest</em>:
- <ol class="algorithm">
- <li>Set <em>entry</em> to the value of <em>graph.listMap</em> for <em>entry.rest</em>.</li>
- <li>Add the value for <em>entry.first</em> to the list array.</li>
- </ol>
- </li>
- </ol>
- </li>
- </ol>
- </li>
- <li>Create <em>array</em> as an empty <tref>array</tref>.</li>
- <li>For each <em>subject</em> and <em>entry</em> in <em>defaultGraph.nodes</em>
- ordered by <em>subject</em>:
- <ol class="algorithm">
- <li>Add <em>entry</em> to <em>array</em>.</li>
- <li>If <em>graphs</em> has an entry for <em>subject</em>, add a property
- <code>@graph</code> in <em>entry</em> containing the ordered entries
- from <em>graphs[subject].nodes</em>.</li>
- </ol>
- </li>
- <li>Return <em>array</em> as the result.</li>
-</ol>
-</section>
-</section> <!-- Convert from RDF algorithm -->
-
-<section>
- <h3>Data Round Tripping</h3>
-
- <p>When <a href="#rdf-conversion">converting JSON-LD to RDF</a> JSON-native types such as
- <em>numbers</em> and <em>booleans</em> are automatically coerced to <strong>xsd:integer</strong>,
- <strong>xsd:double</strong>, or <strong>xsd:boolean</strong>. Implementers MUST ensure that the
- result is in <tref>canonical lexical form</tref>. A
- <tdef>canonical lexical form</tdef> is a set of literals from among the valid set of literals for
- a datatype such that there is a one-to-one mapping between the <tref>canonical lexical form</tref> and a value
- in the value space as defined in [[!XMLSCHEMA11-2]]. In other words, every value MUST be converted
- to a deterministic <tref>string</tref> representation.</p>
-
- <p>The canonical lexical form of an <em>integer</em>, i.e., a number without fractions
- or a number coerced to <strong>xsd:integer</strong>, is a finite-length sequence of decimal
- digits (<code>0-9</code>) with an optional leading minus sign; leading zeros are prohibited.
- To convert the number in JavaScript, implementers can use the following snippet of code:</p>
-
- <pre class="example" data-transform="updateExample"
- title="Sample integer serialization implementation in JavaScript">
- <!--
- (value).toFixed(0).toString()
- -->
- </pre>
-
- <p>The canonical lexical form of a <em>double</em>, i.e., a number with fractions
- or a number coerced to <strong>xsd:double</strong>, consists of a mantissa followed by the
- character "E", followed by an exponent. The mantissa MUST be a decimal number. The exponent
- MUST be an integer. Leading zeros and a preceding plus sign (<code>+</code>) are prohibited
- in the exponent. If the exponent is zero, it must be 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>.
- <strong>xsd:double</strong>'s value space is defined by the IEEE double-precision 64-bit
- floating point type [[!IEEE-754-1985]]; in JSON-LD the mantissa is rounded to 15 digits after the
- decimal point.</p>
-
- <p>To convert the number in JavaScript, implementers can use the following snippet of code:</p>
-
- <pre class="example" data-transform="updateExample"
- title="Sample floating point number serialization implementation in JavaScript">
- <!--
- (value).toExponential(15).replace(/(\d)0*e\+?/,'$1E')
- -->
- </pre>
-
- <p class="note">When data such as decimals need to be normalized, JSON-LD authors should
- not use values that are going to undergo automatic conversion. This is due to the lossy nature
- of <strong>xsd:double</strong> values. Authors should instead use the expanded object form to
- set the canonical lexical form directly.</p>
-
- <p>The canonical lexical form of the <em>boolean</em> values <code>true</code> and <code>false</code>
- are the strings <strong>true</strong> and <strong>false</strong>.</p>
-
- <p>When JSON-native <tref>number</tref>s, are type coerced, lossless data round-tripping can not
- be guaranteed as rounding errors might occur. Additionally, only literals typed as
- <strong>xsd:integer</strong>, <strong>xsd:double</strong>, and <strong>xsd:boolean</strong> are
- automatically converted back to their JSON-native counterparts in when
- <a href="#rdf-conversion">converting from RDF</a>.</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, a JSON-LD serializer MUST NOT backslash-escape forward slashes.</p>
-</section>
-
-<!-- end of Algorithms -->
-</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 a variety of output formats that are easier to work
- with in JavaScript. If a JavaScript JSON-LD API is provided, the entirety
- of the following API MUST be implemented.</p>
+ JSON-LD data into a a variety of output formats that are easier to work
+ with in JavaScript. If a JavaScript JSON-LD API is provided, the entirety
+ of the following API MUST be implemented.</p>
<section>
<h3>JsonLdProcessor</h3>
@@ -4459,7 +3813,6 @@
MUST NOT modify the input parameters.</p>
<dl title="[Constructor] interface JsonLdProcessor" class="idl">
-
<dt>void expand()</dt>
<dd>
<a href="#expansion">Expands</a> the given <code>input</code> according to
@@ -4529,8 +3882,7 @@
</dl>
</dd>
</dl>
-
- </section>
+ </section> <!-- end of JsonLdProcessor -->
<section>
<h3>Callbacks</h3>
@@ -4589,7 +3941,7 @@
<dd>The raw content of the retrieved JSON-LD context.</dd>
</dl>
</section>
- </section>
+ </section> <!-- end of Callbacks -->
<section>
<h3>Data Structures</h3>
@@ -4597,7 +3949,8 @@
<section>
<h3>JsonLdOptions</h3>
- <p>The <a>JsonLdOptions</a> type is used to pass various options to the <a>JsonLdProcessor</a> methods.</p>
+ <p>The <a>JsonLdOptions</a> type is used to pass various options to the
+ <a>JsonLdProcessor</a> methods.</p>
<dl title="dictionary JsonLdOptions" class="idl">
<dt>DOMString base</dt>
<dd>The Base IRI to use when expanding the document. This overrides the value of
@@ -4761,9 +4114,8 @@
lists have been compacted to the same term.</dd>
</dl>
</section>
-
- </section>
-</section>
+ </section> <!-- end of Data Structures -->
+</section> <!-- end of The Application Programming Interfaces -->
<section class="appendix informative">
<h1>Acknowledgements</h1>