Archive for January, 2010

Generate a Form from any JSON for quick and easy editing

I just wrote a JSON form generator that generates a form given any JSON string. With this utility you can:
  • Edit values in any object
  • Add new attributes to objects and arrays
  • Add/remove arrays and objects
  • Specify a custom template to use whenever a new object is created to increase productivity
The application can then give you the results of the form back in JSON.

Example:

Given this:
  
{
   name:"Rouben",
   company:"Cambridge Semantics",
   profile:"http://www.cambridgesemantics.com/people/about/rmeschian",
   "works with":[
      {
         name:"Sean Martin",
         profile:"http://www.cambridgesemantics.com/people/about/sean"
      },
      {
         name:"Simon Martin",
         profile:"http://www.cambridgesemantics.com/people/about/simon"
      },
      {
         name:"Ben Szekely",
         profile:"http://www.cambridgesemantics.com/people/about/ben"
      }
   ]
}
The generated form looks like this: I’ll make it prettier if I find the time. Until then I hope you find it useful.
This is a utility I wrote that comes in handy every now and then, so I thought I would share it with you. It allows you to replaces all the end of line characters in the given text with whatever you define. I often use this to format text for the web by replacing EOLs with break elements. For example, suppose we have this string:
"foo
bar
zoo"
We can use this utility to replace the EOLs with “, ” to get:
"foo, bar, zoo"
Replace EOL characters with:

Openanzo’s javascript RDF library – resource bean

Openanzo has a powerful RDF javascript library in the org.openanzo.js project. In previous posts I talked about some of the low level API available to create, store and find RDF statements. In this tutorial I’ll talk about a simple object called anzo.rdf.GraphResource which takes a graph and resource and creates a bean with familiar getters and setters to allow you to easily modify the properties of that resource.
  
 dojo.require("anzo.rdf.NamedGraph");
 dojo.require("anzo.rdf.GraphResource");

 // register namespaces to make this example simpler
 anzo.rdf.registerNamespace("ex", "http://www.example.org/");
 anzo.rdf.registerNamespace("foaf", "http://xmlns.com/foaf/0.1/");

 // 1. build a sample graph with some data in it
 var graph = new anzo.rdf.NamedGraph('http://graph_1');
 graph.add('ex:me', "foaf:firstName", "Rouben");
 graph.add('ex:me', "foaf:surname", "Meschian");
 graph.add('ex:me', "foaf:knows", "ex:sean");

 // 2. create a bean and specify which properties you want to create methods for
 var bean = new anzo.rdf.GraphResource('ex:me', graph, [ "foaf:firstName", "foaf:surname" ]);
 bean.getFirstName(); // returns a single literal "Rouben"
 bean.setSurname("Smith"); // sets my surname to "Smith"

 // 3. add additional properties whenever you want
 bean.createPropertyMethods(["foaf:knows"]);
 bean.addKnows("ex:ben");
 bean.getKnows(); // returns an array with Sean and Ben's URIs

Openanzo’s javascript RDF library – client quad store

Openanzo has a powerful RDF javascript library in the org.openanzo.js project. The library has a highly optimized quad store. A quadstore stores RDF statements that have namedGraphUri values (in addition to the standard subject, predicate and object values).

anzo.rdf.QuadStore

  
   dojo.require("anzo.rdf.QuadStore"); // reference the object

   // register namespace
   anzo.rdf.registerNamespace("ex", "http://www.example.org/"); 

   var store = new anzo.rdf.QuadStore();
   store.add("ex:subj", "ex:pred", "dog", "ex:graph1");
   store.isEmpty(); // returns false
   store.size(); // returns 1
   store.find("ex:subj"); // returns an array with a single statement in it
We can use anzo.rdf.NamedGraphs as proxies to the quadstore. Once a NamedGraph has been created with the store, all statements are stored in the underlying quadstore. In this way the NamedGraph becomes a convenient way to add triples to a graph which then get passed to the quadstore as quads (with the name of the graph being the fourth value in the statement).
  
  var store = new anzo.rdf.QuadStore();
  
  var graph1 = new anzo.rdf.NamedGraph("ex:graph1", store);
  graph1.add("http://www.example.org/subj1", "ex:pred1", "dog");
   
  var graph2 = new anzo.rdf.NamedGraph("ex:graph2", store);
  graph2.add("ex:subj2", "ex:pred2", "cat");

  graph1.contains(null, null, "dog");  // true
  graph2.contains(null, null, "cat");  // true
  store.contains(null, null, "dog");    // true
  store.contains(null, null, "cat");    // true
