RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information.
—
Support for RDF containers (Bag, Seq, Alt) and collections (rdf:List) providing ordered and unordered groupings of RDF resources according to RDF specifications.
Base class for RDF containers with common functionality for managing collections of resources.
class Container:
def __init__(self, graph: Graph, uri: Node, seq: List[Node] = None, rtype: str = "Bag"):
"""
Create an RDF container.
Parameters:
- graph: Graph to store container in
- uri: Container URI (BNode or URIRef)
- seq: Initial sequence of items
- rtype: Container type ("Bag", "Seq", "Alt")
"""
def append(self, item: Node) -> 'Container':
"""
Add an item to the container.
Parameters:
- item: Item to add
Returns:
Container: Self for method chaining
"""
def __getitem__(self, index: int) -> Node:
"""
Get item by index (1-based).
Parameters:
- index: Item index (starting from 1)
Returns:
Node: Item at index
"""
def __setitem__(self, index: int, item: Node):
"""
Set item at index (1-based).
Parameters:
- index: Item index (starting from 1)
- item: New item value
"""
def __delitem__(self, index: int):
"""
Delete item at index (1-based).
Parameters:
- index: Item index to delete
"""
def __iter__(self) -> Iterator[Node]:
"""
Iterate over container items.
Returns:
Iterator: Container items
"""
def __len__(self) -> int:
"""
Get number of items in container.
Returns:
int: Item count
"""
def index(self, item: Node) -> int:
"""
Find index of item (1-based).
Parameters:
- item: Item to find
Returns:
int: Item index or raises ValueError
"""
def clear(self):
"""Remove all items from container."""
@property
def uri(self) -> Node:
"""
Get container URI.
Returns:
Node: Container identifier
"""
@property
def graph(self) -> Graph:
"""
Get container's graph.
Returns:
Graph: Graph containing container
"""RDF Bag container for unordered collections where duplicates are allowed.
class Bag(Container):
def __init__(self, graph: Graph, uri: Node, seq: List[Node] = None):
"""
Create an RDF Bag.
Parameters:
- graph: Graph to store bag in
- uri: Bag URI (BNode or URIRef)
- seq: Initial sequence of items
"""RDF Sequence container for ordered collections where duplicates are allowed.
class Seq(Container):
def __init__(self, graph: Graph, uri: Node, seq: List[Node] = None):
"""
Create an RDF Sequence.
Parameters:
- graph: Graph to store sequence in
- uri: Sequence URI (BNode or URIRef)
- seq: Initial sequence of items
"""RDF Alternative container representing a set of alternative values.
class Alt(Container):
def __init__(self, graph: Graph, uri: Node, seq: List[Node] = None):
"""
Create an RDF Alternative.
Parameters:
- graph: Graph to store alternative in
- uri: Alternative URI (BNode or URIRef)
- seq: Initial sequence of alternatives
"""Implementation of RDF collections (rdf:List) for ordered sequences.
class Collection:
def __init__(self, graph: Graph, uri: Node, seq: List[Node] = None):
"""
Create an RDF Collection (List).
Parameters:
- graph: Graph to store collection in
- uri: Collection head URI (BNode or URIRef)
- seq: Initial sequence of items
"""
def append(self, item: Node) -> 'Collection':
"""
Add an item to the end of the collection.
Parameters:
- item: Item to add
Returns:
Collection: Self for method chaining
"""
def clear(self):
"""Remove all items, making this an empty list (rdf:nil)."""
def __iter__(self) -> Iterator[Node]:
"""
Iterate over collection items.
Returns:
Iterator: Collection items in order
"""
def __len__(self) -> int:
"""
Get number of items in collection.
Returns:
int: Item count
"""
def __getitem__(self, index: int) -> Node:
"""
Get item by index (0-based).
Parameters:
- index: Item index (starting from 0)
Returns:
Node: Item at index
"""
def __contains__(self, item: Node) -> bool:
"""
Check if collection contains item.
Parameters:
- item: Item to check
Returns:
bool: True if item is in collection
"""
@property
def uri(self) -> Node:
"""
Get collection head URI.
Returns:
Node: Collection head identifier
"""
@property
def graph(self) -> Graph:
"""
Get collection's graph.
Returns:
Graph: Graph containing collection
"""class NoElementException(Exception):
"""Raised when trying to access non-existent container element."""from rdflib import Graph, BNode, Literal, URIRef
from rdflib.container import Bag
from rdflib.namespace import RDF
g = Graph()
# Create a bag
bag_uri = BNode()
fruits = Bag(g, bag_uri, [Literal("Apple"), Literal("Orange"), Literal("Banana")])
# Add more items
fruits.append(Literal("Grape"))
fruits.append(Literal("Apple")) # Duplicates allowed
# Access items
print(f"First fruit: {fruits[1]}") # 1-based indexing
print(f"Bag has {len(fruits)} items")
# Iterate over items
for fruit in fruits:
print(f"Fruit: {fruit}")
# Check the RDF representation
print(g.serialize(format="turtle"))from rdflib import Graph, BNode, Literal
from rdflib.container import Seq
g = Graph()
# Create a sequence (order matters)
seq_uri = BNode()
steps = Seq(g, seq_uri)
# Add steps in order
steps.append(Literal("Mix ingredients"))
steps.append(Literal("Heat oven to 350°F"))
steps.append(Literal("Bake for 30 minutes"))
steps.append(Literal("Cool before serving"))
# Access by index
print(f"Step 2: {steps[2]}")
# Modify a step
steps[2] = Literal("Preheat oven to 350°F")
# Insert is achieved by manipulating the sequence
print(f"Recipe has {len(steps)} steps")
# The sequence maintains order
for i, step in enumerate(steps, 1):
print(f"Step {i}: {step}")from rdflib import Graph, BNode, Literal
from rdflib.container import Alt
g = Graph()
# Create alternatives (representing choices)
alt_uri = BNode()
formats = Alt(g, alt_uri)
# Add format alternatives
formats.append(Literal("PDF"))
formats.append(Literal("HTML"))
formats.append(Literal("XML"))
formats.append(Literal("JSON"))
# Get preferred alternative (typically first)
preferred = formats[1]
print(f"Preferred format: {preferred}")
# List all alternatives
print("Available formats:")
for fmt in formats:
print(f" - {fmt}")from rdflib import Graph, BNode, Literal, URIRef
from rdflib.collection import Collection
from rdflib.namespace import RDF
g = Graph()
# Create a collection
list_uri = BNode()
authors = Collection(g, list_uri)
# Add authors in order
authors.append(Literal("Alice Smith"))
authors.append(Literal("Bob Jones"))
authors.append(Literal("Carol Brown"))
# Collections are ordered and can be accessed by index
print(f"First author: {authors[0]}") # 0-based indexing
print(f"Last author: {authors[-1]}")
# Check membership
if Literal("Alice Smith") in authors:
print("Alice Smith is an author")
# Iterate over authors
for author in authors:
print(f"Author: {author}")
# Collections generate proper rdf:List structure
print(g.serialize(format="turtle"))from rdflib import Graph, URIRef, Literal
from rdflib.container import Bag, Seq
from rdflib.namespace import RDF, RDFS
g = Graph()
# Create a book with multiple authors (bag) and chapters (sequence)
book = URIRef("http://example.org/book/1")
g.add((book, RDF.type, URIRef("http://example.org/Book")))
g.add((book, RDFS.label, Literal("Python Programming")))
# Authors as a bag (unordered)
authors_bag = Bag(g, URIRef("http://example.org/book/1/authors"))
authors_bag.append(Literal("John Doe"))
authors_bag.append(Literal("Jane Smith"))
g.add((book, URIRef("http://example.org/hasAuthors"), authors_bag.uri))
# Chapters as a sequence (ordered)
chapters_seq = Seq(g, URIRef("http://example.org/book/1/chapters"))
chapters_seq.append(Literal("Introduction"))
chapters_seq.append(Literal("Basic Syntax"))
chapters_seq.append(Literal("Data Structures"))
chapters_seq.append(Literal("Functions"))
g.add((book, URIRef("http://example.org/hasChapters"), chapters_seq.uri))
# Query the containers
query = """
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?book ?author ?chapter WHERE {
?book <http://example.org/hasAuthors> ?authors .
?authors ?author_prop ?author .
FILTER(STRSTARTS(STR(?author_prop), STR(rdf:_)))
?book <http://example.org/hasChapters> ?chapters .
?chapters ?chapter_prop ?chapter .
FILTER(STRSTARTS(STR(?chapter_prop), STR(rdf:_)))
}
"""
results = g.query(query)
for row in results:
print(f"Book: {row.book}, Author: {row.author}, Chapter: {row.chapter}")from rdflib import Graph, BNode, Literal
from rdflib.container import Seq
g = Graph()
# Create a mutable sequence
playlist = Seq(g, BNode())
# Build playlist
songs = [
"Song A",
"Song B",
"Song C",
"Song D"
]
for song in songs:
playlist.append(Literal(song))
# Rearrange playlist - remove and insert
song_b = playlist[2] # Get "Song B"
del playlist[2] # Remove "Song B"
playlist.append(song_b) # Add to end
print("Rearranged playlist:")
for i, song in enumerate(playlist, 1):
print(f"{i}. {song}")
# Find position of a song
try:
pos = playlist.index(Literal("Song A"))
print(f"Song A is at position {pos}")
except ValueError:
print("Song A not found")
# Clear playlist
playlist.clear()
print(f"Playlist now has {len(playlist)} songs")from rdflib import Graph, BNode
from rdflib.container import Bag
from rdflib.collection import Collection
from rdflib.namespace import RDF
g = Graph()
# Create empty containers
empty_bag = Bag(g, BNode())
empty_list = Collection(g, BNode())
print(f"Empty bag length: {len(empty_bag)}")
print(f"Empty list length: {len(empty_list)}")
# Empty containers still create RDF structure
print("Empty bag RDF:")
for triple in g.triples((empty_bag.uri, None, None)):
print(f" {triple}")
print("Empty list RDF:")
for triple in g.triples((empty_list.uri, None, None)):
print(f" {triple}")Install with Tessl CLI
npx tessl i tessl/pypi-rdflib