This specification is a work-in-progress which outlines another JSON representation of RDF & N3.

Primary issue..
I can't figure out whether to focus the serialization on being easy to write by hand for those familiar with JSON/turtle, or whether to focus on making the JSON.parse()'d results easy to work with (will we work with raw objects, or via an RDF API?).

If working with an API, is there any need for a JSON serialization? widely supported? Faster to parse?

Introduction

Need to write some kind of introduction.

General approach

My approach involved taking the default JSON [[RFC4627]] representation of each of the RDF Interfaces (from the RDFa API), gained by calling JSON.stringify on an instance of any given interface - and then making changes one step at a time until ultimately ending up with this JSON representation of RDF [[RDF-CONCEPTS]].

Design Goals

My priorities whilst doing this are as follows:

Markup of RDF Concepts

This section outlines the syntax and markup of RDF Concepts in JSN3

Short example

In JSN3:


        

and the same in Turtle


      

Basic Structure

This abstract example aims to show the basic structure of a JSN3 graph.


      

IRI

"http://example.org/some-iri"

Dropped <iri> syntax!
Strongly considering dropping the < and > from IRIs, this isn't an issue for subject and predicate, however does raise the issue of string-literal IRI vs IRI for plain literals in the object position.

How often do users need to use the string-literal form of an IRI and is it low enough to warrent dropping < > from IRI and forcing people to use xsd:string Typed Literals to talk about the lexical form of an IRI?

Feedback to the editor is requested.

CURIE

"foaf:name"

Declaration

"@base": "http://example.org/graph#",
"@prefix": {
  "foaf:": "http://xmlns.com/foaf/0.1/"
}

Triple

":me": {
  "foaf:name": "Nathan"
}

Suggestion: Object always an array.

It has been suggested that Objects should always be inside an array container so that they can easily be iterated over.

However, this complicates the syntax somewhat and it is extremely easy to test whether a value is an array or not at runtime.

// javascript
o = (typeof o != 'array') ? [o] : o;

Plain Literals

":example": {
  "ex:boolean": true,
  "ex:number": -123.3452,
  "ex:basic": "some value here"
}

Plain Literals with repetition

This is the equivalent of comma seperated objects in N3 / Turtle

":example": {
  "ex:likes": ["Red", "Green", "Blue"]
}

Language specific Plain Literals

":London": {
  "rdfs:label": {"@en": "London"} 
}

Suggestion: Include the language in the value

It has been suggested that the form of Language specific Plain Literals be

"London@en"

However this would mean that:

Suggestion: Change the form of Plain Literals to be an Object with two attributes

{ "lang": "en", "value": "London" }

This suggestion is still being actively discussed and considered, any comments for or against this syntax should be sent to the editor.

Language specific Plain Literals with repetition

":London": {
  "rdfs:label": {"@en": ["London", "City of London", "London Town"]} 
}

is shorthand for:

":London": {
  "rdfs:label": [
    {"@en": "London"},
    {"@en": "City of London"},
    {"@en": "London Town"}
  ] 
}

both forms are valid JSN3 syntax.

Typed Literals

":data": {
  "ex:age": {"^^xsd:nonNegativeInteger": "29"} 
}

Suggestion: Include the type in the value

It has been suggested that the form of Typed Literals be

"29^^xsd:nonNegativeInteger"

However this would mean that:

Suggestion: Change the form of Typed Literals to be an Object with two attributes

{ "type": "xsd:nonNegativeInteger", "value": "29" }

This suggestion is still being actively discussed and considered, any comments for or against this syntax should be sent to the editor.

Typed Literals with repetition

":data": {
  "ex:dates": {"^^xsd:dateTime": ["2010-09-24T23:14:52Z", "2010-09-23T19:12:33+02:00"]} 
}

Lists ()

":data": {
  "ex:listOfNumbers": [[1,2,3,4,5]] 
}

Would equate to the following N3/Turtle

:data ex:listOfNumbers (1,2,3,4,5) .
":data": {
  "ex:lists": [
    [[1,2,3]],
    [["a","b","c"]]
  ] 
}

Would equate to the following N3/Turtle

:data ex:lists (1,2,3), ("a","b","c") .

whilst the following list of lists

":data": {
  "ex:listOfLists": [[
    [[1,2,3]],
    [["a","b","c"]]
  ]]
}

Would equate to the following N3/Turtle

:data ex:lists ((1,2,3), ("a","b","c")) .

Blank Nodes

":me": {
  "foaf:knows": {
    "foaf:name": "Jim Smithson",
    "foaf:mbox": "mailto:jim.smithson@example.org"
  }
}

An empty Blank Node in JSN3 is represented as {}, in Turtle/N3 this would be [].

":foo": {
  "ex:any": {}
}

Blank Nodes by reference

