"""This module provides functionality for handling our data as rdf."""
import io
import collections
from clldutils.misc import encoded
from rdflib import Graph, URIRef, Literal
from rdflib.namespace import (
Namespace, DC, DCTERMS, DOAP, FOAF, OWL, RDF, RDFS, SKOS, VOID, XMLNS, XSD,
)
# make flake8 happy, but still have the following importable from here:
assert DOAP
assert XMLNS
__all__ = ['FORMATS', 'NAMESPACES', 'expand_prefix', 'url_for_qname',
'ClldGraph', 'properties_as_xml_snippet', 'convert']
Notation = collections.namedtuple('Notation', 'name extension mimetype uri')
FORMATS = dict((n.name, n) for n in [
Notation('xml', 'rdf', 'application/rdf+xml', 'http://www.w3.org/ns/formats/RDF_XML'),
Notation('n3', 'n3', 'text/n3', 'http://www.w3.org/ns/formats/N3'),
Notation('nt', 'nt', 'text/nt', 'http://www.w3.org/ns/formats/N-Triples'),
Notation('turtle', 'ttl', 'text/turtle', 'http://www.w3.org/ns/formats/Turtle')])
NAMESPACES = {
"rdf": RDF,
"void": VOID,
"foaf": FOAF,
"frbr": Namespace("http://purl.org/vocab/frbr/core#"),
"dcterms": DCTERMS,
"dctype": Namespace("http://purl.org/dc/dcmitype/"),
"rdfs": RDFS,
"geo": Namespace("http://www.w3.org/2003/01/geo/wgs84_pos#"),
"isbd": Namespace("http://iflastandards.info/ns/isbd/elements/"),
"skos": SKOS,
"dc": DC,
"gold": Namespace("http://purl.org/linguistics/gold/"),
"lexvo": Namespace("http://lexvo.org/ontology#"),
"vcard": Namespace("http://www.w3.org/2001/vcard-rdf/3.0#"),
"bibo": Namespace("http://purl.org/ontology/bibo/"),
"owl": OWL,
"xsd": XSD,
}
[docs]def expand_prefix(p):
"""Expand default prefixes if possible.
:param p: a qualified name in prefix:localname notation or a URL.
:return: a string URL or a URIRef
"""
if isinstance(p, str) and ':' in p:
prefix, name = p.split(':', 1)
if prefix in NAMESPACES:
return getattr(NAMESPACES[prefix], name, p)
return p
[docs]def url_for_qname(qname):
"""Expand qname to full URL respecting our default prefixes."""
return str(expand_prefix(qname))
[docs]class ClldGraph(Graph):
"""Augmented rdflib.Graph.
Augment the standard rdflib.Graph by making sure our standard ns prefixes are
always bound.
"""
def __init__(self, *args, **kw):
super(ClldGraph, self).__init__(*args, **kw)
for prefix, ns in NAMESPACES.items():
self.bind(prefix, ns)
[docs]def properties_as_xml_snippet(subject, props):
"""Serialize props of subject as RDF-XML snippet."""
if isinstance(subject, str):
subject = URIRef(subject)
g = ClldGraph()
if props:
for p, o in props:
p = expand_prefix(p)
if p:
if isinstance(o, str):
if o.startswith('http://') or o.startswith('https://'):
o = URIRef(o)
else:
o = Literal(o)
try:
g.add((subject, p, o))
except AssertionError:
pass
res = []
in_desc = False
xml = g.serialize(format='xml')
if not isinstance(xml, str):
xml = xml.decode('utf8') # pragma: no cover
for line in xml.split('\n'):
if line.strip().startswith('</rdf:Description'):
break
if in_desc:
res.append(line)
if line.strip().startswith('<rdf:Description'):
in_desc = True
return '\n'.join(res)
def convert(string, from_, to_):
if from_ == to_:
return encoded(string)
assert from_ in FORMATS and (to_ is None or to_ in FORMATS)
g = Graph()
g.parse(io.BytesIO(encoded(string)), format=from_)
if to_ is None:
return g
out = io.BytesIO()
g.serialize(out, format=to_)
out.seek(0)
return out.read()