RDF Core
Parse, serialize, and query RDF graphs and datasets.
W3C RDF 1.1 compliant core library for Dart.
Getting Started
Install the package
dart pub add locorda_rdf_core import 'package:locorda_rdf_core/core.dart';
void main() {
final turtleData = '''
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<http://example.org/alice> foaf:name "Alice"@en .
''';
final graph = turtle.decode(turtleData);
print('Triples: ${graph.triples.length}'); // Triples: 1
} import 'package:locorda_rdf_core/core.dart';
void main() {
final turtleData = '''
@prefix ex: <http://example.org/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ex:Alice foaf:knows ex:Bob .
ex:Bob foaf:knows ex:Charlie .
''';
final graph = turtle.decode(turtleData);
// Find all triples where the predicate is foaf:knows
final knowsTriples =
graph.findTriples(predicate: IriTerm('http://xmlns.com/foaf/0.1/knows'));
print('People who know someone:');
for (final triple in knowsTriples) {
print(' ${triple.subject}');
}
// Add new triple (creates new immutable graph)
final updatedGraph = graph.withTriple(Triple(
IriTerm('http://example.org/Bob'),
IriTerm('http://xmlns.com/foaf/0.1/knows'),
IriTerm('http://example.org/David'),
));
print('\nTotal triples: ${updatedGraph.triples.length}');
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Create quads with graph context
final alice = const IriTerm('http://example.org/alice');
final bob = const IriTerm('http://example.org/bob');
final foafName = const IriTerm('http://xmlns.com/foaf/0.1/name');
final foafKnows = const IriTerm('http://xmlns.com/foaf/0.1/knows');
final peopleGraph = const IriTerm('http://example.org/graphs/people');
final quads = [
Quad(alice, foafName, LiteralTerm.string('Alice')), // default graph
Quad(alice, foafKnows, bob, peopleGraph), // named graph
Quad(bob, foafName, LiteralTerm.string('Bob'), peopleGraph), // named graph
];
// Create dataset from quads
final dataset = RdfDataset.fromQuads(quads);
// Encode to N-Quads
final nquadsData = nquads.encode(dataset);
print('N-Quads output:');
print(nquadsData);
// Decode N-Quads back to dataset
final decodedDataset = nquads.decode(nquadsData);
// Access default and named graphs
print(
'Default graph has ${decodedDataset.defaultGraph.triples.length} triples');
print('Dataset has ${decodedDataset.namedGraphs.length} named graphs');
for (final namedGraph in decodedDataset.namedGraphs) {
print(
'Named graph ${namedGraph.name} has ${namedGraph.graph.triples.length} triples');
}
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Example: Decode a JSON-LD document
final jsonLdData = '''
{
"@context": {
"name": "http://xmlns.com/foaf/0.1/name",
"knows": {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id"
},
"Person": "http://xmlns.com/foaf/0.1/Person"
},
"@id": "http://example.org/alice",
"@type": "Person",
"name": "Alice",
"knows": [
{
"@id": "http://example.org/bob",
"@type": "Person",
"name": "Bob"
}
]
}
''';
// Using the convenience global variable
final graph = jsonldGraph.decode(jsonLdData);
// Print decoded triples
print('Decoded ${graph.triples.length} triples:');
for (final triple in graph.triples) {
print('${triple.subject} ${triple.predicate} ${triple.object}');
}
// Encode the graph back to JSON-LD
final serialized = jsonldGraph.encode(graph);
print('\nEncoded JSON-LD:');
print(serialized);
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Create individual triples
final subject = const IriTerm('http://example.org/alice');
final predicate = const IriTerm('http://xmlns.com/foaf/0.1/name');
final object = LiteralTerm.string('Alice');
final triple = Triple(subject, predicate, object);
// Create graph with triples
final graph = RdfGraph(triples: [triple]);
print('Created graph with ${graph.triples.length} triple(s)');
print('\nTriples:');
for (final t in graph.triples) {
print(' ${t.subject} ${t.predicate} ${t.object}');
}
// Add more triples using withTriple
final age = const IriTerm('http://xmlns.com/foaf/0.1/age');
final updatedGraph = graph.withTriple(
Triple(subject, age, LiteralTerm.integer(30)),
);
print('\nUpdated graph has ${updatedGraph.triples.length} triples');
// Encode to Turtle
print('\nTurtle format:');
print(turtle.encode(updatedGraph));
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Create two separate graphs
final graph1 = RdfGraph(triples: [
Triple(
const IriTerm('http://example.org/alice'),
const IriTerm('http://xmlns.com/foaf/0.1/name'),
LiteralTerm.string('Alice'),
),
Triple(
const IriTerm('http://example.org/alice'),
const IriTerm('http://xmlns.com/foaf/0.1/age'),
LiteralTerm.integer(30),
),
]);
final graph2 = RdfGraph(triples: [
Triple(
const IriTerm('http://example.org/bob'),
const IriTerm('http://xmlns.com/foaf/0.1/name'),
LiteralTerm.string('Bob'),
),
Triple(
const IriTerm('http://example.org/alice'),
const IriTerm('http://xmlns.com/foaf/0.1/knows'),
const IriTerm('http://example.org/bob'),
),
]);
print('Graph 1 has ${graph1.triples.length} triples');
print('Graph 2 has ${graph2.triples.length} triples');
// Merge graphs
final merged = graph1.merge(graph2);
print('\nMerged graph has ${merged.triples.length} triples');
// Query for specific patterns
final alice = const IriTerm('http://example.org/alice');
final aliceTriples = merged.findTriples(subject: alice);
print('\nAll triples about Alice:');
for (final triple in aliceTriples) {
print(' ${triple.predicate} -> ${triple.object}');
}
// Check if triple exists
final foafKnows = const IriTerm('http://xmlns.com/foaf/0.1/knows');
if (merged.hasTriples(subject: alice, predicate: foafKnows)) {
print('\nAlice knows someone!');
}
// Create filtered graph
final aliceGraph = merged.matching(subject: alice);
print(
'\nFiltered graph with only Alice has ${aliceGraph.triples.length} triples');
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Sample data in Turtle format
final turtleData = '''
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<http://example.org/alice> foaf:name "Alice" ;
foaf:age 30 .
''';
// Using the preconfigured RdfCore instance
// Decode with explicit content type
print('1. Decoding Turtle with RdfCore:');
final graph = rdf.decode(turtleData, contentType: 'text/turtle');
print(' Decoded ${graph.triples.length} triples');
// Encode to different format
print('\n2. Encoding to JSON-LD:');
final jsonld = rdf.encode(graph, contentType: 'application/ld+json');
print(jsonld);
// Encode to N-Triples
print('\n3. Encoding to N-Triples:');
final ntriples = rdf.encode(graph, contentType: 'application/n-triples');
print(ntriples);
// Working with datasets and N-Quads
print('\n4. Working with Datasets:');
final quadsData = '''
<http://example.org/alice> <http://xmlns.com/foaf/0.1/name> "Alice" .
<http://example.org/bob> <http://xmlns.com/foaf/0.1/name> "Bob" <http://example.org/graph1> .
''';
final dataset =
rdf.decodeDataset(quadsData, contentType: 'application/n-quads');
print(' Default graph: ${dataset.defaultGraph.triples.length} triples');
print(' Named graphs: ${dataset.namedGraphs.length}');
// Encode dataset back to N-Quads
final encodedDataset =
rdf.encodeDataset(dataset, contentType: 'application/n-quads');
print('\n5. Encoded Dataset:');
print(encodedDataset);
// Format auto-detection (when contentType is omitted)
print('\n6. Auto-detection:');
final autoDetected = rdf.decode(turtleData); // Automatically detects Turtle
print(' Auto-detected and decoded ${autoDetected.triples.length} triples');
} import 'package:locorda_rdf_core/core.dart';
void main() {
// Example 1: Using individual codec instances directly
print('1. Using codec instances directly:');
final turtleData = '''
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
<http://example.org/alice> foaf:name "Alice" .
''';
// Each format has a global codec instance
final graph1 = turtle.decode(turtleData);
final asJsonLd = jsonldGraph.encode(graph1);
print(' Encoded as JSON-LD:\n$asJsonLd');
// Example 2: Creating a custom RdfCore instance
print('\n2. Creating custom RdfCore with specific codecs:');
// Create RdfCore with only Turtle and N-Triples support
final customRdf = RdfCore.withCodecs(codecs: [
TurtleCodec(),
NTriplesCodec(),
]);
final graph2 = customRdf.decode(turtleData, contentType: 'text/turtle');
final asNTriples =
customRdf.encode(graph2, contentType: 'application/n-triples');
print(' Encoded as N-Triples:\n$asNTriples');
// Example 3: Customizing codec options
print('\n3. Using codecs with custom options:');
// Create a Turtle codec with custom parsing options
final strictTurtle = TurtleCodec(
decoderOptions: TurtleDecoderOptions(
parsingFlags: {
TurtleParsingFlag.allowDigitInLocalName,
},
),
);
final customRdfCore = RdfCore.withCodecs(codecs: [strictTurtle]);
// Use the custom codec
final strictData =
'@prefix ex: <http://example.org/> . ex:resource123 a ex:Type .';
final graph3 = customRdfCore.decode(strictData, contentType: 'text/turtle');
print(' Parsed ${graph3.triples.length} triples with custom options');
// Example 4: Standard codecs (recommended for most use cases)
print('\n4. Using standard codecs (includes all formats):');
final standardRdf = RdfCore.withStandardCodecs();
// Supports Turtle, N-Triples, N-Quads, and JSON-LD out of the box
final graph4 = standardRdf.decode(turtleData, contentType: 'text/turtle');
print(' Standard RdfCore decoded ${graph4.triples.length} triples');
// Can encode to any standard format
final formats = [
'text/turtle',
'application/n-triples',
'application/ld+json'
];
print('\n Available standard formats:');
for (final format in formats) {
final encoded = standardRdf.encode(graph4, contentType: format);
print(' - $format: ${encoded.split('\n').length} lines');
}
} What Can You Build?
ποΈ Knowledge Graphs
Build semantic knowledge bases with typed relationships. Perfect for domain modeling, ontologies, and linked data applications.
π Data Integration
Merge data from multiple sources into a unified graph. Transform between formats (Turtle β JSON-LD β N-Triples) seamlessly.
οΏ½ In-Memory Graph Queries
Graph queries with O(1) subject lookups. Automatic indexing makes complex queries efficient for datasets that fit in RAM.
Key Features
Automatic Performance Optimization
Lazy indexing provides O(1) subject-based queries with zero memory cost until first use. Queries benefit from transparent performance improvements.
Developer-Friendly API
Global convenience variables (turtle, jsonld, ntriples) make parsing trivial. Fluent APIs for graph composition and chaining.
Multiple Formats
Parse and serialize Turtle, N-Triples, N-Quads, and JSON-LD. W3C RDF 1.1 compliant.
Full Dataset Support
Work with named graphs and datasets. Complete quad support for N-Quads with RDF 1.1 Dataset compliance.
Type-Safe
Strongly-typed Dart APIs with full IDE support and autocompletion. Catch errors at compile time.
Zero Dependencies
No external dependencies except logging. Clean, maintainable codebase.
Complete RDF Ecosystem
locorda_rdf_core is the foundation of a complete RDF toolkit. Combine it with companion packages for advanced functionality:
Object Mapper
locorda_rdf_mapper
Bidirectional mapping between Dart objects and RDF. Define your model once, serialize to any format.
Vocabularies
locorda_rdf_terms
Type-safe constants for Schema.org, FOAF, Dublin Core and more. Never typo a property URI again.
Canonicalization
locorda_rdf_canonicalization
RDF-CANON support for canonical serialization and reliable graph comparison.
RDF/XML Support
locorda_rdf_xml
Full RDF/XML encoder and decoder for legacy format support and integration with older systems.
Ready to Start?
Read the documentation or explore other RDF packages.