- From: Nathan <nathan@webr3.org>
- Date: Sun, 19 Sep 2010 23:33:36 +0100
- To: Manu Sporny <msporny@digitalbazaar.com>
- CC: RDFA Working Group <public-rdfa-wg@w3.org>
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