JSON-LD - Linked Data Expression in JSON

A Context-based JSON Serialization for Linked Data

Unofficial Draft 01 February 2011

Editor:
Manu Sporny, Digital Bazaar, Inc.
Authors:
Mark Birbeck, Backplane Ltd.
Manu Sporny, Digital Bazaar, Inc.

Abstract

Developers that embed structured data in their Web pages can choose among a number of languages such as RDFa [RDFA-CORE], Microformats [MICROFORMATS] and Microdata [MICRODATA]. Each of these structured data languages, while incompatible at the syntax level, can be easily mapped to RDF. JSON has proven to be a highly useful object serialization and messaging format. In an attempt to harmonize the representation of Linked Data in JSON, this specification outlines a common JSON representation format for Linked Data that can be used to represent objects specified via RDFa, Microformats and Microdata.

Status of This Document

This document is merely a public working draft of a potential specification. It has no official standing of any kind and does not represent the support or consensus of any standards organisation.

This document is an experimental work in progress.

Table of Contents

1. Introduction

Write the introduction once all of the technical details are hammered out. Explain why JSON-LD is designed as a light-weight mechanism to express RDFa, Microformats and Microdata. It is primarily intended as a way to express Linked Data in Javascript environments as well as a way to pass Linked Data to and from Web services. It is designed to be as simple as possible, utilizing the large number of JSON parsers (and understanding) that is out there already. It is designed to be able to express key-value pairs, RDF data, Microformats data, and Microdata (that is, every data model currently in use) using one unified format. It does not require anyone to change their JSON, but easily add meaning by adding context in a way that is out-of-band - it is designed to not disturb already deployed systems running on JSON, but provide a smooth migration path from JSON to JSON with added semantics. Finally, the format is intended to be fast to parse, fast to generate, stream-based and document-based processing compatible, and require a tiny memory footprint in order to operate.

1.1 How to Read this Document

This document is a detailed specification for a serialization of JSON for Linked data. The document is primarily intended for the following audiences:

To understand this specification you must first be familiar with JSON, which is detailed in [RFC4627] and [RDF-CONCEPTS].

1.2 Contributing

There are a number of ways that one may participate in the development of this specification:

2. Design Goals and Rationale

The following section outlines the design goals and rationale behind the JSON-LD markup language.

2.1 Goals

A number of design considerations were explored during the creation of this markup language:

Simplicity
Developers don't need to know RDF in order to use the basic functionality provided by JSON-LD.
Compatibility
The JSON-LD markup should be 100% compatible with JSON.
Expressiveness
All major RDF concepts must be expressible via the JSON-LD syntax.
Terseness
The JSON-LD syntax must be very terse and human readable.
Zero Edits
JSON-LD provides a mechanism that allows developers to specify context in a way that is out-of-band. This allows organizations that have already deployed large JSON-based infrastructure to add meaning to their JSON in a way that is not disruptive to their day-to-day operations and is transparent to their current customers.
Streaming
The format supports both document-based and stream-based processing.

2.2 Map Terms to IRIs

Establishing a mechanism to map JSON values to IRIs will help in the mapping of JSON objects to RDF. This does not mean that JSON-LD must be restrictive in declaring a set of terms, rather, experimentation and innovation should be supported as part of the core design of JSON-LD. There are, however, a number of very small design criterial that can ensure that developers will generate good RDF data that will create value for the greater semantic web community and JSON/REST-based Web Services community.

We will be using the following JSON object as the example for this section:

{
  "a": "Person",
  "name": "Manu Sporny",
  "homepage": "http://manu.sporny.org/"
}

2.3 The Default Context

A default context is used in RDFa to allow developers to use keywords as aliases for IRIs. So, for instance, the keyword name above could refer to the IRI http://xmlns.com/foaf/0.1/name. The semantic web, just like the document-based web, uses IRIs for unambiguous identification. The idea is that these terms mean something, which you will eventually want to query. The semantic web specifies this via Vocabulary Documents. The IRI http://xmlns.com/foaf/0.1/ specifies a Vocabulary Document, and name is a term in that vocabulary. Paste the two items together and you have an unambiguous identifier for a term.

Developers, and machines, would be able to use this IRI (plugging it directly into a web browser, for instance) to go to the term and get a definition of what the term means. Much like we can use WordNet today to see the definition of words in the English language. Machines need the same sort of dictionary of terms, and URIs provide a way to ensure that these terms are unambiguous.

Non-prefixed terms should have term mappings declared in the default context so that they may be expanded later.

If a set of terms, like Person, name, and homepage, are pre-defined in the default context, and that context is used to resolve the names in JSON objects, machines could automatically expand the terms to something meaningful and unambiguous, like this:

{
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": "<http://xmlns.com/foaf/0.1/Person>",
  "http://xmlns.com/foaf/0.1/name": "Manu Sporny",
  "http://xmlns.com/foaf/0.1/homepage": "<http://manu.sporny.org>"
}

In order to differentiate between plain text and IRIs, the < and > are used around IRIs.

Doing this would mean that JSON would start to become unambiguously machine-readable, play well with the semantic web, and basic markup wouldn't be that much more complex than basic JSON markup. A win, all around.

2.4 Mashing Up Vocabularies

Developers would also benefit by allowing other vocabularies to be used automatically with their JSON API. There are over 200 Vocabulary Documents that are available for use on the Web today. Some of these vocabularies are:

A JSON-LD Web Service could define these as prefixes in their default context beside the terms that are already defined. Using this feature, developers could also express markup like this:

{
  "rdf:type": "<foaf:Person>",
  "foaf:name": "Manu Sporny",
  "foaf:homepage": "<http://manu.sporny.org/>",
  "sioc:avatar": "<http://twitter.com/account/profile_image/manusporny>"
}

Developers can also specify their own Vocabulary documents by modifying the default context in-line using the # character, like so:

{
  "#": { "myvocab": "http://example.org/myvocab#" },
  "a": "<foaf:Person>",
  "foaf:name": "Manu Sporny",
  "foaf:homepage": "<http://manu.sporny.org/>",
  "sioc:avatar": "<http://twitter.com/account/profile_image/manusporny>",
  "myvocab:credits": 500
}

Think of the # character as a "hashtable", which maps one string to another string. In the example above, the myvocab string is replaced with "http://example.org/myvocab#" when it is detected above. In the example above, "myvocab:credits" would expand to "http://example.org/myvocab#credits".

This mechanism is a short-hand for RDF, and if defined, will give developers an unambiguous way to map any JSON value to RDF.

2.5 An Example of a Default Context

JSON-LD strives to ensure that developers don't have to change the JSON that is going into and being returned from their Web applications. A JSON-LD aware Web Service may define a default context. For example, the following default context could apply to all incoming Web Service calls previously accepting only JSON data:

{
  "#": 
  {
    "#vocab": "http://example.org/default-vocab#",
    "#base": "http://example.org/baseurl/",
    "xsd": "http://www.w3.org/2001/XMLSchema#",
    "dc": "http://purl.org/dc/terms/",
    "foaf": "http://xmlns.com/foaf/0.1/",
    "sioc": "http://rdfs.org/sioc/ns#",
    "cc": "http://creativecommons.org/ns#",
    "geo": "http://www.w3.org/2003/01/geo/wgs84_pos#",
    "vcard": "http://www.w3.org/2006/vcard/ns#",
    "cal": "http://www.w3.org/2002/12/cal/ical#",
    "doap": "http://usefulinc.com/ns/doap#",
    "Person": "http://xmlns.com/foaf/0.1/Person",
    "name": "http://xmlns.com/foaf/0.1/name",
    "homepage": "http://xmlns.com/foaf/0.1/homepage"
  }
}

The #vocab string is a special keyword that states that any term that doesn't resolve to a term or a prefix should be appended to the #vocab IRI. This is done to ensure that terms can be transformed to an IRI at all times.

The #base string is a special keyword that states that any relative IRI must be appended to the string specified by #base.

3. Markup Examples

The JSON-LD markup examples below demonstrate how JSON-LD can be used to express semantic data marked up in other languages such as RDFa, Microformats, and Microdata. These sections are merely provided as proof that JSON-LD is very flexible in what it can express across different Linked Data approaches.

3.1 RDFa

The following example describes three people with their respective names and homepages.

<div prefix="foaf: http://xmlns.com/foaf/0.1/">
   <ul>
      <li typeof="foaf:Person">
        <a rel="foaf:homepage" href="http://example.com/bob/" property="foaf:name" >Bob</a>
      </li>
      <li typeof="foaf:Person">
        <a rel="foaf:homepage" href="http://example.com/eve/" property="foaf:name" >Eve</a>
      </li>
      <li typeof="foaf:Person">
        <a rel="foaf:homepage" href="http://example.com/manu/" property="foaf:name" >Manu</a>
      </li>
   </ul>
</div>

An example JSON-LD implementation is described below, however, there are other ways to mark-up this information such that the context is not repeated.