Performance Numbers
In this test I loaded up the quadstore with 100,000 quads. I then ran a number of timed calls to the find method with a pattern from the first of the 100,000 statements that were added, a pattern from the middle of that set and a pattern from the very end. Then, I added an additional 100 quads and timed that. I then removed those 100 and timed that. Here are my results:
  
----------------------------------------------
added: 100000 statements to the store
----------------------------------------------
find(s, p, o, c)
Elapsed time calling find (s, p, o, c) on first added statement pattern: 0 milliseconds. Num stmts found: 0
Elapsed time calling find (s, p, o, c) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 0
Elapsed time calling find (s, p, o, c) on last added statement pattern: 0 milliseconds. Num stmts found: 0
----------------------------------------------
find(?, p, o, c)
Elapsed time calling find (?, p, o, c) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, p, o, c) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 1
Elapsed time calling find (?, p, o, c) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(s, ?, o, c)
Elapsed time calling find (s, ?, o, c) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (s, ?, o, c) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 1
Elapsed time calling find (s, ?, o, c) on last added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 1
----------------------------------------------
find(s, p, ?, c)
Elapsed time calling find (s, p, ?, c) on first added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (s, p, ?, c) on middle added statement pattern: 0.6666666666666666 milliseconds. Num stmts found: 100
Elapsed time calling find (s, p, ?, c) on last added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
----------------------------------------------
find(s, p, o, ?)
Elapsed time calling find (s, p, o, ?) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (s, p, o, ?) on middle added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (s, p, o, ?) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(?, ?, o, c)
Elapsed time calling find (?, ?, o, c) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, ?, o, c) on middle added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, ?, o, c) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(s, ?, ?, c)
Elapsed time calling find (s, ?, ?, c) on first added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (s, ?, ?, c) on middle added statement pattern: 0.6666666666666666 milliseconds. Num stmts found: 100
Elapsed time calling find (s, ?, ?, c) on last added statement pattern: 0.6666666666666666 milliseconds. Num stmts found: 100
----------------------------------------------
find(s, p, ?, ?)
Elapsed time calling find (s, p, ?, ?) on first added statement pattern: 0 milliseconds. Num stmts found: 100
Elapsed time calling find (s, p, ?, ?) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (s, p, ?, ?) on last added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
----------------------------------------------
find(?, p, ?, c)
Elapsed time calling find (?, p, ?, c) on first added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (?, p, ?, c) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (?, p, ?, c) on last added statement pattern: 0.6666666666666666 milliseconds. Num stmts found: 100
----------------------------------------------
find(s, ?, o, ?)
Elapsed time calling find (s, ?, o, ?) on first added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 1
Elapsed time calling find (s, ?, o, ?) on middle added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (s, ?, o, ?) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(?, p, o, ?)
Elapsed time calling find (?, p, o, ?) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, p, o, ?) on middle added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, p, o, ?) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(?, ?, ?, c)
Elapsed time calling find (?, ?, ?, c) on first added statement pattern: 7 milliseconds. Num stmts found: 1000
Elapsed time calling find (?, ?, ?, c) on middle added statement pattern: 7.333333333333333 milliseconds. Num stmts found: 1000
Elapsed time calling find (?, ?, ?, c) on last added statement pattern: 8 milliseconds. Num stmts found: 1000
----------------------------------------------
find(?, ?, o, ?)
Elapsed time calling find (?, ?, o, ?) on first added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, ?, o, ?) on middle added statement pattern: 0 milliseconds. Num stmts found: 1
Elapsed time calling find (?, ?, o, ?) on last added statement pattern: 0 milliseconds. Num stmts found: 1
----------------------------------------------
find(?, p, ?, ?)
Elapsed time calling find (?, p, ?, ?) on first added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (?, p, ?, ?) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (?, p, ?, ?) on last added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
----------------------------------------------
find(s, ?, ?, ?)
Elapsed time calling find (s, ?, ?, ?) on first added statement pattern: 0 milliseconds. Num stmts found: 100
Elapsed time calling find (s, ?, ?, ?) on middle added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
Elapsed time calling find (s, ?, ?, ?) on last added statement pattern: 0.3333333333333333 milliseconds. Num stmts found: 100
----------------------------------------------
find(?, ?, ?, ?)
Elapsed time calling find (?, ?, ?, ?): 350 milliseconds. Num stmts found: 100000
----------------------------------------------
adding num stmts: 100
Elapsed time adding statements: 11.333333333333334 milliseconds.
----------------------------------------------
removing num stmts: 100
Elapsed time removing statements: 0 milliseconds.

