RDFa API proposed changes & IDL

Hi Manu,

As per earlier notes and voice conversations, here are the changes I'm 
proposing along with full notes and reasons for each.

interface DataContext {
     void setMapping (in DOMString prefix, in DOMString iri);
     TypedLiteralConverter registerTypeConversion (in DOMString iri, in 
TypedLiteralConverter converter);
     IRI  resolveCurie (in DOMString curie);
     any  convertType (in DOMString value, in optional DOMString inputType);
     DataParser registerParser( in DOMString name, in DataParser parser );
     DataParser getParser( in DOMString name );
}

[NoInterfaceObject Callback]
interface DataParser {
     boolean parse (in any toparse, in DataStore store);
};

[NoInterfaceObject Callback]
interface TypedLiteralConverter {
     any convert (in DOMString value, in optional IRI inputType);
};

notes:
removed "modifier" from convertType and TypedLiteralConverter.convert
changed return of registerTypeConversion from void to TypedLiteralConverter.
added `registerParser` method to DataContext
added `getParser` method to DataContext
removed DataParser.iterate
removed `domElement` argument from DataParser.parse
added `any toparse` argument to DataParser.parse
added `store` argument to DataParser.parse

TypedLiteralConverter usage:
function myStringIntConverter(value,inputType) {
   // implementation which returns a string representation
   // of an int rather than a native int
}
var context = document.data.context;
// get the native converter and register a custom one
var nativeConverter = context.registerTypeConversion('xsd:int', 
myStringIntConverter);
// work with data
context.registerTypeConversion(nativeConverter); //return to native mode

The above should handle any use case which the modifier parameter could 
handle.

Parser changes:
Formerly there way no way to register new or custom parsers in the API 
meaning usage was limited to only those parsers natively implemented.
The iterate method made no sense on DataParser and was of no concern to 
the parser.
DataParser single parameter was incompatible with almost everything as 
it was set to Element (Document extends Node not Element) thus could not 
be used to parse a document, also could not be used to implement parsers 
for any other type of (non-dom) document in the future, if DOM 
constraint is needed it could be changed to accept `Node node` which 
would be both Element and Document compatible.
DataParser usage required instantiation from DocumentData with no clear 
way to select which DataStore you wanted to parse in to, removing the 
`store` attribute and adding a `store` property to the `parse` method 
allow clear, easy reuse of a parser with user-friendly store selection.
see DocumentData for additional proxy method.
Optionally the Callback extended attribute could be removed if this 
caused problems in different languages.


[NoInterfaceObject]
interface DataStore {
     readonly attribute unsigned long legnth;
     RDFTriple        get (in unsigned long index);
     void             add (in RDFTriple triple);
     DataStore        filter (in RDFTripleCallback filter);
     void             forEach (in RDFTripleCallback callback);
     void             import(in DataStore store);
     boolean          some(in RDFTripleCallback callback);
     boolean          every(in RDFTripleCallback callback);
     DataIterator     iterator();
};

[NoInterfaceObject, Callback, Null=Null]
interface RDFTripleCallback {
     boolean match (in RDFTriple triple, in unsigned long index, in 
DataStore store);
}

