Skip to content

JSON LD

rossbowen edited this page Nov 8, 2022 · 1 revision

JSON-LD is a serialisation of RDF, like turtle, but based around the JSON data format.

Resources

  • The JSON-LD spec has introductory material and examples. We will cover a much smaller set of features in this document.
  • https://json-ld.org/
  • Google's SEO (search engine optimisation) documentation has a section on structured data with many examples of how including JSON-LD within a website's HTML can be used to make Google and other search engines show special results.
  • Google's docs mention structured data for Datasets which include the CSV on the Web standard (see CSV on the Web).
  • Google have a tutorial for adding strutured data to a webpage.

Tools

JSON-LD

JSON-LD defines some special keywords to represent RDF.

@id

Related section in JSON-LD 1.1

  • @id is a special keyword used to specify the URI of a resource.
  • Predicates and objects are specified through further JSON key-value pairs.

The following turtle can be represented as JSON-LD in this way:

<http://example.org#Ross> <http://example.org#knows> <http://example.org#Alex> .
{
    "@id": "http://example.org#Ross",
    "http://example.org#knows": {
        "@id": "http://example.org#Alex"
    }
}

The type of a resource can be indicated by the @type keyword.

<http://example.org#Ross> a <http://example.org#Person> .
{
    "@id": "http://example.org#Ross",
    "@type": "http://example.org#Person"
}

Multiple objects can be written with a JSON array:

@prefix ex: <http://example.org#> .

ex:Ross ex:knows ex:Alex, ex:Andrew .
{
    "@id": "http://example.org#Ross",
    "http://example.org#knows": [
        {
            "@id": "http://example.org#Alex"
        },
        {
            "@id": "http://example.org#Andrew"
        }
    ]
}

Blank nodes are represented by omitting the @id keyword:

@prefix ex: <http://example.org#> .

ex:Ross ex:knows [ ex:name "Alex"@en ] .
{
    "@id": "http://example.org#Ross",
    "http://example.org#knows": {
        // no "@id" here
        "http://example.org#name": {
            "@value": "Alex",
            "@language": "en"
        }
    }
}

Literals

Related section in JSON-LD 1.1

Literals are represented using the @value keyword. A typed literal's type is indicated by the @type keyword.

A date literal can be represented like this:

@prefix ex: <http://example.org#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:Ross ex:birthday "1900-01-01"^^xsd:date .
{
    "@id": "http://example.org#Ross",
    "http://example.org#birthday": {
        "@value": "1900-01-01",
        "@type": "http://www.w3.org/2001/XMLSchema#date"
    }
}

Language strings are similar. The language of a literal can be represented by the @language keyword (while omitting the @type keyword.)

@prefix ex: <http://example.org#> .

ex:Q102438 a ex:Book ;
    ex:name "Harry Potter and the Philosopher's Stone"@en,
        "Harri Potter a Maen yr Athronydd"@cy,
        "Harry Potter à l'école des sorciers"@fr,
        "Harry Potter und der Stein der Weisen"@de,
        "Harry Potter y la piedra filosofal"@es ;
        .
{
    "@id": "http://example.org#Q102438",
    "http://example.org#name": [
        {
            "@value": "Harry Potter and the Philosopher's Stone",
            "@language": "en"
        },
        {
            "@value": "Harri Potter a Maen yr Athronydd",
            "@language": "cy"
        },
        {
            "@value": "Harry Potter à l'école des sorciers",
            "@language": "fr"
        },
        {
            "@value": "Harry Potter und der Stein der Weisen",
            "@language": "de"
        },
        {
            "@value": "Harry Potter y la piedra filosofal",
            "@language": "es"
        }
    ]
}

@context

Related section in JSON-LD 1.1

The @context keyword is similar to the concept of providing prefixes in turtle or SPARQL, though is a bit more powerful. A context can be used to alias URIs, potentially giving an author of JSON-LD the ability to not have to use any of the @id, @value or @language keywords (which some developers think are a bit weird to work with).

