Source code: rdfe-2003-11-30.tar.gz
You can also browse the source via HTTP.
The following is a copy of my seminal email, Schema-Aware FOAF Editor, to the rdfweb-dev mailing list.
Further to Danny's little-RDF-serialization email, I worked on a few ideas to see what the easiest way of entering RDF data on the command line is. It occured to me that since schemata can provide domain and range constraints, we might as well use them in an editor.
When combined with path searching for classes and properties a la $PATH and $CDPATH in bash, qnames, and some other features described below, it makes for a very intuitive data-input environment.
Straight off, here's an example:
$ python rdfe.py RES> Person foaf:Person PROP> name _ foaf:name LIT> Sean B. Palmer _ PROP> knows _ foaf:knows RES> Person _ PROP> name _ foaf:name LIT> Libby Miller _ PROP> _ PROP> homepage _ foaf:homepage RES> http://purl.org/net/sbp/ _ PROP> RES>
There's quite a lot going on in this short example. The only things that I entered come after the first "...>" prompt in each line--all the rest is context data given out by the program.
First of all, what you can't see in the example above is that before you can use the editor, it asks you for some schemata to use. I fed it the RDF, RDFS, OWL, FOAF, and DC schemata, merged them, and then applied the rdfs-closure rules. There were 1044 statements before applying the rules, and 2096 after. It then saves the results locally to a file so that it doesn't have to download from the Web and do the reasoning again every time it loads (it takes a while!).
When initialized with the schema already loaded, as in the example above, it'll prompt for a particular type of data to be entered: RES> for a resource, LIT> for a literal, or PROP> for an rdf:Property instance. It prompts me for a subject with the type of RES first of all, so I give it "Person".
It looks through its path, which at the moment is set to "rdf:rdfs:owl:foaf:dc". The problem with searching through paths is that if, for example, RDF suddenly sprouted an rdf:name property, I'd be flummoxed when entering "name" in and getting it to path-search. @@ It should therefore be possible to change the current subject or predicate in the editor.
So the subject is initially set to foaf:Person. Now it shows what the current subject is in the prompt, and asks me for a PROP to apply. I give it "name", which it resolves to foaf:name.
foaf:Person PROP> name
Now for the first clever bit. It looks at the schemata, and sees that I declared a couple of things in my local editorial schema: "foaf:name rdfe:domain foaf:Person . foaf:Person rdfe:disjointWith rdfs:Class ." Note that I've used rdfe: instead of rdfs: and owl:, since these constraints aren't actually in the FOAF schema. What I'm saying is that locally, for this editor, I will only ever use foaf:name on foaf:Person instances, and that foaf:Person is disjoint with rdfs:Class.
Upon seeing this information, the editor decides that "foaf:Person foaf:name" is not a valid start to a triple, and so it decides that what I really meant is "_:person rdf:type foaf:Person . _:person foaf:name" and accordingly makes the typed statement and resets the subject to be a bNode. It represents bNodes using the "_" (underscore), as shown in the next prompt:
_ foaf:name LIT> Sean B. Palmer
Note here that it also automatically knows that the object of foaf:name is an rdfs:Literal, and so it prompts for LIT> instead of RES>. This means that I don't have to use <> for URIs and "" for Literals, since it should automatically decide.
Aside: note that rdfs:Literal is a subClassOf rdfs:Resource... so there's a minor problem there, though I'm resolving that at the moment by saying that if there's only rdfs:Literal in the range of the property, prompt for LIT>, if there's both, I could probably guess what's meant by using some heuristic (e.g. if the entered object contains a space, then it's a literal), and if there's no rdfs:Literal in the property ranges, prompt for RES>.
Now it asks for another property, and I give it knows. I then say that I know a person.
_ PROP> knows _ foaf:knows RES> Person _ PROP> name
Again, more reasoning: the range of foaf:knows is foaf:Person, so it creates a new subject and types it as being a Person instead of using Person itself as the object. It then says that I know this new subject. To show that we've moved into the graph a bit further, as it were, it indents. So I'm now entering properties for the Person that I foaf:know. I add a name arc.
_ foaf:name LIT> Libby Miller _ PROP> _ PROP> homepage
I give it libby's name, and then enter nothing as a property. Entering nothing as a property makes it go up to the previous level. So now I'm back to entering in properties about myself. I bung in homepage, and it correctly guesses foaf:homepage and prompts for a resource.
_ PROP> homepage _ foaf:homepage RES> http://purl.org/net/sbp/ _ PROP> RES>
I gave it a blank property and blank subject resource to exit the program. I've also been experimenting with commands, which start with "@" (an at-sign), so I could enter @quit to quit, @subj to view the current subject in full, and so on.
Just before the program quits, it pipes out the N-Triples of the result to STDOUT. All of the prompts are on STDIN. Here's what I got for the example above, using QNames to make it readable:
_:NRKRkBbM rdf:type foaf:Person . _:NRKRkBbM foaf:name "Sean B. Palmer" . _:NRKRkBbM foaf:knows _:LDzZyLRa . _:LDzZyLRa rdf:type foaf:Person . _:LDzZyLRa foaf:name "Libby Miller" . _:NRKRkBbM foaf:homepage <http://purl.org/net/sbp/> .
Here's another example:
$ python rdfe.py RES> Person foaf:Person PROP> name _ foaf:name LIT> Sean B. Palmer _ PROP> mbxo Not found: mbxo _ PROP> mbox _ foaf:mbox RES> mailto:sean at mysterylights.com _ PROP> weblog _ foaf:weblog RES> http://miscoranda.com/ _ PROP> RES> http://miscoranda.com/ + PROP> label + rdfs:label LIT> miscoranda + PROP> RES>
The new features of note here are a) if it can't find a property in the current schemata, it says so, and b) "+" (plus-sign) is used to denote a URI as a subject. I'm glad it guessed that rdfs:label was a literal straight off, since it meant I didn't have to add it to my local.nt schema and rebuild the whole lot.
In making the editor, I came across a number of issues, many with FOAF since that's what I've been using to test it generally (and what I think it'll be most useful for--it's what Danny's original example was about).
The first issue is that auto-discovery of the FOAF schema is hard, because it's embedded in the HTML. I had to write something to extract the rdf:RDF from there, and it's all regexp based, of course. Plus, if you want the charset of the embedded RDF, you have to parse it out of the HTML MIME type header, or from http-equiv, which is really horky. I could've sent accept: application/rdf+xml, but the rdf:RDF in the HTML specification is more up-to-date.
So I don't believe that embedding the schema in the HTML is a good idea. If it were <link>'d, as recommended, it would have solved the regexp problem (what happens if there's "</rdf:RDF>" in a literal?), and the charset problem. I suggest that the specification be changed to use that method.
<link rel="meta" type="application/rdf+xml" href="index.rdf" />
Secondly, there are some things missing from the schema. I already pinged danbri on #foaf about adding rdfs:Resource as a domain for foaf:name (actually, I was wanting foaf:Agent or foaf:Person, but oh well--I just added it to my local schema), but foaf:nick is also missing rdfs:Literal as a range.
I'm sure that the editor could have many more features, and that it's actually not all that useful, and there are probably GUI schema-aware RDF editors already that are much better, so I'd be interested to hear about any parallel research or feature requests.
As my colophon, I'd like to note that I've been doing this schema-aware via RDFS-Closure sort of stuff for a couple of years now, and that for me it's quite a pointer to how RDF can actually be useful. My previous experiments were in validating RDF, which I found useful in debugging the EARL schema.
If you've any comments or feedback, please don't hesitate to contact me: you can either email me at email@example.com, or speak to me on IRC as sbp on irc.freenode.net (on #rdfig, #sbp, and #foaf). IRC is preferred at the moment.Sean B. Palmer