[
 {
   "#": { "foaf": "http://xmlns.com/foaf/0.1/" },
   "@": "_:bnode1",
   "a": "foaf:Person",
   "foaf:homepage": "<http://example.com/bob/>",
   "foaf:name": "Bob"
 },
 {
   "#": { "foaf": "http://xmlns.com/foaf/0.1/" },
   "@": "_:bnode2",
   "a": "foaf:Person",
   "foaf:homepage": "<http://example.com/eve/>",
   "foaf:name": "Eve"
 },
 {
   "#": { "foaf": "http://xmlns.com/foaf/0.1/" },
   "@": "_:bnode3",
   "a": "foaf:Person",
   "foaf:homepage": "<http://example.com/manu/>",
   "foaf:name": "Manu"
 }
]

3.2 Microformats

The following example uses a simple Microformats hCard example to express how the Microformat is represented in JSON-LD.

<div class="vcard">
 <a class="url fn" href="http://tantek.com/">Tantek Çelik</a>
</div>

The representation of the hCard expresses the Microformat terms in the context and uses them directly for the url and fn properties. Also note that the Microformat to JSON-LD processor has generated the proper URL type for http://tantek.com.

{
  "#": 
  {
    "vcard": "http://microformats.org/profile/hcard#vcard"
    "url": "http://microformats.org/profile/hcard#url"
    "fn": "http://microformats.org/profile/hcard#fn"
  },
  "@": "_:bnode1",
  "a": "vcard",
  "url": "<http://tantek.com/>",
  "fn": "Tantek Çelik"
}

3.3 Microdata

The Microdata example below expresses book information as a Microdata Work item.

<dl itemscope
    itemtype="http://purl.org/vocab/frbr/core#Work"
    itemid="http://purl.oreilly.com/works/45U8QJGZSQKDH8N">
 <dt>Title</dt>
 <dd><cite itemprop="http://purl.org/dc/terms/title">Just a Geek</cite></dd>
 <dt>By</dt>
 <dd><span itemprop="http://purl.org/dc/terms/creator">Wil Wheaton</span></dd>
 <dt>Format</dt>
 <dd itemprop="http://purl.org/vocab/frbr/core#realization"
     itemscope
     itemtype="http://purl.org/vocab/frbr/core#Expression"
     itemid="http://purl.oreilly.com/products/9780596007683.BOOK">
  <link itemprop="http://purl.org/dc/terms/type" href="http://purl.oreilly.com/product-types/BOOK">
  Print
 </dd>
 <dd itemprop="http://purl.org/vocab/frbr/core#realization"
     itemscope
     itemtype="http://purl.org/vocab/frbr/core#Expression"
     itemid="http://purl.oreilly.com/products/9780596802189.EBOOK">
  <link itemprop="http://purl.org/dc/terms/type" href="http://purl.oreilly.com/product-types/EBOOK">
  Ebook
 </dd>
</dl>

Note that the JSON-LD representation of the Microdata information stays true to the desires of the Microdata community to avoid contexts and instead refer to items by their full IRI.

[
  {
    "@": "<http://purl.oreilly.com/works/45U8QJGZSQKDH8N>",
    "a": "http://purl.org/vocab/frbr/core#Work",
    "http://purl.org/dc/terms/title": "Just a Geek",
    "http://purl.org/dc/terms/creator": "Whil Wheaton",
    "http://purl.org/vocab/frbr/core#realization": 
      ["<http://purl.oreilly.com/products/9780596007683.BOOK>", "<http://purl.oreilly.com/products/9780596802189.EBOOK>"]
  },
  {
    "@": "<http://purl.oreilly.com/products/9780596007683.BOOK>",
    "a": "<http://purl.org/vocab/frbr/core#Expression>",
    "http://purl.org/dc/terms/type": "<http://purl.oreilly.com/product-types/BOOK>"
  },
  {
    "@": "<http://purl.oreilly.com/products/9780596802189.EBOOK>",
    "a": "http://purl.org/vocab/frbr/core#Expression",
    "http://purl.org/dc/terms/type": "<http://purl.oreilly.com/product-types/EBOOK>"
  }
]

4. The JSON-LD Processing Algorithm

The processing algorithm described in this section is provided in order to demonstrate how one might implement a JSON-LD processor. Conformant implementations are only required to produce the same type and number of triples during the output process and are not required to implement the algorithm exactly as described.

The Processing Algorithm is a work in progress, there are still major bugs in the algorithm and it's difficult to follow. It's provided only to very early implementers to give them an idea of how to implement a processor.

Processing Algorithm Terms

Processing Tokens and Keywords

