Turtle is a language. It is desiged for expressing data, partuicularly linked data on the web. Just as HTML is used for linked text, Turtle is used for linked data. Turtle expresses stuff about things. Abstract things, real things, people, documents, So where HTML uses the hash sign like in foo.html#intro to refer to an anchor, which is a part of the document, Turtle uses the same hash sign to refer to something defined by the dococument, like students.ttl#bob or profile.ttl#me.
Turtle is simple. The data model it uses, called RDF, is simple. Turtle was originally designed for writing in chat messages, and on whiteboards, and making quick configuration files or test files, so it tries to be concise.
<profile.ttl#me> <http://xmlns.com/foaf/0.1/knows> <students.ttl#bob> .
That is the simplest thing you can say in Turtle: one fact, one subject-verb-object triple. Note it ends with a dot.
There is a shorthand a which you can use as a verb to give the class of a thing, to say what sort of thing it is. Classes, like properties, also have URIs.
<profile.ttl#me> a <http://xmlns.com/foaf/0.1/Person> .
Turtle uses URIs to identify people all the time, so it has a way of abbrevating them. You declare a prefix say at the top of the file, and then use foo: prefix with a colon:
@prefix foaf: <http://xmlns.com/foaf/0.1/> . <profile.ttl#me> a foaf:Person .
Tip: There are a ste of common prefixes for vocabularies we use a lot in @@@.
When you use URIs in angle brackets, then they relative URIs, relative to the URI of the current document. So if the document is, say, https://alice.example.com/public/profile.ttl then
<#me> | means | <https://alice.example.com/public/profile.ttl#me> |
<#myHome> | means | <https://alice.example.com/public/profile.ttl#myHome> |
<students.ttl#bill> | means | <https://alice.example.com/public/students.ttl#bill> |
Things like <#me> and <myhome> are local identifiers within the file you are creating. They are like const in a JS file in a way, local identifiers. The business of the data document you are writing is done in terms of those local identifiers. Becasue local identifiers are used quite a lot, it is useful to declare a prefix, the empty string prefix :, so that they can be just written with a leading colon:
@prefix : <#>. # The empty prefix means this document :alice a :Person; :age 77 . # All local IDs
In what follows we will often assume a file starts with
@prefix : <#>.
As a shorthand, when you have more than one fact about the same subject, you can just use a semicolon ";" to add more :
@prefix foaf: <http://xmlns.com/foaf/0.1/> . <profile.ttl#me> a foaf:Person ; foaf:name "Alice"; foaf:knows <students.ttl#bob> .
You can also, when have multiple objects with the same subject and predicate, just list them with commas between them, so
<profile.ttl#me> a foaf:Person ; foaf:knows <students.ttl#bob>, <students.ttl#charlie>, <students.ttl#david>; foaf:name "Alice".
means the same as:
# Means the same as above <profile.ttl#me> a foaf:Person. <profile.ttl#me> foaf:knows <students.ttl#bob>. <profile.ttl#me> foaf:knows <students.ttl#charlie> . <profile.ttl#me> foaf:knows <students.ttl#david>. <profile.ttl#me> foaf:name "Alice".
Periods are stronger than semicolons, which are stronger than commas, like in English.
Turtle is a free form language: you can add or remove spaces and new lines anywhere. Comments start with a hash sign.
Above we have shown the triples each expressing the ralationship between things: people and classes. You can also put data values in the object position, like the strng "Alice" above. In Turtle (and the RDF data model underneath) values are typed.
"Alice" | means the string Alice |
"20" | means a string "20", not the number 20 |
20 | means the integer (whole number) 20. |
20.0 | means a decimal number |
2.0e1 | means a (double precision) floating point number 2*10^1 |
These data types cover a lot of values. You can also explictly write something with and explicit data type from the XML data types @@link standard, XSD. To do that you write the data value as a string, then two carets ^^ and then the XSD datatype itself.
@prefix xsd: <http://www.w3.org/2001/XMLShema#>. <profile.ttl#me> a foaf:Person ; foaf:name "Alice"; foaf:age 21; foaf:height 1.76e0; foaf:bithDate @@@ "1990-03-31"^^xsd:date .
Its also worth mentioning that URIs are yor freind if you wat to given email addresses or telephone numbers, as there are RI schemes for those.
<tel:+1781-555-1212> | How to do a phone number as a URI |
<mailto:alice@example.com> | How to put in an email address. |
Why give an explicit tel: URI or an explictly typed data field instead of just a string? Because it means that the systems which re-use the data will be able to be smarter, to automatically pick the appropriate way of displaying it or converting into an other format, and so on. The tradition in linked data is stronger data typing, like Python or C rather than JS.
:Alice :homeAddressStreet "Accaia Ave"; :homeAddressNumber 123; :homeAddressCity "Anytown"; :homePhone <tel:+1-781-555-1212> .
its best to add structure for the home and the address.
:Alice :home [ :address [ :street "Accaia Ave"; :number 123; :city "Anytown" ] :phone <tel:+1-781-555-1212> ] .
This reads in English like "Alice has a home which has an address with street "Aaccia Avenue", number 123 and city ANytown, and has a phone number of +1785551212."
This sort of tree structure is very common: in JSON the nested things are objects; in XML they are elements. In Turtle they are called blank nodes, because they are not labelled with a URI. There is another way of writing them in Turtle, where you make up local ids for them like _:foo to keep track of them but these are not URIs. The _: is a special one for blank nodes.
:Alice :home _:a . _:a address _:b . _:b street "Accaia Ave"; number 123; city "Anytown" . _a :phone <tel:+1-781-555-1212> .
The square bracket syntax is obviously clearer. You can use it in place of object or subject.
<#alice> foaf:children ( <#bob> <#charlie> <#dave> ) .
Imagine we store user input as a string, but separately generate the list of words.
<#userInput> ex:line "turn on light"; ex:inWords ("turn" "on" "light") .
That's it. That's all there is to turtle. You now know it. It is good to get used to reading bits of turtle as though it was English. Yu can now use it in code snippits in chats and in code for things like forms, configuration parameters, and so on.
There a few things which you should not use in data shared generally, but are shortcts for test data and quick scripts. rdflib.js will understand these sytatax but never generate them
:Alice foaf:birthdate 2018-02-31 . |
A raw ISO format date can be put in without explicit type |
:x4 :lastModifiedTime 2018-02-31T08:24:00.0Z . |
A raw ISO format date-time can be put in without explicit type |
A good philosphy is that when there two relations which are inverse of each other, like parent and child, that we just use one, say child, in the data, like
:grampa fam:child :alice, :bob. :gramma fam:child :alice, :bob. :alice fam:child :charlie, :davie, :ellie .
This makes the graph of relationships easier to query. In this example, you can infact express all the information about Alice at once:
:alice is fam:child of :grampa, :gramma; fam:child :charlie, :davie, :ellie .
The is ... of syntax was in the original N3 language which Turtle was derived from but unfortunately left out of the turtle standard.
It is handy to define the empty string prefix : as being for the local document, so it can be used for local identifiers.
@prefix : <#>.
This is in fact assumed by default by rdflib.js so you can miss it out.
:this a :Example; :age 123.
is a fine test file.