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?
Need to write some kind of introduction.
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]].
My priorities whilst doing this are as follows:
This section outlines the syntax and markup of RDF Concepts in JSN3
In JSN3:
and the same in Turtle
This abstract example aims to show the basic structure of a JSN3 graph.
"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.
"foaf:name"
"@base": "http://example.org/graph#",
"@prefix": {
"foaf:": "http://xmlns.com/foaf/0.1/"
}
":me": {
"foaf:name": "Nathan"
}
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;
":example": {
"ex:boolean": true,
"ex:number": -123.3452,
"ex:basic": "some value here"
}
This is the equivalent of comma seperated objects in N3 / Turtle
":example": {
"ex:likes": ["Red", "Green", "Blue"]
}
":London": {
"rdfs:label": {"@en": "London"}
}
It has been suggested that the form of Language specific Plain Literals be
"London@en"
However this would mean that:
{ "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.
":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.
":data": {
"ex:age": {"^^xsd:nonNegativeInteger": "29"}
}
It has been suggested that the form of Typed Literals be
"29^^xsd:nonNegativeInteger"
However this would mean that:
{ "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.
":data": {
"ex:dates": {"^^xsd:dateTime": ["2010-09-24T23:14:52Z", "2010-09-23T19:12:33+02:00"]}
}
":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")) .
":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": {}
}
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"
}
JSN3 also handles many of the concepts found in N3
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
JSN3 also introduces seven special shorthand predicates
@has is missing
| Shorthand | Stands for |
|---|---|
| a | rdf: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"
}
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 Prefix | Stands for |
|---|---|
| ^ | owl:inverseOf |
| > | link:listDocumentProperty |
":child": {
"^ex:hasChild": ":parent"
}
":me": {
">foaf:knows": "http://webr3.org/my-friends"
}
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" ] .
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
"_:g2": {
"==": {
"@graph": { ":bob": { "foaf:knows": ":sue" } }
},
"a": "log:Falsehood"
}
{ :bob foaf:knows :sue } a log:Falsehood
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.
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
":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.
JSN3 supports N3 Quantification.
"@forAll": ":x"
"@forAll": [":x",":y"]
"@forAll": ":g"
"@forSome": [":g",":h"]
{
"@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> .
JSN3 also supports variables and rules..
"?x": {
"foaf:knows": "http://webr3.org/nathan#me"
}
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 }
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.
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)
":me!foaf:knows^foaf:know" Everybody who knows somebody :me knows.":me!foaf:name" foaf:name of :me.":joe!fam:mother^fam:mother" :joe's siblingsOutwith features which aim to make JSN3 compatible with / as expressive as N3; JSN3 introduces the following new features
| Feature | Description |
|---|---|
| ^a | Shorthand predicate which means [owl:inverseOf rdf:type] |
| ^property | Property 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 |
| >property | Property 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
| Feature | Description |
|---|---|
| ^! paths | JSN3 could support simple paths where pathitems could be variable, curie, iri - however N3 supports extemely complex paths.. see more below.. |
| @has | We 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 @of | N3 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> wrapping | JSN3 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?
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
This example is a JSN3 representation of AIR rules used in an ARL scenario, violation of Universal Declaration of Human rights, Article 12
Here's the rough structure of JSN3, still to be formalised and finalised.
Many thanks to Robin Berjon for making our lives so much easier with his cool tool.