How to Implement SHACL Validation and OWL Ontology Generation in Semantica
Semantica provides a composable pipeline for building SHACL shapes from OWL ontologies, validating RDF graphs against those shapes, and exporting ontologies back to OWL format.
The semantica-agi/semantica repository offers a clean Python API for ontology engineering that bridges SHACL validation and OWL ontology generation through shared data structures. The core workflow uses three primary modules: SHACLGenerator for shape creation, _run_pyshacl for validation, and OWLExporter for ontology serialization.
Understanding the Core Architecture
Semantica separates concerns across three layers:
| Layer | Module Path | Purpose |
|---|---|---|
| Shape Generation | semantica/ontology/ontology_generator.py |
Convert ontology dictionaries to SHACL constraints |
| Validation Engine | semantica/ontology/ontology_validator.py |
Execute SHACL validation against RDF data |
| Export Utilities | semantica/export/owl_exporter.py |
Serialize ontologies to OWL Turtle |
This design ensures that your SHACL shapes and OWL output remain synchronized because both consume the same dictionary-based ontology format.
Generating SHACL Shapes from OWL Ontologies
The SHACLGenerator class in semantica/ontology/ontology_generator.py implements a six-stage pipeline that transforms OWL-style dictionaries into executable SHACL graphs:
- Build a fast class index for efficient lookup
- Create a
NodeShapefor every OWL class definition - Attach
PropertyShapeobjects based on property type (literal or object) - Propagate inherited shapes with cycle-safe traversal
- Apply a quality tier (
basic,standard, orstrict) - Serialize to Turtle, JSON-LD, or N-Triples
The generator supports quality tiers that control shape strictness. The strict tier produces closed node shapes (closed=True), preventing graphs from containing properties not explicitly defined in the ontology.
from semantica.ontology.ontology_generator import SHACLGenerator
# Define an ontology as a Python dictionary
ontology = {
"namespace": {"base_uri": "https://example.org/"},
"classes": [
{"name": "Person", "label": "Person"},
{"name": "Employee", "label": "Employee", "superclass": "Person"},
],
"properties": [
{
"name": "name",
"type": "literal",
"domain": ["Person"],
"range": ["xsd:string"],
},
{
"name": "worksFor",
"type": "object",
"domain": ["Employee"],
"range": ["Company"],
},
],
}
# Generate strict SHACL shapes
shacl_gen = SHACLGenerator(quality_tier="strict")
shacl_graph = shacl_gen.generate(ontology)
shacl_turtle = shacl_gen.serialize(shacl_graph, format="turtle")
print(shacl_turtle)
Set include_inherited=True when instantiating SHACLGenerator to automatically expand shapes with constraints from parent classes.
Validating RDF Graphs Against SHACL Shapes
Validation is handled by _run_pyshacl in semantica/ontology/ontology_validator.py. This function wraps the pyshacl library and provides structured error reporting through SHACLViolation and SHACLValidationReport objects.
The _run_pyshacl function:
- Loads data graphs and SHACL shapes using rdflib
- Executes
pyshacl.validatewithinference="none"andabort_on_first=False - Parses ValidationResult triples into typed violation objects
- Aggregates results into a report with conformance status and explanations
If pyshacl is not installed, the function raises an ImportError directing users to install semantica[shacl] extras.
from semantica.ontology.ontology_validator import _run_pyshacl
from semantica.export.rdf_exporter import RDFExporter
# Serialize RDF data for validation
rdf_exporter = RDFExporter()
data_graph = rdf_exporter.export_to_rdf(
{
"triples": [
("https://example.org/Alice", "rdf:type", "ex:Person"),
("https://example.org/Alice", "ex:name", '"Alice"^^xsd:string'),
]
},
format="turtle",
)
# Validate against previously generated SHACL
report = _run_pyshacl(data_graph, shacl_turtle)
print(report.summary())
if not report.conforms:
for violation in report.violations:
print(violation.explanation)
The SHACLValidationReport.summary() method returns conformance status, while each SHACLViolation provides a human-readable explanation of the constraint failure.
Exporting Ontologies to OWL Format
The OWLExporter class in semantica/export/owl_exporter.py converts the same dictionary-based ontologies back to OWL Turtle. Because exporters share namespace handling utilities, your OWL output uses identical prefixes to your SHACL shapes.
from semantica.export.owl_exporter import OWLExporter
# Export the ontology dictionary to OWL
owl_exporter = OWLExporter(ontology_uri="https://example.org/ontology/")
owl_turtle = owl_exporter.export_owl(ontology)
print(owl_turtle)
The ontology_uri parameter establishes the base IRI for the OWL document, ensuring proper identity semantics for imported ontologies.
Complete Integration Workflow
Combine all three components for a round-trip ontology engineering pipeline:
from semantica.ontology.ontology_generator import SHACLGenerator
from semantica.ontology.ontology_validator import _run_pyshacl
from semantica.export.owl_exporter import OWLExporter
from semantica.export.rdf_exporter import RDFExporter
# 1. Define your ontology
ontology = {...} # Your dictionary specification
# 2. Generate SHACL shapes for governance
generator = SHACLGenerator(quality_tier="strict")
shacl = generator.serialize(generator.generate(ontology), format="turtle")
# 3. Validate incoming data
rdf_exporter = RDFExporter()
data = rdf_exporter.export_to_rdf(data_dict, format="turtle")
report = _run_pyshacl(data, shacl)
# 4. Export canonical OWL for documentation
owl = OWLExporter(ontology_uri="https://example.org/").export_owl(ontology)
Source File Reference
| File | Lines | Contains |
|---|---|---|
semantica/ontology/ontology_generator.py |
56-67 | SHACLGenerator class definition and pipeline |
semantica/ontology/ontology_validator.py |
38-84 | _run_pyshacl validation implementation |
semantica/export/owl_exporter.py |
41-57 | OWLExporter class and export_owl() method |
semantica/export/rdf_exporter.py |
— | RDFExporter for data graph serialization |
Summary
- SHACL shapes are generated from dictionary ontologies using
SHACLGeneratorwith configurablequality_tiersettings - SHACL validation executes through
_run_pyshacl, which parses pyshacl results into structuredSHACLViolationobjects - OWL export uses
OWLExporterwith shared namespace handling for consistent prefixes - All three components consume the same ontology dictionary format, enabling synchronized governance and documentation
Frequently Asked Questions
What dependencies are required for SHACL validation?
Install the optional [shacl] extras to enable validation: pip install semantica[shacl]. This installs pyshacl and rdflib. Without these, _run_pyshacl raises an ImportError with installation instructions.
How do quality tiers affect generated SHACL shapes?
The quality_tier parameter controls shape strictness: basic produces open shapes with minimal constraints, standard adds cardinality and type checks, and strict generates closed node shapes (sh:closed true) that reject undefined properties entirely.
Can I validate large RDF graphs efficiently?
The _run_pyshacl function uses abort_on_first=False by default, collecting all violations rather than failing fast. For large graphs, consider streaming validation or partitioning your data graph, as the current implementation loads the full graph into memory via rdflib.
Does Semantica support OWL-to-SHACL round-tripping?
Yes, but through the dictionary format as intermediary. Feed the same ontology dictionary to both SHACLGenerator and OWLExporter to ensure your shapes and OWL documentation remain synchronized. Direct parsing of external OWL files into the internal dictionary format is not described in the current codebase.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →