#!/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 ''
for c in sorted(classes):
print '- '
print '
'
print '- '
sys.stdout.write(c.name())
if c.classes:
o = ', '.join(cls.name(format='text') for cls in sorted(c.classes))
print '(' + o + ')'
else: print
print '
'
for comment in c.comments:
print '- '
print comment
print '
'
for prop, ranges in sorted(c.properties):
print '- '
print ' ' + prop.name()
if ranges:
print ' => ' + ', '.join(range.name() for range in ranges)
print '
'
print ''
print '
'
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()