The algorithm below is designed for streaming (SAX-based) implementations. Implementers will find that non-streaming (document-based) implementations will be much easier to implement as full access to the JSON object model eliminates some of the steps that are necessary for streaming implementations. A conforming JSON-LD processor must implement a processing algorithm that results in the same default graph that the following algorithm generates:

  1. If a default context is supplied to the processing algorithm, push it onto the active context stack.
  2. If an associative array is detected, create a new processor state. Copy the current context stack to the newly created processor state. Push the active context onto the newly created processor state's active context stack. For each key-value pair in the associative array, using the newly created processor state do the following:
    1. If a # key is found, the processor merges each key-value pair in the local context into the active context, overwriting any duplicate values in the active context. Process each object in the list of unprocessed items, starting at Step 2.2.
    2. If the local context has not been detected, the current key-value pair is placed into the list of unprocessed items and processing proceeds to the next key-value pair. Otherwise, if the local context is known perform the following steps:
      1. If a @ key is found, the processor sets the active subject to the value after Object Processing has been performed.
        1. If the inherited subject and inherited property values are specified, generate a triple using the inherited subject for the subject, the inherited property for the property, and the active subject for the object.
        2. If there are any triples in the list of incomplete triples, complete each triple using the active subject as the subject for each triple.
      2. If an a key is found, set the active property to http://www.w3.org/1999/02/22-rdf-syntax-ns#type.
      3. If a key that is not #, @, or a is found, set the active property by performing Property Processing on the key.
      4. If the value is not an array, set the active object by performing Object Processing on the value. Generate a triple representing the active subject, the active property and the active object.
      5. If the value is an associative array, then process the value starting at Step 2.
      6. If the value is a regular array, then process the value starting at Step 3 ensuring that the active subject and the active property are copied to a newly created processor state.
      7. If the end of the associative array is detected, and a active subject was not discovered, then:
        1. Generate a blank node identifier and set it as the active subject.
        2. Complete any previously incomplete triples by running all substeps of Step 2.2.1.
      8. If the end of the associative array is detected, and a local context was not discovered, then assume that the active context is unmodified and run all substeps of Step 2.2 on the list of unprocessed items.
  3. If a regular array is detected, process each value in the array by doing the following:
    1. If the value is an associative array, processes per Step 2, ensuring to set the inherited subject to the active subject and the inherited property to the active property in the newly created processor state.
    2. If the value is not an array, set the active object by performing Object Processing on the value. Generate a triple representing the active subject, the active property and the active object and place it into the default graph.
    3. If the value is a regular array, should we support RDF List/Sequence Processing?
      If the value is a regular array, should we support RDF List/Sequence generation of triples? For example, would implementing this be worth the more complex processing rules: "ex:orderedItems" : [["one", "two", "three"]]

5. Markup of RDF Concepts

JSON-LD is designed to ensure that most Linked Data concepts can be marked up in a way that is simple to understand and author by Web developers. In many cases, Javascript objects can become Linked Data with the simple addition of a context. Since RDF is also an important sub-community of the Linked Data movement, it is important that all RDF concepts are well-represented in this specification. This section details how each RDF concept can be expressed in JSON-LD.

The current specification relies on microsyntaxes to express things like IRIs, typed literals and CURIEs. There is a small amount of debate on whether or not to use full-blown JSON objects containing things like "value" and "datatype". The original authors of the JSON-LD specification feel that microsyntaxes allow a much simpler, less error-prone structure in the JSON-LD objects. Proponents of the verbose mechanism assert that there would be less chance of data markup issues concerning proper escaping and that the objects, while more verbose, would be easier to work with within JavaScript environments. Feedback on this issue would be appreciated.

5.1 IRIs

Expressing IRIs are fundamental to Linked Data as that is how most subjects and many objects are identified. IRIs can be expressed by wrapping a text string with the < and > characters.

{
...
  "foaf:homepage": "<http://manu.sporny.org>",
...
}

The example above would set the object to an IRI with the value of http://manu.sporny.org.

As a general rule, all CURIEs and IRIs may be wrapped in < and > characters. This is to ensure that there is a simple, consistent rule that can be followed when authoring JSON-LD data. There are, however, several instances where angle brackets may be omitted, without introducing ambiguity, to ease authoring burden. These instances are:

Wrapping IRIs with the < and > characters are only mandatory when IRIs are specified as values in the JSON key-value pairs.

To further illustrate, the following example omissions of the < and > characters are allowed:

{
...
  "@": "<http://manu.sporny.org/about#manu>",
  // CURIE/IRI when specifying the subject can be minimized.
  "@": "http://manu.sporny.org/about#manu",
...
  "a": "<foaf:Person>",
  // CURIE/IRI when specifying the type of an object can be minimized.
  "a": "foaf:Person",
...
  "<foaf:homepage>": "<http://manu.sporny.org>",
  // CURIE/IRI when specifying a property can be minimized.
  "foaf:homepage": "<http://manu.sporny.org>",
...
}

At all other times, CURIEs and IRIs must be wrapped with the < and > characters.

5.2 Identifying the Subject

A subject is declared using the @ key. The subject is the first piece of information needed by the JSON-LD processor in order to create the (subject, predicate, object) tuple, also known as a triple.

