Skip to content

Issue 246 nesting #451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions spec/latest/common/terms.html
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ <h1>General Terminology</h1>
specified via the <code>@context</code> <a>keyword</a>.</dd>
<dt><dfn data-lt="named graphs">named graph</dfn></dt><dd>
A <a>linked data graph</a> that is identified by an <a>IRI</a> or <a>blank node</a>
<dt><dfn data-lt="nested properties">nested property</dfn></dt><dd>
A <a>nested property</a> is a <a>property</a> which is contained within an object referenced by
a semantically meaningless <em>nesting property</em>.
</dd>
(the <a>graph name</a>) and a <a>graph</a>.</dd>
<dt><dfn data-lt="nodes">node</dfn></dt><dd>
Every <a>node</a> is an <a>IRI</a>, a <a>blank node</a>,
Expand Down
52 changes: 48 additions & 4 deletions spec/latest/json-ld-api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -987,8 +987,8 @@ <h3>Algorithm</h3>
<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>,
<span class="changed"><code>@id</code>, <code>@type</code></span>
or <code>@language</code>. Otherwise, an
<span class="changed"><code>@id</code>, <code>@type</code></span>,
<code>@nest</code>, or <code>@language</code>. Otherwise, an
<a data-link-for="JsonLdErrorCode">invalid container mapping</a>
has been detected and processing is aborted.</li>
<li>Set the <a>container mapping</a> of <em>definition</em> to
Expand Down Expand Up @@ -1270,7 +1270,7 @@ <h3>Algorithm</h3>
passing <a>active context</a> and the value of the
<code>@context</code> key as <a>local context</a>.</li>
<li>Initialize an empty <a>JSON object</a>, <em>result</em>.</li>
<li>For each <em>key</em> and <em>value</em> in <em>element</em>,
<li id="alg-expand-each-key-value">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
Expand Down Expand Up @@ -1418,6 +1418,10 @@ <h3>Algorithm</h3>
<li>Continue with the next <em>key</em> from <em>element</em>.</li>
</ol>
</li>
<li class="changed">If <em>expanded property</em> is <code>@nest</code>,
add <em>key</em> to <em>nests</em>, initializing it to an empty <a>array</a>,
if necessary.
Continue with the next <em>key</em> from <em>element</em>.</li>
<li class="changed">When the <code>frame expansion</code> flag is set,
if <em>expanded property</em> is any other
framing keyword (<code>@explicit</code>, <code>@default</code>,
Expand Down Expand Up @@ -1559,6 +1563,22 @@ <h3>Algorithm</h3>
member of <em>result</em>.</li>
</ol>
</li>
<li class="changed">For each key <em>nesting-key</em> in <em>nests</em>
<ol class="algorithm">
<li>Set <em>nested values</em> to the value of <em>nesting-key</em>
in <em>element</em>, ensuring that it is an <a>array</a>.</li>
<li>For each <em>nested value</em> in <em>nested values</em>:
<ol class="algorithm">
<li>If <em>nested value</em> is not a <a>JSON object</a>, or any key within
<em>nested value</em> expands to <code>@value</code>, an
<a data-link-for="JsonLdErrorCode">invalid @nest value</a> error
has been detected and processing is aborted.</li>
<li>Recursively repeat <a href="#alg-expand-each-key-value">step 7</a>
using <em>nested value</em> for <em>element</em>.</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>If <em>result</em> contains the key <code>@value</code>:
Expand Down Expand Up @@ -2049,6 +2069,25 @@ <h3>Algorithm</h3>
<em>compacted item</em> to it.</li>
</ol>
</li>
<li class="changed">If container is <code>@nest</code>:
<ol class="algorithm">
<li>Set <em>nest prop</em> to the result of the
<a href="#iri-compaction">IRI Compaction algorithm</a>
passing <a>active context</a>,
<em>item active property</em> as <em>iri</em>, and <code>true</code>
for <em>vocab</em>.</li>
<li>If <em>nest prop</em> is not a key in
<em>result</em>, initialize it to an empty <a>JSON object</a>.
Initialize <em>map object</em> to the value of <em>nest prop</em>
in <em>result</em>.</li>
<li>If <em>item active property</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 <a>array</a>, 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">
Expand Down Expand Up @@ -2401,7 +2440,9 @@ <h3>Algorithm</h3>
</li>
<li>Otherwise, set <em>type/language</em> to <code>@type</code>
and set <em>type/language value</em> to <code>@id</code>.</li>
<li>Append <code>@set</code> to <em>containers</em>.</li>
<li>Append
<span class="changed"><code>@nest</code> and</span>
<code>@set</code> to <em>containers</em>.</li>
</ol>
</li>
<li>Append <code>@none</code> to <em>containers</em>. This represents
Expand Down Expand Up @@ -4092,6 +4133,7 @@ <h4>JsonLdErrorCode</h4>
"invalid language mapping",
"invalid language-tagged string",
"invalid language-tagged value",
"invalid @nest value",
"invalid local context",
"invalid remote context",
"invalid reverse property",
Expand Down Expand Up @@ -4168,6 +4210,8 @@ <h4>JsonLdErrorCode</h4>
associated language tag was detected.</dd>
<dt><dfn>invalid local context</dfn></dt>
<dd>In invalid <a>local context</a> was detected.</dd>
<dt class="changed"><dfn>invalid @nest value</dfn></dt>
<dd class="changed">An invalid value for <code>@nest</code> has been found.</dd>
<dt><dfn>invalid remote context</dfn></dt>
<dd>No valid context document has been found for a referenced,
remote context.</dd>
Expand Down
105 changes: 104 additions & 1 deletion spec/latest/json-ld/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ <h2>Syntax Tokens and Keywords</h2>
<a>IRI</a>. This keyword is described in <a class="sectionRef" href="#default-vocabulary"></a>.</dd>
<dt><code>@graph</code></dt><dd>Used to express a <a>graph</a>.
This keyword is described in <a class="sectionRef" href="#named-graphs"></a>.</dd>
<dt class="changed"><code>@nest</code></dt><dd class="changed">Collects a set of <a>nested properties</a> within
a <a>node object</a>.</dd>
<dt><code>:</code></dt>
<dd>The separator for JSON keys and values that use
<a>compact IRIs</a>.</dd>
Expand Down Expand Up @@ -2684,6 +2686,86 @@ <h2>Node Type Indexing</h2>
as the <code>@type</code> property of the <a>node object</a> value.</p>
</section>

<section class="informative changed">
<h2>Nested Properties</h2>

<p>Many JSON APIs separate properties from their entities using an
intermediate object; in JSON-LD these are called <a>nested properties</a>.
For example, a set of possible labels may be grouped
under a common property:</p>
<pre class="example" data-transform="updateExample"
title="Nested properties">
<!--
{
"@context": {
"skos": "http://www.w3.org/2004/02/skos/core#",
"labels": "@nest",
"main_label": {"@id": "skos:prefLabel"},
"other_label": {"@id": "skos:altLabel"},
"homepage": {"@id":"http://schema.org/description", "@type":"@id"}
},
"@id":"http://example.org/myresource",
"homepage": "http://example.org",
"labels": {
"main_label": "This is the main label for my resource",
"other_label": "This is the other label"
}
}
-->
</pre>

<p>By defining <em>labels</em> using the <a>keyword</a> <code>@nest</code>,
a <a>JSON-LD processor</a> will ignore the nesting created by using the
<em>labels</em> property and process the contents as if it were declared
directly within containing object. In this case, the <em>labels</em>
property is semantically meaningless. Defining it as equivalent to
<code>@nest</code> causes it to be ignored when expanding, making it
equivalent to the following:</p>

<pre class="example" data-transform="updateExample"
title="Nested properties folded into containing object">
<!--
{
"@context": {
"skos": "http://www.w3.org/2004/02/skos/core#",
"labels": "@nest",
"main_label": {"@id": "skos:prefLabel"},
"other_label": {"@id": "skos:altLabel"},
"homepage": {"@id":"http://schema.org/description", "@type":"@id"}
},
"@id":"http://example.org/myresource",
"homepage": "http://example.org",
****"main_label": "This is the main label for my resource",
"other_label": "This is the other label"****
}
-->
</pre>

<p>Similarly, properties may be marked with <code>"@container": "@nest",</code> to cause
them to be nested. Note that the <code>@nest</code> keyword can also be aliased in the
<a>context</a>.</p>
<pre class="example" data-transform="updateExample"
title="Defining property nesting">
<!--
{
"@context": {
"skos": "http://www.w3.org/2004/02/skos/core#",
"labels": "@nest",
"main_label": {"@id": "skos:prefLabel", ****"@container": "@nest"****},
"other_label": {"@id": "skos:altLabel", ****"@container": "@nest"****},
"homepage": {"@id":"http://schema.org/description", "@type":"@id"}
},
"@id":"http://example.org/myresource",
"homepage": "http://example.org",
"labels": {
"main_label": "This is the main label for my resource",
"other_label": "This is the other label"
}
}
-->
</pre>
</section>

<section class="informative">
<h3>Expanded Document Form</h3>

Expand Down Expand Up @@ -3090,6 +3172,7 @@ <h2>Node Objects</h2>
<li><code>@context</code>,</li>
<li><code>@id</code>,</li>
<li><code>@graph</code>,</li>
<li class="changed"><code>@nest</code>,</li>
<li><code>@type</code>,</li>
<li><code>@reverse</code>, or</li>
<li><code>@index</code></li>
Expand Down Expand Up @@ -3145,6 +3228,12 @@ <h2>Node Objects</h2>
<a class="sectionRef" href="#data-indexing"></a> for further discussion
on <code>@index</code> values.</p>

<p class="changed">If the <a>node object</a> contains the <code>@nest</code> key,
its value MUST be an <a>JSON object</a> or an <a>array</a> of <a>JSON objects</a>
which MUST NOT include a <a>value object</a>. See
<a class="sectionRef" href="#property-nesting"></a> for further discussion
on <code>@nest</code> values.</p>

<p>Keys in a <a>node object</a> that are not
<a>keyword</a> MAY expand to an <a>absolute IRI</a>
using the <a>active context</a>. The values associated with keys that expand
Expand Down Expand Up @@ -3315,6 +3404,19 @@ <h2>Type Maps</h2>
the <code>@id</code> of the <a>node object</a> value when expanding.</p>
</section>

<section class="changed">
<h2>Property Nesting</h2>

<p>A <a>nested property</a> is used to gather <a>properties</a> of a <a>node object</a> in a separate
<a>JSON object</a>, or <a>array</a> of <a>JSON objects</a> which are not
<a>value objects</a>. It is semantically transparent and is removed
during the process of expansion. Property nesting is recursive, and
collections of nested properties may contain further nesting.</p>

<p>Semantically, nesting is treated as if the properties and values were declared directly
within the containing <a>node object</a>.</p>
</section>

<section class="normative">
<h2>Context Definitions</h2>

Expand Down Expand Up @@ -3581,7 +3683,8 @@ <h2>Changes since 1.0 Recommendation of 16 January 2014</h2>
<code>@context</code> property, which defines a <a>context</a> used for values of
a <a>property</a> identified with such a <a>term</a>.</li>
<li><code>@container</code> values within an <a>expanded term definition</a> may now
include <code>@id</code> and <code>@type</code>, corresponding to <a>id maps</a> and <a>type maps</a>.</li>
include <code>@id</code> <code>@type</code>, and <code>@nest</code>,
corresponding to <a>id maps</a>, <a>type maps</a> and <a>nested properties</a>.</li>
</ul>
</section>

Expand Down
44 changes: 44 additions & 0 deletions test-suite/tests/compact-manifest.jsonld
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,50 @@
"context": "compact-m004-context.jsonld",
"expect": "compact-m004-out.jsonld",
"option": {"processingMode": "json-ld-1.1"}
}, {
"@id": "#tn001",
"@type": ["jld:PositiveEvaluationTest", "jld:CompactTest"],
"name": "Indexes to @nest for property with @container: @nest",
"purpose": "Compaction using @container: @nest",
"input": "compact-n001-in.jsonld",
"context": "compact-n001-context.jsonld",
"expect": "compact-n001-out.jsonld",
"option": {
"processingMode": "json-ld-1.1"
}
}, {
"@id": "#tn002",
"@type": ["jld:PositiveEvaluationTest", "jld:CompactTest"],
"name": "Indexes to @nest for all properties with @container: @nest",
"purpose": "Compaction using @container: @nest",
"input": "compact-n002-in.jsonld",
"context": "compact-n002-context.jsonld",
"expect": "compact-n002-out.jsonld",
"option": {
"processingMode": "json-ld-1.1"
}
}, {
"@id": "#tn003",
"@type": ["jld:PositiveEvaluationTest", "jld:CompactTest"],
"name": "Nests using alias of @nest",
"purpose": "Compaction using @container: @nest",
"input": "compact-n003-in.jsonld",
"context": "compact-n003-context.jsonld",
"expect": "compact-n003-out.jsonld",
"option": {
"processingMode": "json-ld-1.1"
}
}, {
"@id": "#tn004",
"@type": ["jld:PositiveEvaluationTest", "jld:CompactTest"],
"name": "Arrays of nested values",
"purpose": "Compaction using @container: @nest",
"input": "compact-n004-in.jsonld",
"context": "compact-n004-context.jsonld",
"expect": "compact-n004-out.jsonld",
"option": {
"processingMode": "json-ld-1.1"
}
}
]
}
6 changes: 6 additions & 0 deletions test-suite/tests/compact-n001-context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"@context": {
"@vocab": "http://example.org/",
"p2": {"@container": "@nest"}
}
}
4 changes: 4 additions & 0 deletions test-suite/tests/compact-n001-in.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[{
"http://example.org/p1": [{"@value": "v1"}],
"http://example.org/p2": [{"@value": "v2"}]
}]
10 changes: 10 additions & 0 deletions test-suite/tests/compact-n001-out.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"@context": {
"@vocab": "http://example.org/",
"p2": {"@container": "@nest"}
},
"p1": "v1",
"@nest": {
"p2": "v2"
}
}
7 changes: 7 additions & 0 deletions test-suite/tests/compact-n002-context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"@context": {
"@vocab": "http://example.org/",
"p1": {"@container": "@nest"},
"p2": {"@container": "@nest"}
}
}
4 changes: 4 additions & 0 deletions test-suite/tests/compact-n002-in.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[{
"http://example.org/p1": [{"@value": "v1"}],
"http://example.org/p2": [{"@value": "v2"}]
}]
11 changes: 11 additions & 0 deletions test-suite/tests/compact-n002-out.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"@context": {
"@vocab": "http://example.org/",
"p1": {"@container": "@nest"},
"p2": {"@container": "@nest"}
},
"@nest": {
"p1": "v1",
"p2": "v2"
}
}
7 changes: 7 additions & 0 deletions test-suite/tests/compact-n003-context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"@context": {
"@vocab": "http://example.org/",
"nest": "@nest",
"p2": {"@container": "@nest"}
}
}
4 changes: 4 additions & 0 deletions test-suite/tests/compact-n003-in.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[{
"http://example.org/p1": [{"@value": "v1"}],
"http://example.org/p2": [{"@value": "v2"}]
}]
11 changes: 11 additions & 0 deletions test-suite/tests/compact-n003-out.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"@context": {
"@vocab": "http://example.org/",
"nest": "@nest",
"p2": {"@container": "@nest"}
},
"p1": "v1",
"nest": {
"p2": "v2"
}
}
Loading