Openanzo’s javascript RDF library – parsers and serializers

Openanzo has a powerful RDF javascript library which has RDF parsing and serialization capabilities.

anzo.rdf.parser.TabulatorParser

An RDF/XML parser ported from Tabulator.
  
var graph = new anzo.rdf.NamedGraph(); // graph into which triples are placed
anzo.rdf.parser.TabulatorParser.parse(rdfXMLString, graph); // parse

anzo.rdf.parser.NTripleParser

An RDF N-Triples parser.
  
var graph = new anzo.rdf.NamedGraph(); // the graph into which the parsed data is placed
anzo.rdf.parser.NTripleParser.parse(nTripleString, graph); // run the parser on the given N-Triple string

anzo.rdf.serializer.NTripleSerializer

An RDF N-Triples serializer.
  
var graph = new anzo.rdf.NamedGraph(); // the graph we want to serialize
// we add a bunch of statements to graph via the add() method
var nTripleString = anzo.rdf.serializer.NTripleSerializer.serialize(graph); // serialize the graph to N-Triples

Openanzo’s javascript RDF library – the basics

What most people don’t know is that openanzo has a powerful RDF javascript library. The library can be used as is, but of course it’s designed to work seamlessly with the rest of the openanzo stack. The RDF library is located in the org.openanzo.js project in src/main/resources/docroot/anzo/rdf

Statements, Resources, Literals …

Every RDF library has to have these basics. Here is the inheritance hierarchy:
  • anzo.rdf.Value – base class for all rdf nodes
    • anzo.rdf.Resource – base class for all rdf resources
      • anzo.rdf.URI – equals, toString, serialize, getNamespace, getLocalName
      • anzo.rdf.BNode – equals, toString, serialize
    • anzo.rdf.Literal – equals, toString, serialize, getNativeValue

anzo.rdf.URI

A javascript object representing a URI.
  
   var uri = anzo.createURI("http://www.example.org/foo");
   uri.serialize(); // "<http://www.example.org/foo>"
   uri.getNamespace(); // "http://www.example.org/"
   uri.getLocalName(); // "foo"
We can use short prefixes if we register the namespace:
  
   anzo.rdf.registerNamespace("ex", "http://www.example.org/");
   var uri = anzo.createURI("ex:foo");

anzo.rdf.BNode

Blank nodes are supported by all parts of the library.
  
   var bnode = anzo.createBNode("324453142134353214");
   bnode.toString(); // "324453142134353214"
   bnode.serialize(); //  "_:324453142134353214"

anzo.rdf.Literal

An anzo.rdf.Literal is the object that holds a value like a string, number, boolean, etc.
Creating a literal:
  
      var lit1= anzo.createLiteral("dog");
      lit1.toString(); // "dog"
      lit1.serialize(); // "dog"

      var lit2 = anzo.createLiteral("dog", "en"); // we can specify the language of the literal as the second argument
      lit2.toString(); // "dog"
      lit2.serialize(); // "dog"@en
Creating a typed literal:
  
      var lit3 = anzo.createTypedLiteral(5, "http://www.w3.org/2001/XMLSchema#int");
      lit3.toString(); // "5"
      lit3.serialize(); // "5"^^<http://www.w3.org/2001/XMLSchema#int>
      lit3.getNativeValue(); // returns a javascript number 5
      lit3.datatype; // returns http://www.w3.org/2001/XMLSchema#int as an anzo.rdf.URI