{
...
  "@": "<http://example.org/people#joebob>",
...
}

The example above would set the subject to the IRI http://example.org/people#joebob.

Note that subject do not need to be wrapped in angle brackets. The following example is valid JSON-LD markup:

{
...
  "@": "http://example.org/people#joebob",
...
}

5.3 Specifying the Type

The type of a particular subject can be specified using the a key. Specifying the type in this way will generate a triple of the form (subject, type, type-url).

{
...
  "@": "<http://example.org/people#joebob>",
  "a": "<http://xmlns.com/foaf/0.1/Person>",
...
}

The example above would generate the following triple (in N-Triples notation):

<http://example.org/people#joebob> 
   <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
      <http://xmlns.com/foaf/0.1/Person> .

Note that the type IRI does not need to be wrapped in angle brackets. The following example is valid JSON-LD markup:

{
...
  "@": "http://example.org/people#joebob",
  "a": "http://xmlns.com/foaf/0.1/Person",
...
}

5.4 Plain Literals

Regular text strings are called "plain literals" in RDF and are easily expressed using regular JSON strings.

{
...
  "foaf:name": "Mark Birbeck",
...
}

5.5 Language Specification in Plain Literals

JSON-LD attempts to make sure that it is easy to express triples in other languages while simultaneously ensuring that hefty data structures aren't required to accomplish simple language markup. When the @ symbol is used in a literal, the JSON-LD processor tags the literal text with the language tag that follows the @ symbol.

{
...
  "foaf:name": "??@ja",
...
}

The example above would generate a plain literal for ?? and associate the ja language tag with the triple that is generated. Languages must be expressed in [BCP47] format.

5.6 Typed Literals

Literals may also be typed in JSON-LD by using the ^^ sequence at the end of the text string.

{
...
  "dc:modified": "2010-05-29T14:17:39+02:00^^xsd:dateTime",
...
}

The example above would generate an object with the value of 2010-05-29T14:17:39+02:00 and the datatype of http://www.w3.org/2001/XMLSchema#dateTime.

5.7 Multiple Objects for a Single Property

A JSON-LD author can express multiple triples in a compact way by using arrays. If a subject has multiple values for the same property, the author may express each property as an array.

{
...
  "@": "<http://example.org/people#joebob>",
  "foaf:nick": ["stu", "groknar", "radface"],
...
}

The markup shown above would generate the following triples:

<http://example.org/people#joebob> 
   <http://xmlns.com/foaf/0.1/nick>
      "stu" .
<http://example.org/people#joebob> 
   <http://xmlns.com/foaf/0.1/nick>
      "groknar" .
<http://example.org/people#joebob> 
   <http://xmlns.com/foaf/0.1/nick>
      "radface" .

5.8 Multiple Typed Literals for a Single Property

Multiple typed literals are expressed very much in the same way as multiple properties:

{
...
  "@": "<http://example.org/articles/8>",
  "dcterms:modified": ["2010-05-29T14:17:39+02:00^^xsd:dateTime", "2010-05-30T09:21:28-04:00^^xsd:dateTime"],
...
}

The markup shown above would generate the following triples:

<http://example.org/articles/8> 
   <http://purl.org/dc/terms/modified>
      "2010-05-29T14:17:39+02:00"^^http://www.w3.org/2001/XMLSchema#dateTime .
<http://example.org/articles/8> 
   <http://purl.org/dc/terms/modified>
      "2010-05-30T09:21:28-04:00"^^http://www.w3.org/2001/XMLSchema#dateTime .

5.9 Blank Nodes

At times, it becomes necessary to be able to express information without being able to specify the subject. Typically, this is where blank nodes come into play. In JSON-LD, blank node identifiers are automatically created if a subject is not specified using the @ key. However, authors may name blank nodes by using the special _ CURIE prefix.

{
...
  "@": "_:foo",
...
}

The example above would set the subject to _:foo, which can then be used later on in the JSON-LD markup to refer back to the named blank node.

6. Advanced Features

JSON-LD has a number of features that provide functionality above and beyond the core functionality provided by RDF. The following sections outline the features that are specific to JSON-LD.

6.1 Escape Character

Special characters in property values must be escaped in order to not be interpreted as CURIEs, IRIs, language tags, or TypedLiterals.

The special characters that need to be escaped in property values are: < (at the beginning of a string), > (at the end of a string), @, and ^.

{
...
  "example:code": "\\<foobar\\^\\^2\\>",
...
}

6.2 Automatic Typing

Since JSON is capable of expressing typed information such as doubles, integers, and boolean values. As demonstrated below, JSON-LD utilizes that information to create Typed Literals:

