Skip to content

Python RDF I/O and SPARQL

Oxiland exposes Python functions for parsing, loading, serializing, querying, and updating RDF. Inputs accept Python strings, bytes, and os.PathLike paths; large read paths return lazy iterators.

Supported RDF syntaxes

Syntax Name Extension Can represent named graphs
Turtle turtle .ttl No
N-Triples ntriples .nt No
N-Quads nquads .nq Yes
TriG trig .trig Yes
RDF/XML rdfxml .rdf No

Pass a name string or a Syntax constant. Syntax.from_name(), Syntax.from_media_type(), and Syntax.from_extension() validate external metadata without starting a parse.

JSON-LD and N3 are not supported. Unknown or ambiguous formats raise UnsupportedError; Oxiland does not guess from document contents.

Stream a document

from oxiland import parse, parse_path

for quad in parse(
    '<https://example.com/s> <https://example.com/p> "value" .',
    "turtle",
):
    print(quad)

for quad in parse_path("document.ttl"):
    process(quad)

parse_path() infers syntax from the extension when syntax is omitted. Parsing is lazy: syntax errors may be raised while advancing the iterator, not when the iterator is constructed.

Use base_iri= for relative IRIs. Use graph= to place graph-format input in a named graph.

Named-graph input

N-Quads and TriG are supported formats, and serialization preserves named graphs. The Python parser does not yet expose the dataset graph target for arbitrary named-graph input. Without graph=, named-graph records raise ParseError; with graph=, input must be compatible with that target. Programmatic named-graph CRUD and N-Quads/TriG output are fully available.

Load into a model

from oxiland import Model, load, load_path

model = Model()
turtle_text = '<https://example.com/s> <https://example.com/p> "value" .'

count = load(model, turtle_text, "turtle")
# Named-graph TriG/N-Quads need an explicit graph= target in Python today.
count += load_path(model, "catalog.ttl", transactional=True)

Choose failure behavior explicitly:

Mode Call Failure behavior Best for
Collecting default (collecting=True) Parse first, then insert; parse failure leaves the model unchanged Normal bounded imports
Transactional transactional=True Import is committed atomically Persistent or replace-sensitive workflows
Progressive collecting=False Successful statements before an error may remain Very large trusted inputs where partial progress is acceptable

transactional=True takes precedence over collecting. The return value is the number of statements processed. Loading merges RDF into the existing dataset; call clear() in the same controlled workflow when replacement is intended.

Serialize a dataset

from oxiland import serialize, serialize_path

turtle = serialize(
    model,
    "turtle",
    prefixes={"ex": "https://example.com/"},
)
serialize_path(model, "snapshot.nq")

serialize() returns str. serialize_path() writes directly to a path and infers syntax from the extension when omitted. Prefer N-Quads or TriG when the dataset includes named graphs.

Query result types

from oxiland import query

answer = query(model, "ASK { ?s ?p ?o }")

rows = query(
    model,
    "SELECT ?s ?label WHERE { ?s <https://schema.org/name> ?label }",
    limit=500,
    offset=0,
)
for row in rows:
    subject = row["s"]
    label = row.get("label")

triples = query(
    model,
    "CONSTRUCT { ?s <https://example.com/seen> ?o } WHERE { ?s ?p ?o }",
)
for triple in triples:
    process(triple)
Query form Python result
ASK bool
SELECT lazy SolutionsIter of Solution
CONSTRUCT / DESCRIBE lazy TriplesIter of Triple

A Solution supports access by variable name or position. A selected but unbound variable returns None. An unknown variable name or invalid position raises KeyError. variables() returns the result variable order.

Use base_iri=, limit=, and offset= for query configuration. Use default_graph= with one graph name or a sequence of graph names; a Python string is intentionally rejected because it is not an RDF graph object. default_graph_as_union=True treats all graphs as the default query graph.

SPARQL Update

from oxiland import update

update(
    model,
    '''
    DELETE { ?s <https://example.com/status> "pending" }
    INSERT { ?s <https://example.com/status> "active" }
    WHERE  { ?s <https://example.com/status> "pending" }
    ''',
)

Update accepts base_iri=, default_graph=, and default_graph_as_union=. A parse failure raises SparqlParseError; an execution failure raises SparqlEvaluationError or a storage exception.

Serialize ASK and SELECT results

from oxiland import serialize_results

payload = serialize_results(
    model,
    "SELECT ?s WHERE { ?s ?p ?o }",
    "json",
    limit=100,
)

SPARQL result formats are JSON, XML, CSV, and TSV. serialize_results() is for ASK and SELECT. Serialize CONSTRUCT and DESCRIBE graph results as RDF instead.

Resource control

Use query-level filters and limit= for caller-facing SELECT or graph queries, and consume lazy iterators incrementally. The Python API does not expose a query cancellation token or wall-clock timeout. Do not execute unrestricted SPARQL supplied by untrusted clients in a latency-sensitive worker; enforce limits and isolation at the application boundary.