Each Node is closely coupled with a dispatcher, which is used to provide Visitor Objects to make life easier when workding with the Abstract Syntax API
General Structure
The
Visitor Pattern is used throughout the Abstract Syntax API to efficiently select different behavior based on the Node you access. Each subclass of Node has a visitor - called its Dispatcher - that's specifically tuned to that particular instance. They are called dispatchers since they are not true visitors, only applying to one particular type of node in the hierarchy. The actual visitor interface, NodeVisitor, aggregrates the interface of each Dispatcher to provide a true visitor interface.
Node.Dispatcher <--+
|
Resource.Dispatcher <--+
|
BlankNode.Dispatcher <--+
|
URIRef.Dispatcher <--+-- NodeVisitor <-- NodeVisitor.Default
|
Literal.Dispatcher <--+
|
PlainLiteral.Dispatcher <--+
|
TypedLiteral.Dispatcher <--+
NodeVisitor also provides a
Default Visitor called NodeVisitor.Default. This default implementation calls the dispatcher method for each type of Node up the hierarchy up to the default dispatcher (visiting java.lang.Object), which returns null.
Using Visitors to Work With Data
You can used visitors with SWAPI abstract syntax objects to selectively handle different data structures. For example, the dc:creator of a resource can be a literal string or a blank node. This is explained in more detail by Ian Davis in an article called
Crisis. Here's an example of two statements (in
Turtle):
# Note these prefixes for clarity: @prefix dc: <http://purl.org/dc/elements/1.1/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix sept: <http://internetalchemy.org/2005/09/> . # Statements: sept:crisis dc:creator "Ian Davis" . sept:crisis dc:creator [ foaf:name "Ian Davis" ] .
If we had a graph that contained those statements, then we could query it for the creator of the article:
1 Connection conn = connectToMyDataSource();
2 SyntaxFactory fact = conn.getSyntaxFactory();
3 Graph graph = conn.getGraph( "http://example.com/Graph/Describing/Ian/Davis/Articles" );
4 URIRef crisis = fact.createURIRef( "http://internetalchemy.org/2005/09/crisis" );
5 URIRef creator = fact.createURIRef( "http://purl.org/dc/elements/1.1/creator" );
6 Iterator<Statement> stmts = graph.getStatements( crisis, creator, null );
7
8 while( stmts.hasNext() ) {
9 Node target = stmts.next().getTarget();
10 // Do something with target
11 }
Using Flexible Data Structures
That's easy enough. But how do we differentiate between the literal "Ian Davis" and the blank node []? Simple: Use a visitor!
1 // ...
2 URIRef name = fact.createURIRef( "http://xmlns.com/foaf/0.1/name" );
3 //...
4
5 while( stmts.hasNext() ) {
6 String crisisCreatorName = stmts.next() .getTarget() .visitWith(
7 new NodeVisitor.Default<String>() {
8 String visitLiteral(Literal node) {
9 // Ideally you want to do validation here, but this is just an example.
10 return node.toString();
11 }
12 String visitResource(Resource node) {
13 // Ideally you want to do validation here, but this is just an example.
14 return graph.getStatements( node, name, null ) .next() .getTarget() .toString();
15 }
16 }
17 );
18 // Do something with crisisCreatorName
19 }
Note that in the above version you can have a named URIRef instead of a regular Literal. These style of programming allows you to work with data in more flexible ways.
Validating Input
In addition to selective behavior, you can validate data. This is using the visitor for the opposite reason: instead of adapting to new structures, you want to strictly adhear to a specific structure. There are lots of cases where one or the other approach work, so neither is inheritly better than the other one.
Back to validation. Say we MUST only allow plain literals as the target of dc:creator in our example. That means that there should not blank nodes or URI References at the end of the arcs. Here's how you throw an exception for those exceptional cases:
1 while( stmts.hasNext() ) {
2 Node target = stmts.next().getTarget();
3 try {
4 String crisisCreatorName = target.visitWith(
5 new NodeVisitor.Default<String>() {
6 String visitPlainLiteral(PlainLiteral node) {
7 // Ideally you want to do validation here, but this is just an example.
8 return node.toString();
9 }
10 String visitNode(Object node) {
11 throw new MyException("my message");
12 }
13 }
14 );
15 // Do something with crisisCreatorName
16 } catch( MyException ee ) {
17 // Handle my exception
18 }
19 }
Future Directions
You can also use visitors write to data streams and convert RDF data into your applications internal data structure. See the source code to the implementations of the Jena and OpenRDF drivers for examples of the latter.
In the future (before 1.0 though), SWAPI will probably have some convience methods for helping with the above too. Like a Graph.getStatement method for retrieving just the first match of a selection. Another addition may be visitors for the nodes in a statement. Things are still being standarized, so make your voice heard for your feature requests!
disney sexy |
help stopping smoking |
drunk wife |
super power hentai |
viol sex mpg |
gagging on dick |
pissing on boobs |
sapphic sex orgy |
playboy college girls |
nude petite ebony |
xxx gallery |
cheating wifes |
cream pies pussy |
dirty college fucking |
cigarette lung smoking |
sexy smoking |
gaping assholes |
playboy reality girls |
the simpsons xxx |
grils who gush |
big breasted fucking |
hot kissing bed |
showing my knickers |
young lesbos naked |
fist in ass |
hairy guys jockstraps |
vagina cumming |
bondage femdom |
latin milf women |
desperate house wives |
blond milf sex |
thick black bbws |
nude photography young |
perfect latin ass |
clitoris pleasing
Semantic Web API