{
...
  // The following two values are automatically converted to a type of xsd:double
  // and both values are equivalent to each other.
  "measure:cups": 5.3,
  "measure:cups": 5.3e0,
  // The following value is automatically converted to a type of xsd:double as well
  "space:astronomicUnits": 6.5e73,
  // The following value should never be converted to a language-native type
  "measure:stones": "4.8^^<xsd:decimal>",
  // This value is automatically converted to having a type of xsd:integer
  "chem:protons": 12,
  // This value is automatically converted to having a type of xsd:boolean
  "sensor:active": true,
...
}

When dealing with a number of modern programming languages, including JavaScript ECMA-262, there is no distinction between xsd:decimal and xsd:double values. That is, the number 5.3 and the number 5.3e0 are treated as if they were the same. When converting from JSON-LD to a language-native format and back, datatype information is lost in a number of these languages. Thus, one could say that 5.3 is a xsd:decimal and 5.3e0 is an xsd:double in JSON-LD, but when both values are converted to a language-native format the datatype difference between the two is lost because the machine-level representation will almost always be a double. Implementers should be aware of this potential round-tripping issue between xsd:decimal and xsd:double. Specifically objects with a datatype of xsd:decimal must not be converted to a language native type.

6.3 Type Coercion

JSON-LD supports the coercion of types to ensure that the zero-edit goal of JSON-LD can be accomplished. Type coercion allows someone deploying JSON-LD to coerce and incoming or outgoing types to the proper RDF type based on a mapping of type IRIs to RDF types. Using type conversion, one may convert simple JSON data to properly typed RDF data.

The example below demonstrates how a JSON-LD author can coerce values to plain literals, typed literals and IRIs.

{
  "#": 
  {  
     "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
     "xsd": "http://www.w3.org/2001/XMLSchema#",
     "name": "http://xmlns.com/foaf/0.1/name",
     "age": "http://xmlns.com/foaf/0.1/age",
     "homepage": "http://xmlns.com/foaf/0.1/homepage",
     "#types":
     {
        "name": "rdf:PlainLiteral",
        "age": "xsd:integer",
        "homepage": "xsd:anyURI",
     }
  },
  "name": "<John Smith>",
  "age": "41",
  "homepage": "http://example.org/home/"
}

The example above would generate the following triples:

_:bnode1
   <http://xmlns.com/foaf/0.1/name>
      "<John Smith>" .
_:bnode1
   <http://xmlns.com/foaf/0.1/age>
      "41"^^http://www.w3.org/2001/XMLSchema#integer .
_:bnode1
   <http://xmlns.com/foaf/0.1/homepage>
      <http://example.org/home/> .

7. Best Practices

The nature of Web programming allows one to use basic technologies, such as JSON-LD, across a variety of systems and environments. This section attempts to describe some of those environments and the way in which JSON-LD can be integrated in order to help alleviate certain development headaches.

7.1 JavaScript

It is expected that JSON-LD will be used quite a bit in JavaScript environments, however, features like IRIs requiring angled brackets in JSON-LD means that using JSON-LD directly in JavaScript is going to be annoying without a middleware layer such as a simple library that strips JSON-LD markup before JavaScript uses it. One could say that JSON-LD is a good fit for the RDFa API, which would enable a triple-store in the browser, but some don't want to require that level of functionality just to use JSON-LD. The group is still discussing the best way to proceed, so input on how JSON-LD could more easily be utilized in JavaScript environments would be very much appreciated.

7.2 Schema-less Databases

Databases such as CouchDB and MongoDB allow the creation of schema-less data stores. RDF is a type of schema-less data model and thus lends itself to databases such as CouchDB and MongoDB. Both of these databases can use JSON-LD as their storage format. The group needs feedback from CouchDB and MongoDB experts regarding the usefulness of JSON-LD in those environments.

8. Advanced Concepts

There are a few advanced concepts where it is not clear whether or not the JSON-LD specification is going to support the complexity necessary to support each concept. The entire section on Advanced Concepts should be taken with a grain of salt; it is merely a list of possibilities where all of the benefits and drawbacks have not been explored.

8.1 Vocabulary Profiles

One of the more powerful features of RDFa 1.1 Core is the ability to specify a collection of prefixes and terms that can be re-used by a processor to simplfy markup. JSON-LD provides a similar mechanism called Vocabulary Profiles, which is the inclusion of a context external to the JSON-LD document.

The example below demonstrates how one may specify an external Vocabulary Profile. Assume the following profile exists at this imaginary URL: http://example.org/profiles/contacts.

{
  "#": 
  {
     "xsd": "http://www.w3.org/2001/XMLSchema#",
     "name": "http://xmlns.com/foaf/0.1/name",
     "age": "http://xmlns.com/foaf/0.1/age",
     "homepage": "http://xmlns.com/foaf/0.1/homepage",
     "#types":
     {
        "age": "xsd:integer",
        "homepage": "xsd:anyURI",
     }
  }
}

