279 lines
8.0 KiB
Python
279 lines
8.0 KiB
Python
import warnings
|
|
from random import randint
|
|
|
|
from rdflib.namespace import RDF
|
|
from rdflib.term import BNode, URIRef
|
|
|
|
__all__ = ["Container", "Bag", "Seq", "Alt", "NoElementException"]
|
|
|
|
|
|
class Container:
|
|
"""A class for constructing RDF containers, as per https://www.w3.org/TR/rdf11-mt/#rdf-containers
|
|
|
|
Basic usage, creating a ``Bag`` and adding to it::
|
|
|
|
>>> from rdflib import Graph, BNode, Literal, Bag
|
|
>>> g = Graph()
|
|
>>> b = Bag(g, BNode(), [Literal("One"), Literal("Two"), Literal("Three")])
|
|
>>> print(g.serialize(format="turtle"))
|
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
<BLANKLINE>
|
|
[] a rdf:Bag ;
|
|
rdf:_1 "One" ;
|
|
rdf:_2 "Two" ;
|
|
rdf:_3 "Three" .
|
|
<BLANKLINE>
|
|
<BLANKLINE>
|
|
|
|
>>> # print out an item using an index reference
|
|
>>> print(b[2])
|
|
Two
|
|
|
|
>>> # add a new item
|
|
>>> b.append(Literal("Hello")) # doctest: +ELLIPSIS
|
|
<rdflib.container.Bag object at ...>
|
|
>>> print(g.serialize(format="turtle"))
|
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
<BLANKLINE>
|
|
[] a rdf:Bag ;
|
|
rdf:_1 "One" ;
|
|
rdf:_2 "Two" ;
|
|
rdf:_3 "Three" ;
|
|
rdf:_4 "Hello" .
|
|
<BLANKLINE>
|
|
<BLANKLINE>
|
|
|
|
"""
|
|
|
|
def __init__(self, graph, uri, seq=[], rtype="Bag"):
|
|
"""Creates a Container
|
|
|
|
:param graph: a Graph instance
|
|
:param uri: URI or Blank Node of the Container
|
|
:param seq: the elements of the Container
|
|
:param rtype: the type of Container, one of "Bag", "Seq" or "Alt"
|
|
"""
|
|
|
|
self.graph = graph
|
|
self.uri = uri or BNode()
|
|
self._len = 0
|
|
self._rtype = rtype # rdf:Bag or rdf:Seq or rdf:Alt
|
|
|
|
self.append_multiple(seq)
|
|
|
|
# adding triple corresponding to container type
|
|
self.graph.add((self.uri, RDF.type, RDF[self._rtype]))
|
|
|
|
def n3(self):
|
|
items = []
|
|
for i in range(len(self)):
|
|
v = self[i + 1]
|
|
items.append(v)
|
|
|
|
return "( %s )" % " ".join([a.n3() for a in items])
|
|
|
|
def _get_container(self):
|
|
"""Returns the URI of the container"""
|
|
|
|
return self.uri
|
|
|
|
def __len__(self):
|
|
"""Number of items in container"""
|
|
|
|
return self._len
|
|
|
|
def type_of_conatiner(self):
|
|
warnings.warn(
|
|
"rdflib.container.Container.type_of_conatiner is deprecated. "
|
|
"Use type_of_container method instead.",
|
|
DeprecationWarning,
|
|
stacklevel=2,
|
|
)
|
|
return self._rtype
|
|
|
|
def type_of_container(self):
|
|
return self._rtype
|
|
|
|
def index(self, item):
|
|
"""Returns the 1-based numerical index of the item in the container"""
|
|
|
|
pred = self.graph.predicates(self.uri, item)
|
|
if not pred:
|
|
raise ValueError("%s is not in %s" % (item, "container"))
|
|
li_index = URIRef(str(RDF) + "_")
|
|
|
|
i = None
|
|
for p in pred:
|
|
i = int(p.replace(li_index, ""))
|
|
return i
|
|
|
|
def __getitem__(self, key):
|
|
"""Returns item of the container at index key"""
|
|
|
|
c = self._get_container()
|
|
|
|
assert isinstance(key, int)
|
|
elem_uri = str(RDF) + "_" + str(key)
|
|
if key <= 0 or key > len(self):
|
|
raise KeyError(key)
|
|
v = self.graph.value(c, URIRef(elem_uri))
|
|
if v:
|
|
return v
|
|
else:
|
|
raise KeyError(key)
|
|
|
|
def __setitem__(self, key, value):
|
|
"""Sets the item at index key or predicate rdf:_key of the container to value"""
|
|
|
|
assert isinstance(key, int)
|
|
|
|
c = self._get_container()
|
|
elem_uri = str(RDF) + "_" + str(key)
|
|
if key <= 0 or key > len(self):
|
|
raise KeyError(key)
|
|
|
|
self.graph.set((c, URIRef(elem_uri), value))
|
|
|
|
def __delitem__(self, key):
|
|
"""Removing the item with index key or predicate rdf:_key"""
|
|
|
|
assert isinstance(key, int)
|
|
if key <= 0 or key > len(self):
|
|
raise KeyError(key)
|
|
|
|
graph = self.graph
|
|
container = self.uri
|
|
elem_uri = str(RDF) + "_" + str(key)
|
|
graph.remove((container, URIRef(elem_uri), None))
|
|
for j in range(key + 1, len(self) + 1):
|
|
elem_uri = str(RDF) + "_" + str(j)
|
|
v = graph.value(container, URIRef(elem_uri))
|
|
graph.remove((container, URIRef(elem_uri), v))
|
|
elem_uri = str(RDF) + "_" + str(j - 1)
|
|
graph.add((container, URIRef(elem_uri), v))
|
|
|
|
self._len -= 1
|
|
|
|
def items(self):
|
|
"""Returns a list of all items in the container"""
|
|
|
|
l_ = []
|
|
container = self.uri
|
|
i = 1
|
|
while True:
|
|
elem_uri = str(RDF) + "_" + str(i)
|
|
|
|
if (container, URIRef(elem_uri), None) in self.graph:
|
|
i += 1
|
|
l_.append(self.graph.value(container, URIRef(elem_uri)))
|
|
else:
|
|
break
|
|
return l_
|
|
|
|
def end(self): #
|
|
# find end index (1-based) of container
|
|
|
|
container = self.uri
|
|
i = 1
|
|
while True:
|
|
elem_uri = str(RDF) + "_" + str(i)
|
|
|
|
if (container, URIRef(elem_uri), None) in self.graph:
|
|
i += 1
|
|
else:
|
|
return i - 1
|
|
|
|
def append(self, item):
|
|
"""Adding item to the end of the container"""
|
|
|
|
end = self.end()
|
|
elem_uri = str(RDF) + "_" + str(end + 1)
|
|
container = self.uri
|
|
self.graph.add((container, URIRef(elem_uri), item))
|
|
self._len += 1
|
|
|
|
return self
|
|
|
|
def append_multiple(self, other):
|
|
"""Adding multiple elements to the container to the end which are in python list other"""
|
|
|
|
end = self.end() # it should return the last index
|
|
|
|
container = self.uri
|
|
for item in other:
|
|
end += 1
|
|
self._len += 1
|
|
elem_uri = str(RDF) + "_" + str(end)
|
|
self.graph.add((container, URIRef(elem_uri), item))
|
|
|
|
return self
|
|
|
|
def clear(self):
|
|
"""Removing all elements from the container"""
|
|
|
|
container = self.uri
|
|
graph = self.graph
|
|
i = 1
|
|
while True:
|
|
elem_uri = str(RDF) + "_" + str(i)
|
|
if (container, URIRef(elem_uri), None) in self.graph:
|
|
graph.remove((container, URIRef(elem_uri), None))
|
|
i += 1
|
|
else:
|
|
break
|
|
self._len = 0
|
|
return self
|
|
|
|
|
|
class Bag(Container):
|
|
"""Unordered container (no preference order of elements)"""
|
|
|
|
def __init__(self, graph, uri, seq=[]):
|
|
Container.__init__(self, graph, uri, seq, "Bag")
|
|
|
|
|
|
class Alt(Container):
|
|
def __init__(self, graph, uri, seq=[]):
|
|
Container.__init__(self, graph, uri, seq, "Alt")
|
|
|
|
def anyone(self):
|
|
if len(self) == 0:
|
|
raise NoElementException()
|
|
else:
|
|
p = randint(1, len(self))
|
|
item = self.__getitem__(p)
|
|
return item
|
|
|
|
|
|
class Seq(Container):
|
|
def __init__(self, graph, uri, seq=[]):
|
|
Container.__init__(self, graph, uri, seq, "Seq")
|
|
|
|
def add_at_position(self, pos, item):
|
|
assert isinstance(pos, int)
|
|
if pos <= 0 or pos > len(self) + 1:
|
|
raise ValueError("Invalid Position for inserting element in rdf:Seq")
|
|
|
|
if pos == len(self) + 1:
|
|
self.append(item)
|
|
else:
|
|
for j in range(len(self), pos - 1, -1):
|
|
container = self._get_container()
|
|
elem_uri = str(RDF) + "_" + str(j)
|
|
v = self.graph.value(container, URIRef(elem_uri))
|
|
self.graph.remove((container, URIRef(elem_uri), v))
|
|
elem_uri = str(RDF) + "_" + str(j + 1)
|
|
self.graph.add((container, URIRef(elem_uri), v))
|
|
elem_uri_pos = str(RDF) + "_" + str(pos)
|
|
self.graph.add((container, URIRef(elem_uri_pos), item))
|
|
self._len += 1
|
|
return self
|
|
|
|
|
|
class NoElementException(Exception): # noqa: N818
|
|
def __init__(self, message="rdf:Alt Container is empty"):
|
|
self.message = message
|
|
|
|
def __str__(self):
|
|
return self.message
|