# How to Implement SHACL Validation and OWL Ontology Generation in Semantica

> Learn to implement SHACL validation and OWL ontology generation using Semantica. Build SHACL shapes, validate RDF graphs, and export ontologies effortlessly with this powerful pipeline.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-08-14

---

**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`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_generator.py) | Convert ontology dictionaries to SHACL constraints |
| **Validation Engine** | [`semantica/ontology/ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_validator.py) | Execute SHACL validation against RDF data |
| **Export Utilities** | [`semantica/export/owl_exporter.py`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_generator.py) implements a **six-stage pipeline** that transforms OWL-style dictionaries into executable SHACL graphs:

1. Build a fast class index for efficient lookup
2. Create a `NodeShape` for every OWL class definition
3. Attach `PropertyShape` objects based on property type (literal or object)
4. Propagate inherited shapes with cycle-safe traversal
5. Apply a **quality tier** (`basic`, `standard`, or `strict`)
6. 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.

```python
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`](https://github.com/semantica-agi/semantica/blob/main/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.validate` with `inference="none"` and `abort_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.

```python
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`](https://github.com/semantica-agi/semantica/blob/main/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.

```python
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:

```python
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`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_generator.py) | 56-67 | `SHACLGenerator` class definition and pipeline |
| [`semantica/ontology/ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_validator.py) | 38-84 | `_run_pyshacl` validation implementation |
| [`semantica/export/owl_exporter.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/export/owl_exporter.py) | 41-57 | `OWLExporter` class and `export_owl()` method |
| [`semantica/export/rdf_exporter.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/export/rdf_exporter.py) | — | `RDFExporter` for data graph serialization |

## Summary

- **SHACL shapes** are generated from dictionary ontologies using `SHACLGenerator` with configurable `quality_tier` settings
- **SHACL validation** executes through `_run_pyshacl`, which parses pyshacl results into structured `SHACLViolation` objects
- **OWL export** uses `OWLExporter` with 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.