The profile listed above can be used in the following way:

{
  "#": { "#profile": "http://example.org/profiles/contacts" },
  "name": "John Smith",
  "age": "41",
  "homepage": "http://example.org/home/"
}

The example above would generate the following triples:

_:bnode1
   <http://xmlns.com/foaf/0.1/name>
      "John Smith" .
_:bnode1
   <http://xmlns.com/foaf/0.1/age>
      "41"^^http://www.w3.org/2001/XMLSchema#integer .
_:bnode1
   <http://xmlns.com/foaf/0.1/homepage>
      <http://example.org/home/> .

8.2 Disjoint Graphs

When serializing an RDF graph that contains two or more sections of the graph which are entirely disjoint, one must use an array to express the graph as two graphs. This may not be acceptable to some authors, who would rather express the information as one graph. Since, by definition, disjoint graphs require there to be two top-level objects, JSON-LD utilizes a mechanism that allows disjoint graphs to be expressed using a single graph.

Assume the following RDF graph:

<http://example.org/people#john> 
   <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
      <http://xmlns.com/foaf/0.1/Person> .
<http://example.org/people#jane> 
   <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
      <http://xmlns.com/foaf/0.1/Person> .

Since the two subjects are entirely disjoint with one another, it is impossible to express the RDF graph above using a single JSON-LD associative array.

In JSON-LD, one can use the subject to express disjoint graphs as a single graph:

{
  "#": { "foaf": "http://xmlns.com/foaf/0.1/" },
  "@": 
  [
    {
      "@": "<http://example.org/people#john>",
      "a": "foaf:Person"
    },
    {
      "@": "<http://example.org/people#jane>",
      "a": "foaf:Person"
    }
  ]
}

8.3 The JSON-LD API

This API provides a clean mechanism that enables developers to convert JSON-LD data into a format that is easier to work with in various programming languages.

[NoInterfaceObject]
interface JSONLDParser {
    object   toObject (in DOMString jsonld, in object map, in optional object? options, in optional JSONLDParserCallback? callback);
    RDFGraph toRDFGraph (in DOMString jsonld, in optional JSONLDParserCallback? callback);
};

8.3.1 Methods

toObject
Parses JSON-LD text into an object that allows at least attribute-based or key-based access to the data. If the contents are a disjoint graph, an array of objects are returned. If there are any errors, null is returned.
ParameterTypeNullableOptionalDescription
jsonldDOMString??The JSON-LD string to parse into the return object.
mapobject??The map from IRIs to attribute names for the resulting object. Any term mapping that is not mentioned in the map will not be available in the resulting object. You may map rdf:type using the a key or the rdf:type IRI. You may map the subject by using the @ key.
optionsobject??An associative-array of processing options to enable or disable when processing the JSON-LD string. A conforming JSON-LD processor must support the following options:
indexBySubject
If set to true, the returned object will be indexed by subject.
preserveDatatypes
If set to true, preserves the datatype for object literals.
preserveLanguage
If set to true, preserves the languages for object literals.
callbackJSONLDParserCallback??A callback that is called whenever a processing error occurs on the given JSON-LD string.
No exceptions.
Return type: object
toRDFGraph
Parses JSON-LD and transforms the data into an RDFGraph, which is compatible with the RDFa API specification. This method will return null if there are any errors, or if the RDFa API is not available for use.
ParameterTypeNullableOptionalDescription
jsonldDOMString??The JSON-LD string to parse into the RDFGraph.
callbackJSONLDParserCallback??A callback that is called whenever a processing error occurs on the given JSON-LD string.
No exceptions.
Return type: RDFGraph

The JSONLDParserCallback is called whenever a processing error occurs on input data.

[NoInterfaceObject Callback]
interface JSONLDParserCallback {
    void error (in DOMString error);
};

8.3.2 Methods

error
This callback is invoked whenever an error occurs during processing.
ParameterTypeNullableOptionalDescription
errorDOMString??A descriptive error string returned by the processor.
No exceptions.
Return type: void

The following example demonstrates how to convert JSON-LD to a JSON object that is directly usable in a programming environment:

// retrieve JSON-LD from a Web Service
var jsonldString = fetchPerson();

// This map, usually defined once per script, defines how to map incoming 
// JSON-LD to JavaScript objects
var myMap = { "http://xmlns.com/foaf/0.1/name" : "name",
              "http://xmlns.com/foaf/0.1/age" : "age",
              "http://xmlns.com/foaf/0.1/homepage" : "homepage" };

// Map the JSON-LD to a language-native object
var person = jsonld.toObject(jsonldString, myMap);