This is an example of the CSVW context. (See CSV on the Web.)

Related section in JSON-LD 1.1

Consider the following triple:

<http://example.org#Ross> <http://example.org#knows> <http://example.org#Alex> .

Without a context, a fully expanded JSON-LD document would look like:

{
    "@id": "http://example.org#Ross",
    "http://example.org#knows": {
        "@id": "http://example.org#Alex"
    }
}

We may define a @context which includes a prefix ex. This can be used throughout the JSON-LD similarly to how it would be in turtle.

{
    "@context": {
        "ex": "http://example.org#"
    },
    "@id": "ex:Ross",
    "ex:knows": {
        "@id": "ex:Alex"
    }
}

The context can also map full terms to URIs. The following context includes foaf as a prefix and includes a mapping for the term knows:

  • The @id for knows is set to foaf:knows, meaning it will be interpreted as foaf:knows when interpreted as RDF,
  • The @type for knows is set to @id, which indicates the value associated with knows should be interpreted as a URI instead of a literal.
{
    "@context": {
        "ex": "http://example.org#",
        "foaf": "http://xmlns.com/foaf/0.1/",
        "knows": {
            "@id": "foaf:knows",
            "@type": "@id"
        }
    },
    "@id": "ex:Ross",
    "knows": "ex:Alex"
}
@prefix ex:   <http://example.org#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

ex:Ross foaf:knows ex:Alex .

Contexts can be used to turn "easier" looking JSON into full RDF. You could imagine an API or some software producing JSON which looks as follows:

{
    "book_id": "Q102438",
    "title_en": "Harry Potter and the Philosopher's Stone",
    "title_cy": "Harri Potter a Maen yr Athronydd",
    "title_fr": "Harry Potter à l'école des sorciers",
    "title_de": "Harry Potter und der Stein der Weisen",
    "title_es": "Harry Potter y la piedra filosofal"
}

This JSON doesn't contain any of the @ keywords such as @id, @type, @language or @value which might be expected in an expanded JSON-LD document. Also, no URLs appear in the JSON.

We can add semantics and additional meaning to the JSON by including a context. With the following context, the JSON document is equivalent the he previous RDF example for multiple language strings.

{
    "@context": {     
        "@base": "http://example.org/",
        "book_id": {"@id": "@id"},
        "title_en": {"@id": "ex:title", "@language": "en"},
        "title_cy": {"@id": "ex:title", "@language": "cy"},
        "title_fr": {"@id": "ex:title", "@language": "fr"},
        "title_de": {"@id": "ex:title", "@language": "de"},
        "title_es": {"@id": "ex:title", "@language": "es"}
    },
    "book_id": "Q102438",
    "title_en": "Harry Potter and the Philosopher's Stone",
    "title_cy": "Harri Potter a Maen yr Athronydd",
    "title_fr": "Harry Potter à l'école des sorciers",
    "title_de": "Harry Potter und der Stein der Weisen",
    "title_es": "Harry Potter y la piedra filosofal"
}

We could serve the above inline context as a file at the URL http://ross-book-shop.co.uk/api/context, and then reference the URL - compacting the JSON document further.

{
    "@context": "http://ross-book-shop.co.uk/api/context",
    "book_id": "Q102438",
    "title_en": "Harry Potter and the Philosopher's Stone",
    "title_cy": "Harri Potter a Maen yr Athronydd",
    "title_fr": "Harry Potter à l'école des sorciers",
    "title_de": "Harry Potter und der Stein der Weisen",
    "title_es": "Harry Potter y la piedra filosofal"
}

@reverse

Related section in JSON-LD 1.1

Consider the triple Ross knows Alex:

@prefix ex:   <http://example.org#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

ex:Ross foaf:knows ex:Alex .

Sometimes it is more convienient to produce a JSON where the object of the triple is "above" the subject in the JSON hierarchy. In this case, we can use the @reverse keyword to flip the positions of subject and object.

