#!/usr/bin/env python2.5 # # SpecGen code adapted to be independent of a particular vocabulary (e.g., FOAF) # # # This software is licensed under the terms of the MIT License. # # Copyright 2008 Uldis Bojars # Copyright 2008 Christopher Schmidt # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. __all__ = [ 'main' ] import sys, time, re, urllib, getopt import logging # Configure how we want rdflib logger to log messages _logger = logging.getLogger("rdflib") _logger.setLevel(logging.DEBUG) _hdlr = logging.StreamHandler() _hdlr.setFormatter(logging.Formatter('%(name)s %(levelname)s: %(message)s')) _logger.addHandler(_hdlr) from rdflib.Graph import ConjunctiveGraph as Graph from rdflib import plugin from rdflib.store import Store from rdflib import Namespace from rdflib import Literal from rdflib import URIRef from rdflib.sparql.bison import Parse store = Graph() # with some care this could be made less redundant store.bind("dc", "http://http://purl.org/dc/elements/1.1/") store.bind("foaf", "http://xmlns.com/foaf/0.1/") store.bind("dc", 'http://purl.org/dc/elements/1.1/') store.bind("rdf", 'http://www.w3.org/1999/02/22-rdf-syntax-ns#') store.bind("rdfs", 'http://www.w3.org/2000/01/rdf-schema#') store.bind("owl", 'http://www.w3.org/2002/07/owl#') store.bind("vs", 'http://www.w3.org/2003/06/sw-vocab-status/ns#') # Create a namespace object for the Friend of a friend namespace. foaf = Namespace("http://xmlns.com/foaf/0.1/") dc = Namespace('http://purl.org/dc/elements/1.1/') rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#') rdfs = Namespace('http://www.w3.org/2000/01/rdf-schema#') owl = Namespace('http://www.w3.org/2002/07/owl#') vs = Namespace('http://www.w3.org/2003/06/sw-vocab-status/ns#') # add your namespaces here classranges = {} classdomains = {} termdir = '../doc' # .. for FOAF # namespace for which the spec is being generated. spec_url = "http://xmlns.com/foaf/0.1/" spec_pre = "foaf" # spec_url = "http://rdfs.org/sioc/ns#" # spec_pre = "sioc" spec_ns = Namespace(spec_url) ns_list = { "http://xmlns.com/foaf/0.1/" : "foaf", 'http://purl.org/dc/elements/1.1/' : "dc", 'http://purl.org/dc/terms/' : "dcterms", 'http://usefulinc.com/ns/doap#' : 'doap', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' : "rdf", 'http://www.w3.org/2000/01/rdf-schema#' : "rdfs", 'http://www.w3.org/2002/07/owl#' : "owl", 'http://www.w3.org/2001/XMLSchema#' : 'xsd', 'http://www.w3.org/2003/06/sw-vocab-status/ns#' : "status", 'http://purl.org/rss/1.0/modules/content/' : "content", 'http://rdfs.org/sioc/ns#' : "sioc" } def niceName( uri = None ): if uri is None: return speclog("Nicing uri "+uri) regexp = re.compile( "^(.*[/#])([^/#]+)$" ) rez = regexp.search( uri ) # return uri # temporary skip this whole thing! pref = rez.group(1) # todo: make this work when uri doesn't match the regex --danbri # AttributeError: 'NoneType' object has no attribute 'group' return ns_list.get(pref, pref) + ":" + rez.group(2) def setTermDir(directory): global termdir termdir = directory def termlink(string): """FOAF specific: function which replaces foaf:* with a link to the term in the document.""" return re.sub(r"" + spec_pre + r":(\w+)", r"""""" + spec_pre + r""":\1""", string) def return_name(m, urinode): "Trims the FOAF namespace out of a term to give a name to the term." return str(urinode).replace(spec_url, "") def get_rdfs(m, urinode): "Returns label and comment given an RDF.Node with a URI in it" comment = '' label = '' r = wrap_find_statements(m, urinode, rdfs.label, None) try: l = r.next() label = l[2] #l['todo-labels' # l[0][2] # .current().object.literal_value['string'] except StopIteration: '' r = wrap_find_statements(m, urinode, rdfs.comment, None) try: c = r.next() comment = c[2] # c[2] #.current().object.literal_value['string'] except StopIteration: '' return label, comment def get_status(m, urinode): "Returns the status text for a term." status = '' r = wrap_find_statements(m, urinode, vs.term_status, None) try: s = r.next() status = s[2] except StopIteration: '' return(status) def htmlDocInfo( t ): """Opens a file based on the term name (t) and termdir directory (global). Reads in the file, and returns a linkified version of it.""" doc = "" try: f = open("%s/%s.en" % (termdir, t), "r") doc = f.read() doc = termlink(doc) except: speclog("Failed to open file for more info on "+t+ " termdir: " +termdir) return "" # "

No detailed documentation for this term.

" return doc def owlVersionInfo(m): r = wrap_find_statements(m, None, owl.versionInfo, None) try: v = r.next() return(v[2]) except StopIteration: '' def rdfsPropertyInfo(term,m): """Generate HTML for properties: Domain, range, status.""" doc = "" range = "" domain = "" # Find subPropertyOf information speclog("Finding subPropertyOf info: skipping.") # todo: implement in sparql instead. # r = wrap_find_statements(m, term, rdfs.subPropertyOf, None ) # try: # o = r.next() # doc += "\tsub-property-of:" # rlist = '' # for st in o: # speclog("XXX superProperty: "+st) # k = st[2] # if (spec_url in k): # k = """%s""" % (k.replace(spec_url, ""), niceName(k)) # else: # k = """%s""" % (k, niceName('xxxzzz'+k)) # rlist += "%s " % k # doc += "\n\t%s\n" % rlist # except StopIteration: # '' # domain and range stuff (properties only) r = wrap_find_statements(m, term, rdfs.domain, None) try: d = r.next() domain = d[2] except StopIteration: "" r = wrap_find_statements(m, term, rdfs.range, None) try: rr = r.next() range = rr[2] except StopIteration: '' speclog("range: "+range+ "domain: "+domain) if domain: # NOTE can add a warning of multiple rdfs domains / ranges if (spec_url in domain): domain = """%s""" % (domain.replace(spec_url, ""), niceName(domain)) else: domain = """%s""" % (domain, niceName(domain)) doc += "\tDomain:\n\t%s\n" % domain if range: if (spec_url in range): range = """%s""" % (range.replace(spec_url, ""), niceName(range)) else: range = """%s""" % (range, niceName(range)) doc += "\tRange:\n\t%s\n" % range return doc def rdfsClassInfo(term,m): """Generate rdfs-type information for Classes: ranges, and domains.""" global classranges global classdomains doc = "" # Find subClassOf information o = wrap_find_statements(m, term, rdfs.subClassOf, None ) if o: doc += "\tsub-class-of:" rlist = '' for st in o: k = str( st[2] ) if (spec_url in k): k = """%s""" % (k.replace(spec_url, ""), niceName(k)) else: k = """%s""" % (k, niceName(k)) rlist += "%s " % k doc += "\n\t%s\n" % rlist # Find out about properties which have rdfs:range of t r = classranges.get(term, "") if r: rlist = '' for k in r: if (spec_url in k): k = """%s""" % (k.replace(spec_url, ""), niceName(k)) else: k = """%s""" % (k, niceName(k)) rlist += "%s " % k doc += "in-range-of:"+rlist+"" # Find out about properties which have rdfs:domain of t d = classdomains.get(str(term), "") if d: dlist = '' for k in d: if (spec_url in k): k = """%s""" % (k.replace(spec_url, ""), niceName(k)) else: k = """%s""" % (k, niceName(k)) dlist += "%s " % k doc += "in-domain-of:"+dlist+"" return doc def owlInfo(term,m): """Returns an extra information that is defined about a term (an RDF.Node()) using OWL.""" res = '' # Inverse properties ( owl:inverseOf ) # r = wrap_find_statements(m,term, owl.inverseOf, None) # try: # o = r.next() # res += "\tInverse:" # rlist = '' # for st in o: # k = str( st[2] ) # if (spec_url in k): # k = """%s""" % (k.replace(spec_url, ""), niceName(k)) # else: # k = """%s""" % (k, niceName(k)) # rlist += "%s " % k # res += "\n\t%s\n" % rlist # except StopIteration: # print '' # Datatype Property ( owl.DatatypeProperty ) r = wrap_find_statements( m, term, rdf.type, owl.DatatypeProperty) try: o = r.next() res += "\tOWL Type:\n\tDatatypeProperty\n" except StopIteration: #print '' '' # # Object Property ( owl.ObjectProperty ) r = wrap_find_statements(m, term, rdf.type, owl.ObjectProperty) try: o = r.next() res += "\tOWL Type:\n\tObjectProperty\n" except StopIteration: '' # IFPs ( owl.InverseFunctionalProperty ) r = wrap_find_statements(m, term, rdf.type, owl.InverseFunctionalProperty) try: o = r.next() res += "\tOWL Type:\n\tInverseFunctionalProperty (uniquely identifying property)\n" except StopIteration: '' # Symmetric Property ( owl.SymmetricProperty ) r = wrap_find_statements(m, term, rdf.type, owl.SymmetricProperty) try: o = r.next() res += "\tOWL Type:\n\tSymmetricProperty\n" except StopIteration: '' return res def docTerms(category, list, m): """A wrapper class for listing all the terms in a specific class (either Properties, or Classes. Category is 'Property' or 'Class', list is a list of term names (strings), return value is a chunk of HTML.""" doc = "" nspre = spec_pre for t in list: term = spec_ns[t] doc += """
\n

%s: %s:%s

\n""" % (t, category, nspre, t) label, comment = get_rdfs(m, term) status = get_status(m, term) doc += "

%s - %s

" % (label, comment) doc += """\n""" doc += owlInfo(term,m) if category=='Property': doc += rdfsPropertyInfo(term,m) if category=='Class': doc += rdfsClassInfo(term,m) doc += "
\n" doc += htmlDocInfo(t) doc += "

[back to top]

\n\n" doc += "\n
\n
\n\n" return doc def buildazlist(classlist, proplist): """Builds the A-Z list of terms. Args are a list of classes (strings) and a list of props (strings)""" azlist = """
""" azlist = """%s\n

Classes: |""" % azlist classlist.sort() for c in classlist: speclog("Class "+c+" in azlist generation.") azlist = """%s %s | """ % (azlist, c.replace(" ", ""), c) azlist = """%s\n

""" % azlist azlist = """%s\n

Properties: |""" % azlist proplist.sort() for p in proplist: speclog("Property "+p+" in azlist generation.") azlist = """%s %s | """ % (azlist, p.replace(" ", ""), p) azlist = """%s\n

""" % azlist azlist = """%s\n
""" % azlist return azlist def build_simple_list(classlist, proplist): """Builds a simple