RDF APIs - Cross-platform RDF Interfaces

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

This bundle consists of Python libraries that attempt to bridge the disconnects between the various Python RDF data store implementations. Given that RDF is supposed to be a ubiquitous knowledge representation format, it should be expected that porting API's and applications from one implementation to another should be more trivial in this scenario than in any other.

Advancement in each implementation should benefit the larger advancement of RDF. These libraries are an attempt to bridge the gaps, by taking advantage of the portability of the most common of the host languages used by implementations (Python) as well as APIs written to have as little to do with implementation details as possible (such as rdflib's Graph)

FtRdfBackend

FtRdfBackend implements the rdflib Backend API to provide a wrapper around a 4Suite RDF Model so it can be used interchangeably with any of the other rdflib Backend implementations. Interestingly, since 4Suite RDF itself abstracts the actual underlying data store, this essentially provides rdflib with support for the backend drivers implemented by 4Suite RDF but not by rdflib, such as:

FtRdfBackend can be downloaded from here:

Itinerant Binds (Versa/Sparta and RDF Python Bindings)

ItinerantBinds is a class that takes one or two FtRDF Models (if two are provided, the second is assumed to be a defining ontology - otherwise the single model is expected to include the defining ontology). Both models are wrapped as rdflib backends (using FtRdfBackend) and used to create rdflib Graphs. Finally, Versa queries can be executed and the result (consisting of Python objects bound to Versa data types - including the use of Sparta for binding RDF resources) is returned

The binding rules follow a combination of 4Suite RDF's python binds for Versa Data types and Sparta's RDF resource binding mechanism:

Versa Data Types

            
Spartas Predicate -> Python attribute binding rules (as determined by rdfs:range in defining ontology)     
    rdf:List
        list
    rdf:Seq
        list
    xs:string, xs:normalizedString, xs:token, xs:language
        unicode
    xs:boolean
        bool
    xs:decimal, xs:float, xs:double
        float
    xs:integer, xs:long, xs:unsignedLong, xs:unsignedInt
        long
    xs:nonPositiveInteger, xs:nonNegativeInteger, xs:positiveInteger, xs:negativeInteger, xs:int, xs:short, xs:byte, xs:unsignedShort, xs:unsignedByte
        int
    xs:anyURI
        str        
    
    

The constructor takes the following Keyword arguments:

model - The FtRDF Model instance (required)
schema_model - The defining ontology (as an FtRDF Model instance) - otherwise the defining ontology 
               is assumed to be included in the main Model
aliasMap - A dictionary mapping an attribute name to a URI to which the attribute will always be bound.  
nsMap - A dictionary mapping prefixes to namespace URIs used for the Versa query and by the binding 
        mechanism to setup the prefix_local name binds

The query function takes a Versa result and returns a Python object representing the query result. This is essentially the FtRDF Versa datatype python objects with the exception of Resources (and BlankNodes) which are replaced with Python objects bound by the underlying Spartas ThingFactory.

So data can be extracted via Versa query and the underlying Graph (using the original query as the starting point) can be traversed (and modified) as python objects and (perhaps) subsequent queries.

Software Dependencies:

ItinerantBinds can be downloaded from here:

ItinerantBinds in action

The following piece of code loads my Foaf graph into a single model and the defining ontologies for most of the vocabularies used (foaf/dc/rss/rdf/rdfs) into another model. ItinerantBind is used to fetch all the foaf:Person instances, print their names and mbox_sha1sums, fetch all the rss:channel instances and print their dc:descriptions and dc:titles, bind the foaf:Person instance that represents me to a python object, and add a new resource (the ItinerantBinds module) with rdfs:label/rdfs:comment/dc:description metadata as a foaf:currentProject. Finally, a Versa query is executed to demonstrate that the underying rdflib Graph (and 4Suite RDF Model) reflects the modifications made:

    #Setup FtRDF Model
    Memory.InitializeModule()   
    db = Memory.GetDb('', '')
    db.begin()
    model = Model.Model(db)
    szr = Dom.Serializer()
    foafUri="http://purl.net/net/chimezie/foaf"
    domStr=urllib2.urlopen(foafUri).read()        
    dom = Domlette.NonvalidatingReader.parseString(domStr,foafUri)
    szr.deserialize(model,dom,scope=foafUri)
    
    
    #Setup FtRDF Model Ontological models
    Memory.InitializeModule()   
    db = Memory.GetDb('', '')
    db.begin()
    ontModel = Model.Model(db)
    for ontUri in [
    'http://metacognition.info/ontologies/foaf.rdfs',
    'http://metacognition.info/ontologies/rss.rdfs',
    'http://metacognition.info/ontologies/dc.rdfs',
    'http://metacognition.info/ontologies/rdf.rdfs',
    'http://metacognition.info/ontologies/rdfs.rdfs']:
        domStr=urllib2.urlopen(ontUri).read()        
        dom = Domlette.NonvalidatingReader.parseString(domStr,ontUri)
        szr.deserialize(ontModel,dom,scope=foafUri)
    
    #Setup rdflib.Graph with FtRDF Model as Backend, using FtRdfBackend
    generator=ItinerantBinds(model,ontModel)
    for item in generator.query("type(foaf:Person)"):        
        names = [name for name in item.foaf_name]
        mailBoxShas = [mBox for mBox in item.foaf_mbox_sha1sum]
        print names, mailBoxShas
    
    
    for channel in generator.query("type(rss:channel)"):        
        descriptions = [desc for desc in channel.dc_description]
        titles = [title for title in channel.dc_title]
        print descriptions,titles
    
    #Add this Python module as a project
    me = generator.query("type(foaf:Person)|-foaf:name->eq('Chimezie Ogbuji')")[0]
    anonProject = generator.rdfBindFactory(URIRef("http://metacognition.info/RDF-API/ItinerantBinds.py"))
    anonProject.rdfs_label.add("Itinerant Binds (Versa/Sparta - RDF Pythonic Binding)")
    anonProject.rdfs_comment.add("Versa/Sparta - RDF Pythonic Binding")
    anonProject.dc_description.add("Versa/Sparta - RDF Pythonic Binding")
    
    me.foaf_currentProject.add(anonProject)
    projectDescriptionsQuery="""\
    distribute(
        (type(foaf:Person)|-foaf:name->eq('Chimezie Ogbuji'))-foaf:currentProject->*,
        '.',
        '.-rdfs:label->*'
    )"""
    pprint(generator.query(projectDescriptionsQuery))    

The output:

    [u'Uche Ogbuji'] [u'a76c5d8f40feb06791726d8f1a7cd90abaff015c']
    [u'Sean B. Palmer'] [u'd13cabd9c428d85a2bb1f71d53216f76f7f73a0f']
    [u'Mike J. Brown'] [u'f016a72f4e07eacda0d2b3b9e780ed06ea60a66a']
    [u'Eric Miller'] [u'fd1c7fa497930b8b24e3998927fcebe63509ef20']
    [u'Micah Dubinko'] [u'05fc611e7131de8065b2476a1a659b20872cdb9c']
    [u'Chimezie Ogbuji'] [u'03bdc2418c81b738135573b76fd4bd756aa42953']
    [u'Christopher Schmidt'] [u'd1235763342ad472a26e0cc3b2cc01268c98690d']
    [u"Ogbuji's on just about everything"] [u"Uche and Chime's Blog [ RSS 1.0 ]"]
    [
        [http://4Suite.org, [u'4Suite - Platform for XML/RDF Processing']],
        [http://copia.ogbuji.net/files/YiJingPlotter.py, [u'Yijing SVG Plotter']],
        [http://purl.org/net/chimezie/FuXi/home.html, [u'FuXi - Rete-based forward-chaining reasoning library for 4RDF']],
        [http://metacognition.info/RDF-API/ItinerantBinds.py, [u'Itinerant Binds (Versa/Sparta - RDF Pythonic Binding)']]
    ]

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::