The following JSON-LD results in the above triple.

{
    "@context": {
        "ex": "http://example.org#",
        "foaf": "http://xmlns.com/foaf/0.1/",
        "isKnownBy": {
            "@reverse": "foaf:knows",
            "@type": "@id"
        }
    },
    "@id": "ex:Alex",
    "isKnownBy": "ex:Ross"
}

@nest

Related section in JSON-LD 1.1

The @nest keyword helps with nested JSON structures. The following is equivalent to the previous language string example, despite the JSON structure being different.

{
    "@context": {
        "@base": "http://example.org/",
        "ex": {"@id": "http://example.org/"},
        "book_id": {"@id": "@id"},
        "title": "@nest",
        "en": {"@id": "ex:title", "@language": "en", "@nest": "title"},
        "cy": {"@id": "ex:title", "@language": "cy", "@nest": "title"},
        "fr": {"@id": "ex:title", "@language": "fr", "@nest": "title"},
        "de": {"@id": "ex:title", "@language": "de", "@nest": "title"},
        "es": {"@id": "ex:title", "@language": "es", "@nest": "title"}
    },
    "book_id": "Q102438",
    "title": {
        "en": "Harry Potter and the Philosopher's Stone",
        "cy": "Harri Potter a Maen yr Athronydd",
        "fr": "Harry Potter à l'école des sorciers",
        "de": "Harry Potter und der Stein der Weisen",
        "es": "Harry Potter y la piedra filosofal"
    }
}

Exercise

If you inspect a page on GOV.UK and look at the HTML, you will usually find some HTML tags with <script type="application/ld+json">. This is used to embed JSON-LD structured data in a webpage and helps with search engine optimisation (see Google's docs).

The following JSON-LD was taken from GOV.UK's UK bank holidays page. It uses the schema.org context which can be viewed here. Try writing equivalent RDF in turtle.

{
    "@context": "http://schema.org",
    "@type": "Article",
    "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://www.gov.uk/bank-holidays"
    },
    "name": "UK bank holidays",
    "datePublished": "2016-01-26T13:04:36.000+00:00",
    "dateModified": "2021-12-06T13:26:54.000+00:00",
    "text": "Find out when bank holidays are in England, Wales, Scotland and Northern Ireland - including past and future bank holidays",
    "publisher": {
        "@type": "Organization",
        "name": "GOV.UK",
        "url": "https://www.gov.uk",
        "logo": {
            "@type": "ImageObject",
            "url": "https://www.gov.uk/assets/frontend/govuk_publishing_components/govuk-logo-73b5a4056ffe9988d02c728b56fe9fe7f90bb822322a5f6183ccbb92a99b019a.png"
        }
    },
    "image": [
        "https://www.gov.uk/assets/frontend/govuk_publishing_components/govuk-schema-placeholder-1x1-bf9e64d759af6dfd93bede8168f3087a329f405b382aff36747db0db4b7b23e9.png",
        "https://www.gov.uk/assets/frontend/govuk_publishing_components/govuk-schema-placeholder-4x3-13093f053c15f613acd827aff27cac83d3fab452947cbcae4c7b706dadf2f7f2.png",
        "https://www.gov.uk/assets/frontend/govuk_publishing_components/govuk-schema-placeholder-16x9-4233cd42671827e266e284c4d5ae68fb600bd9f9e35dda663ccabbc2b6ab7ec3.png"
    ],
    "author": {
        "@type": "Organization",
        "name": "Government Digital Service",
        "url": "https://www.gov.uk/government/organisations/government-digital-service"
    },
    "about": [
        {
            "@context": "http://schema.org",
            "@type": "Thing",
            "sameAs": "https://www.gov.uk/employment/time-off"
        }
    ],
    "headLine": "UK bank holidays",
    "description": "Find out when bank holidays are in England, Wales, Scotland and Northern Ireland - including past and future bank holidays"
}

Clone this wiki locally