JSN3 reserves the '_' namespace / prefix for use with blanknodes, this common form is supported by N3, Turtle and NTriples.

":me": {
  "foaf:knows": "_:b0"
},
"_:b0": {
  "foaf:name": "Jim Smithson",
  "foaf:mbox": "mailto:jim.smithson@example.org"
}

Advanced Concepts

JSN3 also handles many of the concepts found in N3

Graph Literals

Graph Literals in JSN3 take exactly the same form as Graphs, however they are wrapped inside "@graph": { ... } syntax, and can only appear in the Object position of triple.

For example, the following JSN3

"_:g1": {
  "diff:delete": {
    "@graph": { ":me": { "foaf:knows": "friends:oldid" } }
  },
  "diff:insert": {
    "@graph": { ":me": { "foaf:knows": "friends:newid" } }
  }
}

Would translate to the following N3:

_:g1
  diff:delete { :me foaf:knows friends:oldid };
  diff:insert { :me foaf:knows friends:newid } . 

Should the @graph symbol be replaced with something difference? @formula, or simply @ - what about @rule's.. scope

Shorthand

JSN3 also introduces seven special shorthand predicates

@has is missing

ShorthandStands for
ardf:type
^a[ owl:inverseOf rdf:type ]
>rdfs:seeAlso
=owl:sameAs
=>log:implies
<=log:implies, but in the other direction
==magic psuedo predicate

^a can be thought of as short-short-hand for "is rdf:type of" in N3

":me": {
  "a": "foaf:Person",
  "=": "http://example.org/other/web#id"
}
"foaf:Person": {
  "^a": ":me"
}

Predicate Prefixes

JSN3 also introduces two special predicate prefixes, an inversion prefix ^ which is short for [ owl:inverseOf predicate ], and > which is short for [ link:listDocumentProperty predicate ]

> can be thought of as rdfs:seeAlso with type hinting

^ can be thought of as short-short-hand for "is predicate of" in N3

Note: ^ and > cannot be used with =, ==, <= or =>. JSN3 provides a special shorthand prefix ^a to handle the predicate [ owl:inverseOf rdf:type ]

Predicate PrefixStands for
^owl:inverseOf
>link:listDocumentProperty
":child": {
  "^ex:hasChild": ":parent"
}
":me": {
  ">foaf:knows": "http://webr3.org/my-friends"
}

== Magic Predicate

describe better!

The shorthand == predicate is both shorthand for owl:sameAs and serves as an instruction to parsers to use the value on the right (in the object position) as the subject for triples which are produced (where supported).

Thus, the following in JSN3:

"_:b1": {
  "==": { "foaf:name": "Ora" },
  "dc:wrote": { "dc:title": "Moby Dick" }
}

Would translate to the following in N3/Turtle:

[ foaf:name "Ora" ] dc:wrote [ dc:title "Moby Dick" ] .

and would also entail that:

_:b1 owl:sameAs [ foaf:name "Ora" ] .

Any Subject

Reword..

The shorthand == also allows any concept which can exist in the object position to exist in the subject position

Thus, literal subjects:

"_:four": {
  "==": 4,
  "ex:lessThan": 5
}
4 ex:lessThan 5

Graph literal subjects

"_:g2": {
  "==": {
    "@graph": { ":bob": { "foaf:knows": ":sue" } }
  },
  "a": "log:Falsehood"
}
{ :bob foaf:knows :sue } a log:Falsehood

Named Graphs

The == shorthand also allows you to 'name' graphs, and annotate them.

":myGraph": {
  "==": {
    "@graph": {
      ":me": { "foaf:name": "Nathan", "foaf:birthday": "03-31" }
    }
  },
  "dc:created": { "^^xsd:dateTime": "2010-09-25T21:48:03Z" }
}
:myGraph owl:sameAs { :me foaf:name "Nathan"; foaf:birthday "03-31" } ;
  dc:created "2010-09-25T21:48:03Z"^^xsd:dateTime.

=: Complex Properties

JSN3 supports complex properties, any expression can be used as a property using this form.

The basic form is as follows:

":me": {
  "=:c1": {
    "@property": true,
    "@object": "foo"
  }   
}

In N3

:me true "foo" .
     

Note: Although this form isn't used often, it allows JSN3 to be able to represent anything that can be represented in N3, thus making it round tripable

Complex Property Example

":me": {
  "foaf:name": "Nathan",
  "=:p4": {
    "@property": { "owl:inverseOf": "dc:creator" },
    "@object": "http://webr3.org/apps/specs/jsn3#doc"
  },
  "foaf:birthday": "03-31"
}

In N3:

:me foaf:name "Nathan";
  [ owl:inverseOf dc:creator ] <http://webr3.org/apps/specs/jsn3#doc>;
  foaf:birthday "03-31" .
     

Note: The above can easier be said in JSN3 as, "^dc:creator": "http...", of by using foaf:made.

