def owlInfo(term, m): """Returns an extra information that is defined about a term (an RDF.Node()) using OWL.""" res = '' # Inverse properties ( owl:inverseOf ) o = m.find_statements(RDF.Statement(term, owl.inverseOf, None)) if o.current(): res += "<dt>Inverse:</dt>" for st in o: res += "<dd>%s</dd>" % getTermLink(str(st.object.uri)) # Datatype Property ( owl.DatatypeProperty ) o = m.find_statements(RDF.Statement(term, rdf.type, owl.DatatypeProperty)) if o.current(): res += "<dt>OWL Type:</dt><dd>DatatypeProperty</dd>\n" # Object Property ( owl.ObjectProperty ) o = m.find_statements(RDF.Statement(term, rdf.type, owl.ObjectProperty)) if o.current(): res += "<dt>OWL Type:</dt><dd>ObjectProperty</dd>\n" # IFPs ( owl.InverseFunctionalProperty ) o = m.find_statements( RDF.Statement(term, rdf.type, owl.InverseFunctionalProperty)) if o.current(): res += "<dt>OWL Type:</dt><dd>InverseFunctionalProperty (uniquely identifying property)</dd>\n" # Symmertic Property ( owl.SymmetricProperty ) o = m.find_statements(RDF.Statement(term, rdf.type, owl.SymmetricProperty)) if o.current(): res += "<dt>OWL Type:</dt><dd>SymmetricProperty</dd>\n" return res
def get_rdfs(m, urinode): "Returns label and comment given an RDF.Node with a URI in it" l = m.find_statements(RDF.Statement(urinode, rdfs.label, None)) label = l.current().object.literal_value['string'] c = m.find_statements(RDF.Statement(urinode, rdfs.comment, None)) comment = c.current().object.literal_value['string'] return label, comment
def parseCollection(model, collection): # #propertyA a rdf:Property ; # rdfs:domain [ # a owl:Class ; # owl:unionOf [ # rdf:parseType Collection ; # #Foo a owl:Class ; # #Bar a owl:Class # ] # ] # # seeAlso "Collections in RDF" uris = [] rdflist = model.find_statements( RDF.Statement(collection.current().object, None, None)) while rdflist and rdflist.current( ) and not rdflist.current().object.is_blank(): one = rdflist.current() if not one.object.is_blank(): uris.append(str(one.object.uri)) rdflist.next() one = rdflist.current() if one.predicate == rdf.rest: rdflist = model.find_statements( RDF.Statement(one.object, None, None)) return uris
def rdfsPropertyInfo(term, m): """Generate HTML for properties: Domain, range, status.""" doc = "" range = "" domain = "" # domain and range stuff (properties only) d = m.find_statements(RDF.Statement(term, rdfs.domain, None)) if d.current(): domain = d.current().object.uri domain = str(domain) else: domain = "" r = m.find_statements(RDF.Statement(term, rdfs.range, None)) if r.current(): range = r.current().object.uri range = str(range) if domain: if ("http://xmlns.com/foaf/0.1/" in domain): domain = domain.replace("http://xmlns.com/foaf/0.1/", "") domain = """<a href="#term_%s">foaf:%s</a>""" % (domain, domain) doc += "\t<tr><th>Domain:</th>\n\t<td>%s</td></tr>\n" % domain if range: if ("http://xmlns.com/foaf/0.1/" in range): range = range.replace("http://xmlns.com/foaf/0.1/", "") range = """<a href="#term_%s">foaf:%s</a>""" % (range, range) doc += "\t<tr><th>Range:</th>\n\t<td>%s</td></tr>\n" % range return doc
def get_option(self, model, subject): option = Option(subject.uri) statement = RDF.Statement(subject, RDF.Uri("http://okfnpad.org/flow/0.1/node"), None) uri = None for s in model.find_statements(statement): if s.object.is_resource(): uri = s.object.uri option.node = uri statement = RDF.Statement(subject, RDF.Uri("http://okfnpad.org/flow/0.1/text"), None) for s in model.find_statements(statement): if s.object.is_literal(): option.text = s.object.literal_value['string'] statement = RDF.Statement(subject, RDF.Uri("http://okfnpad.org/flow/0.1/query"), None) for s in model.find_statements(statement): if s.object.is_literal(): option.query = s.object.literal_value['string'] return option
def voidify(self): """present stats in VoID (http://www.w3.org/TR/void/)""" serializer = self.get_serializer() ########################### # VoID dataset definition # ########################### void_model = RDF.Model() void_dataset_uri = self.namespaces.get_namespace( 'ls_void') + "?source=" + self.rdf_stats.uri #TODO: URI encode ? void_dataset_entity = RDF.Uri(void_dataset_uri) void_model.append( RDF.Statement(void_dataset_entity, self.namespaces.get_rdf_namespace("rdf").type, self.namespaces.get_rdf_namespace("void").Dataset)) #self.generate_general_void_metadata(void_model, void_dataset_entity) #Number of triples number_of_triples_node = RDF.Node( literal=str(self.rdf_stats.get_no_of_triples()), datatype=self.namespaces.get_rdf_namespace("xsd").integer.uri) void_model.append( RDF.Statement(void_dataset_entity, self.namespaces.get_rdf_namespace("void").triples, number_of_triples_node)) # voidify results from custom stats for stat in lodstats.stats.stats_to_do: stat.voidify(void_model, void_dataset_entity) return serializer.serialize_model_to_string(void_model)
def descInfo(self, m): predicates = [ self.dc.description, self.dct.description, self.rdfs.comment, self.dct.abstract ] for p in predicates: try: v = m.find_statements( RDF.Statement(RDF.Uri(self.spec_url), p, None)) if v.current(): return v.current().object.literal_value['string'] except: pass for p in predicates: try: v = m.find_statements( RDF.Statement(RDF.Uri(self.ns_url), p, None)) if v.current(): return v.current().object.literal_value['string'] except: pass for p in predicates: v = m.find_statements(RDF.Statement(None, p, None)) if v.current(): return v.current().object.literal_value['string'] return ""
def specInformation(m): """Read through the spec (provided as a Redland model) and return classlist and proplist. Global variables classranges and classdomains are also filled as appropriate.""" global classranges global classdomains # Find the class information: Ranges, domains, and list of all names. classlist = [] for classStatement in m.find_statements( RDF.Statement(None, rdf.type, rdfs.Class)): for range in m.find_statements( RDF.Statement(None, rdfs.range, classStatement.subject)): classranges.setdefault(str(classStatement.subject.uri), []).append(str(range.subject.uri)) for domain in m.find_statements( RDF.Statement(None, rdfs.domain, classStatement.subject)): classdomains.setdefault(str(classStatement.subject.uri), []).append(str(domain.subject.uri)) classlist.append(return_name(m, classStatement.subject)) # Create a list of properties in the schema. proplist = [] for propertyStatement in m.find_statements( RDF.Statement(None, rdf.type, rdf.Property)): proplist.append(return_name(m, propertyStatement.subject)) return classlist, proplist
def get_node(self, model, subject, is_question): node = Node(subject.uri, is_question) statement = RDF.Statement(subject, RDF.Uri("http://okfnpad.org/flow/0.1/text"), None) for s in model.find_statements(statement): if s.object.is_literal(): node.text = s.object.literal_value['string'] statement = RDF.Statement(subject, RDF.Uri("http://okfnpad.org/flow/0.1/query"), None) for s in model.find_statements(statement): if s.object.is_literal(): node.query = s.object.literal_value['string'] statement = RDF.Statement( subject, RDF.Uri("http://okfnpad.org/flow/0.1/option"), None) for s in model.find_statements(statement): self.get_options(node, model, s.object) return node
def addFiles(model, baseUri, inputPath): for root, subFolders, files in os.walk(inputPath): rootUri = root[len(inputPath) + 1:] sys.stderr.write("rootUri: " + rootUri + "\n") files = [f for f in files if not f[0] == '.'] subFolders[:] = [d for d in subFolders if not d[0] == '.'] for fileName in files: f = open(os.path.join(root, fileName), 'r') if (len(rootUri) > 0): fileUri = RDF.Uri(baseUri + rootUri + "/" + fileName) else: fileUri = RDF.Uri(baseUri + fileName) sys.stderr.write("Add Resource: " + fileUri.__str__() + "\n") markdownString = f.read() model.append( RDF.Statement( fileUri, RDF.Uri("http://ns.ontowiki.net/SysOnt/Site/content"), RDF.Node(markdownString, datatype=RDF.Uri( "http://ns.ontowiki.net/SysOnt/Markdown")))) model.append( RDF.Statement( fileUri, RDF.Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), RDF.Uri("http://xmlns.com/foaf/0.1/Document"))) model.append( RDF.Statement( fileUri, RDF.Uri("http://www.w3.org/2000/01/rdf-schema#label"), fileName))
def getStatements(self, subject=None, predicate=None, object=None, objecttype=None, context=None, asQuad=False): ''' Return all the statements in the model that match the given arguments. Any combination of subject and predicate can be None, and any None slot is treated as a wildcard that matches any value in the model.''' if subject: subject = URI2node(subject) if predicate: predicate = URI2node(predicate) if object is not None: if objecttype is None: #ugh... we need to do two separate queries objecttypes = (OBJECT_TYPE_RESOURCE, OBJECT_TYPE_LITERAL) else: objecttypes = (objecttype, ) else: objecttypes = (None, ) redlandStmts = [] for objecttype in objecttypes: if object is not None: redlandObject = object2node(object, objecttype) else: redlandObject = None if context or not asQuad: if context: redlandContext = URI2node(context) else: redlandContext = None redlandStmts.append( self.model.find_statements(RDF.Statement( subject, predicate, redlandObject), context=redlandContext)) defaultContext = context else: #search across all contexts redlandStmts.append( self.model.find_statements_context( RDF.Statement(subject, predicate, redlandObject))) defaultContext = '' statements = list( utils.flattenSeq([ redland2Statements(rstmts, defaultContext) for rstmts in redlandStmts ])) #statements = list( redland2Statements(redlandStmts, defaultContext)) statements.sort() return removeDupStatementsFromSortedList(statements, asQuad)
def get_alt_options(self, node, model, subject): statement = RDF.Statement(subject, None, None) for s in model.find_statements(statement): if str(s.predicate.uri).startswith( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'): statement2 = RDF.Statement( s.object, RDF.Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), RDF.Uri("http://okfnpad.org/flow/0.1/Option")) for ss in model.find_statements(statement2): node.add_options(self.get_option(model, ss.subject))
def rdfsPropertyInfo(term, m): """Generate HTML for properties: Domain, range, status.""" global classranges global classdomains doc = "" range = "" domain = "" #find subPropertyOf information o = m.find_statements(RDF.Statement(term, rdfs.subPropertyOf, None)) if o.current(): rlist = '' for st in o: k = getTermLink(str(st.object.uri)) rlist += "<dd>%s</dd>" % k doc += "<dt>sub-property-of:</dt> %s" % rlist #domain stuff domains = m.find_statements(RDF.Statement(term, rdfs.domain, None)) domainsdoc = "" for d in domains: collection = m.find_statements( RDF.Statement(d.object, owl.unionOf, None)) if collection.current(): uris = parseCollection(m, collection) for uri in uris: domainsdoc += "<dd>%s</dd>" % getTermLink(uri) add(classdomains, uri, term.uri) else: if not d.object.is_blank(): domainsdoc += "<dd>%s</dd>" % getTermLink(str(d.object.uri)) if (len(domainsdoc) > 0): doc += "<dt>Domain:</dt> %s" % domainsdoc #range stuff ranges = m.find_statements(RDF.Statement(term, rdfs.range, None)) rangesdoc = "" for r in ranges: collection = m.find_statements( RDF.Statement(r.object, owl.unionOf, None)) if collection.current(): uris = parseCollection(m, collection) for uri in uris: rangesdoc += "<dd>%s</dd>" % getTermLink(uri) add(classranges, uri, term.uri) else: if not r.object.is_blank(): rangesdoc += "<dd>%s</dd>" % getTermLink(str(r.object.uri)) if (len(rangesdoc) > 0): doc += "<dt>Range:</dt> %s" % rangesdoc return doc
def get_rdfs(m, urinode): "Returns label and comment given an RDF.Node with a URI in it" comment = '' label = '' if (type(urinode) == str): urinode = RDF.Uri(urinode) l = m.find_statements(RDF.Statement(urinode, rdfs.label, None)) if l.current(): label = l.current().object.literal_value['string'] c = m.find_statements(RDF.Statement(urinode, rdfs.comment, None)) if c.current(): comment = c.current().object.literal_value['string'] return label, comment
def rdfsClassInfo(term, m): """Generate rdfs-type information for Classes: ranges, and domains.""" global classranges global classdomains doc = "" #patch to control incoming strings (FIXME, why??? drop it!) try: term.uri except: term = RDF.Node(RDF.Uri(term)) # Find subClassOf information o = m.find_statements(RDF.Statement(term, rdfs.subClassOf, None)) if o.current(): doc += "<dt>sub-class-of:</dt>" superclasses = [] for st in o: if not st.object.is_blank(): uri = str(st.object.uri) if (not uri in superclasses): superclasses.append(uri) for superclass in superclasses: doc += "<dd>%s</dd>" % getTermLink(superclass) # Find out about properties which have rdfs:domain of t d = classdomains.get(str(term.uri), "") if d: dlist = '' for k in d: dlist += "<dd>%s</dd>" % getTermLink(k) doc += "<dt>in-domain-of:</dt>" + dlist # Find seeAlso relation sa = m.find_statements(RDF.Statement(term, rdfs.seeAlso, None)) if sa.current(): doc += "<dt>see-also:</dt>" for st in sa: uri = str(st.object.uri) doc += """<dd><a style="font-family: monospace" href="%s">%s</a></dd>""" % ( uri, uri) # Find out about properties which have rdfs:range of t r = classranges.get(str(term.uri), "") if r: rlist = '' for k in r: rlist += "<dd>%s</dd>" % getTermLink(k) doc += "<dt>in-range-of:</dt>" + rlist return doc
def rdfsPropertyInfo(term, m): """Generate HTML for properties: Domain, range, status.""" doc = "" range = "" domain = "" # Find subPropertyOf information o = m.find_statements(RDF.Statement(term, rdfs.subPropertyOf, None)) if o.current(): doc += "\t<tr><th>sub-property-of:</th>" rlist = '' for st in o: k = str(st.object.uri) if (spec_url in k): k = """<a href="#term_%s">%s</a>""" % (k.replace( spec_url, ""), niceName(k)) else: k = """<a href="%s">%s</a>""" % (k, niceName(k)) rlist += "%s " % k doc += "\n\t<td>%s</td></tr>\n" % rlist # domain and range stuff (properties only) d = m.find_statements(RDF.Statement(term, rdfs.domain, None)) if d.current(): domain = d.current().object.uri domain = str(domain) else: domain = "" r = m.find_statements(RDF.Statement(term, rdfs.range, None)) if r.current(): range = r.current().object.uri range = str(range) if domain: # NOTE can add a warning of multiple rdfs domains / ranges if (spec_url in domain): domain = """<a href="#term_%s">%s</a>""" % (domain.replace( spec_url, ""), niceName(domain)) else: domain = """<a href="%s">%s</a>""" % (domain, niceName(domain)) doc += "\t<tr><th>Domain:</th>\n\t<td>%s</td></tr>\n" % domain if range: if (spec_url in range): range = """<a href="#term_%s">%s</a>""" % (range.replace( spec_url, ""), niceName(range)) else: range = """<a href="%s">%s</a>""" % (range, niceName(range)) doc += "\t<tr><th>Range:</th>\n\t<td>%s</td></tr>\n" % range return doc
def prefferredNs(self, m): prefns = {'uri': [], 'prefix': []} v = m.find_statements( RDF.Statement(None, self.vann.preferredNamespaceUri, None)) if v.current(): try: prefns['uri'] = v.current().object.literal_value['string'] except: prefns['uri'] = str(v.current().object.uri) v = m.find_statements( RDF.Statement(None, self.vann.preferredNamespacePrefix, None)) if v.current(): prefns['prefix'] = v.current().object.literal_value['string'] return prefns
def voidify(self, void_model, dataset): namespaces = lodstats.util.rdf_namespaces.RDFNamespaces() datatype_uri = namespaces.get_rdf_namespace("xsd").integer.uri for property_uri_k, property_uri_v in self.usage_count.iteritems(): property_partitions_node = RDF.Node() statement_property_uri = RDF.Statement(property_partitions_node, namespaces.get_rdf_namespace("void").property, RDF.Node(uri_string=property_uri_k)) statement_property_triples_value = RDF.Statement(property_partitions_node, namespaces.get_rdf_namespace("void").triples, RDF.Node(literal=str(property_uri_v), datatype=datatype_uri)) statement = RDF.Statement(dataset, namespaces.get_rdf_namespace("void").propertyPartition, property_partitions_node) void_model.append(statement) void_model.append(statement_property_uri) void_model.append(statement_property_triples_value)
def voidify(self, void_model, dataset): # no of classes result_node = RDF.Node(literal=str(len(self.histogram)), datatype=ns_xs.integer.uri) void_model.append(RDF.Statement(dataset, ns_void.classes, result_node)) # class partition for class_uri, result in self.subject_distinct.iteritems(): clid = RDF.Node() void_model.append( RDF.Statement(dataset, ns_void.classPartition, clid)) void_model.append( RDF.Statement(clid, ns_void['class'], RDF.Uri(class_uri))) result_node = RDF.Node(literal=str(result), datatype=ns_xs.integer.uri) void_model.append( RDF.Statement(clid, ns_void.entities, result_node))
def query_to_language_value_dict(subject, predicate, object, model=JURI_MODEL): """Given a model and a subject, predicate, object (one of which is None), generate a dictionary of language values. The dictionary is in the form {'en' : u'Germany'}. Query is implicitly generated from subject, predicate, object.""" # Assume either s, p, or o is None # so that would be what we want back. is_none = [ thing for thing in ('subject', 'predicate', 'object') if (eval(thing) is None) ] die_unless( len(is_none) == 1, "You gave me more than one None, " + "so I don't know what you want back") query = RDF.Statement(subject, predicate, object) results = model.find_statements(query) # list of interesting_ones = [getattr(result, is_none[0]) for result in results] values_with_lang = [ uri2lang_and_value(result) for result in interesting_ones ] # Now, collapse this into a dict, ensuring there are no duplicate keys ret = {} for (lang, val) in values_with_lang: die_unless(lang not in ret, "Duplicate language found; blowing up") ret[lang] = val return ret
def get_status(self, m, urinode): "Returns the status text for a term." status = '' s = m.find_statements(RDF.Statement(urinode, self.vs.term_status, None)) if s.current(): return s.current().object.literal_value['string']
def _generateStatement(subjectNode, attributeNode, objectValue): """ Internal function to generate a statement from its own attributes! @param RDFNode subjectNode : The subject node for this statement. @param RDFNode attributeNode : The attribute node for this statement. @param undef object : The object where the type should be determined! @return Statement : @author """ #Object node might be another resource or a literal if(isinstance(objectValue, Resource)): if(objectValue.isBlank): #It is a blank resource objectNode = RDF.Node(blank = objectValue.blankIdentifier) else: #It is a normal resource with uri objectNode = RDF.Uri(objectValue.uri) else: #It is a literal - Get info about it literalValues = Resource.castTypeToLiteral(objectValue) #Check what the datatype is (might be None for plain literals) if(literalValues[1] is not None): dt = RDF.Uri(literalValues[1]) objectNode = RDF.Node(literal = literalValues[0], datatype = dt) else: objectNode = RDF.Node(literal = literalValues[0]) #Now return the newly created statement return RDF.Statement(subjectNode, attributeNode, objectNode)
def posts(self, *args): alltags = Set() for arg in args: if isinstance(arg, Tag): alltags.add(arg) url = "http://del.icio.us/rss/" + self.user if len(alltags) > 0: url += "/" + "+".join([str(tag) for tag in alltags]) model = RDF.Model() parser = RDF.Parser() try: parser.parse_string_into_model(model, get_url_contents(url), RDF.Uri("http://foo")) posts = [ RSSTagPost(model, p.subject) for p in model.find_statements( RDF.Statement( None, RDF.Uri( "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), RDF.Uri("http://purl.org/rss/1.0/item"))) ] for post in posts: post.user = self return posts except: return []
def posts(self,*args): alltags = Set() extratags = "" user = None for arg in args: if isinstance(arg,Tag): alltags.add(arg) if isinstance(arg,User): user = arg if len(alltags)>0: extratags = "+"+"+".join([str(tag) for tag in alltags]) if user is not None: url = "http://del.icio.us/rss/"+str(user)+"/"+self.name+extratags else: url = "http://del.icio.us/rss/tag/"+self.name model = RDF.Model() parser = RDF.Parser() try: parser.parse_string_into_model(model,get_url_contents(url),RDF.Uri("http://foo")) posts = [RSSTagPost(model,p.subject,self) for p in model.find_statements(RDF.Statement(None,RDF.Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),RDF.Uri("http://purl.org/rss/1.0/item")))] if user is not None: for post in posts: post.user = user return posts except: return []
def addStatement(model, s, p, o): # Assume subject is a URI string if it is not an RDF.Node if type(s) is not RDF.Node: s_node = RDF.Uri(s) else: s_node = s # Assume predicate is a URI string if it is not an RDF.Node if type(p) is not RDF.Node: p_node = RDF.Uri(p) else: p_node = p # Assume object is a literal if it is not an RDF.Node if type(o) is not RDF.Node: o_node = RDF.Node(o) else: o_node = o statement = RDF.Statement(s_node, p_node, o_node) if statement is None: raise Exception("new RDF.Statement failed") model.add_statement(statement)
def get_root(self, model): statement = RDF.Statement(None, RDF.Uri("http://okfnpad.org/flow/0.1/root"), None) for s in model.find_statements(statement): if s.object.is_resource(): self.root = str(s.object.uri)
def createVoIDModel(to): """Creates an RDF Model according to the VoID Dataset spec for the given arguments. Returns: RDF.Model""" # Validate the to string if not isinstance(to, str): logging.error( "Value of 'to' parameter not a string. Failed to update VoID file. Value=%s.", to) return None if not len(to) > 0: logging.error( "Value of 'to' parameter is zero-length. Failed to update VoID file. Value=%s.", to) return None # Prepare the model m = RDF.Model(RDF.MemoryStorage()) rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' void = "http://rdfs.org/ns/void#" d1lod = "http://dataone.org/" dcterms = "http://purl.org/dc/terms/" subject_node = RDF.Node(blank="d1lod") # Add in our statements m.append( RDF.Statement(subject_node, RDF.Uri(rdf + 'type'), RDF.Uri(void + 'Dataset'))) m.append( RDF.Statement(subject_node, RDF.Uri(void + 'feature'), RDF.Uri(d1lod + 'fulldump'))) m.append( RDF.Statement(subject_node, RDF.Uri(dcterms + 'modified'), RDF.Node(to))) m.append( RDF.Statement(subject_node, RDF.Uri(void + 'dataDump'), RDF.Uri(d1lod + DUMP_FILENAME))) return m
def posts(): url = "http://del.icio.us/rss/" model = RDF.Model() parser = RDF.Parser() parser.parse_string_into_model(model,get_url_contents(url),RDF.Uri("http://foo")) posts = [RSSTagPost(model,p.subject) for p in model.find_statements(RDF.Statement(None,RDF.Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),RDF.Uri("http://purl.org/rss/1.0/item")))] return posts
def extract_responsibility(g): print >>sys.stderr, 'Extracting responsible roles ...', for stmt in chain(g.find_statements(RDF.Statement(subject=None, predicate=MHS_NS.responsibility, object=None)), g.find_statements(RDF.Statement(subject=None, predicate=DCTERMS_NS.title, object=None))): responsibility = lxml.html.fromstring(stmt.object.literal_value['string']) for anchor in responsibility.findall('a'): href = RDF.Uri(anchor.get('href')) if MHS_NS.Author in _types(g, href): rels = anchor.get('rel', '').split() if 'contributor' in rels: predicate = DCTERMS_NS.contributor elif 'translator' in rels: predicate = MHS_NS.translator else: predicate = DCTERMS_NS.creator g.append(RDF.Statement(stmt.subject, predicate=predicate, object=href)) print >>sys.stderr, '%d triples' % len(g)
def owlInfo(term, m): """Returns an extra table row if the term (an RDF.Node()) is an IFP.""" o = m.find_statements( RDF.Statement(term, rdf.type, owl.InverseFunctionalProperty)) if o.current(): return ( "\t<tr><th>OWL Type:</th>\n\t<td>An InverseFunctionalProperty (uniquely identifying property)</td></tr>\n" ) return ''