#002: SHACL-driven entity editor with Wikidata-style forms #2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Blocked by
Summary
Implement a form-based RDF entity editor driven by SHACL shapes. Users select a shape (entity type), and the form is generated from the shape's property constraints. The interaction model follows Wikidata's entity editor: mandatory properties appear by default, optional properties can be added via a "+" button, and properties can have qualifiers (nested property-value pairs).
Motivation
Currently, data in Concon datasets can only be edited via raw SPARQL Update. A form-based editor would allow non-technical users to create and edit entities without writing SPARQL, guided by the constraints defined in SHACL shapes.
Design
Entity model
concon:Entity.Stated vs non-stated properties
A property-value pair
(s, p, o)is either:(s, p, o)is present in the graph.The form shows both possibilities. The user toggles whether a property value is stated or not. Non-stated values are kept only in the UI state (or in a separate draft/staging mechanism) but are never asserted in the RDF graph.
SHACL shapes
Form generation from shapes
For each
sh:NodeShape:sh:propertysh:minCount >1=sh:minCount = 0sh:maxCountsh:datatypesh:classsh:insh:namesh:descriptionsh:ordersh:groupsh:patternQualifiers
Properties can have qualifiers — additional context for a statement (e.g., "population: 1,000,000" qualified by "as of: 2024").
Reification approach (to be decided)
Two options under consideration:
RDF 1.2 reification (
rdf:reifies): supported in Oxigraph 0.5.x behind therdf-12feature flag. Cleaner semantics, follows the evolving W3C standard. Requires upgrading from Oxigraph 0.4.x to 0.5.x.Statement node pattern (Wikidata model): uses intermediate nodes. Works with any RDF store, no special features needed. More verbose but well-proven.
Decision deferred — depends on Oxigraph upgrade feasibility and RDF 1.2 spec stability.
Form rendering
Client-side JavaScript rendering (Foundation 6 + vanilla JS or a small library). The SHACL shape is serialized as JSON and sent to the browser. The form is generated dynamically.
Interaction model (inspired by Wikidata):
Technical approach
SHACL parsing: Rudof library
Use the Rudof Rust library (by Jose Emilio Labra) for SHACL parsing.
Key crates:
shacl_ast— AST types:ShaclSchema,NodeShape,PropertyShape,Componentshacl_rdf— parse SHACL from Turtle/RDFrudof_lib— high-level APIThe
ShaclSchemaprovides an iterator over shapes. EachNodeShapehasproperty_shapes(references toPropertyShapeobjects) and eachPropertyShapehas apath(the RDF predicate) andcomponents(constraints likeMinCount,Datatype,Class,In, etc.).RDF storage
Entities stored as triples in regular Concon datasets (Oxigraph stores). SPARQL Update used for create/update/delete operations.
Oxigraph upgrade consideration
Concon currently uses Oxigraph 0.4.x. Upgrading to 0.5.x would enable RDF 1.2 support (
rdf:reifies) but involves substantial API changes.Pros of upgrading to 0.5.x
rdf-12feature flagCons of upgrading to 0.5.x
Store.query()andStore.update()call must be rewritten (newSparqlEvaluatorfluent API replacesQueryOptions)<< s p o >>syntax replaced by RDF 1.2<<( s p o )>>Decision
Pending. The upgrade is recommended but should be a separate issue given the scope of API changes.
SHACL file storage
Each dataset has an associated SHACL store (a second Oxigraph dataset). In this SHACL store:
Constraint: at most one SHACL file (shapes graph) per dataset graph.
Example mapping in the default graph of the SHACL store:
Stated and non-stated triples
Uses RDF-star (or RDF 1.2 quoted triples) to annotate triple status:
Non-stated: the triple
(s, p, o)is NOT in the graph. Only the annotation exists:Stated: the triple
(s, p, o)IS in the graph, plus an annotation:The
concon:StatedTripleannotation is redundant (the triple is already asserted) but enables efficient queries to find all explicitly stated triples via the annotation pattern.Entity IRI generation
Default: user-defined IRIs.
Extension: shapes can be associated with IRI generation functions via a SHACL extension property:
Built-in generators:
concon:UUIDGenerator— generates<base-iri>/{uuid}concon:SlugGenerator— generates<base-iri>/{slug}from a designated property (e.g.,rdfs:label)Form rendering approach
Hybrid server-side + AJAX:
/_ds/{dataset}/_update). Each save constructs a small SPARQL INSERT/DELETE — no page reload.Entity search for object properties
When a property has
sh:class(range is another entity type), the value input becomes an autocomplete field./_api/search?q=term&dataset=name&class=IRIrdfs:label,dcterms:title, or IRI substring).Cross-dataset entity references are deferred to a future issue (#003 Federated entity search).
SHACL store: per-dataset
Each dataset has its own SHACL store (a separate Oxigraph store). This provides clean isolation — shapes for one dataset don't interfere with another.
Storage:
data/shacl/{dataset-name}/alongsidedata/datasets/{dataset-name}/.Access: via a SPARQL endpoint at
/{team}/_ds/{dataset}/_shacl/_query(GET/POST) and/{team}/_ds/{dataset}/_shacl/_update(POST). Users read and edit SHACL shapes through SPARQL. A dedicated SHACL editor UI is deferred to a future issue (#004 SHACL editor).Tests
Unit tests
Integration tests
Manual tests (on dev.kg.degu.cl)
No further open questions
References
Summary
A form-based RDF entity editor driven by SHACL shapes has been implemented. Users select an entity type (SHACL NodeShape), and a form is generated from the shape's property constraints. Mandatory fields appear by default, optional fields can be added via a "+" button, and each property value can be saved individually via AJAX.
Review fixes (second commit)
All findings from the maintainer review were addressed:
Critical: SPARQL injection fixes
search_entities(): addedis_valid_iri()validation that rejects IRIs containing>, whitespace, braces,<, or control characters. Invalid class parameters return an empty result set.saveField()JS: addedisValidIri()regex validation that checks for URL/URN format before interpolating into SPARQL strings.Major: qualifiers
Added "+ Qualifier" button per property field. Each qualifier has a predicate IRI and value input. Qualifiers are stored as RDF 1.2 reification annotations via the
_entities/_reifybackend endpoint:Major: non-stated triple persistence
Added
POST /_ds/{dataset}/_entities/_reifybackend endpoint that uses Turtle I/O (store.load_from_reader()) to store RDF 1.2 reification annotations, since the SPARQL parser does not support<< s p o >>syntax. Supports bothconcon:StatedTripleandconcon:NonStatedTripleannotation types.Major: dataset name bug
The template now receives both
dataset_name(display name) andqualified_name(full path like"materials/pot"). The JavaScript usesqualified_namefor API calls.Medium: shapesjson XSS
Replaced inline
'{{ shapes_json|safe }}'with a typed<script type"application/json">= element, eliminating the single quote breakage.Additional: existing entity values
When selecting an entity from search results, the form now loads existing property values from the dataset via a SPARQL query.
Files created
src/shacl.rstemplates/entity_editor.htmlFiles modified
src/lib.rsshaclmodulesrc/main.rsshaclmodulesrc/store.rssrc/routes/content.rssrc/routes/web.rsentity_editor()handlersrc/routes/sparql.rssparql_update_post_on_store()src/routes/datasets.rs/_api/searchendpointTests
48 tests pass (33 existing + 15 new).
cargo fmtandcargo clippyproduce zero warnings/errors.Branch
issue/002-shacl-driven-entity-editor(2 commits on top of issue/001)