json-ld

metadata format for linked data

information science
Author

Oren Bochman

Published

Thursday, July 1, 2021

I’ve been excited about JSON-LD, when it came out as it offered a much cleaner way to do SEO. However It dawned on me later that it is also a geat format to worked with linked data.

  1. it uses a special @id property to assign a unique URL to each resource in a JSON-LD document, giving every data item its own URL.
  2. it links data items together through the values of properties. For example, if you’re describing a person, their “colleague” property can have another person’s URL as its value, creating a web of interconnected data items.
  3. JSON-LD uses the @context property to map the terms used in the document to URLs, conforming data items to common global, organisational and departmental schemas.

One of the best things about JSON-LD is how easy it is to work with. Developers already familiar with JSON syntax will love using it. And get this: JSON-LD is so popular that it’s now embedded in almost half of all web pages. It’s baffling why all organisations aren’t using JSON-LD more widely to share data between their applications!

So, whether you’re publishing Data Products, creating RESTful applications or improving your website’s SEO, JSON-LD is the way to go! Give it a try and let me know your thoughts in the comments below.

person = {
  "@context": "https://json-ld.org/contexts/person.jsonld",
  "@type": "https://schema.org/Person",
  "@id": "http://dbpedia.org/resource/John_Lennon",
  "https://schema.org/name": "John Lennon",
  "born": "1940-10-09",
  "spouse": "http://dbpedia.org/resource/Cynthia_Lennon"
}
1
the @context refrences your model
2
the @type is the type in your model
3
the @id is the yrl for this item
4
the url is how to reference external data say dbpedia.

python

Compacting

from pyld import jsonld
import json
doc = {
    "http://schema.org/name": "Manu Sporny",
    "http://schema.org/url": {"@id": "http://manu.sporny.org/"},
    "http://schema.org/image": {"@id": "http://manu.sporny.org/images/manu.png"},
    "@type": "https://schema.org/Person",
}
context = {
    "name": "http://schema.org/name",
    "homepage": {"@id": "http://schema.org/url", "@type": "@id"},
    "image": {"@id": "http://schema.org/image", "@type": "@id"}
}

# compact a document according to a particular context

# see: https://json-ld.org/spec/latest/json-ld/#compacted-document-form
compacted = jsonld.compact(doc, context)
print(json.dumps(compacted, indent=2))
{
  "@context": {
    "name": "http://schema.org/name",
    "homepage": {
      "@id": "http://schema.org/url",
      "@type": "@id"
    },
    "image": {
      "@id": "http://schema.org/image",
      "@type": "@id"
    }
  },
  "@type": "https://schema.org/Person",
  "image": "http://manu.sporny.org/images/manu.png",
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}
# compact using URLs
#jsonld.compact('http://example.org/doc', 'http://example.org/context')

Expanding

# expand a document, removing its context

# see: https://json-ld.org/spec/latest/json-ld/#expanded-document-form
expanded = jsonld.expand(compacted)
print(json.dumps(expanded, indent=2))
[
  {
    "@type": [
      "https://schema.org/Person"
    ],
    "http://schema.org/url": [
      {
        "@id": "http://manu.sporny.org/"
      }
    ],
    "http://schema.org/image": [
      {
        "@id": "http://manu.sporny.org/images/manu.png"
      }
    ],
    "http://schema.org/name": [
      {
        "@value": "Manu Sporny"
      }
    ]
  }
]
# expand using URLs

# jsonld.expand('http://example.org/doc')

Flattening

# flatten a document

# see: https://json-ld.org/spec/latest/json-ld/#flattened-document-form
flattened = jsonld.flatten(doc)

# all deep-level trees flattened to the top-level
print(json.dumps(flattened, indent=2))
[
  {
    "@id": "_:b0",
    "@type": [
      "https://schema.org/Person"
    ],
    "http://schema.org/image": [
      {
        "@id": "http://manu.sporny.org/images/manu.png"
      }
    ],
    "http://schema.org/name": [
      {
        "@value": "Manu Sporny"
      }
    ],
    "http://schema.org/url": [
      {
        "@id": "http://manu.sporny.org/"
      }
    ]
  }
]

Framing

docf = {
  "@context": {
    "@vocab": "http://example.org/",
    "contains": {
      "@type": "@id"
    }
  },
  "@graph": [
    {
      "@id": "http://example.org/library",
      "@type": "Library",
      "location": "Athens",
      "contains": "http://example.org/library/the-republic"
    },
    {
      "@id": "http://example.org/library/the-republic",
      "@type": "Book",
      "creator": "Plato",
      "title": "The Republic",
      "contains": "http://example.org/library/the-republic#introduction"
    },
    {
      "@id": "http://example.org/library/the-republic#introduction",
      "@type": "Chapter",
      "description": "An introductory chapter on The Republic.",
      "title": "The Introduction"
    }
  ]
}

frame = {
  "@context": {
    "@vocab": "http://example.org/"
  },
  "location": "Athens",
  "contains": {
    "title": "The Republic",
    "contains": {
      "title": "The Introduction"
    }
  }
}

# frame a document

# see: https://json-ld.org/spec/latest/json-ld-framing/#introduction
framed = jsonld.frame(docf, frame)
print(json.dumps(framed, indent=2))

# document transformed into a particular tree structure per the given frame
{
  "@context": {
    "@vocab": "http://example.org/"
  },
  "@graph": [
    {
      "@id": "http://example.org/library",
      "@type": "Library",
      "contains": {
        "@id": "http://example.org/library/the-republic",
        "@type": "Book",
        "contains": {
          "@id": "http://example.org/library/the-republic#introduction",
          "@type": "Chapter",
          "description": "An introductory chapter on The Republic.",
          "title": "The Introduction"
        },
        "creator": "Plato",
        "title": "The Republic"
      },
      "location": "Athens"
    },
    {
      "@id": "http://example.org/library/the-republic",
      "@type": "Book",
      "contains": null,
      "creator": "Plato",
      "location": null,
      "title": "The Republic"
    }
  ]
}

Normalization

# normalize a document using the RDF Dataset Normalization Algorithm

# (URDNA2015), see: https://json-ld.github.io/normalization/spec/
normalized = jsonld.normalize(
    doc, {'algorithm': 'URDNA2015', 'format': 'application/n-quads'})

# normalized is a string that is a canonical representation of the document

# that can be used for hashing, comparison, etc.
print(json.dumps(normalized, indent=2))
"_:c14n0 <http://schema.org/image> <http://manu.sporny.org/images/manu.png> .\n_:c14n0 <http://schema.org/name> \"Manu Sporny\" .\n_:c14n0 <http://schema.org/url> <http://manu.sporny.org/> .\n_:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://schema.org/Person> .\n"

Resources

  1. json-ld
  2. schema.org
  3. ProductOntology
  4. GoodRelations
  5. Wikidata
  6. https://schemantra.com/
  7. https://github.com/science-periodicals/jsonld-vis
  8. https://github.com/shamilnabiyev/schema-visualizer
  9. https://cloud.google.com/natural-language/

Citation

BibTeX citation:
@online{bochman2021,
  author = {Bochman, Oren},
  title = {Json-Ld},
  date = {2021-07-01},
  url = {https://orenbochman.github.io/posts/2021/2021-07-01-json-ld/json-ld.html},
  langid = {en}
}
For attribution, please cite this work as:
Bochman, Oren. 2021. “Json-Ld.” July 1, 2021. https://orenbochman.github.io/posts/2021/2021-07-01-json-ld/json-ld.html.