// Use the language-native object
alert(person.name + " is " + person.age + " years old. " +
      "Their homepage is: " + person.homepage);

A JSON-LD Serializer is also available to map a language-native object to JSON-LD.

[NoInterfaceObject]
interface JSONLDSerializer {
    DOMString normalize (in object obj);
};

8.3.3 Methods

normalize
Serializes a language-native object into a normalized JSON-LD string. Normalization is important when performing things like equality comparison and digital signature creation and verification.
ParameterTypeNullableOptionalDescription
objobject??An associative array of key-value pairs that should be converted to a JSON-LD string. It is assumed that a map already exists for the data.
No exceptions.
Return type: DOMString

The Normalization Algorithm

This algorithm is very rough, untested, and probably contains many bugs. Use at your own risk. It will change in the coming months.

The JSON-LD normalization algorithm is as follows:

  1. Remove the # key and preserve it as the transformation map while running this algorithm.
  2. For each key
    1. If the key is a CURIE, expand the CURIE to an IRI using the transformation map.
    2. If the transformed key is an IRI, ensure that it is surrounded by angle brackets.
  3. For each value
    1. If the value should be type coerced per the transformation map, ensure that it is transformed to the new value.
    2. If the value is a CURIE, expand the CURIE to an IRI using the transformation map.
    3. If the value is a Typed Literal and the type is a CURIE, expand it to an IRI using the transformation map.
    4. If the final value is an IRI, ensure that it is surrounded by angle brackets.
  4. Output each sorted key-value pair without any extraneous whitespace. If the value is an associative array, perform this algorithm, starting at step #1, recursively on the sub-tree.

var myObj = { "#" : { 
                "xsd" : "http://www.w3.org/2001/XMLSchema#",
                "name" : "http://xmlns.com/foaf/0.1/name",
                "age" : "http://xmlns.com/foaf/0.1/age",
                "homepage" : "http://xmlns.com/foaf/0.1/homepage",
                "#types": {
                   "age" : "xsd:nonNegativeInteger",
                   "homepage" : "xsd:anyURI" 
                }
              },
              "name" : "Joe Jackson",
              "age" : 42,
              "homepage" : "http://example.org/people/joe" };

// Map the language-native object to JSON-LD
var jsonldText = jsonld.normalize(myObj);

After the code in the example above has executed, the jsonldText value will be (line-breaks added for readability):

{"<http://xmlns.com/foaf/0.1/age>":"42^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger>",
"<http://xmlns.com/foaf/0.1/homepage>":"<http://example.org/people/joe>",
"<http://xmlns.com/foaf/0.1/name>":"Joe Jackson"}

When normalizing xsd:double values, implementers must ensure that the normalized value is a string. In order to generate the string from a double value, output equivalent to the printf("%1.6e", value) function in C must be used where "%1.6e" is the string formatter and value is the value to be converted.

To convert the a double value in JavaScript, implementers can use the following snippet of code:

// the variable 'value' below is the JavaScript native double value that is to be converted
(value).toExponential(6).replace(/(e(?:\+|-))([0-9])$/, '$10$2')

When data needs 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 xsd:double values.

A. Acknowledgements

The editor would like to thank Mark Birbeck, who provided a great deal of the rationale and reasoning behind the JSON-LD work via his work on RDFj, Dave Longley who reviewed and provided feedback on the overall specification and contexts, and Ian Davis, who created RDF/JSON. Thanks also to Bradley P. Allen and Richard Cyganiak for their input on the specification.

B. References

B.1 Normative references

[BCP47]
A. Phillips, M. Davis. Tags for Identifying Languages September 2009. IETF Best Current Practice. URL: http://tools.ietf.org/rfc/bcp/bcp47.txt
[RDF-CONCEPTS]
Graham Klyne; Jeremy J. Carroll. Resource Description Framework (RDF): Concepts and Abstract Syntax. 10 February 2004. W3C Recommendation. URL: http://www.w3.org/TR/2004/REC-rdf-concepts-20040210
[RFC4627]
D. Crockford The application/json Media Type for JavaScript Object Notation (JSON) July 2006. Internet RFC 4627. URL: http://www.ietf.org/rfc/rfc4627.txt

B.2 Informative references

[MICRODATA]
Ian Hickson; et al. Microdata 04 March 2010. W3C Working Draft. URL: http://www.w3.org/TR/microdata/
[MICROFORMATS]
Microformats. URL: http://microformats.org
[RDFA-CORE]
Shane McCarron; et al. RDFa Core 1.1: Syntax and processing rules for embedding RDF through attributes.26 October 2010. W3C Working Draft. URL: http://www.w3.org/TR/2010/WD-rdfa-core-20101026