The getNativeValue method allows you to get a native javascript object from any literal. This makes rendering and editing rdf data with widgets from common libraries such as YUI, dojo and jquery very easy. Here is a table showing the mappings between the literal and the type of javascript value you can expect when calling getNativeValue:
XSD DatatypeJavascript Type
http://www.w3.org/2001/XMLSchema#dateTimeDate
http://www.w3.org/2001/XMLSchema#dateDate
http://www.w3.org/2001/XMLSchema#timeDate
http://www.w3.org/2001/XMLSchema#gYearMonthDate
http://www.w3.org/2001/XMLSchema#gYearDate
http://www.w3.org/2001/XMLSchema#gMonthDayDate
http://www.w3.org/2001/XMLSchema#gDayDate
http://www.w3.org/2001/XMLSchema#gMonthDate
http://www.w3.org/2001/XMLSchema#stringString
http://www.w3.org/2001/XMLSchema#booleanBoolean
http://www.w3.org/2001/XMLSchema#decimalNumber
http://www.w3.org/2001/XMLSchema#doubleNumber
http://www.w3.org/2001/XMLSchema#integerNumber
http://www.w3.org/2001/XMLSchema#longNumber
http://www.w3.org/2001/XMLSchema#shortNumber
http://www.w3.org/2001/XMLSchema#byteNumber
http://www.w3.org/2001/XMLSchema#nonPositiveIntegerNumber
http://www.w3.org/2001/XMLSchema#negativeIntegerNumber
http://www.w3.org/2001/XMLSchema#nonnegativeIntegerNumber
http://www.w3.org/2001/XMLSchema#positiveIntegerNumber
http://www.w3.org/2001/XMLSchema#unsignedLongNumber
http://www.w3.org/2001/XMLSchema#unsignedIntNumber
http://www.w3.org/2001/XMLSchema#unsignedShortNumber
http://www.w3.org/2001/XMLSchema#unsignedByteNumber
All the restString

Example of rendering an xsd:date literal in a dojo widget:
  
  var date = new Date(1216330344703); // Thu Jul 17 21:32:24.703 UTC 2008
  var dateLit = anzo.createTypedLiteral(date, "http://www.w3.org/2001/XMLSchema#date");
  dojoWidget.attr('value', dateLit.getNativeValue()); // this renders the literal value in the widget
The serialize method serializes the rdf node into a string that can then easily be deserialized by calling anzo.rdf.getValue(serializedString). This serialization can be used in constructing a SPARQL query:
  
var query = "select ?x where { ?x " + uri.serialize() + " "+lit.serialize() + " }";
// the query will look something like this: select ?x where { ?x <http://www.example.org/age> "5"^^<http://www.w3.org/2001/XMLSchema#int> }

anzo.rdf.Statement

A statement in this library can be used as either a triple or a quad.
  
   var triple = anzo.createStatement("ex:foo", "ex:bar", "dog");
   var quad = anzo.createStatement("ex:foo", "ex:bar", "dog", "ex:graph");

Graphs

anzo.rdf.NamedGraph

An in memory RDF graph. While intended to be used as a named graph, this graph could also be used as just a regular graph with no name.
  
    anzo.rdf.registerNamespace("ex", "http://www.example.org/");

    var graph = new anzo.rdf.NamedGraph("ex:mygraph"); // the graph name URI is optional
    graph.add("ex:foo", "ex:title", "dog");
    graph.find("ex:foo", null, "dog"); // returns an array with a single statement in it
    graph.contains(null, "ex:title"); // true
    graph.size(); // 1
    graph.clear(); // removes all statements - same as calling remove();
Note that in the graph methods allow you to pass native javascript objects. The library will try to guess what you meant and create the proper rdf nodes for you underneath. Be very careful using this feature as the guessed types may not be exactly what you want. The library has a number of other features including a quad store, parsers, etc that I will cover in future tutorials. -Happy hacking Openanzo is an opensource project distributed under the Eclipse Public License.

Anzo on the Web Screenshots

Anzo on the Web is a semantically enabled application that allows users to view and edit their data. It runs in all major browsers, but I strongly recommend that you AVOID using Internet Explorer. Here are some screenshots of the application: