#!/usr/bin/env python """ schemadoc.py - Format RDF Schemata Author: Sean B. Palmer, inamidst.com Usage: ./schemadoc.py URI """ import sys from rdflib.Graph import ConjunctiveGraph as Graph from rdflib import URIRef, Literal, BNode, Namespace from rdflib import RDF, RDFS OWL = Namespace('http://www.w3.org/2002/07/owl#') prefix = { 'http://purl.org/dc/elements/1.1/': 'dc', 'http://www.w3.org/WAI/ER/EARL/nmg-strawman#': 'earl', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf', 'http://www.w3.org/2000/01/rdf-schema#': 'rdfs' } def split(uri): """Split URI into racine (greedy), [#/], component.""" hash = uri.rfind('#') slash = uri.rfind('/') i = max(hash, slash) return uri[:i], uri[i+1:] def format(uriref): uri = str(uriref) for ns in prefix.iterkeys(): if uri.startswith(ns): return prefix[ns], uri[len(ns):] namespace, label = split(uri) racine, nslabel = split(namespace) return nslabel, label class Class(object): def __init__(self, uri): self.uri = str(uri) self.qname = format(self.uri) # @@ rename format self.classes = [] self.properties = [] def __cmp__(self, obj): return cmp(self.qname, obj.qname) def __str__(self): return self.name() def name(self, format='html'): prefix, name = self.qname if format == 'html': return prefix + ':' + name + '' else: return ':'.join([prefix, name]) class Property(object): def __init__(self, uri): self.uri = str(uri) self.qname = format(self.uri) # @@ rename format def __cmp__(self, obj): return cmp(self.qname, obj.qname) def __str__(self): return self.name() def name(self, format='html'): prefix, name = self.qname if format == 'html': return prefix + ':' + name + '' else: return ':'.join([prefix, name]) def test(): uris = [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns', 'http://www.w3.org/2000/01/rdf-schema' # 'http://www.w3.org/2000/10/swap/grammar/ebnf.rdf' # 'http://www.w3.org/2002/07/owl' ] schemadoc(uris) def schemadoc(uris): G = Graph() for uri in uris: G.parse(uri) print """ Schema Documentation

Schema Documentation

""" classes = [] for metaclass in [RDFS.Class, OWL.Class]: for uri in G.subjects(RDF.type, metaclass): if not isinstance(uri, URIRef): continue c = Class(uri) c.classes = [Class(u) for u in G.objects(uri, RDFS.subClassOf) if isinstance(u, URIRef)] for prop in G.subjects(RDFS.domain, uri): p = Property(prop) ranges = [Class(u) for u in G.objects(prop, RDFS.range)] c.properties.append((p, ranges)) # c.properties = [Property(u) for u in G.subjects(RDFS.domain, uri)] c.comments = [str(s) for s in G.objects(uri, RDFS.comment)] classes.append(c) print '

Classes

' print '' print '

Properties

' properties = [] print '
' for propclass in [RDF.Property, OWL.FunctionalProperty, OWL.InverseFunctionalProperty]: for uri in G.subjects(RDF.type, propclass): if not isinstance(uri, URIRef): continue p = Property(uri) properties.append(p) p.kind = Class(propclass) p.domains = [Class(u) for u in G.objects(uri, RDFS.domain) if isinstance(u, URIRef)] p.ranges = [Class(u) for u in G.objects(uri, RDFS.range) if isinstance(u, URIRef)] p.comments = [str(s) for s in G.objects(uri, RDFS.comment)] for p in sorted(properties): print '
' print p.name() + ' (' + p.kind.name(format='text') + ')' print '
' for comment in p.comments: print '
' print comment print '
' if p.domains: print '
domain: ' print ', '.join(domain.name() for domain in p.domains) print '
' if p.ranges: print '
range: ' print ', '.join(range.name() for range in p.ranges) print '
' print '
' print '
' print 'Generated by Schemadoc' print '
' print '' print '' # @@ report errors at the bottom # @@ call from CGI # @@ XHTML vs. Plain Text def main(): try: arg = sys.argv[1] except IndexError: print __doc__.strip() sys.exit() if arg == '--test': test() elif arg == '--help': print __doc__.strip() else: schemadoc([arg]) if __name__ == '__main__': main()