-
Notifications
You must be signed in to change notification settings - Fork 152
Changes in Community Group Drafts Targeted for 1.1
Since it’s original publication in 2014, JSON-LD 1.0 has become an essential format for describing structured data on the World Wide Web. Thanks, in part, to the adoption by schema.org as a recommended format, its use on the Web has grown enormously, used by between 10% to 18.2% of all websites.
Additionally, JSON-LD is one of the formats supported by schema.org, in addition to Microdata and RDFa. JSON-LD is also a required format in the Linked Data platform.
- Web Data Commons publication in November 2017
- Of 26,271,491 domains crawled, 2,685,738 contained embedded JSON-LD 1.0.
- W3Techs reports in January 2018
- 18.2% of all websites use JSON-LD 1.0.
In the time between its original publication by the RDF 1.1 Working Group, the documents have been maintained by the JSON for Linking Data Community Group which has had over 100 participants and filed around 100 issues.
In response, the CG has worked to update the specifications and test-suite, accepting over 90 pull requests for a pending CG 1.1 release. These issues generally relate to allowing more natural JSON idioms to be expressed using JSON-LD:
- Require
@version
announcement to enable new features (PR 473). - Allow all values to be used in a map, through the use of a transparent
@none
index (PR 569). - Index values based on
@id
and@type
(PR 449). - Allow named graphs to be supported as values without the use of the
@graph
keyword (PR 549). - Improve
@container
description to ensure values always take an array form (PR 503). - Allow contexts to be defined within term definitions (Scoped Contexts) that apply for values of that term (PR 445)
- Allow for deeper nesting of properties and values without introducing semantics (PR 451).
For backwards compatibility, version 1.1 must be specified to use new 1.1 features (may be through API).
{
"@context":
{
"@version": 1.1,
"schema": "http://schema.org/",
"name": "schema:name",
"body": "schema:articleBody",
"words": "schema:wordCount",
"post": {
"@id": "schema:blogPost",
"@container": "@id"
}
},
"@id": "http://example.com/",
"@type": "schema:Blog",
"name": "World Financial News",
…
}
JSON-LD 1.0 introduced two concepts to access property values through a map (an object with keys referencing values, where the key is logically part of the value).
- Language Indexing
- Allow string values to be indexed by their language tag. When expanded, these become an array of values having associated strings and languages.
- Data Indexing
- These allow both literal values and object values to be indexed using an semantically meaningless index. When expanded, the keys become values of an `@index` element added to the expanded values.
Both of these mechanisms worked great for conforming values, but would not allow values without a language or index to be compacted in the same way. JSON-LD 1.1 introduces the @none
index. For example:
{
"@context": {
"vocab": "http://example.com/vocab/",
"label": {
"@id": "vocab:label",
"@container": "@language"
}
},
"@id": "http://example.com/queen",
"label": {
"en": "The Queen",
"de": [ "Die Königin", "Ihre Majestät" ],
"@none": "The Queen"
}
}
In this case values of label can be represented if they have an associated language, or if they don't. This example expands to the following:
[
{
"@id": "http://example.com/queen",
"http://example.com/vocab/label": [
{
"@value": "The Queen"
},
{
"@value": "Die Königin",
"@language": "de"
},
{
"@value": "Ihre Majestät",
"@language": "de"
},
{
"@value": "The Queen",
"@language": "en"
}
]
}
]
Compacting this representation back will use the same Language Index, unless a term which is a better match for a string without a language is found, to aid in backwards compatibility.
The same @none
indexing method works for Data Indexing as well.
JSON-LD expands on the indexing theme to index nodes by their identifier (@id
value).
{
"@context":
{
"@version": 1.1,
"schema": "http://schema.org/",
"name": "schema:name",
"body": "schema:articleBody",
"words": "schema:wordCount",
"post": {
"@id": "schema:blogPost",
"@container": "@id"
}
},
"@id": "http://example.com/",
"@type": "schema:Blog",
"name": "World Financial News",
"post": {
"http://example.com/posts/1/en": {
"body": "World commodities were up today with heavy trading of crude oil...",
"words": 1539
},
"http://example.com/posts/1/de": {
"body": "Die Werte an Warenbörsen stiegen im Sog eines starken Handels von Rohöl...",
"words": 1204
}
}
}
In this case, the post
property indexes two node objects via their @id
. When expanded, it becomes the following:
[
{
"@id": "http://example.com/",
"@type": ["http://schema.org/Blog"],
"http://schema.org/blogPost": [{
"@id": "http://example.com/posts/1/de",
"http://schema.org/articleBody": [
{"@value": "Die Werte an Warenbörsen stiegen im Sog eines starken Handels von Rohöl..."}
],
"http://schema.org/wordCount": [{"@value": 1204}]
}, {
"@id": "http://example.com/posts/1/en",
"http://schema.org/articleBody": [
{"@value": "World commodities were up today with heavy trading of crude oil..."}
],
"http://schema.org/wordCount": [{"@value": 1539}]
}],
"http://schema.org/name": [{"@value": "World Financial News"}]
}
]
As with Language Indexing and Data Indexing, node objects without an @id
can be indexed using @none
.
This uses the same principle as Identifier Indexing, but using the first value of @type
instead.
{
"@context": {
"@version": 1.1,
"schema": "http://schema.org/",
"name": "schema:name",
"affiliation": {
"@id": "schema:affiliation",
"@container": "@type"
}
},
"name": "Manu Sporny",
"affiliation": {
"schema:Corporation": {
"@id": "https://digitalbazaar.com/",
"name": "Digital Bazaar"
},
"schema:ProfessionalService": {
"@id": "https://spec-ops.io",
"name": "Spec-Ops"
}
}
}
Named Graphs have been supported since 1.0 using the @graph
key, but this adds semantic overhead to the representation, so JSON-LD 1.1 supports property values which are interpreted as anonymous named graphs as well:
{
"@context": {
"@version": 1.1,
"generatedAt": {
"@id": "http://www.w3.org/ns/prov#generatedAtTime",
"@type": "http://www.w3.org/2001/XMLSchema#date"
},
"Person": "http://xmlns.com/foaf/0.1/Person",
"name": "http://xmlns.com/foaf/0.1/name",
"knows": "http://xmlns.com/foaf/0.1/knows",
"claim": {
"@id": "https://w3id.org/credentials#claim",
"@container": "@graph"
}
},
"generatedAt": "2012-04-09",
"claim": [
{
"@id": "http://manu.sporny.org/about#manu",
"@type": "Person",
"name": "Manu Sporny",
"knows": "http://greggkellogg.net/foaf#me"
}, {
"@id": "http://greggkellogg.net/foaf#me",
"@type": "Person",
"name": "Gregg Kellogg",
"knows": "http://manu.sporny.org/about#manu"
}
]
}
In this case, because the term definition for claim
has @container: @graph
, the value becomes an anonymous graph. When expanded, it looks like the following:
[
{
"http://www.w3.org/ns/prov#generatedAtTime": [
{
"@value": "2012-04-09",
"@type": "http://www.w3.org/2001/XMLSchema#date"
}
],
"https://w3id.org/credentials#claim": [
{
"@graph": [
{
"@id": "http://manu.sporny.org/about#manu",
"@type": [
"http://xmlns.com/foaf/0.1/Person"
],
"http://xmlns.com/foaf/0.1/knows": [
{
"@value": "http://greggkellogg.net/foaf#me"
}
],
"http://xmlns.com/foaf/0.1/name": [
{
"@value": "Manu Sporny"
}
]
},
{
"@id": "http://greggkellogg.net/foaf#me",
"@type": [
"http://xmlns.com/foaf/0.1/Person"
],
"http://xmlns.com/foaf/0.1/knows": [
{
"@value": "http://manu.sporny.org/about#manu"
}
],
"http://xmlns.com/foaf/0.1/name": [
{
"@value": "Gregg Kellogg"
}
]
}
]
}
]
}
]
There are variations to allow graphs to be indexed via their explicit identifier, or an @index
value as well.
Since JSON-LD 1.0, it has been possible to ensure that singular property values were represented as an array using the @container: @set
term definition; this is useful to simplify access code which would otherwise need to check to see if the value is singular, or already in an array form, due to the presence of multiple values. However, if the @container
was set to something else, such as @language
or @index
, there was no way to also use @set
. JSON-LD allows the @container
property in a term definition to have an array form, so that @set
can be specified as well as other values.
{
"@context": {
"vocab": "http://example.com/vocab/",
"label": {
"@id": "vocab:label",
"@container": ["@language", "@set"]
}
},
"@id": "http://example.com/queen",
"label": {
"en": ["The Queen"],
"de": [ "Die Königin", "Ihre Majestät" ]
}
}
When compacting data, it will always use an array form.
JSON-LD uses a context to give value to data, and the @context
key could appear anywhere in a document to layer on a new interpretation for terms. But in some cases, such as when framing, it's not possible to specify an embedded context. JSON-LD 1.1 introduces the scoped context, which allows a context to be specified as part of a term definition (which may recursively define terms with scoped contexts). This can be used in two ways, the first is for values of a property defined in such a way:
{
"@context": {
"@version": 1.1,
"@vocab": "@http://schema.org/",
"name": "http://schema.org/name",
"interest": {
"@id": "http://xmlns.com/foaf/0.1/interest",
"@context": {"@vocab": "http://xmlns.com/foaf/0.1/"}
}
},
"name": "Manu Sporny",
"interest": {
"@id": "https://www.w3.org/TR/json-ld/",
"name": "JSON-LD",
"topic": "Linking Data"
}
}
In this case, the top-level context creates a common vocabulary at schema.org with some term definitions. For values of interest
, the embedded @context
is added, which changes the default vocabulary to FOAF.
Scoping can also be performed based on @type
:
"@context": {
"@version": 1.1,
"name": "http://schema.org/name",
"interest": "http://xmlns.com/foaf/0.1/interest",
"Document": {
"@id": "http://xmlns.com/foaf/0.1/Document",
"@context": {"@vocab": "http://xmlns.com/foaf/0.1/"}
}
},
"@type": "Person",
"name": "Manu Sporny",
"interest": {
"@id": "https://www.w3.org/TR/json-ld/",
"@type": "Document",
"name": "JSON-LD",
"topic": "Linking Data"
}
}
In this case, the fact that the @type
of is Document
causes the scoped context to be applied.
Many JSON APIs separate properties from their entities using an intermediate object; in JSON-LD these are called nested properties. For example, a set of possible labels may be grouped under a common property:
{
"@context": {
"@version": 1.1,
"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"
}
}
In this case, the values of labels
are treated as if they were made at the top level. Nesting can be recursive as well.
Similarly, node definitions may contain a @nest
property to reference a term aliased to @nest
which causes such values to be nested under that aliased term when compacting.
{
"@context": {
"@version": 1.1,
"skos": "http://www.w3.org/2004/02/skos/core#",
"labels": "@nest",
"main_label": {"@id": "skos:prefLabel", "@nest": "labels"},
"other_label": {"@id": "skos:altLabel", "@nest": "labels"},
"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"
}
}