Fork me on GitHub
#rdf
<
2023-02-19
>
quoll00:02:16

I know other people have other tools for RDF, but I'm kinda happy with Donatello now 🙂

gratitude 6
quoll00:02:29

For instance, if I have an entity with a url of and my prefix ex is mapped accordingly, I can represent it with the keyword :ex/_1 If I have a set of properties on it, then I can just put those into a map:

{:a :ex/MyClass
 :rdfs/label "An instance of the class"
 :ex/fib [1 1 2 3 5 8]}
I can write that with write-triples-map!
(ttl/write-triples-map!
 out
 :ex/_1
 {:a :ex/MyClass
  :rdfs/label "An instance of the class"
  :ex/fib [1 1 2 3 5 8]})

quoll00:02:28

Of course, I can also write triples directly:

(ttl/write-triple! out :ex/_1 :a :ex/MyClass)
(ttl/write-triple! out (URI. "") :rdfs/label "An instance of the class")

quoll00:02:02

And it handles anonymous nodes as well:

(ttl/write-triple! out
                  {:rdfs/label "An anonymous instance"
                   :ex/fib [1 1 2 3 5 8]} :a :ex/Class)  

quoll00:02:15

It writes all of this pretty much as you'd expect, complete with indenting.

quoll00:02:47

e.g. one of my test cases looks like:

(ttl/write-triple! out
                   {:a :data/Class
                    :b/data :data/_123
                    :b/more {:a :data/Inner :b/list [1 2 3]}}
                   :data/rel
                   {:p1 #{"data a" "data b"}
                    (URI. "") 5})
and the output is:
[a data:Class;
 b:data data:_123;
 b:more [a data:Inner;
         b:list (1 2 3)]] data:rel [:p1 "data a", "data b";
                                    <> 5].

quoll00:02:38

Feeling good about it, and wanted to show it off 😄

👍 4
🙏 2
💪 2
simongray10:02:18

I might have a good use for it, @U051N6TTC!

💖 2
Bart Kleijngeld08:03:57

Really nice @U051N6TTC! I like the readable way blank nodes are outputted, rather than them being enumerated.

Bart Kleijngeld18:03:52

@U051N6TTC I've been looking for a Turtle autoformatter, i.e. given a .ttl file, that it deterministically autoformats it. This would make collaboration in our team a lot nicer. If I'm not mistaken, if Donatello supported .ttl files as input as well, it could basically serve as an autoformatter. Correct? I don't know if this is something you think Donatello should support, but I'd love to see something like this

quoll18:03:45

This is what Raphael is for

Bart Kleijngeld18:03:47

Of course I could easily compose Raphael and Donatello, (i.e. basically summon the TMNTs 😉) to get that done. Perhaps I can run clj such that it runs Raphael for a given ttl file and output that in the shell

Bart Kleijngeld18:03:04

Yes I was just realizing!

quoll18:03:10

I built them to complement each other

quoll18:03:18

An in-memory Asami graph is just a nested map like what you give to Donatello to output. Raphael takes TTL input and gives you a stream of triples, but those are easy to insert into a nested map

Bart Kleijngeld18:03:16

I see what you're saying

Bart Kleijngeld18:03:05

This is really nice 😄. I'm so annoyed by inconsistent and noisy Turtle code messy people are outputting. This will put an end to that 🙂. Thanks!

💖 2
Bart Kleijngeld18:03:34

(it's also really nice for doing version control)

quoll18:03:54

When I say “easy”, I just meant a small amount of code. This is what Asami grew out of, back-in-the-day: https://github.com/threatgrid/naga/blob/d149904da8ecb510ddbbb5b73824c74da4b05d77/src/naga/storage/memory/index.clj#L9

quoll18:03:38

It uses Plumatic Schema (hence the unusual typing syntax)

👍 2
quoll18:03:20

Sorry, about to start driving again, so I can’t respond for the next hour or more

Bart Kleijngeld18:03:33

Np. I've got plenty to look at

quoll18:03:42

I’ll respond as soon as I can though!

🙌 2
quoll20:03:46

I’m actually in the process of updating Raphael so that it no longer does look-ahead (this is only in 3 places)

quoll20:03:09

Why? Well, every function accepts a string and an offset as the first 2 parameters. It calls get-char to get the character at whatever the current offset is, and then increments the offset. This pair could be replaced with a StringReader, and everything could then just call getChar on the reader. Meaning that it wouldn’t need to be a StringReader… it could just be a Reader

quoll20:03:17

Well, it would actually be my own protocol, and I could use it to wrap a Reader. That way it will stay ClojureScript compatible

quoll20:03:34

But that’s just a technicality

quoll20:03:04

However, it’s a technicality that means that I want to avoid a PushbackReader (yes, I could write this for ClojureScript, but the correct approach is to avoid look-ahead)

quoll20:03:52

I pulled it out of 2 of the 3 places yesterday, though I haven’t tested it yet

Bart Kleijngeld20:03:37

I'm afraid this goes straight over my head. What does look-ahead (and the avoidance thereof) mean in this context?

quoll20:03:04

I do a subs at the front of the string, and if it doesn’t match what I’m looking for, I go to the other thing it could match. ie. I look several characters into the stream for something, and if it doesn’t match, I rewind and match it to something else

quoll20:03:05

eg. If I see a line starting with:

prefix
Then it could be the start of a prefix operation:
prefix ex:  .
Or it could be the start of a triple:
prefix:xyz rdf:value 5 .
So I need to look at the first 6 characters to match to prefix without knowing what kind of line I’m parsing. If the next character is a whitespace then it’s a directive. Otherwise it’s prefixed name like prefixes:abc

quoll20:03:45

The parser can’t know what kind of line it’s looking at until it’s looked ahead by 7 characters

Bart Kleijngeld20:03:40

Ah, yes that clears things up!