Quantification

JSN3 supports N3 Quantification.

@forAll - Universal Quantification

"@forAll": ":x"
"@forAll": [":x",":y"]

@forSome - Existential Quanitification

"@forAll": ":g"
"@forSome": [":g",":h"]

Examples

{
  "@forAll": ":x",
  "_:g1": {
    "==": {
      "@graph": { ":thermostat": { ":temp": ":x" } }
    }
    "=>": {
      "@graph": { ":cooling": { ":power": ":x" } }
    }
  }
}
@forAll :x.
{ :thermostat :temp :x } => { :cooling :power :x } .
       
{
  "@forAll": "#h",
  "@forSome": "#g",
  "#g": { "#loves": "#h" }
}
@forAll <#h> .
@forSome <#g> .
<#g> <#loves> <#h> .
       

Variables and Rules

JSN3 also supports variables and rules..

Variables

"?x": {
  "foaf:knows": "http://webr3.org/nathan#me"
}

Rules

Example simple rule

"_:f1": {
  "==": {
    "@graph": { "?x": { ":parent": "?y" } }
  },
  "=>": {
    "@graph": { "?y": { ":child": "?x" } }
  }
}
 { ?x :parent ?y } => { ?y :child ?x } 

Example more complex rule

"_:f1": {
  "==": {
    "@graph": {
      "?x": { ":parent": "?y" },
      "?y": { ":brother": "?z" }
    }
  },
  "=>": {
    "@graph": {
      "?x": { "a": ":Male", ":uncle": "?z" },
      "?z": { "a": ":Male", ":nephew": "?x" }
    }
  }
}
 { ?x :parent ?y . ?y :brother ?z } => { ?x a :Male; :uncle ?z . ?z a :Male, :nephew ?x } 

Named Rules

With JSN3, as with N3, it is possible to name and annotate rules. by naming a graph which contains said rules.

Note: Anybody creating complex / named / annotated rules with either N3 or JSN3 may be wise to consider using AIR

":family": {
  "==": {
    "@graph": {
      "_:f1": {
        "==": {
          "@graph": { "?x": { ":parent": "?y" } }
        },
        "=>": {
          "@graph": { "?y": { ":child": "?x" } }
        }
      }
    }
  },
  "dc:created": { "^^xsd:dateTime": "2010-09-25T21:48:03Z" }
}
:family = { { ?x :parent ?y } => { ?y :child ?x } };
  dc:created "2010-09-25T21:48:03Z"^^xsd:dateTime.

Paths

JSN3 supports a N3 paths (^!), however only simply paths are supported. Each pathitem can be a Variable, a CURIE or an IRI (whereas in N3 any expression can be a path item).

Paths can be used in any position (subject, property or object)

JSN3 and N3 comparison

Outwith features which aim to make JSN3 compatible with / as expressive as N3; JSN3 introduces the following new features

FeatureDescription
^aShorthand predicate which means [owl:inverseOf rdf:type]
^propertyProperty inversion prefix which inverts any given property [owl:inverseOf property], can be thought of as N3 @is property @of
>Shorthand predicate which mean rdfs:seeAlso
>propertyProperty prefix which can be thought of as a type hinted rdfs:seeAlso [link:listDocumentProperty property]

N3 has some features which as yet cannot be expressed in JSN3

FeatureDescription
^! paths JSN3 could support simple paths where pathitems could be variable, curie, iri - however N3 supports extemely complex paths.. see more below..
@hasWe may be able to support this, I'm as yet to find any documentation for has or examples in the wild so can't yet.
complex @is p @ofN3 supports complex expressions like { :x is { :a :b :c } of :y } . - currently JSN3 cannot support these, however an additional complex property operator could be introduced ^=: which would allow this.
<IRI> wrappingJSN3 could implement required or optional IRI wrapping, however currently it does not support it.

N3 supports extremely complex paths which cannot realistically be introduced in to JSN3 without pointing to the complex pathitems as blank node references.

For instance the following two examples are valid N3 paths:

:me!foo:bar^[a :Cat]!{ {?a :x ?b} => {?b :y ?a} }^?baz!foaf:name
true!foaf:name^false^true!23.456!false

address the above paths issue, should these be valid N3?

Full Example - Profile

This example is a JSN3 representation of Nathan's personal profile converted from [[N3]]

The example (including full cert:hex) is 3.94KB, (3.22KB with whitespace stripped)

For reference, here's the same graph in Talis RDF/XML [9.49KB/6.61KB], and the again in


    

Complex Example - AIR Rules

This example is a JSN3 representation of AIR rules used in an ARL scenario, violation of Universal Declaration of Human rights, Article 12


    

Structure

Here's the rough structure of JSN3, still to be formalised and finalised.


    

Acknowledgements

Many thanks to Robin Berjon for making our lives so much easier with his cool tool.