rdf

quoll 2023-02-19T00:08:16.131829Z

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

3
quoll 2023-02-19T00:08:29.284509Z

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]})

quoll 2023-02-19T00:10:28.257499Z

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")

quoll 2023-02-19T00:13:02.376699Z

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)  

quoll 2023-02-19T00:14:15.313879Z

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

quoll 2023-02-19T00:17:47.143499Z

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].

quoll 2023-02-19T00:18:38.519689Z

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

👍 2
💪 1
🙏 1
simongray 2023-02-27T10:02:18.057459Z

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

💖 1
simongray 2023-02-27T10:02:20.377949Z

thanks

Bart Kleijngeld 2023-03-06T08:33:57.631159Z

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

Bart Kleijngeld 2023-03-06T18:41:52.239009Z

@quoll 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

quoll 2023-03-06T18:46:45.012039Z

This is what Raphael is for

Bart Kleijngeld 2023-03-06T18:46:47.755629Z

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 Kleijngeld 2023-03-06T18:47:04.483469Z

Yes I was just realizing!

quoll 2023-03-06T18:47:10.425339Z

I built them to complement each other

quoll 2023-03-06T18:49:18.558229Z

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 Kleijngeld 2023-03-06T18:50:16.304879Z

I see what you're saying

Bart Kleijngeld 2023-03-06T18:51:05.091719Z

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!

💖 1
Bart Kleijngeld 2023-03-06T18:51:34.212889Z

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

quoll 2023-03-06T18:51:54.380939Z

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

quoll 2023-03-06T18:52:38.639209Z

It uses Plumatic Schema (hence the unusual typing syntax)

👍 1
quoll 2023-03-06T18:54:20.550849Z

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

Bart Kleijngeld 2023-03-06T18:54:33.177349Z

Np. I've got plenty to look at

quoll 2023-03-06T18:54:42.103049Z

I’ll respond as soon as I can though!

🙌 1
Bart Kleijngeld 2023-03-06T18:54:52.287119Z

Thanks!

quoll 2023-03-06T20:00:46.106619Z

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

quoll 2023-03-06T20:05:09.763139Z

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

quoll 2023-03-06T20:06:17.237879Z

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

quoll 2023-03-06T20:06:34.397149Z

But that’s just a technicality

quoll 2023-03-06T20:08:04.556599Z

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)

quoll 2023-03-06T20:08:52.415979Z

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

Bart Kleijngeld 2023-03-06T20:14:37.427319Z

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

quoll 2023-03-06T20:26:04.757789Z

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

quoll 2023-03-06T20:31:05.219239Z

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

quoll 2023-03-06T20:31:45.269039Z

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

Bart Kleijngeld 2023-03-06T20:50:40.127639Z

Ah, yes that clears things up!