Piglet - "Tiny Wilbur" in C++
Piglet is a re-implementation of the Wilbur Semantic Web toolkit in C++. The aim is to make it small and embeddable. The initial prototype is now functional. It makes use of the SQLite3 relational database library for many data handling tasks.
Piglet is written in C++ and makes some use of STL. The main API is thus expressed in terms of C++ class definitions (to be documented here later). For those of you who don't care about C++, there is a small "C wrapper" that provides a simple C API (below, 2008-05-08 version). This API, in turn, is used by wrappers for Common Lisp ("cl-piglet", via CFFI) and Python.
1 typedef unsigned short bool;
2 #define true 1
3 #define false 0
4
5 typedef int Node;
6
7 typedef void *DB;
8
9 typedef bool (*TripleCallback)(DB db, void *userdata, Node s, Node p, Node o);
10
11 typedef bool (*NodeCallback)(DB db, void *userdata, Node node);
12
13 typedef enum { PigletFalse, PigletTrue, PigletError } PigletStatus;
14
15 extern char *piglet_error_message;
16
17 // Open triple store or create a new one, then make it "current"
18 DB piglet_open(char *name);
19
20 // Close triple store
21 PigletStatus piglet_close(DB db);
22
23 // Query for triples
24 PigletStatus piglet_query(DB db, Node s, Node p, Node o, Node source, void* userdata, TripleCallback callback);
25
26 // Query for triple sources
27 PigletStatus piglet_sources(DB db, Node s, Node p, Node o, void *userdata, NodeCallback callback);
28
29 // Count triples in a triple store
30 int piglet_count(DB db, Node s, Node p, Node o, Node source, bool temporary);
31
32 // Add triple to triple store
33 PigletStatus piglet_add(DB db, Node s, Node p, Node o, Node source, bool temporary);
34
35 // Remove triple from triple store
36 PigletStatus piglet_del(DB db, Node s, Node p, Node o, Node source, bool temporary);
37
38 // Remove an entire source from triple store
39 PigletStatus piglet_del_source(DB db, Node source, bool triplesOnly);
40
41 // Load triples from source node's URL
42 PigletStatus piglet_load(DB db, Node source, bool append);
43
44 // Return the URI of node (or string if node is a literal)
45 char *piglet_info(DB db, Node node, Node *datatype, char *language);
46
47 // Return Node for given URI
48 Node piglet_node(DB db, const char *uri);
49
50 // Return literal Node for given string, datatype (or 0), xml:lang (or NULL)
51 Node piglet_literal(DB db, const char *string, Node datatype, const char *lang);
52
53 // Get Wilbur representation of node as a string
54 char *piglet_node_tostring(DB db, Node node);
55
56 // Get Wilbur debugging representation of triple as a string
57 char *piglet_triple_tostring(DB db, Node s, Node p, Node o);
58
59 // Expand a QName into a URI string
60 char *piglet_expand(DB db, const char *qname);
61
62 // "Reverse expand" a URI into a QName, if possible
63 char *piglet_reverse_expand(DB db, const char *uri);
64
65 // Add a namespace prefix for a given URI
66 PigletStatus piglet_add_namespace(DB db, const char *prefix, const char *uri);
67
68 // Delete a namespace
69 PigletStatus piglet_del_namespace(DB db, const char *prefix);
70
71 // Match node URIs and literal strings
72 PigletStatus piglet_match(DB db, const char *pattern, void* userdata, NodeCallback callback);
Here's a small example of how to make use of this library: Given an existing triple store, open it, and find all triples where the subject is dc:creator:
1 #include "cpiglet.h"
2 #include <stdlib.h>
3
4 bool callback(DB db, void *userdata, Node s, Node p, Node o)
5 {
6 printf("%s\n", piglet_triple_tostring(db, s, p, o));
7 return true;
8 }
9
10 int main(int argc, char *argv[])
11 {
12 DB db = piglet_open(argv[1]);
13 if (db)
14 piglet_query(db, piglet_node(db, "http://purl.org/dc/elements/1.1/creator"), 0, 0, NULL, callback);
15 piglet_close(db);
16 exit(0);
17 }
The same program using Piglet's C++ API would look something like this:
1 #include "piglet.h"
2
3 using namespace Piglet;
4
5 class TestAction : public TripleAction {
6 public:
7 TestAction(DB *db) : TripleAction(db) {}
8 bool operator()(Triple *t) MAYFAIL { std::cout << t << "\n"; delete t; return true; }
9 };
10
11 int main(int argc, char *argv[])
12 {
13 DB db(argv[1]);
14 TestAction action(&db);
15 db.query(db.node("http://purl.org/dc/elements/1.1/creator"), NULL_NODE, NULL_NODE, &action);
16 exit(0);
17 }
The C++ API makes use of exceptions, but the C API merely returns false, NULL, etc. when things fail. The above two sample programs are both small, the main difference is that the C++ API allows one to extend the library by subclassing the existing classes. Also, the C++ API offers alternative ways of querying; for example, to return a list of triples rather than using a callback, the code would look like this:
1 #include "piglet.h"
2
3 using namespace Piglet;
4
5 int main(int argc, char *argv[])
6 {
7 DB db(argv[1]);
8 Nodes *nodes = db.query(db.node("http://purl.org/dc/elements/1.1/creator"), NULL_NODE, NULL_NODE);
9 for (Nodes::iterator i = nodes->begin(); i != nodes->end(); i++)
10 std::cout << *i << "\n";
11 exit(0);
12 }
Similar program using Python looks like this:
1 #!/usr/bin/python
2
3 import sys
4 import piglet
5
6 db = piglet.open(sys.argv[1])
7 for (s, p, o) in db.query(db.node("http://purl.org/dc/elements/1.1/creator"), 0, 0) :
8 print db.tripleToString(s, p, o)
9 db.close()
Finally, using cl-piglet, the sample program takes this form:
(use-package :piglet)
(defun cl-piglet-demo (file)
(let ((db (%open file)))
(dolist (triple (%query-collected db (%node db "http://purl.org/dc/elements/1.1/creator") 0 0))
(format t "~&~A" (apply #'%triple-to-string db triple)))
(%close db)))
All this is the lower layer of the triple store API ("Piglet0"). Next up: WilburQL path query engine and corresponding path query API.
Comments are welcome.
