Skip to content

Commit 9814198

Browse files
committed
docs: add virtual properties configuration guide
1 parent e278341 commit 9814198

File tree

3 files changed

+300
-0
lines changed

3 files changed

+300
-0
lines changed

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default defineConfig({
6060
{ label: 'Application settings', slug: 'configuration/app-settings' },
6161
{ label: 'SHACL configuration', slug: 'configuration/shacl' },
6262
{ label: 'Display rules configuration', slug: 'configuration/display-rules' },
63+
{ label: 'Virtual properties', slug: 'configuration/virtual-properties' },
6364
],
6465
},
6566
{

docs/src/content/docs/configuration/display-rules.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,37 @@ rules:
402402
fetchValueFromQuery: *author_query # Use the author query
403403
```
404404

405+
## Virtual properties: Bridging user mental models and data models
406+
407+
Sometimes, the way data is structured in your RDF ontology doesn't align with how users naturally think about it. **Virtual properties** are HERITRACE's solution to this mismatch, allowing you to present data in a way that matches users' mental models while maintaining the integrity of your underlying data model.
408+
409+
### The problem: Ontological vs. intuitive representation
410+
411+
Consider citations. In the CITO ontology, a citation is modeled as a **first-class entity** (a `cito:Citation` class) that links two bibliographic resources:
412+
413+
```turtle
414+
:citation1 a cito:Citation ;
415+
cito:hasCitingEntity :articleA ;
416+
cito:hasCitedEntity :articleB .
417+
```
418+
419+
This is ontologically sound and enables rich metadata about citations (citation type, semantics, etc.). However, most users think of citations as **relationships**, not entities. When editing an article, users expect to simply "add a citation" to another resource, not "create a Citation entity that links this article to another resource."
420+
421+
### The solution: Virtual properties
422+
423+
Virtual properties let you hide the complexity of the underlying data model and present a simpler, more intuitive interface. When a user adds a value to a virtual property, HERITRACE automatically creates and manages the intermediate entities behind the scenes.
424+
425+
For the citation example, you can configure:
426+
- A "Citations" virtual property that appears as a simple relationship field
427+
- When the user adds a citation, HERITRACE creates the `Citation` entity automatically
428+
- The user never sees or manages the `Citation` entity directly
429+
430+
You can even show both directions of the relationship ("Citations" and "Is Cited By") as separate virtual properties, even though they're backed by the same set of `Citation` entities in the graph.
431+
432+
### Learn more
433+
434+
For detailed configuration instructions, complete examples, and best practices, see the [Virtual properties configuration guide](/heritrace/configuration/virtual-properties/).
435+
405436
## Testing your rules
406437

407438
When running HERITRACE in development mode, any changes to `resources/display_rules.yaml` will automatically restart the server, so you can see your updates instantly.
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
---
2+
title: Virtual properties
3+
description: Configure virtual properties in HERITRACE to align the user interface with user mental models while maintaining ontological correctness in the underlying RDF data.
4+
---
5+
import { Aside, Code } from '@astrojs/starlight/components';
6+
7+
Virtual properties allow you to create properties that appear in the user interface but don't exist directly as predicates in your RDF graph. They bridge the gap between how data is ontologically modeled (often as classes) and how users naturally think about it (typically as relationships), making the interface more intuitive without compromising the integrity of your data model.
8+
9+
## What are virtual properties?
10+
11+
A virtual property is a user-facing field that, when populated, automatically creates one or more intermediate entities in the knowledge graph. From the user's perspective, they're adding a simple relationship. Behind the scenes, HERITRACE creates the necessary RDF structure to represent it correctly.
12+
13+
<Aside type="note" title="Virtual vs. Regular Properties">
14+
**Regular properties** directly correspond to RDF predicates in your data model. When you add a value, a triple is created.
15+
16+
**Virtual properties** have no direct RDF predicate. When you add a value, HERITRACE creates intermediate entities with specific properties based on your configuration.
17+
</Aside>
18+
19+
## Why use virtual properties?
20+
21+
The primary purpose of virtual properties is to **bridge the gap between ontological representation and user mental models**.
22+
23+
In RDF ontologies, certain concepts are correctly modeled as classes (first-class entities) because they carry important metadata and enable complex relationships. However, domain experts often think of these same concepts as simple relationships or attributes. This mismatch creates cognitive friction and makes the interface harder to use.
24+
25+
For example, in the CITO ontology, citations are modeled as a `cito:Citation` class—an entity that links two bibliographic resources. This is ontologically correct: citations can have types, contexts, and other metadata. But when users edit an article, they think "I want to cite this paper," not "I want to create a Citation entity that links my article to that paper."
26+
27+
Virtual properties resolve this tension by:
28+
29+
- **Presenting a simplified view**: Users interact with what appears to be a simple relationship field
30+
- **Managing complexity automatically**: HERITRACE creates and configures the intermediate entities behind the scenes
31+
- **Maintaining data model integrity**: The underlying RDF structure remains correct and compliant with the ontology
32+
- **Supporting bidirectional navigation**: Both directions of a relationship can be shown (e.g., "Citations" and "Is Cited By") even though they're backed by the same entities in the graph
33+
34+
Use virtual properties when your ontology models something as a class, but users naturally think of it as a relationship or when you need to hide implementation details from domain experts who shouldn't need to understand the full ontological structure.
35+
36+
## Configuration structure
37+
38+
Virtual properties are configured within the `displayProperties` section of a display rule, using several specific keys.
39+
40+
### Basic structure
41+
42+
```yaml
43+
displayProperties:
44+
- displayName: "Property Label"
45+
isVirtual: true
46+
shouldBeDisplayed: true
47+
fetchValueFromQuery: |
48+
# SPARQL query to fetch and format values
49+
implementedVia:
50+
target:
51+
class: "http://example.org/IntermediateClass"
52+
shape: "http://example.org/IntermediateShape"
53+
fieldOverrides:
54+
"http://example.org/property1":
55+
shouldBeDisplayed: false
56+
value: "${currentEntity}"
57+
"http://example.org/property2":
58+
displayName: "User-Facing Label"
59+
```
60+
61+
### Configuration keys
62+
63+
- **`isVirtual`**: Must be set to `true` to enable virtual property behavior
64+
- **`displayName`**: The label shown in the user interface for this property
65+
- **`shouldBeDisplayed`**: Controls whether this property appears in forms and entity views
66+
- **`fetchValueFromQuery`**: A SPARQL query that retrieves and formats the display value. The query context is the intermediate entity, referenced by `[[value]]`
67+
- **`implementedVia`**: Defines how the virtual property is implemented in the RDF graph
68+
69+
#### The `implementedVia` section
70+
71+
This section tells HERITRACE what kind of intermediate entity to create and how to configure its properties.
72+
73+
**`target`**: Specifies the type of intermediate entity
74+
- `class`: The RDF class (`rdf:type`) for the intermediate entity
75+
- `shape`: The SHACL shape the intermediate entity conforms to
76+
77+
**`fieldOverrides`**: A mapping of property URIs to their configuration
78+
- Each key is a property URI on the intermediate entity
79+
- Each value is an object that can contain:
80+
- `shouldBeDisplayed`: If `false`, the field is hidden from the user and automatically populated
81+
- `value`: The value to set automatically. Can use the special placeholder `${currentEntity}` to reference the URI of the entity being edited
82+
- `displayName`: A custom label for fields that are shown to the user
83+
84+
## Complete example: Bidirectional citations
85+
86+
This example shows how to configure virtual properties for a citation system where citations can be viewed from both directions.
87+
88+
### The scenario
89+
90+
You have bibliographic resources that cite each other. In your RDF model, a `Citation` entity represents each citation, linking the citing resource to the cited resource. You want users to see:
91+
92+
- On the citing resource: A "Citations" property showing what it cites
93+
- On the cited resource: An "Is Cited By" property showing what cites it
94+
95+
But you only want to store one `Citation` entity in the graph, not duplicate data.
96+
97+
### The data model
98+
99+
```turtle
100+
@prefix cito: <http://purl.org/spar/cito/> .
101+
@prefix : <http://example.org/> .
102+
103+
# A citation entity links the two resources
104+
:citation1 a cito:Citation ;
105+
cito:hasCitingEntity :articleA ;
106+
cito:hasCitedEntity :articleB ;
107+
cito:hasCitationCharacterization cito:cites .
108+
```
109+
110+
In this model:
111+
- `:articleA` is the resource that cites
112+
- `:articleB` is the resource being cited
113+
- The `Citation` entity holds the relationship and can describe it (e.g., the type of citation)
114+
115+
### Configuring the "Citations" property
116+
117+
This virtual property appears on the citing resource and shows what it cites.
118+
119+
```yaml
120+
# First, define the query as a reusable anchor
121+
queries:
122+
citations_query: &citations_query |
123+
PREFIX cito: <http://purl.org/spar/cito/>
124+
PREFIX dcterms: <http://purl.org/dc/terms/>
125+
SELECT ?display ?target WHERE {
126+
[[value]] a cito:Citation ;
127+
cito:hasCitingEntity [[subject]] ;
128+
cito:hasCitedEntity ?target .
129+
?target dcterms:title ?title .
130+
BIND(CONCAT(?title, " (", STR(?target), ")") AS ?display)
131+
}
132+
133+
# Then use it in a virtual property
134+
virtual_properties:
135+
citations_property: &citations_property
136+
displayName: "Citations"
137+
isVirtual: true
138+
shouldBeDisplayed: true
139+
fetchValueFromQuery: *citations_query
140+
implementedVia:
141+
target:
142+
class: "http://purl.org/spar/cito/Citation"
143+
shape: "http://schema.org/CitationShape"
144+
fieldOverrides:
145+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type":
146+
shouldBeDisplayed: false
147+
value: "http://purl.org/spar/cito/Citation"
148+
"http://purl.org/spar/cito/hasCitingEntity":
149+
shouldBeDisplayed: false
150+
value: "${currentEntity}"
151+
"http://purl.org/spar/cito/hasCitedEntity":
152+
displayName: "Cited Resource"
153+
"http://purl.org/spar/cito/hasCitationCharacterization":
154+
displayName: "Citation Type"
155+
```
156+
157+
**What happens when a user adds a citation:**
158+
159+
1. The user sees a "Citations" field and a form to add a cited resource
160+
2. The `rdf:type` field is hidden and automatically set to `cito:Citation`
161+
3. The `cito:hasCitingEntity` field is hidden and automatically set to the current article's URI
162+
4. The user selects the cited resource in the `cito:hasCitedEntity` field (labeled "Cited Resource")
163+
5. The user optionally selects a citation type in the `cito:hasCitationCharacterization` field
164+
6. HERITRACE creates a new `Citation` entity with all these properties
165+
166+
### Configuring the "Is Cited By" property
167+
168+
This virtual property appears on the cited resource and shows what cites it. It queries for `Citation` entities where the current resource is the cited entity.
169+
170+
```yaml
171+
# Define the inverse query
172+
queries:
173+
citing_entity_query: &citing_entity_query |
174+
PREFIX cito: <http://purl.org/spar/cito/>
175+
PREFIX dcterms: <http://purl.org/dc/terms/>
176+
SELECT ?display ?target WHERE {
177+
[[value]] cito:hasCitingEntity ?target .
178+
?target dcterms:title ?title .
179+
BIND(CONCAT(?title, " (", STR(?target), ")") AS ?display)
180+
}
181+
182+
# Configure the reverse virtual property
183+
virtual_properties:
184+
is_cited_by_property: &is_cited_by_property
185+
displayName: "Is Cited By"
186+
isVirtual: true
187+
shouldBeDisplayed: true
188+
fetchValueFromQuery: *citing_entity_query
189+
implementedVia:
190+
target:
191+
class: "http://purl.org/spar/cito/Citation"
192+
shape: "http://schema.org/ReverseCitationShape"
193+
fieldOverrides:
194+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type":
195+
shouldBeDisplayed: false
196+
value: "http://purl.org/spar/cito/Citation"
197+
"http://purl.org/spar/cito/hasCitedEntity":
198+
shouldBeDisplayed: false
199+
value: "${currentEntity}"
200+
"http://purl.org/spar/cito/hasCitingEntity":
201+
displayName: "Citing Resource"
202+
"http://purl.org/spar/cito/hasCitationCharacterization":
203+
displayName: "Citation Type"
204+
```
205+
206+
**Key differences from the forward citation:**
207+
- The `fetchValueFromQuery` retrieves the citing entity instead of the cited entity
208+
- `hasCitedEntity` is now automatically set to `${currentEntity}` (instead of `hasCitingEntity`)
209+
- `hasCitingEntity` is now the user-facing field (instead of `hasCitedEntity`)
210+
- A different SHACL shape (`ReverseCitationShape`) distinguishes it from forward citations
211+
212+
### Using the virtual properties in display rules
213+
214+
Once defined, you use the virtual properties in your entity rules:
215+
216+
```yaml
217+
rules:
218+
- target:
219+
class: "http://purl.org/spar/fabio/JournalArticle"
220+
displayName: "Journal Article"
221+
displayProperties:
222+
# ... other properties ...
223+
- *citations_property
224+
- *is_cited_by_property
225+
```
226+
227+
Now, when a user views or edits a journal article, they see both "Citations" and "Is Cited By" fields, even though the underlying data is stored as `Citation` entities.
228+
229+
## The `${currentEntity}` placeholder
230+
231+
The special `${currentEntity}` placeholder is replaced with the URI of the entity currently being created or edited. This is essential for linking the intermediate entity back to the main entity.
232+
233+
**Example:**
234+
```yaml
235+
fieldOverrides:
236+
"http://example.org/linksBackTo":
237+
shouldBeDisplayed: false
238+
value: "${currentEntity}"
239+
```
240+
241+
When creating a citation from Article A's page, `${currentEntity}` becomes Article A's URI. This ensures the `Citation` entity correctly references Article A.
242+
243+
## Understanding `fetchValueFromQuery` context
244+
245+
For virtual properties, the `fetchValueFromQuery` has a specific context:
246+
247+
- `[[subject]]`: The URI of the main entity being viewed (e.g., the article)
248+
- `[[value]]`: The URI of the intermediate entity (e.g., the `Citation` entity)
249+
250+
The query starts from the intermediate entity and navigates to retrieve the display value.
251+
252+
**Example:**
253+
```sparql
254+
SELECT ?display ?target WHERE {
255+
# [[value]] is the Citation entity URI
256+
[[value]] cito:hasCitedEntity ?target .
257+
258+
# Navigate from the Citation to get the cited resource's title
259+
?target dcterms:title ?title .
260+
261+
# Format the display string
262+
BIND(CONCAT(?title, " (citation)") AS ?display)
263+
}
264+
```
265+
266+
The query must return two variables in order:
267+
1. The formatted display string
268+
2. The URI of the final target entity

0 commit comments

Comments
 (0)