#rdflib (python):如何从 'ns:xxx' 等字符串中获取 URIRef?

#rdflib (python): how to get a URIRef from a string such as 'ns:xxx'?

我有一个 RDFlib 图 g,它的 NameSpaceManager 知道一些命名空间。

如何从 'ns:xxx' 等字符串中获取 URIRef,其中 ns 是与 g.namespace_manager 已知的命名空间关联的前缀?基本上,我正在寻找一种对 URIRef 的 n3(g.namespace_manager) 进行逆运算的方法。我非常有信心有一种方法可以做到这一点,因为需要类似的函数来解析 turtle 文件或 sparql 查询,但我找不到它。不然当然写起来一定不会很难。

TIA

from rdflib.namespace import NamespaceManager
import rdflib as rdflib

class MyNamespacesInfo:
    def __init__(self, namespace_manager: NamespaceManager):
        # as I don't know how to get the namespace from a prefix from the API
        # I construct a dict
        self.pref2ns = {}
        for pref, ns in namespace_manager.namespaces():
            self.pref2ns[pref] = ns
    
    def uriref(self, n3uri: str) -> rdflib.URIRef:
        # n3uri: either 'ns:xxx', '<http://..../xxx>' or 'http://..../xxx'
        if n3uri[0] == '<':
            if n3uri[len(n3uri)-1] == '>':
                return rdflib.URIRef(n3uri[1:-1])
            else:
                raise ValueError("Illegal uri: ", n3uri)
        else:
            return self.prefixed_2_uriref(n3uri, laxist=True)

    def prefixed_2_uriref(self, short_uri: str, laxist=True) -> rdflib.URIRef:
        # param short_uri eg. 'ns:xxx', where ns declared in namespace_manager
        # using laxist = True, you also can pass a long uri
        s = short_uri.split(':')
        if len(s) < 2:
            if laxist:
                return rdflib.URIRef(short_uri)
            else:
                raise ValueError('Not a prefix:localname string: ' + short_uri)
        prefix = s[0]
        ns = self.pref2ns.get(prefix)
        if ns == None:
            if laxist:
                return rdflib.URIRef(short_uri)
            else:
                raise ValueError('Unknown prefix: ' + prefix)
        else:
            x = ns + s[1]
            for i in range(2, len(s)):
                x = x + (':' + s[i])
            return x

# example of use:

g = rdflib.Graph()
g.parse('http://www.semanlink.net/tag/rdf_tools.rdf')
ns_info = MyNamespacesInfo(g.namespace_manager)

# all of following calls print http://www.semanlink.net/tag/rdflib

x = ns_info.uriref('tag:rdflib')
print(x)
x = ns_info.uriref('http://www.semanlink.net/tag/rdflib')
print(x)
x = ns_info.uriref('<http://www.semanlink.net/tag/rdflib>')
print(x)
from rdflib import Graph, Namespace
from rdflib.namespace import RDF

g = Graph()
NS = Namespace("http://example.com/")

# then, say Xxx is a class and Aaa is an instance of Xxx...
g.add((NS.Aaa, RDF.type, NS.Xxx))

# so use NS.Xxx (or NS["Xxx"]) to get a URIRef of NS.Xxx from Namespace NS
print(type(NS))     # --> <class 'rdflib.term.URIRef'>
print(type(NS.Xxx)) # --> <class 'rdflib.term.URIRef'>
print(NS.Xxx)       # --> "http://example.com/Xxx"

如果你想在图中绑定一个前缀,你可以使用 rdflib Graph class' bind() 方法,所以对于上面的代码,你可以使用:

g.bind("ns", NS)

现在,如果使用了解前缀的格式(如 Turtle)序列化图表,将使用“ns”。以上数据为:

@prefix ns: <http://example.com/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

ns:Aaa rdf:type ns:Xxx .

因此,在 Python 中,如果您想从字符串“ns:Xxx”中创建 URI“http://example.com/Xxx”,您应该拥有所需的一切:

  • 命名空间声明:NS = Namespace("http://example.com/")
  • prefix/namespace绑定g.bind("ns", NS)

IFF,另一方面,您没有自己声明名称空间,但它在图中,您只有短格式 URI“ns:Xxx”,您可以这样做以列出所有绑定的前缀和名称空间图中使用:

for n in g.namespace_manager.namespaces():
    print(n)

returns,对于上面的数据:

('xml', rdflib.term.URIRef('http://www.w3.org/XML/1998/namespace'))
('rdf', rdflib.term.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#'))
('rdfs', rdflib.term.URIRef('http://www.w3.org/2000/01/rdf-schema#'))
('xsd', rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#'))
('eg', rdflib.term.URIRef('http://example.com/'))

因此,如果您知道“eg:Xxx”,则可以拆分“eg”部分并制作您想要的 URI,如下所示:

print(
    [str(x[1]) for x in g.namespace_manager.namespaces() if x[0] == s.split(":")[0]]
    [0] + s.split(":")[1]
)

打印:

http://example.com/Xxx