Source code for clld.lib.rdf

"""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()