Notes:
changed `size` to `length` to align with ECMAScript and most languages 
(array.length)
removed `create**` methods (they don't belong here see DocumentData 
changes for reasons)
changed return type of `add` to void as it is impossible to ever return 
boolean False. (should add return unsigned long, the index?)
removed `getter` property of get method to remove indexed sequence 
functionality (see notes further down)
removed `pattern` from filter(), all functionality this could implement 
can be handled by DataQuery or by RDFTripleFilter, `pattern` allows for 
non-standardized implementation specific functionality to be introduced, 
in fact it forces this to happen, best left to libraries if they want to 
provide it (even though it isn't needed).
removed redundant `element` from filter - no need/use.
made `RDFTripleFilter filter` non optional
removed `clear` method, it isn't needed
changed `merge` method to `import` to make it clearer
changed return type of `import` (formerly `merge`) to void as it was 
impossible to ever return boolean False.
added quantification methods .some and .every
added `iterator` method, could be named `iterate` however feel best to 
align with common naming conventions, and given the meaning of iterator 
"one which iterates".
removed RDFTripleFilter and replaced with RDFTripleCallback, 
functionality is the same and is used in .filter, .forEach .some and 
.every (for all callbacks), the method takes 3 params, the RDFTriple, 
the index and the store which holds the triple, also aligned to match 
ECMAScript v5.
removed DataStoreIterator and replaced with universal RDFTripleCallback, 
formerly DataStoreIterator accepted 4 params, index, subject, property, 
object however this meant that the triple could not be accessed (for 
instance to use the .toString() method) and if using any other method in 
the api such as DataStore.add() a new RDFTriple would have had to be 
created. Changing the method to accept RDFTriple as param one exposes 
more functionality, saves the user code, and aligns with the rest of the 
API.


Why move create** methods:
Simply, they don't belong here, it is of no concern to a DataStore how 
IRI, RDFTriple, PlainLiteral etc are created. More technically having 
the create** methods on DataStore decoupled them from the default 
context which leads to unexpected behaviour, cross cutting concerns and 
a difficult implementation. Whereas if they are located on the 
DocumentData interface they are always coupled to a specific context, 
behaviour is expected, dependency is clear and cross cutting concerns 
are removed. (DocumentData can "see" .context, DataStore cannot see 
DataContext in any way).

Why remove indexed behaviour:
Indexed behaviour and array accessors [] raised an important issue over 
expected functionality, namely setting by index `store[23] = triple;`, 
in one case this meant editing the contents of the graph (something 
which couldn't be implemented with user expected functionality - i.e. 
changing the document source) and in another case it would make it 
almost impossible to prevent duplicates being added. From an 
implementation perspective it would be impossible in many languages, 
including ECMAScript to implement. Instead the DataStore should be 
treated like a typed int hash IntHash<RDFTriple> which nicely wraps the 
array/collection hiding any inadvisable methods; this can easily be 
implemented in any language. Iteration is still possible in two common 
forms:
   for(i=0;i<store.length;i++) {
     triple = store.get(i);
   }
and
   iterator = store.iterator();
   while((triple = iterator.next()) !== null) {
     // work with triple
   }
and of course there's the callback interface .forEach too.

Optional:
One could also add a `sequence<RDFTriple> toArray()` method to DataStore 
but this may be unneeded - I'm easy, it's an easy hit if it has benefits 
in other languages.


interface DocumentData {
     attribute DataStore   store;
     attribute DataContext context;
     attribute DataQuery   query;
     IRI           createIRI (in DOMString iri);
     PlainLiteral  createPlainLiteral (in DOMString value, in optional 
DOMString? language);
     TypedLiteral  createTypedLiteral (in DOMString value, in DOMString 
type);
     BlankNode     createBlankNode ();
     RDFTriple     createTriple (in RDFResource subject, in IRI 
property, in RDFNode object);
     DataContext   createContext ();
     DataStore     createStore ();
     DataQuery     createQuery (in DOMString type, in DataStore store);
     boolean       parse(in any toParse, in optional DataStore store, in 
optional DataParser parser);
};

Notes:
Added the create** methods from DataStore (as per notes above)
removed the `node` param from createIRI
removed `type` param from createStore
removed `parser` property
removed `createParser` method
removed `name` parameter from `createBlankNode`
added `parse` method

Notes:
`node` param on createIRI was legacy/editorial error and needed removed
`type` param on createStore was unused (if this is wrong, ad it back in)
`name` param on createBlankNode was unneeded, introduced a possible 
exception to BlankNode construction and encouraged people to think of 
blanknode names as dependable in some way, the unique per context "name" 
of a BlankNode can be retrieved by calling BlankNode.toString, or the 
blank node itself can be passed around when referring to it multiple 
times (such as using the same blank node as the object of one triple, 
and the subject of another).

More on Parser changes:
see earlier in the document, these changes make the `parser` attribute 
redundant in addition to the createParser method (which made it 
impossible to use custom parsers).
a new method has been added `parse` which only requires a single 
argument, namely what to parse.
An optional `store` parameter has been added which allows one to specify 
which store to parse in to without modifying the default value of 
DocumentData.store, similarly a `parser` parameter has been added which 
allows one to execute custom parsers easily.
This adds the constraint that all RDFa API implementations must support 
the default parser "rdfa1.1" which is used when 
document.data.parse(document) is called and no custom parser is handed in.
Optionally the `toparse` argument on this method could be changed to 
`Node node` to require usage within a DOM environment, whilst still 
supporting non-DOM environments via DataContext.getParser


[NoInterfaceObject]
interface DataIterator {
     readonly attribute DataStore store;
     boolean hasNext();
     RDFTriple next();
};

changed `store` attribute to readonly (changing the store at runtime 
will produce unexpected results)
removed attribute `root`, unused
removed attribute `filter`, no need, constrains DataIterator to only be 
used with DataStore.filter method
removed attribute `triplePattern`, redundant/unused
added hasNext() method to make iteration easier and prevent users making 
double calls to `next` by accident / getting confused.
usage:
   while(iterator.hasNext()) {
     triple = iterator.next();
   }
basic ECMAScript Datastore.iterator implementation:
   Datastore.prototype.iterator = function() {
     return {
       cur : 0,
       store : this,
       hasNext: function() { return cur < store.length; },
       next: function() { return store.get(cur++); }
     };
   }

Final change is simply to change RDFTriple.size to RDFTriple.length to 
align with most languages and common usage.

Best,

Nathan

Received on Sunday, 19 September 2010 22:34:17 UTC