- Implemented `owl_to_mermaid.py` to convert OWL/Turtle files into Mermaid class diagrams. - Implemented `owl_to_plantuml.py` to convert OWL/Turtle files into PlantUML class diagrams. - Added two new PlantUML files for custodian multi-aspect diagrams.
1168 lines
36 KiB
Markdown
1168 lines
36 KiB
Markdown
# SPARQL Query Library for Heritage Custodian Ontology
|
||
|
||
**Version**: 1.0.0
|
||
**Schema Version**: v0.7.0
|
||
**Last Updated**: 2025-11-22
|
||
**Purpose**: Query patterns for organizational structures, collections, and staff relationships
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Prefixes](#prefixes)
|
||
2. [Staff Queries](#1-staff-queries)
|
||
3. [Collection Queries](#2-collection-queries)
|
||
4. [Combined Staff + Collection Queries](#3-combined-staff--collection-queries)
|
||
5. [Organizational Change Queries](#4-organizational-change-queries)
|
||
6. [Validation Queries (SPARQL)](#5-validation-queries-sparql)
|
||
7. [Advanced Temporal Queries](#6-advanced-temporal-queries)
|
||
|
||
---
|
||
|
||
## Prefixes
|
||
|
||
All queries use these standard prefixes:
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
PREFIX pico: <https://w3id.org/pico/ontology/>
|
||
PREFIX schema: <https://schema.org/>
|
||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
||
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
|
||
PREFIX prov: <http://www.w3.org/ns/prov#>
|
||
PREFIX time: <http://www.w3.org/2006/time#>
|
||
```
|
||
|
||
---
|
||
|
||
## 1. Staff Queries
|
||
|
||
### 1.1 Find All Curators
|
||
|
||
**Use Case**: List all staff with curator roles across all institutions.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||
|
||
SELECT ?person ?personLabel ?unit ?unitName
|
||
WHERE {
|
||
?person a custodian:PersonObservation ;
|
||
custodian:staff_role "CURATOR" ;
|
||
custodian:unit_affiliation ?unit .
|
||
|
||
?unit custodian:unit_name ?unitName .
|
||
|
||
OPTIONAL { ?person rdfs:label ?personLabel }
|
||
}
|
||
ORDER BY ?unitName ?personLabel
|
||
```
|
||
|
||
**Expected Result** (from test data):
|
||
| person | personLabel | unit | unitName |
|
||
|--------|-------------|------|----------|
|
||
| `hc/person-obs/nl-rm/sophia-van-gogh/curator-dutch-paintings` | Sophia van Gogh | `hc/org-unit/rm-paintings-dept` | Paintings Department |
|
||
|
||
**Explanation**: Filters `PersonObservation` by `staff_role = "CURATOR"` and joins with organizational units via `unit_affiliation`.
|
||
|
||
---
|
||
|
||
### 1.2 List Staff in Organizational Unit
|
||
|
||
**Use Case**: Find all staff members in a specific department or division.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?person ?role ?startDate ?endDate
|
||
WHERE {
|
||
<https://nde.nl/ontology/hc/org-unit/rm-paintings-dept>
|
||
org:hasMember ?person .
|
||
|
||
?person custodian:staff_role ?role .
|
||
|
||
OPTIONAL { ?person custodian:employment_start_date ?startDate }
|
||
OPTIONAL { ?person custodian:employment_end_date ?endDate }
|
||
}
|
||
ORDER BY ?role ?startDate
|
||
```
|
||
|
||
**Expected Result** (from test data):
|
||
| person | role | startDate | endDate |
|
||
|--------|------|-----------|---------|
|
||
| `hc/person-obs/nl-rm/sophia-van-gogh/curator-dutch-paintings` | CURATOR | 2015-06-01 | null |
|
||
| `hc/person-obs/nl-rm/pieter-de-vries/curator-flemish-paintings` | CURATOR | 2018-09-01 | null |
|
||
|
||
**Explanation**: Uses `org:hasMember` (same as `custodian:staff_members`) to retrieve all persons in the unit. Filters by specific unit URI.
|
||
|
||
---
|
||
|
||
### 1.3 Track Role Changes Over Time
|
||
|
||
**Use Case**: Find staff who have changed roles within an institution.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX pico: <https://w3id.org/pico/ontology/>
|
||
|
||
SELECT ?personLabel ?role1 ?endDate1 ?role2 ?startDate2 ?unit
|
||
WHERE {
|
||
# First role observation
|
||
?obs1 a custodian:PersonObservation ;
|
||
pico:hasRole ?personLabel ;
|
||
custodian:staff_role ?role1 ;
|
||
custodian:employment_end_date ?endDate1 .
|
||
|
||
# Second role observation (same person, different role)
|
||
?obs2 a custodian:PersonObservation ;
|
||
pico:hasRole ?personLabel ;
|
||
custodian:staff_role ?role2 ;
|
||
custodian:employment_start_date ?startDate2 ;
|
||
custodian:unit_affiliation ?unit .
|
||
|
||
# Ensure second role starts after first ends
|
||
FILTER(?startDate2 >= ?endDate1)
|
||
# Ensure different roles
|
||
FILTER(?role1 != ?role2)
|
||
}
|
||
ORDER BY ?personLabel ?endDate1
|
||
```
|
||
|
||
**Expected Result**: Shows role transitions (e.g., ASSISTANT_CURATOR → CURATOR).
|
||
|
||
**Explanation**: Uses PiCo pattern to link multiple `PersonObservation` instances for the same person with different roles. Temporal filter ensures chronological order.
|
||
|
||
---
|
||
|
||
### 1.4 Find Staff by Time Period
|
||
|
||
**Use Case**: Who was working in a unit during a specific date range?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX schema: <https://schema.org/>
|
||
|
||
SELECT ?person ?role ?unit ?unitName
|
||
WHERE {
|
||
?person a custodian:PersonObservation ;
|
||
custodian:staff_role ?role ;
|
||
custodian:unit_affiliation ?unit ;
|
||
custodian:employment_start_date ?startDate .
|
||
|
||
?unit custodian:unit_name ?unitName .
|
||
|
||
# Either no end date (still employed) or end date after query period
|
||
OPTIONAL { ?person custodian:employment_end_date ?endDate }
|
||
|
||
# Query period: 2015-01-01 to 2020-12-31
|
||
FILTER(?startDate <= "2020-12-31"^^xsd:date)
|
||
FILTER(!BOUND(?endDate) || ?endDate >= "2015-01-01"^^xsd:date)
|
||
}
|
||
ORDER BY ?unitName ?role
|
||
```
|
||
|
||
**Expected Result**: Lists all staff employed during the 2015-2020 period.
|
||
|
||
**Explanation**: Uses temporal overlap logic:
|
||
- Start date ≤ query end date
|
||
- End date ≥ query start date OR no end date (still employed)
|
||
|
||
---
|
||
|
||
### 1.5 Find Staff by Expertise
|
||
|
||
**Use Case**: Locate staff with specific subject expertise (e.g., Dutch Golden Age art).
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?person ?expertise ?role ?unit ?unitName
|
||
WHERE {
|
||
?person a custodian:PersonObservation ;
|
||
custodian:subject_expertise ?expertise ;
|
||
custodian:staff_role ?role ;
|
||
custodian:unit_affiliation ?unit .
|
||
|
||
?unit custodian:unit_name ?unitName .
|
||
|
||
# Search for expertise containing "Dutch"
|
||
FILTER(CONTAINS(LCASE(?expertise), "dutch"))
|
||
}
|
||
ORDER BY ?expertise
|
||
```
|
||
|
||
**Expected Result**: Staff with "Dutch painting", "Dutch Golden Age", etc. in expertise field.
|
||
|
||
**Explanation**: Uses `CONTAINS()` for case-insensitive substring matching on `subject_expertise`.
|
||
|
||
---
|
||
|
||
## 2. Collection Queries
|
||
|
||
### 2.1 Find Managing Unit for a Collection
|
||
|
||
**Use Case**: Which department manages a specific collection?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?unit ?unitName ?unitType
|
||
WHERE {
|
||
<https://nde.nl/ontology/hc/collection/rm-dutch-paintings>
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:managing_unit ?unit .
|
||
|
||
?unit custodian:unit_name ?unitName ;
|
||
custodian:unit_type ?unitType .
|
||
|
||
BIND(<https://nde.nl/ontology/hc/collection/rm-dutch-paintings> AS ?collection)
|
||
}
|
||
```
|
||
|
||
**Expected Result**:
|
||
| collection | collectionName | unit | unitName | unitType |
|
||
|------------|----------------|------|----------|----------|
|
||
| `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings | `hc/org-unit/rm-paintings-dept` | Paintings Department | DEPARTMENT |
|
||
|
||
**Explanation**: Direct lookup via `custodian:managing_unit` property. Returns unit metadata.
|
||
|
||
---
|
||
|
||
### 2.2 List All Collections Managed by a Unit
|
||
|
||
**Use Case**: What collections does a department oversee?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?collectionScope ?extent
|
||
WHERE {
|
||
<https://nde.nl/ontology/hc/org-unit/rm-paintings-dept>
|
||
custodian:managed_collections ?collection .
|
||
|
||
?collection custodian:collection_name ?collectionName ;
|
||
custodian:collection_scope ?collectionScope ;
|
||
custodian:extent ?extent .
|
||
}
|
||
ORDER BY ?collectionName
|
||
```
|
||
|
||
**Expected Result** (from test data):
|
||
| collection | collectionName | collectionScope | extent |
|
||
|------------|----------------|-----------------|--------|
|
||
| `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings | 17th-century Dutch painting | 1,200 paintings |
|
||
| `hc/collection/rm-flemish-paintings` | Flemish Baroque Paintings | 17th-century Flemish painting | 450 paintings |
|
||
| `hc/collection/rm-italian-paintings` | Italian Renaissance Paintings | Italian Renaissance and Baroque painting | 280 paintings |
|
||
|
||
**Explanation**: Uses `custodian:managed_collections` (inverse of `managing_unit`) to retrieve all collections linked to a unit.
|
||
|
||
---
|
||
|
||
### 2.3 Find Collections by Type
|
||
|
||
**Use Case**: Search for all born-digital archival collections.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?managingUnit ?unitName
|
||
WHERE {
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:collection_type ?type .
|
||
|
||
# Filter for born-digital archives
|
||
FILTER(?type = "born_digital" || ?type = "archival")
|
||
|
||
OPTIONAL {
|
||
?collection custodian:managing_unit ?managingUnit .
|
||
?managingUnit custodian:unit_name ?unitName
|
||
}
|
||
}
|
||
ORDER BY ?collectionName
|
||
```
|
||
|
||
**Expected Result**:
|
||
| collection | collectionName | managingUnit | unitName |
|
||
|------------|----------------|--------------|----------|
|
||
| `hc/collection/na-born-digital-archives` | Born-Digital Government Records | `hc/org-unit/na-digital-preservation` | Digital Preservation Division |
|
||
|
||
**Explanation**: Filters `CustodianCollection` by `collection_type` values. Uses OPTIONAL for unit join (collections may not have managing unit assigned).
|
||
|
||
---
|
||
|
||
### 2.4 Find Collections by Temporal Coverage
|
||
|
||
**Use Case**: Find all collections covering the 17th century.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX time: <http://www.w3.org/2006/time#>
|
||
|
||
SELECT ?collection ?collectionName ?beginDate ?endDate
|
||
WHERE {
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:temporal_coverage ?temporalCoverage .
|
||
|
||
?temporalCoverage custodian:begin_of_the_begin ?beginDate ;
|
||
custodian:end_of_the_end ?endDate .
|
||
|
||
# Query for 17th century: 1600-1699
|
||
FILTER(?beginDate <= "1699-12-31"^^xsd:date)
|
||
FILTER(?endDate >= "1600-01-01"^^xsd:date)
|
||
}
|
||
ORDER BY ?beginDate ?collectionName
|
||
```
|
||
|
||
**Expected Result** (from test data):
|
||
| collection | collectionName | beginDate | endDate |
|
||
|------------|----------------|-----------|---------|
|
||
| `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings | 1600-01-01 | 1699-12-31 |
|
||
| `hc/collection/rm-flemish-paintings` | Flemish Baroque Paintings | 1600-01-01 | 1699-12-31 |
|
||
|
||
**Explanation**: Uses temporal overlap logic with Allen interval algebra:
|
||
- Collection begins before query period ends
|
||
- Collection ends after query period begins
|
||
|
||
---
|
||
|
||
### 2.5 Count Collections by Institution
|
||
|
||
**Use Case**: How many collections does each heritage custodian maintain?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?custodian ?collectionCount
|
||
WHERE {
|
||
{
|
||
SELECT ?custodian (COUNT(DISTINCT ?collection) AS ?collectionCount)
|
||
WHERE {
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:refers_to_custodian ?custodian .
|
||
}
|
||
GROUP BY ?custodian
|
||
}
|
||
}
|
||
ORDER BY DESC(?collectionCount)
|
||
```
|
||
|
||
**Expected Result**:
|
||
| custodian | collectionCount |
|
||
|-----------|-----------------|
|
||
| `hc/custodian/nl-rm` | 3 |
|
||
| `hc/custodian/nl-na` | 2 |
|
||
|
||
**Explanation**: Aggregates collections by custodian using `refers_to_custodian` property. Uses subquery for aggregation.
|
||
|
||
---
|
||
|
||
## 3. Combined Staff + Collection Queries
|
||
|
||
### 3.1 Find Curator Managing Specific Collection
|
||
|
||
**Use Case**: Who is the curator responsible for the Dutch Paintings collection?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?curator ?role ?expertise ?collection ?collectionName
|
||
WHERE {
|
||
# Collection and its managing unit
|
||
<https://nde.nl/ontology/hc/collection/rm-dutch-paintings>
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:managing_unit ?unit .
|
||
|
||
# Staff in that unit with curator role
|
||
?unit org:hasMember ?curator .
|
||
|
||
?curator custodian:staff_role ?role ;
|
||
custodian:subject_expertise ?expertise .
|
||
|
||
# Filter for curators only
|
||
FILTER(?role = "CURATOR")
|
||
|
||
BIND(<https://nde.nl/ontology/hc/collection/rm-dutch-paintings> AS ?collection)
|
||
}
|
||
```
|
||
|
||
**Expected Result**:
|
||
| curator | role | expertise | collection | collectionName |
|
||
|---------|------|-----------|------------|----------------|
|
||
| `hc/person-obs/nl-rm/sophia-van-gogh/curator-dutch-paintings` | CURATOR | Dutch Golden Age painting | `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings |
|
||
|
||
**Explanation**: Two-step join:
|
||
1. Collection → managing unit
|
||
2. Managing unit → staff members (filtered by role = CURATOR)
|
||
|
||
---
|
||
|
||
### 3.2 List Collections and Curators by Department
|
||
|
||
**Use Case**: Department inventory showing collections + responsible curators.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?unit ?unitName ?collection ?collectionName ?curator ?curatorExpertise
|
||
WHERE {
|
||
# Organizational unit
|
||
?unit a custodian:OrganizationalStructure ;
|
||
custodian:unit_name ?unitName ;
|
||
custodian:unit_type "DEPARTMENT" .
|
||
|
||
# Collections managed by unit
|
||
OPTIONAL {
|
||
?unit custodian:managed_collections ?collection .
|
||
?collection custodian:collection_name ?collectionName
|
||
}
|
||
|
||
# Curators in unit
|
||
OPTIONAL {
|
||
?unit org:hasMember ?curator .
|
||
?curator custodian:staff_role "CURATOR" ;
|
||
custodian:subject_expertise ?curatorExpertise
|
||
}
|
||
}
|
||
ORDER BY ?unitName ?collectionName ?curatorExpertise
|
||
```
|
||
|
||
**Expected Result** (Paintings Department):
|
||
| unit | unitName | collection | collectionName | curator | curatorExpertise |
|
||
|------|----------|------------|----------------|---------|------------------|
|
||
| `hc/org-unit/rm-paintings-dept` | Paintings Department | `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings | `hc/person-obs/nl-rm/sophia-van-gogh/...` | Dutch Golden Age painting |
|
||
| `hc/org-unit/rm-paintings-dept` | Paintings Department | `hc/collection/rm-flemish-paintings` | Flemish Baroque Paintings | `hc/person-obs/nl-rm/pieter-de-vries/...` | Flemish Baroque painting |
|
||
| ... | ... | ... | ... | ... | ... |
|
||
|
||
**Explanation**: Retrieves all departments with OPTIONAL joins for both collections and curators. This produces a Cartesian product (all collections × all curators per department).
|
||
|
||
---
|
||
|
||
### 3.3 Match Curators to Collections by Subject Expertise
|
||
|
||
**Use Case**: Which curator's expertise matches which collection's scope?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?curator ?expertise ?collection ?collectionName ?collectionScope
|
||
WHERE {
|
||
# Curator in a unit
|
||
?curator a custodian:PersonObservation ;
|
||
custodian:staff_role "CURATOR" ;
|
||
custodian:subject_expertise ?expertise ;
|
||
custodian:unit_affiliation ?unit .
|
||
|
||
# Collections managed by that unit
|
||
?unit custodian:managed_collections ?collection .
|
||
|
||
?collection custodian:collection_name ?collectionName ;
|
||
custodian:collection_scope ?collectionScope .
|
||
|
||
# Match expertise to collection scope (case-insensitive substring)
|
||
FILTER(CONTAINS(LCASE(?collectionScope), LCASE(?expertise)) ||
|
||
CONTAINS(LCASE(?expertise), LCASE(?collectionScope)))
|
||
}
|
||
ORDER BY ?unit ?curator
|
||
```
|
||
|
||
**Expected Result**:
|
||
| curator | expertise | collection | collectionName | collectionScope |
|
||
|---------|-----------|------------|----------------|-----------------|
|
||
| `hc/person-obs/nl-rm/sophia-van-gogh/...` | Dutch Golden Age painting | `hc/collection/rm-dutch-paintings` | Dutch Golden Age Paintings | 17th-century Dutch painting |
|
||
|
||
**Explanation**: Fuzzy matching between curator's `subject_expertise` and collection's `collection_scope`. Uses bidirectional CONTAINS for partial matches.
|
||
|
||
---
|
||
|
||
### 3.4 Department Inventory Report
|
||
|
||
**Use Case**: Generate comprehensive report of department resources (staff, collections, temporal validity).
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?unitName ?staffCount ?staffRole ?collectionCount ?validFrom ?validTo
|
||
WHERE {
|
||
?unit a custodian:OrganizationalStructure ;
|
||
custodian:unit_name ?unitName ;
|
||
custodian:unit_type "DEPARTMENT" ;
|
||
custodian:staff_count ?staffCount .
|
||
|
||
OPTIONAL { ?unit custodian:valid_from ?validFrom }
|
||
OPTIONAL { ?unit custodian:valid_to ?validTo }
|
||
|
||
# Count collections
|
||
{
|
||
SELECT ?unit (COUNT(?collection) AS ?collectionCount)
|
||
WHERE {
|
||
?unit custodian:managed_collections ?collection
|
||
}
|
||
GROUP BY ?unit
|
||
}
|
||
|
||
# Count staff by role
|
||
OPTIONAL {
|
||
SELECT ?unit ?staffRole (COUNT(?staff) AS ?staffRoleCount)
|
||
WHERE {
|
||
?unit org:hasMember ?staff .
|
||
?staff custodian:staff_role ?staffRole
|
||
}
|
||
GROUP BY ?unit ?staffRole
|
||
}
|
||
}
|
||
ORDER BY ?unitName
|
||
```
|
||
|
||
**Expected Result**: Summary statistics per department.
|
||
|
||
**Explanation**: Combines multiple aggregations:
|
||
- Collection count (subquery)
|
||
- Staff count by role (OPTIONAL subquery)
|
||
- Temporal validity (OPTIONAL fields)
|
||
|
||
---
|
||
|
||
## 4. Organizational Change Queries
|
||
|
||
### 4.1 Track Custody Transfers During Mergers
|
||
|
||
**Use Case**: Which collections were transferred when two organizations merged?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX prov: <http://www.w3.org/ns/prov#>
|
||
|
||
SELECT ?collection ?collectionName ?oldUnit ?newUnit ?transferDate ?changeEvent
|
||
WHERE {
|
||
# Collection with custody history
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:custody_history ?custodyEvent .
|
||
|
||
# Custody event details
|
||
?custodyEvent custodian:previous_custodian ?oldUnit ;
|
||
custodian:new_custodian ?newUnit ;
|
||
custodian:transfer_date ?transferDate ;
|
||
prov:wasInformedBy ?changeEvent .
|
||
|
||
# Change event = MERGER
|
||
?changeEvent a custodian:OrganizationalChangeEvent ;
|
||
custodian:change_type "MERGER" .
|
||
}
|
||
ORDER BY ?transferDate ?collectionName
|
||
```
|
||
|
||
**Expected Result** (from test data merger scenario):
|
||
| collection | collectionName | oldUnit | newUnit | transferDate | changeEvent |
|
||
|------------|----------------|---------|---------|--------------|-------------|
|
||
| `hc/collection/rm-paintings-conservation-records` | Conservation Treatment Records | `hc/org-unit/rm-paintings-conservation-pre-2013` | `hc/org-unit/rm-conservation-division-post-2013` | 2013-03-01 | `hc/event/rm-conservation-merger-2013` |
|
||
|
||
**Explanation**: Three-way join:
|
||
1. Collection → custody history
|
||
2. Custody event → old/new units + transfer date
|
||
3. Custody event → organizational change event (filtered by MERGER type)
|
||
|
||
Uses `prov:wasInformedBy` to link custody transfers to organizational changes.
|
||
|
||
---
|
||
|
||
### 4.2 Find Staff Affected by Restructuring
|
||
|
||
**Use Case**: Which staff members changed units during a reorganization?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?person ?oldUnit ?newUnit ?changeDate ?changeType
|
||
WHERE {
|
||
# Staff with unit affiliation
|
||
?person a custodian:PersonObservation ;
|
||
custodian:unit_affiliation ?newUnit .
|
||
|
||
# New unit has organizational change history
|
||
?newUnit custodian:organizational_history ?changeEvent .
|
||
|
||
?changeEvent custodian:change_type ?changeType ;
|
||
custodian:change_date ?changeDate ;
|
||
custodian:previous_organization ?oldUnit .
|
||
|
||
# Filter for staff employed before change date
|
||
?person custodian:employment_start_date ?startDate .
|
||
FILTER(?startDate <= ?changeDate)
|
||
|
||
# Filter for restructuring events
|
||
FILTER(?changeType IN ("MERGER", "REORGANIZATION", "SPLIT"))
|
||
}
|
||
ORDER BY ?changeDate ?person
|
||
```
|
||
|
||
**Expected Result**: Staff who were transferred between units during mergers/reorganizations.
|
||
|
||
**Explanation**: Temporal logic:
|
||
- Staff employment start date ≤ change date (they were there before the change)
|
||
- Unit's organizational history contains restructuring event
|
||
- Links person to previous/new organizational unit
|
||
|
||
---
|
||
|
||
### 4.3 Timeline of Organizational Changes
|
||
|
||
**Use Case**: Show chronological history of all organizational changes for an institution.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?changeDate ?changeType ?description ?affectedUnit ?resultingUnit
|
||
WHERE {
|
||
# All organizational change events
|
||
?event a custodian:OrganizationalChangeEvent ;
|
||
custodian:change_date ?changeDate ;
|
||
custodian:change_type ?changeType ;
|
||
custodian:change_description ?description .
|
||
|
||
# Units affected by change
|
||
OPTIONAL { ?event custodian:previous_organization ?affectedUnit }
|
||
OPTIONAL { ?event custodian:new_organization ?resultingUnit }
|
||
|
||
# Filter by institution
|
||
FILTER(CONTAINS(STR(?event), "nl-rm"))
|
||
}
|
||
ORDER BY ?changeDate
|
||
```
|
||
|
||
**Expected Result**: Chronological list of mergers, reorganizations, splits, etc.
|
||
|
||
**Explanation**: Retrieves all `OrganizationalChangeEvent` instances filtered by institution identifier (here: Rijksmuseum "nl-rm"). Uses OPTIONAL for affected/resulting units (not all change types have both).
|
||
|
||
---
|
||
|
||
### 4.4 Collections Impacted by Unit Dissolution
|
||
|
||
**Use Case**: When a department closed, which collections were affected and where did they go?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?dissolvedUnit ?collection ?collectionName ?newUnit ?dissolutionDate
|
||
WHERE {
|
||
# Dissolved unit
|
||
?dissolvedUnit a custodian:OrganizationalStructure ;
|
||
custodian:valid_to ?dissolutionDate .
|
||
|
||
# Collections that were managed by dissolved unit
|
||
?collection custodian:managing_unit ?newUnit ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:custody_history ?custodyEvent .
|
||
|
||
# Custody event shows transfer from dissolved unit
|
||
?custodyEvent custodian:previous_custodian ?dissolvedUnit ;
|
||
custodian:new_custodian ?newUnit ;
|
||
custodian:transfer_date ?dissolutionDate .
|
||
}
|
||
ORDER BY ?dissolutionDate ?collectionName
|
||
```
|
||
|
||
**Expected Result**: Collections transferred when a unit closed (valid_to date ≠ null).
|
||
|
||
**Explanation**: Identifies closed units (valid_to is set), then traces collections via custody history to find what was transferred and where.
|
||
|
||
---
|
||
|
||
## 5. Validation Queries (SPARQL)
|
||
|
||
These queries implement the 5 validation rules from Phase 5 in SPARQL.
|
||
|
||
### 5.1 Temporal Consistency: Collection Managed Before Unit Exists
|
||
|
||
**Use Case**: Find collections with managing_unit temporal inconsistencies.
|
||
|
||
**Validation Rule**: Collection's `valid_from` must be ≥ managing unit's `valid_from`.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?collectionValidFrom ?unit ?unitName ?unitValidFrom
|
||
WHERE {
|
||
# Collection with managing unit
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:managing_unit ?unit ;
|
||
custodian:valid_from ?collectionValidFrom .
|
||
|
||
?unit custodian:unit_name ?unitName ;
|
||
custodian:valid_from ?unitValidFrom .
|
||
|
||
# VIOLATION: Collection starts before unit exists
|
||
FILTER(?collectionValidFrom < ?unitValidFrom)
|
||
}
|
||
ORDER BY ?collectionValidFrom
|
||
```
|
||
|
||
**Expected Result**: Empty (no violations) or list of temporally inconsistent collections.
|
||
|
||
**Explanation**: Implements Rule 1 from Phase 5 validation framework. Finds collections where custody begins before the managing unit was established.
|
||
|
||
---
|
||
|
||
### 5.2 Bidirectional Consistency: Missing Inverse Relationship
|
||
|
||
**Use Case**: Find collections that reference a managing unit, but the unit doesn't reference them back.
|
||
|
||
**Validation Rule**: If collection.managing_unit = unit, then unit.managed_collections must include collection.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?unit ?unitName
|
||
WHERE {
|
||
# Collection references unit
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:managing_unit ?unit .
|
||
|
||
?unit custodian:unit_name ?unitName .
|
||
|
||
# VIOLATION: Unit does NOT reference collection back
|
||
FILTER NOT EXISTS {
|
||
?unit custodian:managed_collections ?collection
|
||
}
|
||
}
|
||
ORDER BY ?unitName ?collectionName
|
||
```
|
||
|
||
**Expected Result**: Empty (no violations) or list of broken bidirectional relationships.
|
||
|
||
**Explanation**: Implements Rule 2 from Phase 5. Uses `FILTER NOT EXISTS` to find missing inverse relationships.
|
||
|
||
---
|
||
|
||
### 5.3 Custody Transfer Continuity Check
|
||
|
||
**Use Case**: Find collections with gaps or overlaps in custody history.
|
||
|
||
**Validation Rule**: Custody end date of previous unit = custody start date of new unit.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?collection ?collectionName ?prevUnit ?prevEndDate ?newUnit ?newStartDate ?gap
|
||
WHERE {
|
||
# Collection with custody history
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:custody_history ?event1 ;
|
||
custodian:custody_history ?event2 .
|
||
|
||
# First custody period
|
||
?event1 custodian:new_custodian ?prevUnit ;
|
||
custodian:transfer_date ?prevEndDate .
|
||
|
||
# Second custody period (chronologically after)
|
||
?event2 custodian:new_custodian ?newUnit ;
|
||
custodian:transfer_date ?newStartDate .
|
||
|
||
FILTER(?newStartDate > ?prevEndDate)
|
||
|
||
# Calculate gap in days
|
||
BIND((xsd:date(?newStartDate) - xsd:date(?prevEndDate)) AS ?gap)
|
||
|
||
# VIOLATION: Gap > 1 day
|
||
FILTER(?gap > 1)
|
||
}
|
||
ORDER BY ?collection ?prevEndDate
|
||
```
|
||
|
||
**Expected Result**: Collections with custody gaps (e.g., 30 days between transfers).
|
||
|
||
**Explanation**: Implements Rule 3 from Phase 5. Identifies discontinuities in custody chain using date arithmetic.
|
||
|
||
---
|
||
|
||
### 5.4 Staff-Unit Temporal Consistency
|
||
|
||
**Use Case**: Find staff employed before their unit was established.
|
||
|
||
**Validation Rule**: Staff `employment_start_date` must be ≥ unit's `valid_from`.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?person ?role ?employmentStart ?unit ?unitName ?unitValidFrom
|
||
WHERE {
|
||
# Staff with unit affiliation
|
||
?person a custodian:PersonObservation ;
|
||
custodian:staff_role ?role ;
|
||
custodian:unit_affiliation ?unit ;
|
||
custodian:employment_start_date ?employmentStart .
|
||
|
||
?unit custodian:unit_name ?unitName ;
|
||
custodian:valid_from ?unitValidFrom .
|
||
|
||
# VIOLATION: Employment starts before unit exists
|
||
FILTER(?employmentStart < ?unitValidFrom)
|
||
}
|
||
ORDER BY ?unitValidFrom ?employmentStart
|
||
```
|
||
|
||
**Expected Result**: Empty (no violations) or list of temporally inconsistent staff records.
|
||
|
||
**Explanation**: Implements Rule 4 from Phase 5. Analogous to collection-unit temporal check but for staff.
|
||
|
||
---
|
||
|
||
### 5.5 Staff-Unit Bidirectional Consistency
|
||
|
||
**Use Case**: Find staff who reference a unit, but the unit doesn't list them as members.
|
||
|
||
**Validation Rule**: If person.unit_affiliation = unit, then unit.staff_members must include person.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?person ?role ?unit ?unitName
|
||
WHERE {
|
||
# Person references unit
|
||
?person a custodian:PersonObservation ;
|
||
custodian:staff_role ?role ;
|
||
custodian:unit_affiliation ?unit .
|
||
|
||
?unit custodian:unit_name ?unitName .
|
||
|
||
# VIOLATION: Unit does NOT list person as member
|
||
FILTER NOT EXISTS {
|
||
?unit org:hasMember ?person
|
||
}
|
||
}
|
||
ORDER BY ?unitName ?role
|
||
```
|
||
|
||
**Expected Result**: Empty (no violations) or list of broken staff-unit relationships.
|
||
|
||
**Explanation**: Implements Rule 5 from Phase 5. Uses `org:hasMember` (same as `custodian:staff_members`).
|
||
|
||
---
|
||
|
||
## 6. Advanced Temporal Queries
|
||
|
||
### 6.1 Point-in-Time Snapshot
|
||
|
||
**Use Case**: Reconstruct organizational state at a specific historical date (e.g., 2015-06-01).
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?unit ?unitName ?collection ?collectionName ?staff ?staffRole
|
||
WHERE {
|
||
# Units that existed on 2015-06-01
|
||
?unit a custodian:OrganizationalStructure ;
|
||
custodian:unit_name ?unitName ;
|
||
custodian:valid_from ?unitValidFrom .
|
||
|
||
OPTIONAL { ?unit custodian:valid_to ?unitValidTo }
|
||
|
||
FILTER(?unitValidFrom <= "2015-06-01"^^xsd:date)
|
||
FILTER(!BOUND(?unitValidTo) || ?unitValidTo >= "2015-06-01"^^xsd:date)
|
||
|
||
# Collections managed on that date
|
||
OPTIONAL {
|
||
?unit custodian:managed_collections ?collection .
|
||
?collection custodian:collection_name ?collectionName ;
|
||
custodian:valid_from ?collectionValidFrom .
|
||
|
||
OPTIONAL { ?collection custodian:valid_to ?collectionValidTo }
|
||
|
||
FILTER(?collectionValidFrom <= "2015-06-01"^^xsd:date)
|
||
FILTER(!BOUND(?collectionValidTo) || ?collectionValidTo >= "2015-06-01"^^xsd:date)
|
||
}
|
||
|
||
# Staff employed on that date
|
||
OPTIONAL {
|
||
?unit org:hasMember ?staff .
|
||
?staff custodian:staff_role ?staffRole ;
|
||
custodian:employment_start_date ?employmentStart .
|
||
|
||
OPTIONAL { ?staff custodian:employment_end_date ?employmentEnd }
|
||
|
||
FILTER(?employmentStart <= "2015-06-01"^^xsd:date)
|
||
FILTER(!BOUND(?employmentEnd) || ?employmentEnd >= "2015-06-01"^^xsd:date)
|
||
}
|
||
}
|
||
ORDER BY ?unitName ?collectionName ?staffRole
|
||
```
|
||
|
||
**Expected Result**: Complete snapshot of units, collections, and staff on 2015-06-01.
|
||
|
||
**Explanation**: Uses temporal overlap logic across three entity types (units, collections, staff) to reconstruct past state. OPTIONAL joins prevent missing data from excluding entire record.
|
||
|
||
---
|
||
|
||
### 6.2 Change Frequency Analysis
|
||
|
||
**Use Case**: Which units have the most organizational changes?
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?unit ?unitName (COUNT(?changeEvent) AS ?changeCount)
|
||
WHERE {
|
||
?unit a custodian:OrganizationalStructure ;
|
||
custodian:unit_name ?unitName ;
|
||
custodian:organizational_history ?changeEvent .
|
||
}
|
||
GROUP BY ?unit ?unitName
|
||
ORDER BY DESC(?changeCount)
|
||
```
|
||
|
||
**Expected Result**: Units ranked by number of reorganizations.
|
||
|
||
**Explanation**: Aggregates `organizational_history` events per unit to identify frequently restructured departments.
|
||
|
||
---
|
||
|
||
### 6.3 Collection Provenance Chain
|
||
|
||
**Use Case**: Trace complete custody history of a collection from founding to present.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX prov: <http://www.w3.org/ns/prov#>
|
||
|
||
SELECT ?collection ?collectionName ?custodian ?transferDate ?changeEvent
|
||
WHERE {
|
||
<https://nde.nl/ontology/hc/collection/rm-dutch-paintings>
|
||
custodian:collection_name ?collectionName ;
|
||
custodian:custody_history ?custodyEvent .
|
||
|
||
?custodyEvent custodian:new_custodian ?custodian ;
|
||
custodian:transfer_date ?transferDate .
|
||
|
||
OPTIONAL {
|
||
?custodyEvent prov:wasInformedBy ?changeEvent .
|
||
?changeEvent custodian:change_description ?changeDescription
|
||
}
|
||
|
||
BIND(<https://nde.nl/ontology/hc/collection/rm-dutch-paintings> AS ?collection)
|
||
}
|
||
ORDER BY ?transferDate
|
||
```
|
||
|
||
**Expected Result**: Chronological list of all custodians (organizational units) that managed the collection.
|
||
|
||
**Explanation**: Retrieves all custody transfer events ordered by date, creating a provenance chain. Links to organizational change events when custody transfers were caused by restructuring.
|
||
|
||
---
|
||
|
||
### 6.4 Staff Tenure Analysis
|
||
|
||
**Use Case**: Calculate average staff tenure by role.
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
|
||
SELECT ?role (AVG(?tenureYears) AS ?avgTenure) (COUNT(?person) AS ?staffCount)
|
||
WHERE {
|
||
?person a custodian:PersonObservation ;
|
||
custodian:staff_role ?role ;
|
||
custodian:employment_start_date ?startDate .
|
||
|
||
OPTIONAL { ?person custodian:employment_end_date ?endDate }
|
||
|
||
# Calculate tenure (end date or current date)
|
||
BIND(IF(BOUND(?endDate), ?endDate, NOW()) AS ?effectiveEndDate)
|
||
BIND((YEAR(?effectiveEndDate) - YEAR(?startDate)) AS ?tenureYears)
|
||
}
|
||
GROUP BY ?role
|
||
ORDER BY DESC(?avgTenure)
|
||
```
|
||
|
||
**Expected Result**: Roles ranked by average years of employment.
|
||
|
||
**Explanation**: Calculates tenure using start/end dates (or current date if still employed). Uses aggregation to compute averages per role.
|
||
|
||
---
|
||
|
||
### 6.5 Organizational Complexity Score
|
||
|
||
**Use Case**: Measure complexity of organizational structure (units, collections, staff).
|
||
|
||
```sparql
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
PREFIX org: <http://www.w3.org/ns/org#>
|
||
|
||
SELECT ?custodian
|
||
(COUNT(DISTINCT ?unit) AS ?unitCount)
|
||
(COUNT(DISTINCT ?collection) AS ?collectionCount)
|
||
(COUNT(DISTINCT ?staff) AS ?staffCount)
|
||
((?unitCount + ?collectionCount + ?staffCount) AS ?complexityScore)
|
||
WHERE {
|
||
# Units
|
||
?unit a custodian:OrganizationalStructure ;
|
||
custodian:refers_to_custodian ?custodian .
|
||
|
||
# Collections
|
||
OPTIONAL {
|
||
?collection a custodian:CustodianCollection ;
|
||
custodian:refers_to_custodian ?custodian
|
||
}
|
||
|
||
# Staff
|
||
OPTIONAL {
|
||
?staff a custodian:PersonObservation .
|
||
?unit org:hasMember ?staff
|
||
}
|
||
}
|
||
GROUP BY ?custodian
|
||
ORDER BY DESC(?complexityScore)
|
||
```
|
||
|
||
**Expected Result**: Institutions ranked by organizational complexity (total entities).
|
||
|
||
**Explanation**: Aggregates distinct units, collections, and staff per custodian to create a simple complexity metric. Can be weighted differently (e.g., staff count × 2).
|
||
|
||
---
|
||
|
||
## Usage Examples
|
||
|
||
### Execute Query on RDF Triple Store
|
||
|
||
**Using Apache Jena Fuseki**:
|
||
|
||
```bash
|
||
# Load RDF data
|
||
tdbloader2 --loc=/path/to/tdb custodian_data.ttl
|
||
|
||
# Start Fuseki server
|
||
fuseki-server --loc=/path/to/tdb --port=3030 /custodian
|
||
|
||
# Execute query via HTTP
|
||
curl -X POST http://localhost:3030/custodian/sparql \
|
||
--data-urlencode "query=$(cat query.sparql)"
|
||
```
|
||
|
||
**Using Python rdflib**:
|
||
|
||
```python
|
||
from rdflib import Graph
|
||
|
||
# Load RDF data
|
||
g = Graph()
|
||
g.parse("custodian_data.ttl", format="turtle")
|
||
|
||
# Execute SPARQL query
|
||
query = """
|
||
PREFIX custodian: <https://nde.nl/ontology/hc/custodian/>
|
||
SELECT ?collection ?collectionName ?unit
|
||
WHERE {
|
||
?collection custodian:collection_name ?collectionName ;
|
||
custodian:managing_unit ?unit .
|
||
}
|
||
"""
|
||
|
||
results = g.query(query)
|
||
for row in results:
|
||
print(f"{row.collectionName} → {row.unit}")
|
||
```
|
||
|
||
---
|
||
|
||
## Query Optimization Tips
|
||
|
||
### 1. Use Property Paths Sparingly
|
||
Property paths (e.g., `?a custodian:unit*/custodian:parent ?b`) are powerful but slow. Use explicit triple patterns when possible.
|
||
|
||
### 2. Filter Early
|
||
Place `FILTER` clauses close to the triple patterns they filter to reduce intermediate results.
|
||
|
||
```sparql
|
||
# GOOD - Filter immediately after relevant triple
|
||
?person custodian:staff_role ?role .
|
||
FILTER(?role = "CURATOR")
|
||
|
||
# BAD - Filter at the end after many joins
|
||
?person custodian:staff_role ?role .
|
||
# ... 10 more triple patterns ...
|
||
FILTER(?role = "CURATOR")
|
||
```
|
||
|
||
### 3. Use OPTIONAL for Sparse Data
|
||
Collections may not always have managing units. Use OPTIONAL to avoid excluding entire records:
|
||
|
||
```sparql
|
||
OPTIONAL { ?collection custodian:managing_unit ?unit }
|
||
```
|
||
|
||
### 4. Limit Result Sets
|
||
Add `LIMIT` for exploratory queries:
|
||
|
||
```sparql
|
||
SELECT ?collection ?collectionName
|
||
WHERE { ... }
|
||
LIMIT 100
|
||
```
|
||
|
||
### 5. Index Temporal Properties
|
||
For large datasets, ensure triple stores index date properties (`valid_from`, `valid_to`, `employment_start_date`, etc.) for faster temporal queries.
|
||
|
||
---
|
||
|
||
## Testing Queries Against Test Data
|
||
|
||
To verify these queries work correctly:
|
||
|
||
1. **Convert YAML to RDF**:
|
||
```bash
|
||
linkml-convert -s schemas/20251121/linkml/01_custodian_name_modular.yaml \
|
||
-t rdf \
|
||
schemas/20251121/examples/collection_department_integration_examples.yaml \
|
||
> test_data.ttl
|
||
```
|
||
|
||
2. **Load into Triple Store** (e.g., Apache Jena Fuseki or GraphDB).
|
||
|
||
3. **Execute Queries** via SPARQL endpoint or `rdflib`.
|
||
|
||
4. **Verify Expected Results** match test data from `collection_department_integration_examples.yaml`.
|
||
|
||
---
|
||
|
||
## Next Steps
|
||
|
||
### Phase 7: SHACL Shapes
|
||
Convert validation queries (Section 5) into SHACL constraints for automatic RDF validation.
|
||
|
||
### Phase 8: LinkML Schema Constraints
|
||
Embed temporal validation rules directly into LinkML schema using `minimum_value`, `pattern`, and custom validators.
|
||
|
||
### Phase 9: Real-World Integration
|
||
Apply queries to production heritage institution data (ISIL registries, museum databases, archival finding aids).
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- **Schema**: `schemas/20251121/linkml/01_custodian_name_modular.yaml` (v0.7.0)
|
||
- **Test Data**: `schemas/20251121/examples/collection_department_integration_examples.yaml`
|
||
- **RDF Output**: `schemas/20251121/rdf/01_custodian_name_modular_20251122_205111.owl.ttl`
|
||
- **Validation Rules**: `docs/VALIDATION_RULES.md`
|
||
- **SPARQL 1.1 Spec**: https://www.w3.org/TR/sparql11-query/
|
||
- **W3C PROV-O**: https://www.w3.org/TR/prov-o/
|
||
- **W3C Org Ontology**: https://www.w3.org/TR/vocab-org/
|
||
|
||
---
|
||
|
||
**Document Version**: 1.0.0
|
||
**Schema Version**: v0.7.0
|
||
**Last Updated**: 2025-11-22
|
||
**Total Queries**: 31 (5 staff + 5 collection + 4 combined + 4 org change + 5 validation + 8 advanced)
|
||
|