Compare commits

...

5 commits

Author SHA1 Message Date
kempersc
e922ff3640 Refactor UML module selection UI and enhance schema mappings across various YAML files
All checks were successful
Deploy Frontend / build-and-deploy (push) Successful in 2m3s
2026-02-20 12:05:37 +01:00
kempersc
2fd6f491ef Add UML density section with display mode options and module picker 2026-02-19 13:00:41 +01:00
kempersc
ee4f31ea1b Update generated timestamp in manifest.json for accuracy 2026-02-18 21:44:27 +01:00
kempersc
3e540832b7 Add new slots for payment context and update manifest with generated timestamp 2026-02-18 21:43:53 +01:00
kempersc
b34a8ac777 Update LinkML manifest generation timestamp and enhance MappingExplorer with schema validation
- Updated the generated timestamp in the LinkML manifest file.
- Added new CSS styles for schema status and warning indicators in MappingExplorer.
- Implemented schema validation logic in MappingExplorer to check field validity against the loaded LinkML schema.
- Enhanced the UI to display schema status and warnings for invalid fields in the mapping interface.
- Refactored field details panel to show schema validity messages for target classes and slots.
- Updated various target classes and slots in custodian data mappings for consistency and accuracy.
2026-02-18 18:44:03 +01:00
89 changed files with 6043 additions and 3481 deletions

View file

@ -6,8 +6,9 @@
"scripts": { "scripts": {
"sync-schemas": "rsync -av --delete --exclude=\"archive/\" ../schemas/20251121/linkml/ public/schemas/20251121/linkml/", "sync-schemas": "rsync -av --delete --exclude=\"archive/\" ../schemas/20251121/linkml/ public/schemas/20251121/linkml/",
"generate-manifest": "node scripts/generate-schema-manifest.cjs", "generate-manifest": "node scripts/generate-schema-manifest.cjs",
"dev": "pnpm run sync-schemas && pnpm run generate-manifest && vite", "generate-uml": "node scripts/generate-ontology-uml.cjs",
"build": "pnpm run sync-schemas && pnpm run generate-manifest && tsc -b && vite build", "dev": "pnpm run sync-schemas && pnpm run generate-manifest && pnpm run generate-uml && vite",
"build": "pnpm run sync-schemas && pnpm run generate-manifest && pnpm run generate-uml && tsc -b && vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview", "preview": "vite preview",
"test": "vitest", "test": "vitest",

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ imports:
classes: classes:
Curator: Curator:
is_a: StaffRole is_a: StaffRole
class_uri: schema:curator class_uri: hc:Curator
description: | description: |
Curator responsible for collections research, acquisition, and exhibitions. Curator responsible for collections research, acquisition, and exhibitions.
@ -41,8 +41,7 @@ classes:
- Object interpretation and labeling - Object interpretation and labeling
- Loan negotiations - Loan negotiations
exact_mappings: exact_mappings:
- schema:curator - wikidata:Q674426
- wikidata:Q674426
slot_usage: slot_usage:
role_category: role_category:
ifabsent: string(CURATORIAL) ifabsent: string(CURATORIAL)
@ -53,8 +52,8 @@ classes:
range: TemplateSpecificityScores range: TemplateSpecificityScores
inlined: true inlined: true
slots: slots:
- specificity_annotation - specificity_annotation
- template_specificity - template_specificity
CollectionsManager: CollectionsManager:
is_a: StaffRole is_a: StaffRole
description: | description: |
@ -80,7 +79,7 @@ classes:
- Rights and reproductions - Rights and reproductions
- Insurance and valuation coordination - Insurance and valuation coordination
exact_mappings: exact_mappings:
- wikidata:Q65963513 - wikidata:Q65963513
slot_usage: slot_usage:
role_category: role_category:
ifabsent: string(CURATORIAL) ifabsent: string(CURATORIAL)
@ -91,8 +90,8 @@ classes:
range: TemplateSpecificityScores range: TemplateSpecificityScores
inlined: true inlined: true
slots: slots:
- specificity_annotation - specificity_annotation
- template_specificity - template_specificity
Conservator: Conservator:
is_a: StaffRole is_a: StaffRole
description: | description: |

View file

@ -7,6 +7,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
gn: http://www.geonames.org/ontology# gn: http://www.geonames.org/ontology#
rdac: http://rdaregistry.info/Elements/c/
wdt: http://www.wikidata.org/prop/direct/ wdt: http://www.wikidata.org/prop/direct/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
prov: http://www.w3.org/ns/prov# prov: http://www.w3.org/ns/prov#
@ -58,6 +59,7 @@ classes:
close_mappings: close_mappings:
- crm:E53_Place - crm:E53_Place
- gn:Feature - gn:Feature
- rdac:C10009 # RDA Registry: Place (RDA Classes)
slots: slots:
- has_label - has_label
- has_name - has_name

View file

@ -1,12 +1,12 @@
{ {
"generated": "2026-02-18T11:39:46.457Z", "generated": "2026-02-18T20:43:54.475Z",
"schemaRoot": "/schemas/20251121/linkml", "schemaRoot": "/schemas/20251121/linkml",
"totalFiles": 2183, "totalFiles": 2187,
"categoryCounts": { "categoryCounts": {
"main": 4, "main": 4,
"class": 1377, "class": 1377,
"enum": 158, "enum": 158,
"slot": 640, "slot": 644,
"module": 4 "module": 4
}, },
"categories": [ "categories": [
@ -10387,6 +10387,21 @@
"path": "modules/slots/owned_by.yaml", "path": "modules/slots/owned_by.yaml",
"category": "slot" "category": "slot"
}, },
{
"name": "paid_amount",
"path": "modules/slots/paid_amount.yaml",
"category": "slot"
},
{
"name": "paid_from",
"path": "modules/slots/paid_from.yaml",
"category": "slot"
},
{
"name": "paid_to",
"path": "modules/slots/paid_to.yaml",
"category": "slot"
},
{ {
"name": "part_of", "name": "part_of",
"path": "modules/slots/part_of.yaml", "path": "modules/slots/part_of.yaml",
@ -10847,6 +10862,11 @@
"path": "modules/slots/transferred.yaml", "path": "modules/slots/transferred.yaml",
"category": "slot" "category": "slot"
}, },
{
"name": "transferred_from",
"path": "modules/slots/transferred_from.yaml",
"category": "slot"
},
{ {
"name": "transferred_to", "name": "transferred_to",
"path": "modules/slots/transferred_to.yaml", "path": "modules/slots/transferred_to.yaml",

View file

@ -91,7 +91,7 @@ classes:
- crm:E8_Acquisition - crm:E8_Acquisition
close_mappings: close_mappings:
- prov:Activity - prov:Activity
- schema:AcquireAction - schema:TradeAction
related_mappings: related_mappings:
- rico:Event - rico:Event
- dwc:Event - dwc:Event

View file

@ -17,7 +17,9 @@ imports:
- ../slots/temporal_extent - ../slots/temporal_extent
classes: classes:
Agreement: Agreement:
class_uri: schema:Contract class_uri: hc:Agreement
close_mappings:
- schema:Thing
description: >- description: >-
Formal arrangement between two or more parties establishing mutual Formal arrangement between two or more parties establishing mutual
obligations, rights, or expectations, typically documented in writing obligations, rights, or expectations, typically documented in writing

View file

@ -17,7 +17,9 @@ imports:
- ../slots/categorized_as - ../slots/categorized_as
classes: classes:
Animal: Animal:
class_uri: schema:Animal class_uri: wd:Q729
exact_mappings:
- wikidata:Q729
description: >- description: >-
Multicellular living organism characterized by heterotrophic nutrition, Multicellular living organism characterized by heterotrophic nutrition,
motility at some life stage, and sensory response capacity. motility at some life stage, and sensory response capacity.
@ -83,10 +85,7 @@ classes:
- zoological - zoological
- wildlife - wildlife
- fauna - fauna
exact_mappings:
- schema:Animal
broad_mappings: broad_mappings:
- wd:Q729
- schema:Thing - schema:Thing
slots: slots:
- has_label - has_label
@ -103,7 +102,7 @@ classes:
Preserved from prior description: Preserved from prior description:
**Ontological Alignment**: **Ontological Alignment**:
- `schema:Animal`: Generic animal class. - `wikidata:Q729`: Animal (kingdom Animalia) - Wikidata entity for animals.
- 'Preserved from prior description: Living organism belonging to the kingdom Animalia, characterized by voluntary movement, consumption of organic material, and typically sensory and nervous systems, relevant to natural history collections and zoological specimens.' - 'Preserved from prior description: Living organism belonging to the kingdom Animalia, characterized by voluntary movement, consumption of organic material, and typically sensory and nervous systems, relevant to natural history collections and zoological specimens.'
annotations: annotations:
specificity_score: "0.2" specificity_score: "0.2"

View file

@ -42,7 +42,7 @@ classes:
description: Specialized auction house description: Specialized auction house
close_mappings: close_mappings:
- schema:Organization - schema:Organization
- schema:AuctionHouse - schema:LocalBusiness
broad_mappings: broad_mappings:
- skos:Concept - skos:Concept
structured_aliases: structured_aliases:

View file

@ -15,7 +15,9 @@ prefixes:
default_prefix: hc default_prefix: hc
classes: classes:
AvailabilityStatus: AvailabilityStatus:
class_uri: schema:Availability class_uri: hc:AvailabilityStatus
broad_mappings:
- schema:ItemAvailability
description: >- description: >-
Availability state of a resource, service, or feature, indicating whether Availability state of a resource, service, or feature, indicating whether
something is currently available for use with optional temporal validity something is currently available for use with optional temporal validity

View file

@ -12,6 +12,7 @@ prefixes:
gbif: http://rs.gbif.org/terms/ gbif: http://rs.gbif.org/terms/
aat: http://vocab.getty.edu/aat/ aat: http://vocab.getty.edu/aat/
imports: imports:
- ./ExhibitedObject
- linkml:types - linkml:types
- ../enums/PreservationMethodEnum - ../enums/PreservationMethodEnum
- ../metadata - ../metadata
@ -47,6 +48,7 @@ imports:
default_prefix: hc default_prefix: hc
classes: classes:
BiologicalObject: BiologicalObject:
is_a: ExhibitedObject
class_uri: crm:E20_Biological_Object class_uri: crm:E20_Biological_Object
description: >- description: >-
Natural specimen or organism-derived item held in a heritage collection, with associated taxonomic identification and preservation metadata. Natural specimen or organism-derived item held in a heritage collection, with associated taxonomic identification and preservation metadata.
@ -397,29 +399,64 @@ classes:
in_language: zh in_language: zh
- literal_form: value: https://nde.nl/ontology/hc/taxon/raphus-cucullatus broad_mappings:
- crm:E20_Biological_Object
close_mappings:
- dwc:Occurrence
- gbif:Specimen
related_mappings:
- crm:E19_Physical_Object
- crm:E22_Human-Made_Object
- schema:Taxon
predicate: EXACT_SYNONYM slots:
- identified_by
- has_label
- has_name
- has_rank
- has_authority
- commented_on
- identified_through
- has_specimen
- symbolize
- has_status
- has_gender
- has_stage
- contain
- has_quantity
- has_method
- has_detail
- prepared_on
- prepared_by
- acquired_through
- in_place
- describe
- acquired_by
- has_habitat
- has_hypernym
- listed_in
- has_provenance
- has_type
in_language: zh slot_usage:
# range: string # uriorcurie identified_by:
multivalued: true multivalued: true
inlined: false # Fixed invalid inline for primitive type inlined: false # Fixed invalid inline for primitive type
inlined_as_list: false # Fixed invalid inline for primitive type inlined_as_list: false # Fixed invalid inline for primitive type
required: false required: false
any_of: any_of:
- range: FieldNumber - range: FieldNumber
- range: BOLDIdentifier - range: BOLDIdentifier
- range: WikiDataIdentifier - range: WikiDataIdentifier
- range: string # uriorcurie - range: string # uriorcurie
examples: examples:
- value: - value:
has_type: FieldNumber has_type: FieldNumber
- value: - value:
id: https://nde.nl/ontology/hc/bold-id/NLNAT001-21 id: https://nde.nl/ontology/hc/bold-id/NLNAT001-21
has_type: BOLDIdentifier has_type: BOLDIdentifier
- value: - value:
has_type: WikiDataIdentifier has_type: WikiDataIdentifier
has_label: has_label:
range: TaxonName range: TaxonName
inlined: true inlined: true

View file

@ -5,6 +5,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
rec: https://w3id.org/rec#
qudt: http://qudt.org/schema/qudt/ qudt: http://qudt.org/schema/qudt/
default_prefix: hc default_prefix: hc
imports: imports:
@ -15,7 +16,7 @@ imports:
classes: classes:
Classroom: Classroom:
is_a: Facility is_a: Facility
class_uri: schema:Classroom class_uri: rec:Classroom
description: >- description: >-
Instructional room entity for teaching, workshops, and guided learning sessions within institutional premises. Instructional room entity for teaching, workshops, and guided learning sessions within institutional premises.
alt_descriptions: alt_descriptions:
@ -42,7 +43,7 @@ classes:
examples: examples:
- value: 'unit_type: CLASSROOM ' - value: 'unit_type: CLASSROOM '
exact_mappings: exact_mappings:
- schema:Classroom - rec:Classroom
close_mappings: close_mappings:
- schema:Room - schema:Room
- schema:Place - schema:Place

View file

@ -54,8 +54,6 @@ classes:
required: false required: false
close_mappings: close_mappings:
- dcterms:conformsTo - dcterms:conformsTo
related_mappings:
- schema:assessment
annotations: annotations:
custodian_types: '["A", "L", "M"]' custodian_types: '["A", "L", "M"]'
custodian_types_rationale: Compliance tracking is common for archives, libraries, and museums with preservation mandates. custodian_types_rationale: Compliance tracking is common for archives, libraries, and museums with preservation mandates.

View file

@ -17,7 +17,9 @@ imports:
- ../slots/has_score - ../slots/has_score
classes: classes:
Currency: Currency:
class_uri: schema:Currency class_uri: qudt:CurrencyUnit
exact_mappings:
- qudt:CurrencyUnit
description: >- description: >-
Standardized monetary unit with ISO 4217 code representation for pricing, budgeting, and financial valuation metadata. Standardized monetary unit with ISO 4217 code representation for pricing, budgeting, and financial valuation metadata.
alt_descriptions: alt_descriptions:

View file

@ -17,7 +17,9 @@ imports:
- ../slots/temporal_extent - ../slots/temporal_extent
classes: classes:
DeceasedStatus: DeceasedStatus:
class_uri: schema:DeathEvent class_uri: hc:DeceasedStatus
broad_mappings:
- schema:Event
description: >- description: >-
Structured event record for a person's death including causal, Structured event record for a person's death including causal,
temporal, and contextual attributes. temporal, and contextual attributes.
@ -38,9 +40,8 @@ classes:
- {literal_form: status kematian, in_language: id} - {literal_form: status kematian, in_language: id}
- {literal_form: 死亡状态记录, in_language: zh} - {literal_form: 死亡状态记录, in_language: zh}
exact_mappings: exact_mappings:
- schema:DeathEvent
close_mappings:
- crm:E69_Death - crm:E69_Death
close_mappings:
related_mappings: related_mappings:
- prov:End - prov:End
keywords: keywords:

View file

@ -36,195 +36,81 @@ classes:
zh: >- zh: >-
描述平台界面、操作程序或用户实施指南的技术参考资料。 描述平台界面、操作程序或用户实施指南的技术参考资料。
structured_aliases: structured_aliases:
- literal_form: documentatie - literal_form: documentatie
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: nl in_language: nl
- literal_form: technische handleiding - literal_form: technische handleiding
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: nl in_language: nl
- literal_form: Dokumentation - literal_form: Dokumentation
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: de in_language: de
- literal_form: technische Anleitung - literal_form: technische Anleitung
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: de in_language: de
- literal_form: documentation - literal_form: documentation
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: fr in_language: fr
- literal_form: guide technique - literal_form: guide technique
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: fr in_language: fr
- literal_form: documentación - literal_form: documentación
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: es in_language: es
- literal_form: guía técnica - literal_form: guía técnica
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: es in_language: es
- literal_form: التوثيق - literal_form: التوثيق
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: ar in_language: ar
- literal_form: الدليل الفني - literal_form: الدليل الفني
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: ar in_language: ar
- literal_form: dokumentasi - literal_form: dokumentasi
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: id in_language: id
- literal_form: panduan teknis - literal_form: panduan teknis
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: id in_language: id
- literal_form: 文档 - literal_form: 文档
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: 技术指南 - literal_form: 技术指南
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: documentation broad_mappings:
- schema:TechArticle
- foaf:Document
close_mappings:
- crm:E73_Information_Object
predicate: EXACT_SYNONYM slots:
- identified_by
- has_label
- has_description
- temporal_extent
in_language: zh slot_usage:
identified_by:
- literal_form: technical guide range: uri
required: true
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: API reference
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: user manual
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: operational guide
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: schema:CreativeWork
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: foaf:Document
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: schema:TechArticle
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: crm:E73_Information_Object
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: dcterms:references
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: has_label
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: has_description
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: identified_by
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: temporal_extent
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: value: https://data.rijksmuseum.nl/object-metadata/api/
predicate: EXACT_SYNONYM
in_language: zh
# range: string
examples: examples:
- value: API Reference Documentation - value: https://data.rijksmuseum.nl/object-metadata/api/
- value: Developer Integration Guide has_label:
required: true
examples:
- value: Rijksmuseum Collection API
has_description: has_description:
# range: string
examples:
- value: Complete REST API reference with endpoint specifications, authentication, and response formats.
temporal_extent:
range: TimeSpan
inlined: true
required: false required: false
examples: examples:
- value: - value: Complete REST API reference with endpoint specifications, authentication, and response formats.
begin_of_the_begin: '2015-01-01' temporal_extent:
required: false
examples:
- value:
begin_of_the_begin: '2015-01-01'
has_verbatim_value: 2015-
comments: comments:
- Generic documentation class replacing domain-specific documentation slots - Generic documentation class replacing domain-specific documentation slots
- Supports multiple documentation types (API, user, developer, system) - Supports multiple documentation types (API, user, developer, system)

View file

@ -186,19 +186,19 @@ classes:
in_language: zh in_language: zh
- literal_form: value: | - literal_form: "value: |"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: expense_type: ADMINISTRATIVE - literal_form: "expense_type: ADMINISTRATIVE"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: expense_type: PROGRAM - literal_form: "expense_type: PROGRAM"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -12,7 +12,7 @@ imports:
- ../slots/has_description - ../slots/has_description
classes: classes:
ForkliftAccess: ForkliftAccess:
class_uri: schema:AmenityFeature class_uri: schema:LocationFeatureSpecification
description: >- description: >-
Facility access feature indicating whether spaces permit forklift entry Facility access feature indicating whether spaces permit forklift entry
for logistics, handling, or collection movement. for logistics, handling, or collection movement.

View file

@ -12,7 +12,7 @@ imports:
- ../slots/has_description - ../slots/has_description
classes: classes:
HandsOnFacility: HandsOnFacility:
class_uri: schema:AmenityFeature class_uri: schema:LocationFeatureSpecification
description: >- description: >-
Amenity feature indicating availability of interactive, practical learning Amenity feature indicating availability of interactive, practical learning
or handling spaces for visitors and participants. or handling spaces for visitors and participants.

View file

@ -15,7 +15,9 @@ imports:
classes: classes:
InstitutionalRepository: InstitutionalRepository:
is_a: ArchiveOrganizationType is_a: ArchiveOrganizationType
class_uri: schema:DigitalLibrary class_uri: hc:InstitutionalRepository
broad_mappings:
- schema:Library
description: >- description: >-
Digital repository service for preserving, publishing, and providing access Digital repository service for preserving, publishing, and providing access
to scholarly output produced by an academic or research institution. to scholarly output produced by an academic or research institution.
@ -62,8 +64,6 @@ classes:
- literal_form: 机构仓储 - literal_form: 机构仓储
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
broad_mappings:
- schema:DigitalLibrary
close_mappings: close_mappings:
- skos:Concept - skos:Concept
slots: slots:

View file

@ -11,7 +11,7 @@ imports:
- ../slots/has_description - ../slots/has_description
classes: classes:
LoadingDock: LoadingDock:
class_uri: schema:AmenityFeature class_uri: schema:LocationFeatureSpecification
description: >- description: >-
Designated area for receiving and dispatching physical items through vehicular transport. Designated area for receiving and dispatching physical items through vehicular transport.
alt_descriptions: alt_descriptions:

View file

@ -11,7 +11,7 @@ imports:
- ../slots/has_description - ../slots/has_description
classes: classes:
Locker: Locker:
class_uri: schema:AmenityFeature class_uri: schema:LocationFeatureSpecification
description: >- description: >-
Secure storage compartment provided as a visitor or staff amenity for temporary personal item retention. Secure storage compartment provided as a visitor or staff amenity for temporary personal item retention.
alt_descriptions: alt_descriptions:
@ -52,7 +52,7 @@ classes:
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
broad_mappings: broad_mappings:
- schema:AmenityFeature - schema:LocationFeatureSpecification
slots: slots:
- has_description - has_description
comments: comments:

View file

@ -185,7 +185,7 @@ classes:
in_language: zh in_language: zh
- literal_form: value: | - literal_form: "value: |"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
@ -197,37 +197,37 @@ classes:
in_language: zh in_language: zh
- literal_form: has_label: Manufacturer name (String or Label) - literal_form: "has_label: Manufacturer name (String or Label)"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_url: Manufacturer website (URL) - literal_form: "has_url: Manufacturer website (URL)"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: identified_by: Unique identifier - literal_form: "identified_by: Unique identifier"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Primary**: `schema:Organization` - Schema.org organization - literal_form: "**Primary**: `schema:Organization` - Schema.org organization"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Close**: `org:Organization` - W3C ORG organization - literal_form: "**Close**: `org:Organization` - W3C ORG organization"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Related**: `prov:Agent` - PROV-O agent responsible for production - literal_form: "**Related**: `prov:Agent` - PROV-O agent responsible for production"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -174,13 +174,13 @@ classes:
in_language: zh in_language: zh
- literal_form: value: PRIMARY - literal_form: "value: PRIMARY"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: CO_ORGANIZER - literal_form: "value: CO_ORGANIZER"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
@ -192,43 +192,43 @@ classes:
in_language: zh in_language: zh
- literal_form: PRIMARY: Main organizing institution - literal_form: "PRIMARY: Main organizing institution"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: CO_ORGANIZER: Partner institution with significant organizational role - literal_form: "CO_ORGANIZER: Partner institution with significant organizational role"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: SPONSOR_ORGANIZER: Sponsor with curatorial/organizational input - literal_form: "SPONSOR_ORGANIZER: Sponsor with curatorial/organizational input"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: LENDING_INSTITUTION: Institution lending objects with exhibition involvement - literal_form: "LENDING_INSTITUTION: Institution lending objects with exhibition involvement"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: HOST_VENUE: Venue hosting a traveling exhibition - literal_form: "HOST_VENUE: Venue hosting a traveling exhibition"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Primary**: `schema:Role` - Schema.org role - literal_form: "**Primary**: `schema:Role` - Schema.org role"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Close**: `prov:Role` - PROV-O role in activity - literal_form: "**Close**: `prov:Role` - PROV-O role in activity"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -380,163 +380,163 @@ classes:
in_language: zh in_language: zh
- literal_form: value: https://nde.nl/ontology/hc/aux/kroller-muller-sculpture - literal_form: "value: https://nde.nl/ontology/hc/aux/kroller-muller-sculpture"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Kroller-Muller Beeldentuin - literal_form: "value: Kroller-Muller Beeldentuin"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Paleis Het Loo Tuinen - literal_form: "value: Paleis Het Loo Tuinen"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Archeologisch Park Matilo - literal_form: "value: Archeologisch Park Matilo"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: One of Europe's largest sculpture gardens with 160 works set in 25 hectares of park landscape within De Hoge Veluwe National Park. - literal_form: "value: One of Europe's largest sculpture gardens with 160 works set in 25 hectares of park landscape within De Hoge Veluwe National Park."
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: range: OutdoorSiteTypeEnum - literal_form: "range: OutdoorSiteTypeEnum"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: range: FeatureType - literal_form: "range: FeatureType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: SCULPTURE_GARDEN - literal_form: "value: SCULPTURE_GARDEN"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: ARCHAEOLOGICAL_SITE - literal_form: "value: ARCHAEOLOGICAL_SITE"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: FORMAL_GARDEN - literal_form: "value: FORMAL_GARDEN"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: BotanicalInstitutionClassification - literal_form: "value: BotanicalInstitutionClassification"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: ZoologicalInstitutionClassification - literal_form: "value: ZoologicalInstitutionClassification"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: 160 - literal_form: "value: 160"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: 2500 - literal_form: "value: 2500"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 25.0 - literal_form: "area_value: 25.0"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Included with museum ticket - literal_form: "has_label: Included with museum ticket"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Paved paths - literal_form: "has_label: Paved paths"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Wheelchair routes available - literal_form: "has_label: Wheelchair routes available"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 650.0 - literal_form: "area_value: 650.0"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Included with palace ticket - literal_form: "has_label: Included with palace ticket"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 3.5 - literal_form: "area_value: 3.5"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Free - literal_form: "has_label: Free"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -200,13 +200,13 @@ classes:
in_language: zh in_language: zh
- literal_form: value: hc:ArchiveOrganizationType - literal_form: "value: hc:ArchiveOrganizationType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: hc:HolySacredSiteType - literal_form: "value: hc:HolySacredSiteType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -42,7 +42,7 @@ classes:
zh: >- zh: >-
分类概念,根据分类系统中的共同特征、功能、材料或预期用途对产品或项目进行分组。 分类概念,根据分类系统中的共同特征、功能、材料或预期用途对产品或项目进行分组。
exact_mappings: exact_mappings:
- schema:Category - schema:CategoryCode
broad_mappings: broad_mappings:
- skos:Concept - skos:Concept
- schema:Thing - schema:Thing

View file

@ -13,7 +13,9 @@ imports:
- ../slots/has_description - ../slots/has_description
classes: classes:
SupervisedHandling: SupervisedHandling:
class_uri: schema:Policy class_uri: hc:SupervisedHandling
close_mappings:
- schema:Thing
description: >- description: >-
Policy mandating that access to or manipulation of materials occurs only under staff observation and guidance to ensure proper care. Policy mandating that access to or manipulation of materials occurs only under staff observation and guidance to ensure proper care.
alt_descriptions: alt_descriptions:

View file

@ -44,7 +44,6 @@ classes:
broad_mappings: broad_mappings:
- prov:Entity - prov:Entity
related_mappings: related_mappings:
- schema:Award
- crm:E7_Activity - crm:E7_Activity
- schema:Organization - schema:Organization
slots: [] slots: []

View file

@ -24,13 +24,12 @@ classes:
ar: نسخ فيديو YouTube بما في ذلك معرف الفيديو واللغة ونوع النسخ (يدوي أو مولد تلقائيًا) والنص الكامل وبيانات الاستخراج الوصفية للوصول وتحليل المحتوى. ar: نسخ فيديو YouTube بما في ذلك معرف الفيديو واللغة ونوع النسخ (يدوي أو مولد تلقائيًا) والنص الكامل وبيانات الاستخراج الوصفية للوصول وتحليل المحتوى.
id: Transkrip video YouTube termasuk ID video, bahasa, jenis transkrip (manual atau dihasilkan otomatis), teks lengkap, dan metadata ekstraksi untuk aksesibilitas dan analisis konten. id: Transkrip video YouTube termasuk ID video, bahasa, jenis transkrip (manual atau dihasilkan otomatis), teks lengkap, dan metadata ekstraksi untuk aksesibilitas dan analisis konten.
zh: YouTube视频字幕包括视频ID、语言、字幕类型手动或自动生成、 全文和提取元数据,用于无障碍访问和内容分析。 zh: YouTube视频字幕包括视频ID、语言、字幕类型手动或自动生成、 全文和提取元数据,用于无障碍访问和内容分析。
class_uri: schema:Transcript class_uri: hc:YoutubeTranscript
close_mappings: close_mappings:
- schema:Transcript - schema:MediaObject
related_mappings: related_mappings:
- oa:TextualBody - oa:TextualBody
- prov:Entity - prov:Entity
- schema:MediaObject
slots: slots:
- in_language - in_language
structured_aliases: structured_aliases:

View file

@ -573,7 +573,6 @@ enums:
SPONSORSHIP_EXHIBITION: SPONSORSHIP_EXHIBITION:
description: | description: |
Corporate or individual sponsorship of temporary exhibition. Corporate or individual sponsorship of temporary exhibition.
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
typical_benefits: | typical_benefits: |
@ -586,7 +585,6 @@ enums:
SPONSORSHIP_GALLERY: SPONSORSHIP_GALLERY:
description: | description: |
Named sponsorship of permanent gallery or wing. Named sponsorship of permanent gallery or wing.
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
custodian_types: "G, M, B, H" custodian_types: "G, M, B, H"
@ -595,7 +593,6 @@ enums:
description: | description: |
Sponsorship of institutional event (gala, lecture series, Sponsorship of institutional event (gala, lecture series,
education program). education program).
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
custodian_types: "G, L, A, M, O, R, B, E, S, H, D" custodian_types: "G, L, A, M, O, R, B, E, S, H, D"
@ -604,7 +601,6 @@ enums:
description: | description: |
Sponsorship of ongoing program (education, outreach, Sponsorship of ongoing program (education, outreach,
conservation, research). conservation, research).
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
examples: | examples: |
@ -615,7 +611,6 @@ enums:
SPONSORSHIP_DIGITIZATION: SPONSORSHIP_DIGITIZATION:
description: | description: |
Sponsorship of digitization projects for online access. Sponsorship of digitization projects for online access.
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
examples: | examples: |
@ -626,7 +621,6 @@ enums:
SPONSORSHIP_CONSERVATION: SPONSORSHIP_CONSERVATION:
description: | description: |
Sponsorship of conservation or restoration work. Sponsorship of conservation or restoration work.
meaning: schema:SponsorAction
annotations: annotations:
category: sponsorship category: sponsorship
examples: | examples: |

View file

@ -17,18 +17,13 @@ enums:
permissible_values: permissible_values:
NATIVE_BILINGUAL: NATIVE_BILINGUAL:
description: Native or bilingual proficiency description: Native or bilingual proficiency
meaning: schema:Expert
FULL_PROFESSIONAL: FULL_PROFESSIONAL:
description: Full professional proficiency description: Full professional proficiency
meaning: schema:Advanced
PROFESSIONAL_WORKING: PROFESSIONAL_WORKING:
description: Professional working proficiency description: Professional working proficiency
meaning: schema:Intermediate
LIMITED_WORKING: LIMITED_WORKING:
description: Limited working proficiency description: Limited working proficiency
meaning: schema:Intermediate
ELEMENTARY: ELEMENTARY:
description: Elementary proficiency description: Elementary proficiency
meaning: schema:Beginner
UNKNOWN: UNKNOWN:
description: Proficiency level not specified description: Proficiency level not specified

View file

@ -57,7 +57,6 @@ enums:
description: | description: |
Initial loan request submitted by borrowing institution. Initial loan request submitted by borrowing institution.
Loan is awaiting review by lending institution. Loan is awaiting review by lending institution.
meaning: schema:PendingAction
annotations: annotations:
loan_phase: "initiation" loan_phase: "initiation"
next_states: '["UNDER_REVIEW", "DECLINED", "CANCELLED"]' next_states: '["UNDER_REVIEW", "DECLINED", "CANCELLED"]'
@ -110,7 +109,6 @@ enums:
description: | description: |
Object in transit from lender to borrower. Object in transit from lender to borrower.
May involve courier accompaniment for high-value items. May involve courier accompaniment for high-value items.
meaning: schema:InTransitAction
annotations: annotations:
loan_phase: "transit" loan_phase: "transit"
next_states: '["ON_LOAN", "RETURNED"]' next_states: '["ON_LOAN", "RETURNED"]'
@ -144,7 +142,6 @@ enums:
description: | description: |
Object in transit from borrower back to lender. Object in transit from borrower back to lender.
Return journey underway. Return journey underway.
meaning: schema:InTransitAction
annotations: annotations:
loan_phase: "transit" loan_phase: "transit"
next_states: '["RETURNED"]' next_states: '["RETURNED"]'

View file

@ -23,7 +23,6 @@ enums:
meaning: schema:size meaning: schema:size
VISITOR_COUNT: VISITOR_COUNT:
description: Number of visitors (annual, daily, etc.). description: Number of visitors (annual, daily, etc.).
meaning: schema:numberOfAttendees
BUDGET_AMOUNT: BUDGET_AMOUNT:
description: Financial amount (budget, revenue, cost). description: Financial amount (budget, revenue, cost).
meaning: schema:amount meaning: schema:amount
@ -53,7 +52,6 @@ enums:
meaning: schema:numberOfItems meaning: schema:numberOfItems
CHARACTER_COUNT: CHARACTER_COUNT:
description: Number of characters in text content. description: Number of characters in text content.
meaning: schema:characterCount
WORD_COUNT: WORD_COUNT:
description: Number of words in text content. description: Number of words in text content.
meaning: schema:wordCount meaning: schema:wordCount

View file

@ -18,6 +18,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
rec: https://w3id.org/rec#
imports: imports:
- linkml:types - linkml:types
@ -34,7 +35,7 @@ enums:
# Educational spaces # Educational spaces
CLASSROOM: CLASSROOM:
description: Teaching/learning space for group instruction description: Teaching/learning space for group instruction
meaning: schema:Classroom meaning: rec:Classroom
annotations: annotations:
usage_context: education usage_context: education
typical_capacity: "20-40" typical_capacity: "20-40"

View file

@ -538,6 +538,9 @@ imports:
- ./outbound_to - ./outbound_to
- ./overlap_with - ./overlap_with
- ./owned_by - ./owned_by
- ./paid_amount
- ./paid_from
- ./paid_to
- ./part_of - ./part_of
- ./participate_in - ./participate_in
- ./performed_by - ./performed_by
@ -628,6 +631,7 @@ imports:
- ./threatened_by - ./threatened_by
- ./track - ./track
- ./transferred - ./transferred
- ./transferred_from
- ./transferred_to - ./transferred_to
- ./transmission - ./transmission
- ./transmit_through - ./transmit_through

View file

@ -31,6 +31,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -96,6 +97,7 @@ slots:
- schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically accessioning. - schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically accessioning.
related_mappings: related_mappings:
- crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of accessioning. - crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of accessioning.
- la:added_member # Linked Art extensions: member added to a Set via an Addition activity
aliases: aliases:
- objects_added - objects_added
examples: examples:

View file

@ -24,6 +24,7 @@ prefixes:
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
owl: http://www.w3.org/2002/07/owl# owl: http://www.w3.org/2002/07/owl#
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -87,6 +88,7 @@ slots:
close_mappings: close_mappings:
- owl:sameAs # W3C OWL 2 standard - Identity assertion (stronger claim than semantic equivalence). - owl:sameAs # W3C OWL 2 standard - Identity assertion (stronger claim than semantic equivalence).
- schema:sameAs # schemaorg.owl:34129-34148 - "URL unambiguously indicating the item's identity." - schema:sameAs # schemaorg.owl:34129-34148 - "URL unambiguously indicating the item's identity."
- la:equivalent # Linked Art extensions: equivalent instance (skos:exactMatch-like without Concept inference)
aliases: aliases:
- is_or_was_equivalent_to - is_or_was_equivalent_to
- wikidata_equivalent - wikidata_equivalent

View file

@ -142,17 +142,17 @@ slots:
- has_or_had_accessibility_feature - has_or_had_accessibility_feature
- is_accessible - is_accessible
examples: examples:
- value: "schema:wheelchairAccessible" - value: "wheelchairAccessible"
description: Physical location is accessible by wheelchair description: Physical location is accessible by wheelchair
- value: "schema:audioDescription" - value: "audioDescription"
description: Content includes audio description for visually impaired users description: Content includes audio description for visually impaired users
- value: "schema:captions" - value: "captions"
description: Content includes captions for deaf or hard-of-hearing users description: Content includes captions for deaf or hard-of-hearing users
- value: "schema:signLanguage" - value: "signLanguage"
description: Content includes sign language interpretation description: Content includes sign language interpretation
- value: "schema:braille" - value: "braille"
description: Materials available in Braille format description: Materials available in Braille format
- value: "schema:largePrint" - value: "largePrint"
description: Materials available in large print format description: Materials available in large print format
comments: comments:
- Updated 2026-02-03 with verified ontology mappings and translations - Updated 2026-02-03 with verified ontology mappings and translations

View file

@ -25,6 +25,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
la: https://linked.art/ns/terms/
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
default_prefix: hc default_prefix: hc
@ -82,6 +83,8 @@ slots:
- crm:P49_has_former_or_current_keeper # CIDOC_CRM_v7.1.3.rdf:2383-2408 - includes former keepers (broader temporal scope) - crm:P49_has_former_or_current_keeper # CIDOC_CRM_v7.1.3.rdf:2383-2408 - includes former keepers (broader temporal scope)
- crm:P50_has_current_keeper # CIDOC_CRM_v7.1.3.rdf:2410-2424 - "current keeper" but domain E18 Physical Thing / range E39 Actor (typed objects) - crm:P50_has_current_keeper # CIDOC_CRM_v7.1.3.rdf:2410-2424 - "current keeper" but domain E18 Physical Thing / range E39 Actor (typed objects)
- rico:hasOrHadHolder # RiC-O_1-1.rdf:6436-6475 - "has or had holder" — archival holding context, domain RecordResource/Instantiation - rico:hasOrHadHolder # RiC-O_1-1.rdf:6436-6475 - "has or had holder" — archival holding context, domain RecordResource/Instantiation
related_mappings:
- la:current_permanent_custodian # Linked Art extensions: normal/permanent custodian of a physical object (E19->E39)
comments: comments:
- | - |
MIGRATED 2026-02-03 from has_or_had_custodian for conciseness. MIGRATED 2026-02-03 from has_or_had_custodian for conciseness.

View file

@ -23,6 +23,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
dcat: http://www.w3.org/ns/dcat# dcat: http://www.w3.org/ns/dcat#
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
ardo: https://w3id.org/ardo/2.0/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -80,6 +81,8 @@ slots:
- dcat:keyword # dcat3.ttl:1208-1231 - "A keyword or tag describing a resource" - dcat:keyword # dcat3.ttl:1208-1231 - "A keyword or tag describing a resource"
close_mappings: close_mappings:
- dcterms:subject # dcterms.rdf:1968-1988 - "A topic of the resource" - dcterms:subject # dcterms.rdf:1968-1988 - "A topic of the resource"
related_mappings:
- ardo:has_keyword # ArDO 2.0: links a thematic subcategory to a keyword (object property)
comments: comments:
- "Used for discovery and classification." - "Used for discovery and classification."
annotations: annotations:

View file

@ -25,6 +25,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
org: http://www.w3.org/ns/org# org: http://www.w3.org/ns/org#
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
default_prefix: hc default_prefix: hc
imports: imports:
@ -80,5 +81,7 @@ slots:
exact_mappings: exact_mappings:
- org:hasMember # org.rdf:427-446 - "Indicates a person who is a member of the subject Organization." Domain: Organization, Range: Agent. Organization membership only; this slot also covers collection elements. - org:hasMember # org.rdf:427-446 - "Indicates a person who is a member of the subject Organization." Domain: Organization, Range: Agent. Organization membership only; this slot also covers collection elements.
- schema:member # schemaorg.owl:26055-26085 - "A member of an Organization or a ProgramMembership." Domain: Organization/ProgramMembership. Does not cover collection elements. - schema:member # schemaorg.owl:26055-26085 - "A member of an Organization or a ProgramMembership." Domain: Organization/ProgramMembership. Does not cover collection elements.
related_mappings:
- la:has_member # Linked Art extensions: membership (Set→Entity)
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -19,6 +19,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pca: http://rds.posccaesar.org/ontology/plm/rdl/
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -82,3 +83,5 @@ slots:
custodian_types: '["*"]' custodian_types: '["*"]'
close_mappings: close_mappings:
- dcterms:conformsTo # dcterms.rdf:987-1010 - "An established standard to which the described resource conforms." Conformance relationship ≠ having a standard. - dcterms:conformsTo # dcterms.rdf:987-1010 - "An established standard to which the described resource conforms." Conformance relationship ≠ having a standard.
related_mappings:
- pca:PCA_100003538 # POSC Caesar RDL (PCA PLM core): Standard (class)

View file

@ -24,6 +24,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pav: http://purl.org/pav/2.3#
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -81,6 +82,7 @@ slots:
multivalued: false multivalued: false
related_mappings: related_mappings:
- dcterms:hasVersion # dcterms.rdf:1371-1395 — "A related resource that is a version, edition, or adaptation." Relates resources to each other, not a version identifier. - dcterms:hasVersion # dcterms.rdf:1371-1395 — "A related resource that is a version, edition, or adaptation." Relates resources to each other, not a version identifier.
- pav:hasVersion # PAV 2.3 (used by ArDO): links a resource to a version resource
aliases: aliases:
- has_or_had_version - has_or_had_version
- api_ver - api_ver

View file

@ -27,6 +27,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -115,6 +116,7 @@ slots:
custodian_types: '["*"]' custodian_types: '["*"]'
related_mappings: related_mappings:
- schema:owns # schemaorg.owl:28732-28760 — "Things owned by the organization or person." Ownership ≠ custody/holding. - schema:owns # schemaorg.owl:28732-28760 — "Things owned by the organization or person." Ownership ≠ custody/holding.
- la:current_permanent_custodian_of # Linked Art extensions: inverse of current_permanent_custodian (Actor->Physical Object)
close_mappings: close_mappings:
- crm:P49i_is_former_or_current_keeper_of # CIDOC_CRM:2410-2435 — "is former or current keeper of." Custody relationship. - crm:P49i_is_former_or_current_keeper_of # CIDOC_CRM:2410-2435 — "is former or current keeper of." Custody relationship.
- rico:isOrWasHolderOf # RiC-O_1-1.rdf:6436-6470 — "has or had holder" (inverse). Archives holding. - rico:isOrWasHolderOf # RiC-O_1-1.rdf:6436-6470 — "has or had holder" (inverse). Archives holding.

View file

@ -32,6 +32,7 @@ prefixes:
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
org: http://www.w3.org/ns/org# org: http://www.w3.org/ns/org#
foaf: http://xmlns.com/foaf/0.1/ foaf: http://xmlns.com/foaf/0.1/
la: https://linked.art/ns/terms/
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -98,6 +99,7 @@ slots:
- rico:isOrWasMemberOf # RiC-O_1-1.rdf:14505-14550 - Person→Group (restricted domain) - rico:isOrWasMemberOf # RiC-O_1-1.rdf:14505-14550 - Person→Group (restricted domain)
related_mappings: related_mappings:
- foaf:member # foaf.ttl:410-417 - INVERSE: Group→Agent (not Agent→Group) - foaf:member # foaf.ttl:410-417 - INVERSE: Group→Agent (not Agent→Group)
- la:member_of # Linked Art extensions: membership (Entity→Set)
annotations: annotations:
inverse_slot: has_or_had_member inverse_slot: has_or_had_member
deprecates: is_member_of deprecates: is_member_of

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_amount
# ==============================================================================
# Monetary amount paid in a payment/transfer context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|------------------|---------|------------------------------------------------------|
# | **Linked Art** | `la:paid_amount` | exact | Payment -> Monetary Amount in Linked Art extensions. |
# | **Schema.org** | `schema:price` | close | Price/value expression, broader commerce usage. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_amount
name: paid_amount
title: Paid Amount
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_amount:
slot_uri: hc:paidAmount
description: >-
Specifies the amount that was paid as part of a payment or transfer.
range: string
multivalued: false
exact_mappings:
- la:paid_amount
close_mappings:
- schema:price
aliases:
- is_or_was_paid_amount
annotations:
custodian_types: '["*"]'

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_from
# ==============================================================================
# Paying party/source in a payment context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|----------------|---------|-----------------------------------------------------------|
# | **Linked Art** | `la:paid_from` | exact | Payment source actor in Linked Art extensions. |
# | **Schema.org** | `schema:buyer` | related | Buyer role; related commercial payer perspective. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_from
name: paid_from
title: Paid From
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_from:
slot_uri: hc:paidFrom
description: >-
Identifies the party or source from which a payment originated.
range: string
multivalued: false
exact_mappings:
- la:paid_from
related_mappings:
- schema:buyer
aliases:
- is_or_was_paid_from
annotations:
custodian_types: '["*"]'

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_to
# ==============================================================================
# Receiving party/destination in a payment context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|-----------------|---------|-----------------------------------------------------------|
# | **Linked Art** | `la:paid_to` | exact | Payment recipient actor in Linked Art extensions. |
# | **Schema.org** | `schema:seller` | related | Seller role; related commercial payee perspective. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_to
name: paid_to
title: Paid To
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_to:
slot_uri: hc:paidTo
description: >-
Identifies the party or destination to which a payment was made.
range: string
multivalued: false
exact_mappings:
- la:paid_to
related_mappings:
- schema:seller
aliases:
- is_or_was_paid_to
annotations:
custodian_types: '["*"]'

View file

@ -35,6 +35,7 @@ prefixes:
time: http://www.w3.org/2006/time# time: http://www.w3.org/2006/time#
schema: http://schema.org/ schema: http://schema.org/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pav: http://purl.org/pav/2.3#
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -110,6 +111,7 @@ slots:
- schema:predecessorOf # schemaorg.owl:30406-30420 - "Previous variant of product; ProductModel domain" - schema:predecessorOf # schemaorg.owl:30406-30420 - "Previous variant of product; ProductModel domain"
- schema:previousItem # schemaorg.owl:30559-30575 - "Preceding ListItem; ListItem domain" - schema:previousItem # schemaorg.owl:30559-30575 - "Preceding ListItem; ListItem domain"
- dcterms:replaces # dcterms.rdf:1827-1846 - "Supplants/supersedes described resource; implies replacement" - dcterms:replaces # dcterms.rdf:1827-1846 - "Supplants/supersedes described resource; implies replacement"
- pav:previousVersion # PAV 2.3 (used by ArDO): previous version link (version chain)
aliases: aliases:
- previous_observation - previous_observation
examples: examples:

View file

@ -32,6 +32,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -98,6 +99,7 @@ slots:
- schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically deaccessioning. - schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically deaccessioning.
related_mappings: related_mappings:
- crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of deaccessioning/disposal. - crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of deaccessioning/disposal.
- la:removed_member # Linked Art extensions: member removed from a Set via a Removal activity
aliases: aliases:
- objects_removed - objects_removed
examples: examples:

View file

@ -22,6 +22,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
@ -83,5 +84,6 @@ slots:
- is_or_was_transferred - is_or_was_transferred
related_mappings: related_mappings:
- schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects" - schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects"
- la:transferred # Linked Art extensions: what was transferred (Transfer->Entity). Note: this slot is boolean, so mapping is conceptual only.
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -0,0 +1,45 @@
# ==============================================================================
# LinkML Slot Definition: transferred_from
# ==============================================================================
# Source party/place from which something was transferred.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|-----------------------|---------|-------------------------------------------------------------|
# | **Linked Art** | `la:transferred_from` | exact | Source entity in a transfer in Linked Art extensions. |
# | **CIDOC-CRM** | `crm:P27_moved_from` | narrow | Location-only origin (place), narrower than general source. |
# | **Schema.org** | `schema:fromLocation` | narrow | Location-only source in action logistics. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/transferred_from
name: transferred_from
title: Transferred From
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
transferred_from:
slot_uri: hc:transferredFrom
description: >-
Identifies the source party, owner, custodian, or location from which
something was transferred.
range: string
multivalued: false
exact_mappings:
- la:transferred_from
narrow_mappings:
- crm:P27_moved_from
- schema:fromLocation
aliases:
- is_or_was_transferred_from
annotations:
custodian_types: '["*"]'

View file

@ -24,6 +24,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
odrl: http://www.w3.org/ns/odrl/2/ odrl: http://www.w3.org/ns/odrl/2/
la: https://linked.art/ns/terms/
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
@ -86,5 +87,6 @@ slots:
- is_or_was_transferred_to - is_or_was_transferred_to
related_mappings: related_mappings:
- schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects" - schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects"
- la:transferred_to # Linked Art extensions: transferred to (Transfer→Entity)
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -0,0 +1,356 @@
#!/usr/bin/env node
/*
* Generate a Mermaid UML class diagram from the synced LinkML schemas.
*
* Output: frontend/public/data/heritage_custodian_ontology.mmd
*
* The Visualize page loads this file from /data/heritage_custodian_ontology.mmd.
*/
const fs = require('fs');
const path = require('path');
const SCHEMA_DIR = path.join(__dirname, '../public/schemas/20251121/linkml');
const MANIFEST_PATH = path.join(SCHEMA_DIR, 'manifest.json');
const OUTPUT_PATH = path.join(__dirname, '../public/data/heritage_custodian_ontology.mmd');
function readJson(p) {
return JSON.parse(fs.readFileSync(p, 'utf8'));
}
function readText(p) {
return fs.readFileSync(p, 'utf8');
}
function ensureDir(p) {
const dir = path.dirname(p);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
}
function safeArray(v) {
return Array.isArray(v) ? v : [];
}
function indentOf(line) {
const m = line.match(/^ */);
return m ? m[0].length : 0;
}
function isBlankOrComment(line) {
const t = line.trim();
return t === '' || t.startsWith('#');
}
function stripInlineComment(v) {
// Conservative: only strip comments when preceded by whitespace.
// This avoids clobbering URLs like http://example.com#fragment.
return v.replace(/\s+#.*$/, '').trim();
}
function stripQuotes(v) {
const s = v.trim();
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
return s.slice(1, -1);
}
return s;
}
function collectIndentedBlock(lines, startIndex, startIndent) {
const block = [lines[startIndex]];
for (let i = startIndex + 1; i < lines.length; i++) {
const line = lines[i];
if (isBlankOrComment(line)) {
block.push(line);
continue;
}
const ind = indentOf(line);
if (ind <= startIndent) break;
block.push(line);
}
return block;
}
function findScalarInBlock(blockLines, key, minIndent) {
// Returns a single-line scalar value for `${key}: value`.
// Ignores folded/literal multi-line scalars (>- / |).
for (const line of blockLines) {
if (isBlankOrComment(line)) continue;
if (indentOf(line) < minIndent) continue;
const m = line.match(new RegExp(`^\\s*${key}:\\s*(.+)\\s*$`));
if (!m) continue;
const raw = stripInlineComment(m[1]);
if (raw === '' || raw === '|' || raw === '>-') continue;
return stripQuotes(raw);
}
return null;
}
function findListInBlock(blockLines, key, minIndent) {
// Parses:
// key:
// - item
// - item2
const out = [];
for (let i = 0; i < blockLines.length; i++) {
const line = blockLines[i];
if (isBlankOrComment(line)) continue;
const ind = indentOf(line);
if (ind < minIndent) continue;
const keyMatch = line.match(new RegExp(`^\\s*${key}:\\s*$`));
if (!keyMatch) continue;
const keyIndent = ind;
for (let j = i + 1; j < blockLines.length; j++) {
const l = blockLines[j];
if (isBlankOrComment(l)) continue;
const li = indentOf(l);
if (li <= keyIndent) break;
const m = l.match(/^\s*-\s*(.+)\s*$/);
if (m) {
out.push(stripQuotes(stripInlineComment(m[1])));
}
}
break;
}
return out;
}
function parseSlotUsageOverrides(classBlockLines, minIndent) {
// Parses:
// slot_usage:
// slot_name:
// range: SomeClass
const overrides = new Map();
for (let i = 0; i < classBlockLines.length; i++) {
const line = classBlockLines[i];
if (isBlankOrComment(line)) continue;
const ind = indentOf(line);
if (ind < minIndent) continue;
if (!line.match(/^\s*slot_usage:\s*$/)) continue;
const usageIndent = ind;
let currentSlot = null;
let currentSlotIndent = null;
for (let j = i + 1; j < classBlockLines.length; j++) {
const l = classBlockLines[j];
if (isBlankOrComment(l)) continue;
const li = indentOf(l);
if (li <= usageIndent) break;
// Slot key line: ` slot_name:`
if (li === usageIndent + 2) {
const mKey = l.trim().match(/^([^\s:]+):\s*$/);
if (mKey) {
currentSlot = mKey[1];
currentSlotIndent = li;
continue;
}
}
if (currentSlot && currentSlotIndent !== null && li > currentSlotIndent) {
const mRange = l.match(/^\s*range:\s*(.+)\s*$/);
if (mRange) {
const range = stripQuotes(stripInlineComment(mRange[1]));
if (range) overrides.set(currentSlot, range);
}
}
}
break;
}
return overrides;
}
function extractNamedMappingBlock(text, rootKey, itemName) {
// Extract the YAML-ish block for `rootKey: { itemName: {...} }` without parsing YAML.
// This is resilient to invalid YAML elsewhere in the file.
const lines = text.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (isBlankOrComment(line)) continue;
const rootMatch = line.match(new RegExp(`^\\s*${rootKey}:\\s*$`));
if (!rootMatch) continue;
const rootIndent = indentOf(line);
for (let j = i + 1; j < lines.length; j++) {
const l = lines[j];
if (isBlankOrComment(l)) continue;
const li = indentOf(l);
if (li <= rootIndent) break;
if (li === rootIndent + 2 && l.trim() === `${itemName}:`) {
return {
blockLines: collectIndentedBlock(lines, j, li),
baseIndent: li,
};
}
}
}
return null;
}
function extractAllNamedMappingBlocks(text, rootKey) {
// Extract all mapping entry blocks under `rootKey:`
// Example:
// classes:
// Foo:
// ...
// Bar:
// ...
const lines = text.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (isBlankOrComment(line)) continue;
const rootMatch = line.match(new RegExp(`^\\s*${rootKey}:\\s*$`));
if (!rootMatch) continue;
const rootIndent = indentOf(line);
const blocks = [];
for (let j = i + 1; j < lines.length; j++) {
const l = lines[j];
if (isBlankOrComment(l)) continue;
const li = indentOf(l);
if (li <= rootIndent) break;
if (li === rootIndent + 2) {
const mKey = l.trim().match(/^([^\s:]+):\s*$/);
if (mKey) {
blocks.push({
name: mKey[1],
blockLines: collectIndentedBlock(lines, j, li),
baseIndent: li,
});
}
}
}
return blocks;
}
return [];
}
function main() {
if (!fs.existsSync(MANIFEST_PATH)) {
console.error(`[generate-ontology-uml] Missing manifest: ${MANIFEST_PATH}`);
console.error('[generate-ontology-uml] Run pnpm run generate-manifest first.');
process.exit(1);
}
const manifest = readJson(MANIFEST_PATH);
const classCategory = (manifest.categories || []).find((c) => c.name === 'class');
const slotCategory = (manifest.categories || []).find((c) => c.name === 'slot');
const classFiles = safeArray(classCategory && classCategory.files);
const slotFiles = safeArray(slotCategory && slotCategory.files);
const slotIndex = new Map();
for (const f of slotFiles) {
const fullPath = path.join(SCHEMA_DIR, f.path);
if (!fs.existsSync(fullPath)) continue;
const text = readText(fullPath);
const slotBlocks = extractAllNamedMappingBlocks(text, 'slots');
for (const b of slotBlocks) {
const range = findScalarInBlock(b.blockLines, 'range', b.baseIndent + 2);
const multivaluedRaw = findScalarInBlock(b.blockLines, 'multivalued', b.baseIndent + 2);
const multivalued = multivaluedRaw === 'true' || multivaluedRaw === 'True';
if (!slotIndex.has(b.name)) {
slotIndex.set(b.name, {
range,
multivalued,
});
}
}
}
const classIndex = new Map();
for (const f of classFiles) {
const fullPath = path.join(SCHEMA_DIR, f.path);
if (!fs.existsSync(fullPath)) continue;
const text = readText(fullPath);
const classBlocks = extractAllNamedMappingBlocks(text, 'classes');
for (const b of classBlocks) {
const baseIndent = b.baseIndent;
const parent = findScalarInBlock(b.blockLines, 'is_a', baseIndent + 2);
const slots = findListInBlock(b.blockLines, 'slots', baseIndent + 2);
const overrides = parseSlotUsageOverrides(b.blockLines, baseIndent + 2);
if (!classIndex.has(b.name)) {
classIndex.set(b.name, {
is_a: parent,
slots,
slot_usage_overrides: overrides,
});
}
}
}
const classNames = [...classIndex.keys()].sort((a, b) => a.localeCompare(b));
const lines = [];
lines.push('```mermaid');
lines.push('classDiagram');
lines.push(`%% Generated from LinkML manifest: /schemas/20251121/linkml/manifest.json`);
if (manifest.generated) {
lines.push(`%% Manifest generated: ${manifest.generated}`);
}
lines.push('direction LR');
for (const c of classNames) {
lines.push(`class ${c}`);
}
const edgeSet = new Set();
const addEdge = (a, b, kind, label) => {
const key = `${a}|${b}|${kind}|${label || ''}`;
if (edgeSet.has(key)) return;
edgeSet.add(key);
if (kind === 'inheritance') {
lines.push(`${b} <|-- ${a}`);
return;
}
if (kind === 'association') {
lines.push(`${a} --> ${b} : ${label}`);
}
};
for (const [className, classDef] of classIndex.entries()) {
const parent = classDef.is_a;
if (parent && classIndex.has(parent)) {
addEdge(className, parent, 'inheritance');
}
const slots = safeArray(classDef.slots);
const slotUsageOverrides = classDef.slot_usage_overrides instanceof Map ? classDef.slot_usage_overrides : new Map();
for (const slotName of slots) {
const slotDef = slotIndex.get(slotName) || {};
const range = slotUsageOverrides.get(slotName) || slotDef.range;
if (!range) continue;
if (classIndex.has(range)) {
addEdge(className, range, 'association', slotName);
}
}
}
lines.push('```');
lines.push('');
ensureDir(OUTPUT_PATH);
fs.writeFileSync(OUTPUT_PATH, lines.join('\n'), 'utf8');
console.log(`[generate-ontology-uml] Wrote ${OUTPUT_PATH}`);
console.log(`[generate-ontology-uml] Classes: ${classIndex.size}, Slots indexed: ${slotIndex.size}, Edges: ${edgeSet.size}`);
}
main();

View file

@ -263,6 +263,25 @@
flex-shrink: 0; flex-shrink: 0;
} }
.mapping-explorer__schema-status {
display: flex;
align-items: center;
height: 34px;
padding: 0 10px;
border-radius: 6px;
border: 1px solid #e0e0e0;
background: #ffffff;
color: #172a59;
font-size: 12px;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
white-space: nowrap;
}
.mapping-explorer__schema-status--warn {
border-color: #fa5200;
box-shadow: 0 0 0 2px rgba(250, 82, 0, 0.15);
}
/* ============================================================================ /* ============================================================================
* STATISTICS BAR * STATISTICS BAR
* ============================================================================ */ * ============================================================================ */
@ -528,6 +547,29 @@
white-space: nowrap; white-space: nowrap;
} }
.mapping-explorer__schema-warning {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
border-radius: 999px;
border: 1px solid rgba(250, 82, 0, 0.45);
background: rgba(250, 82, 0, 0.12);
color: #fa5200;
font-size: 12px;
font-weight: 700;
line-height: 1;
}
.mapping-explorer__schema-warning-text {
margin-left: 8px;
font-size: 12px;
color: #fa5200;
font-weight: 600;
}
/* ============================================================================ /* ============================================================================
* CENTER PANEL: MAPPING ARROWS * CENTER PANEL: MAPPING ARROWS
* ============================================================================ */ * ============================================================================ */

View file

@ -25,6 +25,7 @@ import {
type MappingStatus, type MappingStatus,
type CategoryGroup, type CategoryGroup,
} from '../../lib/linkml/custodian-data-mappings'; } from '../../lib/linkml/custodian-data-mappings';
import { loadManifest } from '../../lib/linkml/schema-loader';
import './MappingExplorer.css'; import './MappingExplorer.css';
// ============================================================================ // ============================================================================
@ -139,6 +140,7 @@ interface SourceTreeItemProps {
isSelected: boolean; isSelected: boolean;
selectedField: FieldMapping | null; selectedField: FieldMapping | null;
dataSource: DataSourceType; dataSource: DataSourceType;
getFieldSchemaValidity?: (field: FieldMapping) => { classOk: boolean; slotOk: boolean };
onToggle: () => void; onToggle: () => void;
onSelectSource: () => void; onSelectSource: () => void;
onSelectField: (field: FieldMapping) => void; onSelectField: (field: FieldMapping) => void;
@ -156,6 +158,7 @@ const SourceTreeItem: React.FC<SourceTreeItemProps> = ({
isSelected, isSelected,
selectedField, selectedField,
dataSource, dataSource,
getFieldSchemaValidity,
onToggle, onToggle,
onSelectSource, onSelectSource,
onSelectField, onSelectField,
@ -182,19 +185,32 @@ const SourceTreeItem: React.FC<SourceTreeItemProps> = ({
{isExpanded && ( {isExpanded && (
<div className="mapping-explorer__field-list"> <div className="mapping-explorer__field-list">
{mapping.fields.map((field, idx) => ( {mapping.fields.map((field, idx) => {
<div const validity = getFieldSchemaValidity?.(field);
key={idx} const isInvalid = validity ? (!validity.classOk || !validity.slotOk) : false;
className={`mapping-explorer__field-item ${selectedField === field ? 'mapping-explorer__field-item--selected' : ''}`}
onClick={() => onSelectField(field)} return (
> <div
<span className="mapping-explorer__field-path"> key={idx}
{(field.sourcePath ?? '—').replace(`${mapping.sourceBlock}.`, '')} className={`mapping-explorer__field-item ${selectedField === field ? 'mapping-explorer__field-item--selected' : ''}`}
</span> onClick={() => onSelectField(field)}
{field.status && <StatusBadge status={field.status} />} >
<TransformationBadge type={field.transformation} /> <span className="mapping-explorer__field-path">
</div> {(field.sourcePath ?? '—').replace(`${mapping.sourceBlock}.`, '')}
))} </span>
{isInvalid && (
<span
className="mapping-explorer__schema-warning"
title="Target class/slot not found in current LinkML schema"
>
!
</span>
)}
{field.status && <StatusBadge status={field.status} />}
<TransformationBadge type={field.transformation} />
</div>
);
})}
</div> </div>
)} )}
</div> </div>
@ -234,6 +250,7 @@ interface FieldDetailsPanelProps {
field: FieldMapping; field: FieldMapping;
sourceBlock: string; sourceBlock: string;
viewMode: 'linkml' | 'typedb' | 'rdf'; viewMode: 'linkml' | 'typedb' | 'rdf';
schemaValidity?: { classOk: boolean; slotOk: boolean };
translations: { translations: {
copyPath: string; copyPath: string;
copyRdf: string; copyRdf: string;
@ -243,7 +260,7 @@ interface FieldDetailsPanelProps {
}; };
} }
const FieldDetailsPanel: React.FC<FieldDetailsPanelProps> = ({ field, sourceBlock: _sourceBlock, viewMode, translations }) => { const FieldDetailsPanel: React.FC<FieldDetailsPanelProps> = ({ field, sourceBlock: _sourceBlock, viewMode, schemaValidity, translations }) => {
const [copiedField, setCopiedField] = useState<string | null>(null); const [copiedField, setCopiedField] = useState<string | null>(null);
const copyToClipboard = (text: string, fieldName: string) => { const copyToClipboard = (text: string, fieldName: string) => {
@ -301,30 +318,36 @@ const FieldDetailsPanel: React.FC<FieldDetailsPanelProps> = ({ field, sourceBloc
)} )}
</div> </div>
{viewMode === 'linkml' && ( {viewMode === 'linkml' && (
<div className="mapping-explorer__details-section"> <div className="mapping-explorer__details-section">
<h5> <h5>
<FileCode size={16} className="mapping-explorer__section-icon" /> <FileCode size={16} className="mapping-explorer__section-icon" />
LinkML Target LinkML Target
</h5> </h5>
<div className="mapping-explorer__details-row"> <div className="mapping-explorer__details-row">
<span className="mapping-explorer__details-label">Class:</span> <span className="mapping-explorer__details-label">Class:</span>
<code className="mapping-explorer__details-value mapping-explorer__details-value--class"> <code className="mapping-explorer__details-value mapping-explorer__details-value--class">
{field.targetClass} {field.targetClass}
</code> </code>
{schemaValidity && !schemaValidity.classOk && (
<span className="mapping-explorer__schema-warning-text">Unknown in schema</span>
)}
</div>
<div className="mapping-explorer__details-row">
<span className="mapping-explorer__details-label">Slot:</span>
<code className="mapping-explorer__details-value">{field.targetSlot}</code>
{schemaValidity && !schemaValidity.slotOk && (
<span className="mapping-explorer__schema-warning-text">Unknown in schema</span>
)}
</div>
<div className="mapping-explorer__details-row">
<span className="mapping-explorer__details-label">Required:</span>
<span className={`mapping-explorer__details-value ${field.required ? 'mapping-explorer__details-value--required' : ''}`}>
{field.required ? 'Yes' : 'No'}
</span>
</div>
</div> </div>
<div className="mapping-explorer__details-row"> )}
<span className="mapping-explorer__details-label">Slot:</span>
<code className="mapping-explorer__details-value">{field.targetSlot}</code>
</div>
<div className="mapping-explorer__details-row">
<span className="mapping-explorer__details-label">Required:</span>
<span className={`mapping-explorer__details-value ${field.required ? 'mapping-explorer__details-value--required' : ''}`}>
{field.required ? 'Yes' : 'No'}
</span>
</div>
</div>
)}
{viewMode === 'typedb' && field.typedbEntity && ( {viewMode === 'typedb' && field.typedbEntity && (
<div className="mapping-explorer__details-section"> <div className="mapping-explorer__details-section">
@ -522,6 +545,8 @@ export const MappingExplorer: React.FC<MappingExplorerProps> = ({ language = 'en
const [viewMode, setViewMode] = useState<'linkml' | 'typedb' | 'rdf'>('linkml'); const [viewMode, setViewMode] = useState<'linkml' | 'typedb' | 'rdf'>('linkml');
const [isExporting, setIsExporting] = useState(false); const [isExporting, setIsExporting] = useState(false);
const [schemaIndex, setSchemaIndex] = useState<{ classes: Set<string>; slots: Set<string>; generated?: string } | null>(null);
// Reset selection when data source changes // Reset selection when data source changes
useEffect(() => { useEffect(() => {
const defaultSource = dataSource === 'custodian' ? 'ghcid' : 'profile_identity'; const defaultSource = dataSource === 'custodian' ? 'ghcid' : 'profile_identity';
@ -539,6 +564,56 @@ export const MappingExplorer: React.FC<MappingExplorerProps> = ({ language = 'en
const currentMappings = useMemo(() => getMappingsForDataSource(dataSource), [dataSource]); const currentMappings = useMemo(() => getMappingsForDataSource(dataSource), [dataSource]);
const currentCategories = useMemo(() => getCategoriesForDataSource(dataSource), [dataSource]); const currentCategories = useMemo(() => getCategoriesForDataSource(dataSource), [dataSource]);
// Load LinkML schema manifest for validation (best-effort)
useEffect(() => {
let cancelled = false;
(async () => {
try {
const manifest = await loadManifest();
if (!manifest || cancelled) return;
const classes = new Set<string>();
const slots = new Set<string>();
for (const category of manifest.categories ?? []) {
if (category.name === 'class') {
for (const f of category.files ?? []) classes.add(f.name);
}
if (category.name === 'slot') {
for (const f of category.files ?? []) slots.add(f.name);
}
}
setSchemaIndex({ classes, slots, generated: manifest.generated });
} catch (e) {
// Ignore - mapping explorer should remain usable without schema assets
console.warn('[MappingExplorer] Could not load LinkML manifest for validation', e);
}
})();
return () => {
cancelled = true;
};
}, []);
const getFieldSchemaValidity = useCallback((field: FieldMapping) => {
if (!schemaIndex) return { classOk: true, slotOk: true };
const classOk = field.targetClass ? schemaIndex.classes.has(field.targetClass) : true;
const slotOk = field.targetSlot ? schemaIndex.slots.has(field.targetSlot) : true;
return { classOk, slotOk };
}, [schemaIndex]);
const schemaMismatchCounts = useMemo(() => {
if (!schemaIndex) return { invalidFields: 0 };
let invalidFields = 0;
currentMappings.forEach(m => {
m.fields.forEach(f => {
const v = getFieldSchemaValidity(f);
if (!v.classOk || !v.slotOk) invalidFields++;
});
});
return { invalidFields };
}, [schemaIndex, currentMappings, getFieldSchemaValidity]);
// Status counts for statistics panel // Status counts for statistics panel
const statusCounts = useMemo((): StatusCounts => { const statusCounts = useMemo((): StatusCounts => {
const counts: StatusCounts = { mapped: 0, partial: 0, out_of_scope: 0, future: 0 }; const counts: StatusCounts = { mapped: 0, partial: 0, out_of_scope: 0, future: 0 };
@ -849,6 +924,15 @@ export const MappingExplorer: React.FC<MappingExplorerProps> = ({ language = 'en
<Download size={16} /> <Download size={16} />
{isExporting ? t('exporting') : t('exportLinkMLMap')} {isExporting ? t('exporting') : t('exportLinkMLMap')}
</button> </button>
{schemaIndex && (
<div
className={`mapping-explorer__schema-status ${schemaMismatchCounts.invalidFields > 0 ? 'mapping-explorer__schema-status--warn' : ''}`}
title={`LinkML schema manifest loaded${schemaIndex.generated ? ` (generated: ${schemaIndex.generated})` : ''}`}
>
Schema: {schemaMismatchCounts.invalidFields === 0 ? 'OK' : `${schemaMismatchCounts.invalidFields} invalid targets`}
</div>
)}
</div> </div>
</div> </div>
@ -872,6 +956,7 @@ export const MappingExplorer: React.FC<MappingExplorerProps> = ({ language = 'en
isSelected={selectedSource === mapping.sourceBlock} isSelected={selectedSource === mapping.sourceBlock}
selectedField={selectedField} selectedField={selectedField}
dataSource={dataSource} dataSource={dataSource}
getFieldSchemaValidity={getFieldSchemaValidity}
onToggle={() => toggleSource(mapping.sourceBlock)} onToggle={() => toggleSource(mapping.sourceBlock)}
onSelectSource={() => handleSelectSource(mapping.sourceBlock)} onSelectSource={() => handleSelectSource(mapping.sourceBlock)}
onSelectField={handleSelectField} onSelectField={handleSelectField}
@ -913,6 +998,7 @@ export const MappingExplorer: React.FC<MappingExplorerProps> = ({ language = 'en
field={selectedField} field={selectedField}
sourceBlock={selectedSource} sourceBlock={selectedSource}
viewMode={viewMode} viewMode={viewMode}
schemaValidity={getFieldSchemaValidity(selectedField)}
translations={{ translations={{
copyPath: t('copyPath'), copyPath: t('copyPath'),
copyRdf: t('copyRdf'), copyRdf: t('copyRdf'),

View file

@ -508,7 +508,7 @@ Example: NL-NH-AMS-M-RM (Rijksmuseum, Amsterdam, Netherlands)
GHCIDs are deterministically generated and hashed to multiple UUID formats GHCIDs are deterministically generated and hashed to multiple UUID formats
for different use cases (UUID v5 for primary, UUID v8 for future-proofing). for different use cases (UUID v5 for primary, UUID v8 for future-proofing).
`.trim(), `.trim(),
linkmlClass: 'GHCID', linkmlClass: 'GHCIdentifier',
typedbEntity: 'ghcid', typedbEntity: 'ghcid',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -518,8 +518,8 @@ for different use cases (UUID v5 for primary, UUID v8 for future-proofing).
{ {
sourcePath: 'ghcid.ghcid_current', sourcePath: 'ghcid.ghcid_current',
sourceDescription: 'Current GHCID string', sourceDescription: 'Current GHCID string',
targetClass: 'GHCID', targetClass: 'GHCIdentifier',
targetSlot: 'identified_by', targetSlot: 'has_value',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'ghcid', typedbEntity: 'ghcid',
typedbAttribute: 'ghcid-string', typedbAttribute: 'ghcid-string',
@ -534,8 +534,8 @@ for different use cases (UUID v5 for primary, UUID v8 for future-proofing).
{ {
sourcePath: 'ghcid.ghcid_uuid', sourcePath: 'ghcid.ghcid_uuid',
sourceDescription: 'UUID v5 derived from GHCID string', sourceDescription: 'UUID v5 derived from GHCID string',
targetClass: 'GHCID', targetClass: 'GHCIdentifier',
targetSlot: 'identified_by', targetSlot: 'has_value',
transformation: 'computed', transformation: 'computed',
transformationDetails: 'UUID v5 generated using SHA-1 hash of GHCID string with heritage namespace', transformationDetails: 'UUID v5 generated using SHA-1 hash of GHCID string with heritage namespace',
typedbEntity: 'ghcid', typedbEntity: 'ghcid',
@ -550,8 +550,8 @@ for different use cases (UUID v5 for primary, UUID v8 for future-proofing).
{ {
sourcePath: 'ghcid.ghcid_numeric', sourcePath: 'ghcid.ghcid_numeric',
sourceDescription: '64-bit numeric ID for database optimization', sourceDescription: '64-bit numeric ID for database optimization',
targetClass: 'GHCID', targetClass: 'GHCIdentifier',
targetSlot: 'identified_by', targetSlot: 'has_value',
transformation: 'computed', transformation: 'computed',
transformationDetails: 'SHA-256 hash truncated to 64-bit integer', transformationDetails: 'SHA-256 hash truncated to 64-bit integer',
typedbEntity: 'ghcid', typedbEntity: 'ghcid',
@ -561,8 +561,8 @@ for different use cases (UUID v5 for primary, UUID v8 for future-proofing).
{ {
sourcePath: 'ghcid.location_resolution', sourcePath: 'ghcid.location_resolution',
sourceDescription: 'GeoNames resolution metadata', sourceDescription: 'GeoNames resolution metadata',
targetClass: 'GHCID', targetClass: 'LocationResolution',
targetSlot: 'has_location', targetSlot: 'based_on',
transformation: 'nested', transformation: 'nested',
transformationDetails: 'Maps to LocationResolution class with GeoNames provenance', transformationDetails: 'Maps to LocationResolution class with GeoNames provenance',
typedbEntity: 'location-resolution', typedbEntity: 'location-resolution',
@ -784,7 +784,7 @@ Each enrichment creates a CustodianObservation with google_maps_api provenance.
apiEndpoint: 'https://maps.googleapis.com/maps/api/place/', apiEndpoint: 'https://maps.googleapis.com/maps/api/place/',
updateFrequency: 'On-demand', updateFrequency: 'On-demand',
}, },
generatedClasses: ['Place', 'GeoCoordinates', 'OpeningHours'], generatedClasses: ['Place', 'SourceCoordinates', 'OpeningHours'],
fields: [ fields: [
{ {
sourcePath: 'google_maps_enrichment.place_id', sourcePath: 'google_maps_enrichment.place_id',
@ -804,7 +804,7 @@ Each enrichment creates a CustodianObservation with google_maps_api provenance.
{ {
sourcePath: 'google_maps_enrichment.coordinates.latitude', sourcePath: 'google_maps_enrichment.coordinates.latitude',
sourceDescription: 'Latitude coordinate', sourceDescription: 'Latitude coordinate',
targetClass: 'GeoCoordinates', targetClass: 'SourceCoordinates',
targetSlot: 'has_latitude', targetSlot: 'has_latitude',
transformation: 'nested', transformation: 'nested',
typedbEntity: 'geo-coordinates', typedbEntity: 'geo-coordinates',
@ -820,7 +820,7 @@ Each enrichment creates a CustodianObservation with google_maps_api provenance.
{ {
sourcePath: 'google_maps_enrichment.coordinates.longitude', sourcePath: 'google_maps_enrichment.coordinates.longitude',
sourceDescription: 'Longitude coordinate', sourceDescription: 'Longitude coordinate',
targetClass: 'GeoCoordinates', targetClass: 'SourceCoordinates',
targetSlot: 'has_longitude', targetSlot: 'has_longitude',
transformation: 'nested', transformation: 'nested',
typedbEntity: 'geo-coordinates', typedbEntity: 'geo-coordinates',
@ -964,7 +964,7 @@ Creates a CustodianObservation with wikidata_api provenance.
dataTier: 'TIER_3_CROWD_SOURCED', dataTier: 'TIER_3_CROWD_SOURCED',
apiEndpoint: 'https://www.wikidata.org/wiki/Special:EntityData/', apiEndpoint: 'https://www.wikidata.org/wiki/Special:EntityData/',
}, },
generatedClasses: ['WikidataEntity', 'Sitelink'], generatedClasses: ['WikidataEntity', 'WikidataSitelinks'],
fields: [ fields: [
{ {
sourcePath: 'wikidata_enrichment.entity_id', sourcePath: 'wikidata_enrichment.entity_id',
@ -1006,7 +1006,7 @@ Creates a CustodianObservation with wikidata_api provenance.
{ {
sourcePath: 'wikidata_enrichment.sitelinks', sourcePath: 'wikidata_enrichment.sitelinks',
sourceDescription: 'Links to Wikipedia articles', sourceDescription: 'Links to Wikipedia articles',
targetClass: 'Sitelink', targetClass: 'WikidataSitelinks',
targetSlot: 'has_url', targetSlot: 'has_url',
transformation: 'array_map', transformation: 'array_map',
transformationDetails: 'Each sitelink maps to Wikipedia article URL', transformationDetails: 'Each sitelink maps to Wikipedia article URL',
@ -1033,7 +1033,7 @@ Creates a CustodianObservation with wikidata_api provenance.
{ {
sourcePath: 'wikidata_enrichment.coordinates', sourcePath: 'wikidata_enrichment.coordinates',
sourceDescription: 'Geographic coordinates from Wikidata (P625)', sourceDescription: 'Geographic coordinates from Wikidata (P625)',
targetClass: 'GeoCoordinates', targetClass: 'WikidataCoordinates',
targetSlot: 'has_coordinates', targetSlot: 'has_coordinates',
transformation: 'nested', transformation: 'nested',
typedbEntity: 'geo-coordinates', typedbEntity: 'geo-coordinates',
@ -1104,7 +1104,7 @@ This is the single source of truth for the custodian's physical location.
sourcePath: 'location.city', sourcePath: 'location.city',
sourceDescription: 'City name', sourceDescription: 'City name',
targetClass: 'Place', targetClass: 'Place',
targetSlot: 'cover_place', targetSlot: 'has_locality',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'place', typedbEntity: 'place',
typedbAttribute: 'city', typedbAttribute: 'city',
@ -1119,7 +1119,7 @@ This is the single source of truth for the custodian's physical location.
sourcePath: 'location.country', sourcePath: 'location.country',
sourceDescription: 'ISO 3166-1 alpha-2 country code', sourceDescription: 'ISO 3166-1 alpha-2 country code',
targetClass: 'Place', targetClass: 'Place',
targetSlot: 'cover_country', targetSlot: 'in_country',
transformation: 'lookup', transformation: 'lookup',
transformationDetails: 'Maps to CountryCodeEnum', transformationDetails: 'Maps to CountryCodeEnum',
typedbEntity: 'place', typedbEntity: 'place',
@ -1139,7 +1139,7 @@ This is the single source of truth for the custodian's physical location.
sourcePath: 'location.region', sourcePath: 'location.region',
sourceDescription: 'Region/province name', sourceDescription: 'Region/province name',
targetClass: 'Place', targetClass: 'Place',
targetSlot: 'region', targetSlot: 'has_geographic_subdivision',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'place', typedbEntity: 'place',
typedbAttribute: 'region', typedbAttribute: 'region',
@ -1214,7 +1214,7 @@ All claims must have XPath provenance per Rule 6.
sourcePath: 'web_enrichment.source_url', sourcePath: 'web_enrichment.source_url',
sourceDescription: 'URL of scraped page', sourceDescription: 'URL of scraped page',
targetClass: 'WebObservation', targetClass: 'WebObservation',
targetSlot: 'source_url', targetSlot: 'retrieved_from',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'web-observation', typedbEntity: 'web-observation',
typedbAttribute: 'source-url', typedbAttribute: 'source-url',
@ -1226,7 +1226,7 @@ All claims must have XPath provenance per Rule 6.
sourcePath: 'web_enrichment.retrieved_on', sourcePath: 'web_enrichment.retrieved_on',
sourceDescription: 'Timestamp when page was archived', sourceDescription: 'Timestamp when page was archived',
targetClass: 'WebObservation', targetClass: 'WebObservation',
targetSlot: 'retrieved_on', targetSlot: 'retrieved_at',
transformation: 'temporal', transformation: 'temporal',
typedbEntity: 'web-observation', typedbEntity: 'web-observation',
typedbAttribute: 'retrieved-on', typedbAttribute: 'retrieved-on',
@ -1326,7 +1326,7 @@ Claims without XPath provenance are fabricated and must be removed per Rule 6.
sourcePath: 'web_claims[].source_url', sourcePath: 'web_claims[].source_url',
sourceDescription: 'URL where claim was extracted', sourceDescription: 'URL where claim was extracted',
targetClass: 'WebClaim', targetClass: 'WebClaim',
targetSlot: 'source_url', targetSlot: 'retrieved_from',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'web-claim', typedbEntity: 'web-claim',
typedbAttribute: 'source-url', typedbAttribute: 'source-url',
@ -2222,7 +2222,7 @@ Classes: RegionalArchive, ProvincialArchive, ProvincialHistoricalArchive,
sourcePath: 'region', sourcePath: 'region',
sourceDescription: 'Geographic region served', sourceDescription: 'Geographic region served',
targetClass: 'RegionalArchive', targetClass: 'RegionalArchive',
targetSlot: 'region', targetSlot: 'cover_geographic_subdivision',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'regional-archive', typedbEntity: 'regional-archive',
typedbAttribute: 'region', typedbAttribute: 'region',
@ -3500,7 +3500,7 @@ Supports:
sourcePath: 'person.experience[].role', sourcePath: 'person.experience[].role',
sourceDescription: 'Job title/role', sourceDescription: 'Job title/role',
targetClass: 'WorkExperience', targetClass: 'WorkExperience',
targetSlot: 'role_title', targetSlot: 'has_position',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'work-experience', typedbEntity: 'work-experience',
typedbAttribute: 'role-title', typedbAttribute: 'role-title',
@ -3510,8 +3510,8 @@ Supports:
{ {
sourcePath: 'person.education[].institution', sourcePath: 'person.education[].institution',
sourceDescription: 'Educational institution', sourceDescription: 'Educational institution',
targetClass: 'EducationCredential', targetClass: 'Education',
targetSlot: 'affiliated_with', targetSlot: 'has_label',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'education-credential', typedbEntity: 'education-credential',
typedbAttribute: 'institution', typedbAttribute: 'institution',
@ -3520,7 +3520,7 @@ Supports:
}, },
], ],
generatedClasses: [ generatedClasses: [
'WorkExperience', 'EducationCredential', 'StaffRole', 'StaffRoles', 'WorkExperience', 'Education', 'StaffRole', 'StaffRoles',
], ],
exampleYaml: ` exampleYaml: `
# Work and education # Work and education
@ -3645,7 +3645,7 @@ Includes:
{ {
sourcePath: 'api_endpoints.iiif', sourcePath: 'api_endpoints.iiif',
sourceDescription: 'IIIF Image API', sourceDescription: 'IIIF Image API',
targetClass: 'IIPImageServer', targetClass: 'IIIF',
targetSlot: 'has_url', targetSlot: 'has_url',
transformation: 'direct', transformation: 'direct',
typedbEntity: 'iip-image-server', typedbEntity: 'iip-image-server',
@ -3656,7 +3656,7 @@ Includes:
], ],
generatedClasses: [ generatedClasses: [
'DataServiceEndpoint', 'OAIPMHEndpoint', 'SearchAPI', 'FileAPI', 'EADDownload', 'DataServiceEndpoint', 'OAIPMHEndpoint', 'SearchAPI', 'FileAPI', 'EADDownload',
'METSAPI', 'IIPImageServer', 'InternetOfThings', 'METSAPI', 'IIIF', 'InternetOfThings',
], ],
exampleYaml: ` exampleYaml: `
# API endpoints # API endpoints
@ -4208,7 +4208,7 @@ Includes:
sourcePath: 'funding.agendas', sourcePath: 'funding.agendas',
sourceDescription: 'Funding agendas', sourceDescription: 'Funding agendas',
targetClass: 'FundingAgenda', targetClass: 'FundingAgenda',
targetSlot: 'related_agenda', targetSlot: 'has_detail',
transformation: 'array_direct', transformation: 'array_direct',
typedbEntity: 'funding-agenda', typedbEntity: 'funding-agenda',
typedbAttribute: 'agenda-name', typedbAttribute: 'agenda-name',
@ -4797,7 +4797,7 @@ location, and organizational metadata like company size and industry.
This data is crucial for understanding a person's professional This data is crucial for understanding a person's professional
trajectory and their experience in heritage-related roles. trajectory and their experience in heritage-related roles.
`.trim(), `.trim(),
linkmlClass: 'CareerPosition', linkmlClass: 'WorkExperience',
typedbEntity: 'career-position', typedbEntity: 'career-position',
provenance: { provenance: {
sourceType: 'external_api', sourceType: 'external_api',
@ -4807,8 +4807,8 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].organization', sourcePath: 'profile_data.career_history[].organization',
sourceDescription: 'Employer organization name', sourceDescription: 'Employer organization name',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'affiliated_with', targetSlot: 'employed_by',
typedbAttribute: 'organization-name', typedbAttribute: 'organization-name',
rdfPredicate: 'schema:worksFor', rdfPredicate: 'schema:worksFor',
transformation: 'direct', transformation: 'direct',
@ -4818,7 +4818,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].organization_linkedin', sourcePath: 'profile_data.career_history[].organization_linkedin',
sourceDescription: 'LinkedIn URL for organization', sourceDescription: 'LinkedIn URL for organization',
targetClass: 'CareerPosition', targetClass: 'Employer',
targetSlot: 'has_url', targetSlot: 'has_url',
typedbAttribute: 'organization-linkedin-url', typedbAttribute: 'organization-linkedin-url',
rdfPredicate: 'schema:sameAs', rdfPredicate: 'schema:sameAs',
@ -4829,8 +4829,8 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].role', sourcePath: 'profile_data.career_history[].role',
sourceDescription: 'Job title/role', sourceDescription: 'Job title/role',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'has_role', targetSlot: 'has_position',
typedbAttribute: 'role-title', typedbAttribute: 'role-title',
rdfPredicate: 'schema:jobTitle', rdfPredicate: 'schema:jobTitle',
transformation: 'direct', transformation: 'direct',
@ -4840,8 +4840,8 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].role_english', sourcePath: 'profile_data.career_history[].role_english',
sourceDescription: 'English translation of role', sourceDescription: 'English translation of role',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'has_role', targetSlot: 'has_position',
typedbAttribute: 'role-title-english', typedbAttribute: 'role-title-english',
rdfPredicate: 'schema:jobTitle', rdfPredicate: 'schema:jobTitle',
transformation: 'direct', transformation: 'direct',
@ -4851,7 +4851,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].dates', sourcePath: 'profile_data.career_history[].dates',
sourceDescription: 'Employment date range', sourceDescription: 'Employment date range',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'temporal_extent', targetSlot: 'temporal_extent',
typedbAttribute: 'date-range', typedbAttribute: 'date-range',
rdfPredicate: 'schema:temporalCoverage', rdfPredicate: 'schema:temporalCoverage',
@ -4862,7 +4862,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].duration', sourcePath: 'profile_data.career_history[].duration',
sourceDescription: 'Employment duration', sourceDescription: 'Employment duration',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'temporal_extent', targetSlot: 'temporal_extent',
typedbAttribute: 'duration', typedbAttribute: 'duration',
rdfPredicate: 'schema:duration', rdfPredicate: 'schema:duration',
@ -4873,7 +4873,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].location', sourcePath: 'profile_data.career_history[].location',
sourceDescription: 'Work location', sourceDescription: 'Work location',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'has_location', targetSlot: 'has_location',
typedbAttribute: 'work-location', typedbAttribute: 'work-location',
rdfPredicate: 'schema:workLocation', rdfPredicate: 'schema:workLocation',
@ -4884,7 +4884,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].current', sourcePath: 'profile_data.career_history[].current',
sourceDescription: 'Is current position', sourceDescription: 'Is current position',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'current', targetSlot: 'current',
typedbAttribute: 'is-current', typedbAttribute: 'is-current',
rdfPredicate: 'schema:currentPosition', rdfPredicate: 'schema:currentPosition',
@ -4895,7 +4895,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].company_size', sourcePath: 'profile_data.career_history[].company_size',
sourceDescription: 'Company employee count range', sourceDescription: 'Company employee count range',
targetClass: 'CareerPosition', targetClass: 'Employer',
targetSlot: 'has_detail', targetSlot: 'has_detail',
typedbAttribute: 'company-size', typedbAttribute: 'company-size',
rdfPredicate: 'schema:numberOfEmployees', rdfPredicate: 'schema:numberOfEmployees',
@ -4906,7 +4906,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].company_founded', sourcePath: 'profile_data.career_history[].company_founded',
sourceDescription: 'Year company was founded', sourceDescription: 'Year company was founded',
targetClass: 'CareerPosition', targetClass: 'Employer',
targetSlot: 'founded_through', targetSlot: 'founded_through',
typedbAttribute: 'company-founded-year', typedbAttribute: 'company-founded-year',
rdfPredicate: 'schema:foundingDate', rdfPredicate: 'schema:foundingDate',
@ -4917,7 +4917,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].company_type', sourcePath: 'profile_data.career_history[].company_type',
sourceDescription: 'Type of company', sourceDescription: 'Type of company',
targetClass: 'CareerPosition', targetClass: 'Employer',
targetSlot: 'has_type', targetSlot: 'has_type',
typedbAttribute: 'company-type', typedbAttribute: 'company-type',
rdfPredicate: 'schema:additionalType', rdfPredicate: 'schema:additionalType',
@ -4928,7 +4928,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].industry', sourcePath: 'profile_data.career_history[].industry',
sourceDescription: 'Industry sector', sourceDescription: 'Industry sector',
targetClass: 'CareerPosition', targetClass: 'Employer',
targetSlot: 'has_domain', targetSlot: 'has_domain',
typedbAttribute: 'industry', typedbAttribute: 'industry',
rdfPredicate: 'schema:industry', rdfPredicate: 'schema:industry',
@ -4939,7 +4939,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].department', sourcePath: 'profile_data.career_history[].department',
sourceDescription: 'Department within organization', sourceDescription: 'Department within organization',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'department_of', targetSlot: 'department_of',
typedbAttribute: 'department', typedbAttribute: 'department',
rdfPredicate: 'schema:department', rdfPredicate: 'schema:department',
@ -4950,7 +4950,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].level', sourcePath: 'profile_data.career_history[].level',
sourceDescription: 'Seniority level', sourceDescription: 'Seniority level',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'has_level', targetSlot: 'has_level',
typedbAttribute: 'seniority-level', typedbAttribute: 'seniority-level',
rdfPredicate: 'schema:occupationalCategory', rdfPredicate: 'schema:occupationalCategory',
@ -4961,7 +4961,7 @@ trajectory and their experience in heritage-related roles.
{ {
sourcePath: 'profile_data.career_history[].description', sourcePath: 'profile_data.career_history[].description',
sourceDescription: 'Role description', sourceDescription: 'Role description',
targetClass: 'CareerPosition', targetClass: 'WorkExperience',
targetSlot: 'has_description', targetSlot: 'has_description',
typedbAttribute: 'role-description', typedbAttribute: 'role-description',
rdfPredicate: 'schema:description', rdfPredicate: 'schema:description',
@ -5175,7 +5175,7 @@ current institution, sector role, and years of heritage experience.
This provides a quick overview of where the person fits This provides a quick overview of where the person fits
within the heritage ecosystem. within the heritage ecosystem.
`.trim(), `.trim(),
linkmlClass: 'HeritageRelevance', linkmlClass: 'HeritageRelevanceAssessment',
typedbEntity: 'heritage-relevance', typedbEntity: 'heritage-relevance',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -5185,7 +5185,7 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.heritage_type', sourcePath: 'heritage_sector_relevance.heritage_type',
sourceDescription: 'Heritage type code', sourceDescription: 'Heritage type code',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'has_type', targetSlot: 'has_type',
typedbAttribute: 'heritage-type-code', typedbAttribute: 'heritage-type-code',
rdfPredicate: 'glam:heritageType', rdfPredicate: 'glam:heritageType',
@ -5196,8 +5196,8 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.heritage_type_label', sourcePath: 'heritage_sector_relevance.heritage_type_label',
sourceDescription: 'Heritage type label', sourceDescription: 'Heritage type label',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'has_label', targetSlot: 'has_note',
typedbAttribute: 'heritage-type-label', typedbAttribute: 'heritage-type-label',
rdfPredicate: 'rdfs:label', rdfPredicate: 'rdfs:label',
transformation: 'direct', transformation: 'direct',
@ -5207,8 +5207,8 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.current_institution', sourcePath: 'heritage_sector_relevance.current_institution',
sourceDescription: 'Current heritage institution', sourceDescription: 'Current heritage institution',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'affiliated_with', targetSlot: 'has_note',
typedbAttribute: 'current-institution', typedbAttribute: 'current-institution',
rdfPredicate: 'schema:worksFor', rdfPredicate: 'schema:worksFor',
transformation: 'direct', transformation: 'direct',
@ -5218,7 +5218,7 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.institution_type', sourcePath: 'heritage_sector_relevance.institution_type',
sourceDescription: 'Type of institution', sourceDescription: 'Type of institution',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'has_type', targetSlot: 'has_type',
typedbAttribute: 'institution-type', typedbAttribute: 'institution-type',
rdfPredicate: 'schema:additionalType', rdfPredicate: 'schema:additionalType',
@ -5229,8 +5229,8 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.sector_role', sourcePath: 'heritage_sector_relevance.sector_role',
sourceDescription: 'Role within heritage sector', sourceDescription: 'Role within heritage sector',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'has_role', targetSlot: 'has_note',
typedbAttribute: 'sector-role', typedbAttribute: 'sector-role',
rdfPredicate: 'schema:jobTitle', rdfPredicate: 'schema:jobTitle',
transformation: 'direct', transformation: 'direct',
@ -5240,8 +5240,8 @@ within the heritage ecosystem.
{ {
sourcePath: 'heritage_sector_relevance.years_in_heritage', sourcePath: 'heritage_sector_relevance.years_in_heritage',
sourceDescription: 'Years of heritage experience', sourceDescription: 'Years of heritage experience',
targetClass: 'HeritageRelevance', targetClass: 'HeritageRelevanceAssessment',
targetSlot: 'has_detail', targetSlot: 'has_score',
typedbAttribute: 'years-in-heritage', typedbAttribute: 'years-in-heritage',
rdfPredicate: 'schema:experienceYears', rdfPredicate: 'schema:experienceYears',
transformation: 'direct', transformation: 'direct',
@ -5273,7 +5273,7 @@ Extracted from full career history with relevance annotations.
Includes both current and past positions at heritage institutions Includes both current and past positions at heritage institutions
with notes explaining their relevance to the GLAM sector. with notes explaining their relevance to the GLAM sector.
`.trim(), `.trim(),
linkmlClass: 'HeritageExperience', linkmlClass: 'WorkExperience',
typedbEntity: 'heritage-experience', typedbEntity: 'heritage-experience',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -5283,8 +5283,8 @@ with notes explaining their relevance to the GLAM sector.
{ {
sourcePath: 'profile_data.heritage_relevant_experience[].organization', sourcePath: 'profile_data.heritage_relevant_experience[].organization',
sourceDescription: 'Heritage organization name', sourceDescription: 'Heritage organization name',
targetClass: 'HeritageExperience', targetClass: 'WorkExperience',
targetSlot: 'affiliated_with', targetSlot: 'employed_by',
typedbAttribute: 'heritage-org-name', typedbAttribute: 'heritage-org-name',
rdfPredicate: 'schema:worksFor', rdfPredicate: 'schema:worksFor',
transformation: 'direct', transformation: 'direct',
@ -5294,8 +5294,8 @@ with notes explaining their relevance to the GLAM sector.
{ {
sourcePath: 'profile_data.heritage_relevant_experience[].role', sourcePath: 'profile_data.heritage_relevant_experience[].role',
sourceDescription: 'Role at heritage organization', sourceDescription: 'Role at heritage organization',
targetClass: 'HeritageExperience', targetClass: 'WorkExperience',
targetSlot: 'has_role', targetSlot: 'has_position',
typedbAttribute: 'heritage-role', typedbAttribute: 'heritage-role',
rdfPredicate: 'schema:jobTitle', rdfPredicate: 'schema:jobTitle',
transformation: 'direct', transformation: 'direct',
@ -5305,8 +5305,8 @@ with notes explaining their relevance to the GLAM sector.
{ {
sourcePath: 'profile_data.heritage_relevant_experience[].relevance', sourcePath: 'profile_data.heritage_relevant_experience[].relevance',
sourceDescription: 'Relevance explanation', sourceDescription: 'Relevance explanation',
targetClass: 'HeritageExperience', targetClass: 'WorkExperience',
targetSlot: 'has_significance', targetSlot: 'has_note',
typedbAttribute: 'relevance-notes', typedbAttribute: 'relevance-notes',
rdfPredicate: 'schema:description', rdfPredicate: 'schema:description',
transformation: 'direct', transformation: 'direct',
@ -5316,7 +5316,7 @@ with notes explaining their relevance to the GLAM sector.
{ {
sourcePath: 'profile_data.heritage_relevant_experience[].current', sourcePath: 'profile_data.heritage_relevant_experience[].current',
sourceDescription: 'Is current position', sourceDescription: 'Is current position',
targetClass: 'HeritageExperience', targetClass: 'WorkExperience',
targetSlot: 'current', targetSlot: 'current',
typedbAttribute: 'is-current-heritage', typedbAttribute: 'is-current-heritage',
rdfPredicate: 'schema:currentPosition', rdfPredicate: 'schema:currentPosition',
@ -5325,7 +5325,7 @@ with notes explaining their relevance to the GLAM sector.
notes: 'Whether this is a current position', notes: 'Whether this is a current position',
}, },
], ],
generatedClasses: ['HeritageExperience'], generatedClasses: ['WorkExperience'],
exampleYaml: ` exampleYaml: `
profile_data: profile_data:
heritage_relevant_experience: heritage_relevant_experience:
@ -5354,7 +5354,7 @@ role title, and heritage classification.
These affiliations enable network analysis across the heritage These affiliations enable network analysis across the heritage
sector workforce. sector workforce.
`.trim(), `.trim(),
linkmlClass: 'Affiliation', linkmlClass: 'Membership',
typedbEntity: 'affiliation', typedbEntity: 'affiliation',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -5364,7 +5364,7 @@ sector workforce.
{ {
sourcePath: 'affiliations[].custodian_name', sourcePath: 'affiliations[].custodian_name',
sourceDescription: 'Heritage custodian name', sourceDescription: 'Heritage custodian name',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'has_name', targetSlot: 'has_name',
typedbAttribute: 'custodian-name', typedbAttribute: 'custodian-name',
rdfPredicate: 'schema:memberOf', rdfPredicate: 'schema:memberOf',
@ -5375,8 +5375,8 @@ sector workforce.
{ {
sourcePath: 'affiliations[].custodian_slug', sourcePath: 'affiliations[].custodian_slug',
sourceDescription: 'Custodian identifier slug', sourceDescription: 'Custodian identifier slug',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'identified_by', targetSlot: 'has_slug',
typedbAttribute: 'custodian-slug', typedbAttribute: 'custodian-slug',
rdfPredicate: 'schema:identifier', rdfPredicate: 'schema:identifier',
transformation: 'direct', transformation: 'direct',
@ -5386,8 +5386,8 @@ sector workforce.
{ {
sourcePath: 'affiliations[].role_title', sourcePath: 'affiliations[].role_title',
sourceDescription: 'Role at custodian', sourceDescription: 'Role at custodian',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'role_title', targetSlot: 'has_role',
typedbAttribute: 'affiliation-role', typedbAttribute: 'affiliation-role',
rdfPredicate: 'schema:jobTitle', rdfPredicate: 'schema:jobTitle',
transformation: 'direct', transformation: 'direct',
@ -5397,8 +5397,8 @@ sector workforce.
{ {
sourcePath: 'affiliations[].heritage_relevant', sourcePath: 'affiliations[].heritage_relevant',
sourceDescription: 'Is heritage relevant', sourceDescription: 'Is heritage relevant',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'has_significance', targetSlot: 'has_note',
typedbAttribute: 'is-heritage-relevant', typedbAttribute: 'is-heritage-relevant',
rdfPredicate: 'glam:heritageRelevant', rdfPredicate: 'glam:heritageRelevant',
transformation: 'direct', transformation: 'direct',
@ -5408,7 +5408,7 @@ sector workforce.
{ {
sourcePath: 'affiliations[].heritage_type', sourcePath: 'affiliations[].heritage_type',
sourceDescription: 'Heritage type code', sourceDescription: 'Heritage type code',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'has_type', targetSlot: 'has_type',
typedbAttribute: 'affiliation-heritage-type', typedbAttribute: 'affiliation-heritage-type',
rdfPredicate: 'glam:heritageType', rdfPredicate: 'glam:heritageType',
@ -5419,7 +5419,7 @@ sector workforce.
{ {
sourcePath: 'affiliations[].current', sourcePath: 'affiliations[].current',
sourceDescription: 'Is current affiliation', sourceDescription: 'Is current affiliation',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'current', targetSlot: 'current',
typedbAttribute: 'is-current-affiliation', typedbAttribute: 'is-current-affiliation',
rdfPredicate: 'schema:currentPosition', rdfPredicate: 'schema:currentPosition',
@ -5430,7 +5430,7 @@ sector workforce.
{ {
sourcePath: 'affiliations[].observed_on', sourcePath: 'affiliations[].observed_on',
sourceDescription: 'Observation timestamp', sourceDescription: 'Observation timestamp',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'observed_in', targetSlot: 'observed_in',
typedbAttribute: 'observed-on', typedbAttribute: 'observed-on',
rdfPredicate: 'prov:generatedAtTime', rdfPredicate: 'prov:generatedAtTime',
@ -5441,8 +5441,8 @@ sector workforce.
{ {
sourcePath: 'affiliations[].source_url', sourcePath: 'affiliations[].source_url',
sourceDescription: 'Source URL for affiliation', sourceDescription: 'Source URL for affiliation',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'source_url', targetSlot: 'retrieved_from',
typedbAttribute: 'affiliation-source-url', typedbAttribute: 'affiliation-source-url',
rdfPredicate: 'prov:wasDerivedFrom', rdfPredicate: 'prov:wasDerivedFrom',
transformation: 'direct', transformation: 'direct',
@ -5450,7 +5450,7 @@ sector workforce.
notes: 'URL where affiliation was discovered', notes: 'URL where affiliation was discovered',
}, },
], ],
generatedClasses: ['Affiliation'], generatedClasses: ['Membership'],
exampleYaml: ` exampleYaml: `
affiliations: affiliations:
- custodian_name: Nationaal Archief - custodian_name: Nationaal Archief
@ -5478,7 +5478,7 @@ and custodian records (heritage institution YAML files).
These links enable navigation between person profiles and These links enable navigation between person profiles and
the institutions they work for. the institutions they work for.
`.trim(), `.trim(),
linkmlClass: 'LinkedRecords', linkmlClass: 'FileLocation',
typedbEntity: 'linked-records', typedbEntity: 'linked-records',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -5488,8 +5488,8 @@ the institutions they work for.
{ {
sourcePath: 'linked_records.staff_record.file', sourcePath: 'linked_records.staff_record.file',
sourceDescription: 'Staff record file path', sourceDescription: 'Staff record file path',
targetClass: 'LinkedRecords', targetClass: 'FileLocation',
targetSlot: 'has_file_location', targetSlot: 'has_value',
typedbAttribute: 'staff-record-path', typedbAttribute: 'staff-record-path',
rdfPredicate: 'prov:wasDerivedFrom', rdfPredicate: 'prov:wasDerivedFrom',
transformation: 'direct', transformation: 'direct',
@ -5499,8 +5499,8 @@ the institutions they work for.
{ {
sourcePath: 'linked_records.staff_record.staff_id', sourcePath: 'linked_records.staff_record.staff_id',
sourceDescription: 'Staff record ID', sourceDescription: 'Staff record ID',
targetClass: 'LinkedRecords', targetClass: 'Identifier',
targetSlot: 'staff_id', targetSlot: 'has_value',
typedbAttribute: 'staff-id', typedbAttribute: 'staff-id',
rdfPredicate: 'schema:identifier', rdfPredicate: 'schema:identifier',
transformation: 'direct', transformation: 'direct',
@ -5510,8 +5510,8 @@ the institutions they work for.
{ {
sourcePath: 'linked_records.custodian_record.ghcid', sourcePath: 'linked_records.custodian_record.ghcid',
sourceDescription: 'Custodian GHCID', sourceDescription: 'Custodian GHCID',
targetClass: 'LinkedRecords', targetClass: 'GHCIdentifier',
targetSlot: 'identified_by', targetSlot: 'has_value',
typedbAttribute: 'linked-ghcid', typedbAttribute: 'linked-ghcid',
rdfPredicate: 'glam:ghcid', rdfPredicate: 'glam:ghcid',
transformation: 'direct', transformation: 'direct',
@ -5521,7 +5521,7 @@ the institutions they work for.
{ {
sourcePath: 'linked_records.custodian_record.notes', sourcePath: 'linked_records.custodian_record.notes',
sourceDescription: 'Custodian record notes', sourceDescription: 'Custodian record notes',
targetClass: 'LinkedRecords', targetClass: 'FileLocation',
targetSlot: 'has_note', targetSlot: 'has_note',
typedbAttribute: 'custodian-notes', typedbAttribute: 'custodian-notes',
rdfPredicate: 'schema:description', rdfPredicate: 'schema:description',
@ -5530,7 +5530,7 @@ the institutions they work for.
notes: 'Additional notes about the custodian link', notes: 'Additional notes about the custodian link',
}, },
], ],
generatedClasses: ['LinkedRecords'], generatedClasses: ['FileLocation'],
exampleYaml: ` exampleYaml: `
linked_records: linked_records:
staff_record: staff_record:
@ -5555,7 +5555,7 @@ with confidence scores indicating reliability.
Also includes profile photo URLs and external lookup service links. Also includes profile photo URLs and external lookup service links.
`.trim(), `.trim(),
linkmlClass: 'ContactData', linkmlClass: 'ContactDetails',
typedbEntity: 'contact-data', typedbEntity: 'contact-data',
provenance: { provenance: {
sourceType: 'computed', sourceType: 'computed',
@ -5565,7 +5565,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.provenance.source', sourcePath: 'contact_data.provenance.source',
sourceDescription: 'Contact data source', sourceDescription: 'Contact data source',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_source', targetSlot: 'has_source',
typedbAttribute: 'contact-source', typedbAttribute: 'contact-source',
rdfPredicate: 'prov:wasAttributedTo', rdfPredicate: 'prov:wasAttributedTo',
@ -5576,7 +5576,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.emails[].email', sourcePath: 'contact_data.emails[].email',
sourceDescription: 'Email address', sourceDescription: 'Email address',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_email_address', targetSlot: 'has_email_address',
typedbAttribute: 'email-address', typedbAttribute: 'email-address',
rdfPredicate: 'schema:email', rdfPredicate: 'schema:email',
@ -5587,7 +5587,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.emails[].type', sourcePath: 'contact_data.emails[].type',
sourceDescription: 'Email type', sourceDescription: 'Email type',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_type', targetSlot: 'has_type',
typedbAttribute: 'email-type', typedbAttribute: 'email-type',
rdfPredicate: 'schema:contactType', rdfPredicate: 'schema:contactType',
@ -5598,7 +5598,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.emails[].confidence', sourcePath: 'contact_data.emails[].confidence',
sourceDescription: 'Email confidence score', sourceDescription: 'Email confidence score',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_confidence_measure', targetSlot: 'has_confidence_measure',
typedbAttribute: 'email-confidence', typedbAttribute: 'email-confidence',
rdfPredicate: 'prov:confidence', rdfPredicate: 'prov:confidence',
@ -5609,7 +5609,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.emails[].verified', sourcePath: 'contact_data.emails[].verified',
sourceDescription: 'Email verification status', sourceDescription: 'Email verification status',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_detail', targetSlot: 'has_detail',
typedbAttribute: 'email-verified', typedbAttribute: 'email-verified',
rdfPredicate: 'schema:verified', rdfPredicate: 'schema:verified',
@ -5620,7 +5620,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.profile_photo_url', sourcePath: 'contact_data.profile_photo_url',
sourceDescription: 'Profile photo URL', sourceDescription: 'Profile photo URL',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_image', targetSlot: 'has_image',
typedbAttribute: 'profile-photo', typedbAttribute: 'profile-photo',
rdfPredicate: 'schema:image', rdfPredicate: 'schema:image',
@ -5631,7 +5631,7 @@ Also includes profile photo URLs and external lookup service links.
{ {
sourcePath: 'contact_data.rocketreach_url', sourcePath: 'contact_data.rocketreach_url',
sourceDescription: 'RocketReach lookup URL', sourceDescription: 'RocketReach lookup URL',
targetClass: 'ContactData', targetClass: 'ContactDetails',
targetSlot: 'has_url', targetSlot: 'has_url',
typedbAttribute: 'rocketreach-url', typedbAttribute: 'rocketreach-url',
rdfPredicate: 'schema:sameAs', rdfPredicate: 'schema:sameAs',
@ -5640,7 +5640,7 @@ Also includes profile photo URLs and external lookup service links.
notes: 'Link to RocketReach profile lookup', notes: 'Link to RocketReach profile lookup',
}, },
], ],
generatedClasses: ['ContactData'], generatedClasses: ['ContactDetails'],
exampleYaml: ` exampleYaml: `
contact_data: contact_data:
provenance: provenance:
@ -5685,7 +5685,7 @@ reproducibility of the extraction process.
sourcePath: 'extraction_metadata.source_file', sourcePath: 'extraction_metadata.source_file',
sourceDescription: 'Source file path', sourceDescription: 'Source file path',
targetClass: 'ExtractionMetadata', targetClass: 'ExtractionMetadata',
targetSlot: 'source_file', targetSlot: 'has_file_location',
typedbAttribute: 'source-file-path', typedbAttribute: 'source-file-path',
rdfPredicate: 'prov:wasDerivedFrom', rdfPredicate: 'prov:wasDerivedFrom',
transformation: 'direct', transformation: 'direct',
@ -5696,7 +5696,7 @@ reproducibility of the extraction process.
sourcePath: 'extraction_metadata.staff_id', sourcePath: 'extraction_metadata.staff_id',
sourceDescription: 'Staff identifier', sourceDescription: 'Staff identifier',
targetClass: 'ExtractionMetadata', targetClass: 'ExtractionMetadata',
targetSlot: 'staff_id', targetSlot: 'has_slug',
typedbAttribute: 'extraction-staff-id', typedbAttribute: 'extraction-staff-id',
rdfPredicate: 'schema:identifier', rdfPredicate: 'schema:identifier',
transformation: 'direct', transformation: 'direct',
@ -5762,7 +5762,7 @@ reproducibility of the extraction process.
sourcePath: 'extraction_metadata.request_id', sourcePath: 'extraction_metadata.request_id',
sourceDescription: 'API request identifier', sourceDescription: 'API request identifier',
targetClass: 'ExtractionMetadata', targetClass: 'ExtractionMetadata',
targetSlot: 'request_id', targetSlot: 'has_code',
typedbAttribute: 'api-request-id', typedbAttribute: 'api-request-id',
rdfPredicate: 'schema:identifier', rdfPredicate: 'schema:identifier',
transformation: 'direct', transformation: 'direct',
@ -5830,7 +5830,7 @@ This follows the WebObservation pattern for verifiable data claims.
sourcePath: 'web_claims[].source_url', sourcePath: 'web_claims[].source_url',
sourceDescription: 'URL source of claim', sourceDescription: 'URL source of claim',
targetClass: 'WebClaim', targetClass: 'WebClaim',
targetSlot: 'source_url', targetSlot: 'retrieved_from',
typedbAttribute: 'claim-source-url', typedbAttribute: 'claim-source-url',
rdfPredicate: 'prov:wasDerivedFrom', rdfPredicate: 'prov:wasDerivedFrom',
transformation: 'direct', transformation: 'direct',
@ -5841,7 +5841,7 @@ This follows the WebObservation pattern for verifiable data claims.
sourcePath: 'web_claims[].retrieved_on', sourcePath: 'web_claims[].retrieved_on',
sourceDescription: 'Retrieval timestamp', sourceDescription: 'Retrieval timestamp',
targetClass: 'WebClaim', targetClass: 'WebClaim',
targetSlot: 'retrieved_on', targetSlot: 'retrieved_at',
typedbAttribute: 'claim-retrieved-on', typedbAttribute: 'claim-retrieved-on',
rdfPredicate: 'prov:generatedAtTime', rdfPredicate: 'prov:generatedAtTime',
transformation: 'direct', transformation: 'direct',
@ -5852,7 +5852,7 @@ This follows the WebObservation pattern for verifiable data claims.
sourcePath: 'web_claims[].retrieval_agent', sourcePath: 'web_claims[].retrieval_agent',
sourceDescription: 'Agent that retrieved claim', sourceDescription: 'Agent that retrieved claim',
targetClass: 'WebClaim', targetClass: 'WebClaim',
targetSlot: 'retrieval_agent', targetSlot: 'retrieved_by',
typedbAttribute: 'claim-retrieval-agent', typedbAttribute: 'claim-retrieval-agent',
rdfPredicate: 'prov:wasAttributedTo', rdfPredicate: 'prov:wasAttributedTo',
transformation: 'direct', transformation: 'direct',
@ -5941,7 +5941,7 @@ showing the semantic alignment between the ontologies.
sourcePath: 'extraction_metadata.linkedin_url', sourcePath: 'extraction_metadata.linkedin_url',
sourceDescription: 'LinkedIn profile URL as primary source', sourceDescription: 'LinkedIn profile URL as primary source',
targetClass: 'PersonObservation', targetClass: 'PersonObservation',
targetSlot: 'source_url', targetSlot: 'retrieved_from',
typedbAttribute: 'source-url', typedbAttribute: 'source-url',
rdfPredicate: 'prov:hadPrimarySource', rdfPredicate: 'prov:hadPrimarySource',
transformation: 'direct', transformation: 'direct',
@ -5952,8 +5952,8 @@ showing the semantic alignment between the ontologies.
{ {
sourcePath: 'affiliations[].role_title', sourcePath: 'affiliations[].role_title',
sourceDescription: 'Role at heritage institution', sourceDescription: 'Role at heritage institution',
targetClass: 'Affiliation', targetClass: 'Membership',
targetSlot: 'role_title', targetSlot: 'has_role',
typedbAttribute: 'role-title', typedbAttribute: 'role-title',
rdfPredicate: 'pico:hasRole', rdfPredicate: 'pico:hasRole',
transformation: 'direct', transformation: 'direct',

View file

@ -1050,6 +1050,151 @@
cursor: not-allowed; cursor: not-allowed;
} }
/* UML Density Section */
.uml-density-section {
padding: 1rem 1.5rem;
background: #f0f4ff;
border-bottom: 1px solid #4a7dff;
}
.uml-density-section h3 {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: #172a59;
font-weight: 600;
}
.uml-density-desc {
margin: 0 0 0.75rem 0;
font-size: 0.75rem;
color: #666;
}
.uml-density-options {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.uml-density-option {
display: flex;
flex-direction: column;
gap: 0.125rem;
width: 100%;
padding: 0.625rem 0.75rem;
background: white;
border: 1px solid #e0e0e0;
border-radius: 6px;
text-align: left;
cursor: pointer;
transition: all 0.15s ease;
}
.uml-density-option:hover {
border-color: #4a7dff;
background: #f8f9ff;
}
.uml-density-option.active {
border-color: #4a7dff;
background: #ebefff;
}
.uml-density-label {
font-size: 0.8125rem;
font-weight: 500;
color: #172a59;
}
.uml-density-hint {
font-size: 0.6875rem;
color: #888;
}
.uml-density-option.active .uml-density-label {
color: #4a7dff;
}
.uml-density-info {
margin: 0.625rem 0 0 0;
font-size: 0.75rem;
color: #4a7dff;
font-weight: 500;
}
.uml-module-picker {
margin-top: 0.75rem;
}
.uml-module-chips {
margin-top: 0.75rem;
}
.uml-module-chips-title {
margin: 0 0 0.375rem 0;
font-size: 0.75rem;
color: #172a59;
font-weight: 500;
}
.uml-module-chip-row {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
}
.uml-module-chip {
padding: 0.35rem 0.625rem;
border: 1px solid #c8d4ff;
background: white;
color: #2c5ce6;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
}
.uml-module-chip:hover {
border-color: #4a7dff;
background: #f8f9ff;
}
.uml-module-chip.active {
border-color: #4a7dff;
background: #4a7dff;
color: white;
}
.uml-module-label {
display: block;
margin: 0 0 0.375rem 0;
font-size: 0.75rem;
color: #172a59;
font-weight: 500;
}
.uml-module-select {
width: 100%;
padding: 0.5rem;
border: 1px solid #c8d4ff;
border-radius: 4px;
background: white;
font-size: 0.8125rem;
color: #172a59;
cursor: pointer;
}
.uml-module-select:hover {
border-color: #4a7dff;
}
.uml-module-select:focus {
outline: none;
border-color: #4a7dff;
box-shadow: 0 0 0 2px rgba(74, 125, 255, 0.2);
}
/* Node Info Section */ /* Node Info Section */
.node-info-section { .node-info-section {
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
@ -2346,6 +2491,85 @@ body:has(.visualize-page.is-mobile .sidebar--mobile:not(.collapsed)) {
background: #6b9eff; background: #6b9eff;
} }
[data-theme="dark"] .uml-density-section {
background: #2d2d4a;
border-bottom-color: #4a7dff;
}
[data-theme="dark"] .uml-density-section h3 {
color: #e0e0e0;
}
[data-theme="dark"] .uml-density-desc {
color: #a0a0b0;
}
[data-theme="dark"] .uml-density-option {
background: #1e1e32;
border-color: #3d3d5c;
}
[data-theme="dark"] .uml-density-option:hover {
border-color: #4a7dff;
background: #2d2d4a;
}
[data-theme="dark"] .uml-density-option.active {
border-color: #4a7dff;
background: #2d2d4a;
}
[data-theme="dark"] .uml-density-label {
color: #e0e0e0;
}
[data-theme="dark"] .uml-density-hint {
color: #888;
}
[data-theme="dark"] .uml-density-option.active .uml-density-label {
color: #6b9eff;
}
[data-theme="dark"] .uml-density-info {
color: #6b9eff;
}
[data-theme="dark"] .uml-module-label {
color: #e0e0e0;
}
[data-theme="dark"] .uml-module-chips-title {
color: #e0e0e0;
}
[data-theme="dark"] .uml-module-chip {
background: #1e1e32;
border-color: #3d3d5c;
color: #a7c1ff;
}
[data-theme="dark"] .uml-module-chip:hover {
border-color: #4a7dff;
background: #2d2d4a;
}
[data-theme="dark"] .uml-module-chip.active {
border-color: #4a7dff;
background: #4a7dff;
color: white;
}
[data-theme="dark"] .uml-module-select {
background: #1e1e32;
border-color: #3d3d5c;
color: #e0e0e0;
}
[data-theme="dark"] .uml-module-select:hover {
border-color: #4a7dff;
}
/* Node Info Section */ /* Node Info Section */
[data-theme="dark"] .node-info-section { [data-theme="dark"] .node-info-section {
background: #2d2d4a; background: #2d2d4a;

View file

@ -3,7 +3,7 @@
* Supports both RDF (Turtle, N-Triples) and UML (Mermaid, PlantUML, GraphViz) formats * Supports both RDF (Turtle, N-Triples) and UML (Mermaid, PlantUML, GraphViz) formats
*/ */
import React, { useState, useCallback, useRef, useEffect } from 'react'; import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { useDatabase } from '@/hooks/useDatabase'; import { useDatabase } from '@/hooks/useDatabase';
import { useRdfParser } from '@/hooks/useRdfParser'; import { useRdfParser } from '@/hooks/useRdfParser';
import { useGraphData } from '@/hooks/useGraphData'; import { useGraphData } from '@/hooks/useGraphData';
@ -60,6 +60,100 @@ function isAdvancedRdfLayout(layout: string): layout is RdfAdvancedLayoutType {
return ['chord', 'radial-tree', 'sankey', 'edge-bundling', 'pack', 'tree', 'sunburst'].includes(layout); return ['chord', 'radial-tree', 'sankey', 'edge-bundling', 'pack', 'tree', 'sunburst'].includes(layout);
} }
type UmlDensityMode = 'full' | 'streamlined' | 'module';
type UmlModuleOption = { id: string; label: string; count: number };
const POPULAR_UML_MODULE_IDS = ['custodian', 'legal', 'collections'];
function humanizeModuleName(moduleId: string): string {
return moduleId
.replace(/_/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase());
}
function buildStreamlinedUmlDiagram(diagram: UMLDiagram): UMLDiagram {
if (!diagram || !diagram.nodes || !diagram.links) {
return diagram;
}
const nodeCount = diagram.nodes.length;
if (nodeCount <= 300) {
return diagram;
}
const degree = new Map<string, number>();
diagram.nodes.forEach((node) => degree.set(node.id, 0));
diagram.links.forEach((link) => {
if (!degree.has(link.source) || !degree.has(link.target)) return;
degree.set(link.source, (degree.get(link.source) || 0) + 1);
degree.set(link.target, (degree.get(link.target) || 0) + 1);
});
const threshold = nodeCount > 1200 ? 3 : nodeCount > 600 ? 2 : 1;
const keepIds = new Set<string>();
degree.forEach((d, id) => {
if (d >= threshold) keepIds.add(id);
});
const coreAnchors = ['Custodian', 'CustodianType', 'Organization', 'Person'];
coreAnchors.forEach((id) => {
if (degree.has(id)) keepIds.add(id);
});
const nodes = diagram.nodes.filter((node) => keepIds.has(node.id));
const links = diagram.links.filter((link) => keepIds.has(link.source) && keepIds.has(link.target));
if (nodes.length < 50) {
return diagram;
}
return {
...diagram,
nodes,
links,
};
}
function buildModuleFocusedUmlDiagram(diagram: UMLDiagram, moduleId: string): UMLDiagram {
if (!diagram || !diagram.nodes || !diagram.links) {
return diagram;
}
if (!moduleId || moduleId === '__all__') {
return diagram;
}
const primaryNodes = diagram.nodes.filter((node) => (node.module || 'other') === moduleId);
if (primaryNodes.length === 0) {
return diagram;
}
const keepIds = new Set<string>(primaryNodes.map((n) => n.id));
// Include one-hop neighbors for context around the selected module.
diagram.links.forEach((link) => {
if (keepIds.has(link.source)) keepIds.add(link.target);
if (keepIds.has(link.target)) keepIds.add(link.source);
});
let nodes = diagram.nodes.filter((node) => keepIds.has(node.id));
let links = diagram.links.filter((link) => keepIds.has(link.source) && keepIds.has(link.target));
// If the result is still too small, keep only direct module internals.
if (nodes.length < 20) {
const primaryIds = new Set(primaryNodes.map((n) => n.id));
nodes = primaryNodes;
links = diagram.links.filter((link) => primaryIds.has(link.source) && primaryIds.has(link.target));
}
return {
...diagram,
nodes,
links,
};
}
// Bilingual text object for translations // Bilingual text object for translations
const TEXT = { const TEXT = {
// Sidebar // Sidebar
@ -90,6 +184,18 @@ const TEXT = {
refreshUml: { nl: 'UML Vernieuwen', en: 'Refresh UML' }, refreshUml: { nl: 'UML Vernieuwen', en: 'Refresh UML' },
refreshRdf: { nl: 'RDF Vernieuwen', en: 'Refresh RDF' }, refreshRdf: { nl: 'RDF Vernieuwen', en: 'Refresh RDF' },
refreshHint: { nl: 'Haal de nieuwste versie op', en: 'Fetch the latest version' }, refreshHint: { nl: 'Haal de nieuwste versie op', en: 'Fetch the latest version' },
umlDensity: { nl: 'UML Weergavemodus', en: 'UML Display Mode' },
umlDensityDesc: { nl: 'Kies tussen volledig en gestroomlijnd overzicht', en: 'Choose between full and streamlined overview' },
umlModeFull: { nl: 'Volledig', en: 'Full' },
umlModeFullHint: { nl: 'Toon alle klassen en relaties', en: 'Show all classes and relationships' },
umlModeStreamlined: { nl: 'Gestroomlijnd', en: 'Streamlined' },
umlModeStreamlinedHint: { nl: 'Toon de belangrijkste, meest verbonden klassen', en: 'Show key, high-connectivity classes' },
umlModeModule: { nl: 'Module Focus', en: 'Module Focus' },
umlModeModuleHint: { nl: 'Toon een domein met context', en: 'Show one domain with context' },
umlModuleSelect: { nl: 'Module', en: 'Module' },
umlModuleAll: { nl: 'Alle modules', en: 'All modules' },
umlPopularModules: { nl: 'Populaire modules', en: 'Popular modules' },
umlShowingClasses: { nl: 'klassen zichtbaar', en: 'classes visible' },
// View switcher // View switcher
viewUml: { nl: 'UML Weergave', en: 'UML View' }, viewUml: { nl: 'UML Weergave', en: 'UML View' },
@ -364,6 +470,14 @@ export function Visualize() {
} }
return null; return null;
}); });
const [umlDensityMode, setUmlDensityMode] = useState<UmlDensityMode>(() => {
const saved = localStorage.getItem('visualize-uml-density-mode');
return (saved === 'streamlined' || saved === 'module') ? saved : 'full';
});
const [selectedUmlModule, setSelectedUmlModule] = useState<string>(() => {
return localStorage.getItem('visualize-uml-module') || '__all__';
});
// Dropdown state // Dropdown state
const [exportDropdownOpen, setExportDropdownOpen] = useState<boolean>(false); const [exportDropdownOpen, setExportDropdownOpen] = useState<boolean>(false);
@ -1063,6 +1177,51 @@ export function Visualize() {
const hasUmlContent = umlDiagram !== null; const hasUmlContent = umlDiagram !== null;
const hasContent = hasRdfContent || hasUmlContent; const hasContent = hasRdfContent || hasUmlContent;
const umlModuleOptions = useMemo<UmlModuleOption[]>(() => {
if (!umlDiagram) return [];
const counts = new Map<string, number>();
umlDiagram.nodes.forEach((node) => {
const moduleId = node.module || 'other';
counts.set(moduleId, (counts.get(moduleId) || 0) + 1);
});
const options: UmlModuleOption[] = [{ id: '__all__', label: t('umlModuleAll'), count: umlDiagram.nodes.length }];
const sorted = Array.from(counts.entries()).sort((a, b) => {
if (b[1] !== a[1]) return b[1] - a[1];
return a[0].localeCompare(b[0]);
});
sorted.forEach(([id, count]) => {
options.push({ id, label: humanizeModuleName(id), count });
});
return options;
}, [umlDiagram, t]);
const popularUmlModules = useMemo(() => {
if (!umlModuleOptions.length) return [];
return umlModuleOptions.filter((option) => POPULAR_UML_MODULE_IDS.includes(option.id));
}, [umlModuleOptions]);
useEffect(() => {
if (!umlModuleOptions.length) return;
if (umlModuleOptions.some((option) => option.id === selectedUmlModule)) return;
setSelectedUmlModule('__all__');
localStorage.setItem('visualize-uml-module', '__all__');
}, [umlModuleOptions, selectedUmlModule]);
const displayUmlDiagram = useMemo(() => {
if (!umlDiagram) return null;
if (umlDensityMode === 'streamlined') {
return buildStreamlinedUmlDiagram(umlDiagram);
}
if (umlDensityMode === 'module') {
return buildModuleFocusedUmlDiagram(umlDiagram, selectedUmlModule);
}
return umlDiagram;
}, [umlDiagram, umlDensityMode, selectedUmlModule]);
return ( return (
<div className={`visualize-page ${isFullscreen ? 'fullscreen-active' : ''} ${isMobile ? 'is-mobile' : ''}`}> <div className={`visualize-page ${isFullscreen ? 'fullscreen-active' : ''} ${isMobile ? 'is-mobile' : ''}`}>
{/* Mobile overlay when sidebar is open */} {/* Mobile overlay when sidebar is open */}
@ -1350,6 +1509,99 @@ export function Visualize() {
</div> </div>
)} )}
{hasUmlContent && currentCategory === 'uml' && (
<div className="uml-density-section">
<h3>{t('umlDensity')}</h3>
<p className="uml-density-desc">{t('umlDensityDesc')}</p>
<div className="uml-density-options">
<button
className={`uml-density-option ${umlDensityMode === 'full' ? 'active' : ''}`}
onClick={() => {
setUmlDensityMode('full');
localStorage.setItem('visualize-uml-density-mode', 'full');
}}
>
<span className="uml-density-label">{t('umlModeFull')}</span>
<span className="uml-density-hint">{t('umlModeFullHint')}</span>
</button>
<button
className={`uml-density-option ${umlDensityMode === 'streamlined' ? 'active' : ''}`}
onClick={() => {
setUmlDensityMode('streamlined');
localStorage.setItem('visualize-uml-density-mode', 'streamlined');
}}
>
<span className="uml-density-label">{t('umlModeStreamlined')}</span>
<span className="uml-density-hint">{t('umlModeStreamlinedHint')}</span>
</button>
<button
className={`uml-density-option ${umlDensityMode === 'module' ? 'active' : ''}`}
onClick={() => {
setUmlDensityMode('module');
localStorage.setItem('visualize-uml-density-mode', 'module');
}}
>
<span className="uml-density-label">{t('umlModeModule')}</span>
<span className="uml-density-hint">{t('umlModeModuleHint')}</span>
</button>
</div>
{umlDensityMode === 'module' && umlModuleOptions.length > 0 && (
<>
<div className="uml-module-chips">
<p className="uml-module-chips-title">{t('umlPopularModules')}</p>
<div className="uml-module-chip-row">
<button
className={`uml-module-chip ${selectedUmlModule === '__all__' ? 'active' : ''}`}
onClick={() => {
setSelectedUmlModule('__all__');
localStorage.setItem('visualize-uml-module', '__all__');
}}
>
{t('umlModuleAll')}
</button>
{popularUmlModules.map((option) => (
<button
key={option.id}
className={`uml-module-chip ${selectedUmlModule === option.id ? 'active' : ''}`}
onClick={() => {
setSelectedUmlModule(option.id);
localStorage.setItem('visualize-uml-module', option.id);
}}
>
{option.label}
</button>
))}
</div>
</div>
<div className="uml-module-picker">
<label htmlFor="uml-module-select" className="uml-module-label">{t('umlModuleSelect')}</label>
<select
id="uml-module-select"
className="uml-module-select"
value={selectedUmlModule}
onChange={(e) => {
const next = e.target.value;
setSelectedUmlModule(next);
localStorage.setItem('visualize-uml-module', next);
}}
>
{umlModuleOptions.map((option) => (
<option key={option.id} value={option.id}>
{option.label} ({option.count.toLocaleString()})
</option>
))}
</select>
</div>
</>
)}
{displayUmlDiagram && umlDiagram && (
<p className="uml-density-info">
{displayUmlDiagram.nodes.length.toLocaleString()} / {umlDiagram.nodes.length.toLocaleString()} {t('umlShowingClasses')}
</p>
)}
</div>
)}
{/* Graph Controls (RDF only) */} {/* Graph Controls (RDF only) */}
{hasRdfContent && currentCategory === 'rdf' && ( {hasRdfContent && currentCategory === 'rdf' && (
<GraphControls <GraphControls
@ -1814,7 +2066,7 @@ export function Visualize() {
{!isLoading && !umlError && hasUmlContent && currentCategory === 'uml' && ( {!isLoading && !umlError && hasUmlContent && currentCategory === 'uml' && (
<div className="uml-canvas"> <div className="uml-canvas">
<UMLVisualization <UMLVisualization
diagram={umlDiagram!} diagram={displayUmlDiagram || umlDiagram!}
width={1400} width={1400}
height={900} height={900}
layoutType={layoutType} layoutType={layoutType}

View file

@ -7,6 +7,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
gn: http://www.geonames.org/ontology# gn: http://www.geonames.org/ontology#
rdac: http://rdaregistry.info/Elements/c/
wdt: http://www.wikidata.org/prop/direct/ wdt: http://www.wikidata.org/prop/direct/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
prov: http://www.w3.org/ns/prov# prov: http://www.w3.org/ns/prov#
@ -58,6 +59,7 @@ classes:
close_mappings: close_mappings:
- crm:E53_Place - crm:E53_Place
- gn:Feature - gn:Feature
- rdac:C10009 # RDA Registry: Place (RDA Classes)
slots: slots:
- has_label - has_label
- has_name - has_name

View file

@ -1,12 +1,12 @@
{ {
"generated": "2026-02-18T10:16:43.406Z", "generated": "2026-02-18T20:43:54.475Z",
"schemaRoot": "/schemas/20251121/linkml", "schemaRoot": "/schemas/20251121/linkml",
"totalFiles": 2183, "totalFiles": 2187,
"categoryCounts": { "categoryCounts": {
"main": 4, "main": 4,
"class": 1377, "class": 1377,
"enum": 158, "enum": 158,
"slot": 640, "slot": 644,
"module": 4 "module": 4
}, },
"categories": [ "categories": [
@ -10387,6 +10387,21 @@
"path": "modules/slots/owned_by.yaml", "path": "modules/slots/owned_by.yaml",
"category": "slot" "category": "slot"
}, },
{
"name": "paid_amount",
"path": "modules/slots/paid_amount.yaml",
"category": "slot"
},
{
"name": "paid_from",
"path": "modules/slots/paid_from.yaml",
"category": "slot"
},
{
"name": "paid_to",
"path": "modules/slots/paid_to.yaml",
"category": "slot"
},
{ {
"name": "part_of", "name": "part_of",
"path": "modules/slots/part_of.yaml", "path": "modules/slots/part_of.yaml",
@ -10847,6 +10862,11 @@
"path": "modules/slots/transferred.yaml", "path": "modules/slots/transferred.yaml",
"category": "slot" "category": "slot"
}, },
{
"name": "transferred_from",
"path": "modules/slots/transferred_from.yaml",
"category": "slot"
},
{ {
"name": "transferred_to", "name": "transferred_to",
"path": "modules/slots/transferred_to.yaml", "path": "modules/slots/transferred_to.yaml",

View file

@ -12,6 +12,7 @@ prefixes:
gbif: http://rs.gbif.org/terms/ gbif: http://rs.gbif.org/terms/
aat: http://vocab.getty.edu/aat/ aat: http://vocab.getty.edu/aat/
imports: imports:
- ./ExhibitedObject
- linkml:types - linkml:types
- ../enums/PreservationMethodEnum - ../enums/PreservationMethodEnum
- ../metadata - ../metadata
@ -47,6 +48,7 @@ imports:
default_prefix: hc default_prefix: hc
classes: classes:
BiologicalObject: BiologicalObject:
is_a: ExhibitedObject
class_uri: crm:E20_Biological_Object class_uri: crm:E20_Biological_Object
description: >- description: >-
Natural specimen or organism-derived item held in a heritage collection, with associated taxonomic identification and preservation metadata. Natural specimen or organism-derived item held in a heritage collection, with associated taxonomic identification and preservation metadata.
@ -397,29 +399,64 @@ classes:
in_language: zh in_language: zh
- literal_form: value: https://nde.nl/ontology/hc/taxon/raphus-cucullatus broad_mappings:
- crm:E20_Biological_Object
close_mappings:
- dwc:Occurrence
- gbif:Specimen
related_mappings:
- crm:E19_Physical_Object
- crm:E22_Human-Made_Object
- schema:Taxon
predicate: EXACT_SYNONYM slots:
- identified_by
- has_label
- has_name
- has_rank
- has_authority
- commented_on
- identified_through
- has_specimen
- symbolize
- has_status
- has_gender
- has_stage
- contain
- has_quantity
- has_method
- has_detail
- prepared_on
- prepared_by
- acquired_through
- in_place
- describe
- acquired_by
- has_habitat
- has_hypernym
- listed_in
- has_provenance
- has_type
in_language: zh slot_usage:
# range: string # uriorcurie identified_by:
multivalued: true multivalued: true
inlined: false # Fixed invalid inline for primitive type inlined: false # Fixed invalid inline for primitive type
inlined_as_list: false # Fixed invalid inline for primitive type inlined_as_list: false # Fixed invalid inline for primitive type
required: false required: false
any_of: any_of:
- range: FieldNumber - range: FieldNumber
- range: BOLDIdentifier - range: BOLDIdentifier
- range: WikiDataIdentifier - range: WikiDataIdentifier
- range: string # uriorcurie - range: string # uriorcurie
examples: examples:
- value: - value:
has_type: FieldNumber has_type: FieldNumber
- value: - value:
id: https://nde.nl/ontology/hc/bold-id/NLNAT001-21 id: https://nde.nl/ontology/hc/bold-id/NLNAT001-21
has_type: BOLDIdentifier has_type: BOLDIdentifier
- value: - value:
has_type: WikiDataIdentifier has_type: WikiDataIdentifier
has_label: has_label:
range: TaxonName range: TaxonName
inlined: true inlined: true

View file

@ -36,195 +36,81 @@ classes:
zh: >- zh: >-
描述平台界面、操作程序或用户实施指南的技术参考资料。 描述平台界面、操作程序或用户实施指南的技术参考资料。
structured_aliases: structured_aliases:
- literal_form: documentatie - literal_form: documentatie
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: nl in_language: nl
- literal_form: technische handleiding - literal_form: technische handleiding
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: nl in_language: nl
- literal_form: Dokumentation - literal_form: Dokumentation
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: de in_language: de
- literal_form: technische Anleitung - literal_form: technische Anleitung
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: de in_language: de
- literal_form: documentation - literal_form: documentation
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: fr in_language: fr
- literal_form: guide technique - literal_form: guide technique
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: fr in_language: fr
- literal_form: documentación - literal_form: documentación
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: es in_language: es
- literal_form: guía técnica - literal_form: guía técnica
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: es in_language: es
- literal_form: التوثيق - literal_form: التوثيق
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: ar in_language: ar
- literal_form: الدليل الفني - literal_form: الدليل الفني
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: ar in_language: ar
- literal_form: dokumentasi - literal_form: dokumentasi
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: id in_language: id
- literal_form: panduan teknis - literal_form: panduan teknis
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: id in_language: id
- literal_form: 文档 - literal_form: 文档
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: 技术指南 - literal_form: 技术指南
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: documentation broad_mappings:
- schema:TechArticle
- foaf:Document
close_mappings:
- crm:E73_Information_Object
predicate: EXACT_SYNONYM slots:
- identified_by
- has_label
- has_description
- temporal_extent
in_language: zh slot_usage:
identified_by:
- literal_form: technical guide range: uri
required: true
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: API reference
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: user manual
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: operational guide
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: schema:CreativeWork
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: foaf:Document
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: schema:TechArticle
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: crm:E73_Information_Object
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: dcterms:references
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: has_label
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: has_description
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: identified_by
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: temporal_extent
predicate: EXACT_SYNONYM
in_language: zh
- literal_form: value: https://data.rijksmuseum.nl/object-metadata/api/
predicate: EXACT_SYNONYM
in_language: zh
# range: string
examples: examples:
- value: API Reference Documentation - value: https://data.rijksmuseum.nl/object-metadata/api/
- value: Developer Integration Guide has_label:
required: true
examples:
- value: Rijksmuseum Collection API
has_description: has_description:
# range: string
examples:
- value: Complete REST API reference with endpoint specifications, authentication, and response formats.
temporal_extent:
range: TimeSpan
inlined: true
required: false required: false
examples: examples:
- value: - value: Complete REST API reference with endpoint specifications, authentication, and response formats.
begin_of_the_begin: '2015-01-01' temporal_extent:
required: false
examples:
- value:
begin_of_the_begin: '2015-01-01'
has_verbatim_value: 2015-
comments: comments:
- Generic documentation class replacing domain-specific documentation slots - Generic documentation class replacing domain-specific documentation slots
- Supports multiple documentation types (API, user, developer, system) - Supports multiple documentation types (API, user, developer, system)

View file

@ -186,19 +186,19 @@ classes:
in_language: zh in_language: zh
- literal_form: value: | - literal_form: "value: |"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: expense_type: ADMINISTRATIVE - literal_form: "expense_type: ADMINISTRATIVE"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: expense_type: PROGRAM - literal_form: "expense_type: PROGRAM"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -185,7 +185,7 @@ classes:
in_language: zh in_language: zh
- literal_form: value: | - literal_form: "value: |"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
@ -197,37 +197,37 @@ classes:
in_language: zh in_language: zh
- literal_form: has_label: Manufacturer name (String or Label) - literal_form: "has_label: Manufacturer name (String or Label)"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_url: Manufacturer website (URL) - literal_form: "has_url: Manufacturer website (URL)"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: identified_by: Unique identifier - literal_form: "identified_by: Unique identifier"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Primary**: `schema:Organization` - Schema.org organization - literal_form: "**Primary**: `schema:Organization` - Schema.org organization"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Close**: `org:Organization` - W3C ORG organization - literal_form: "**Close**: `org:Organization` - W3C ORG organization"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Related**: `prov:Agent` - PROV-O agent responsible for production - literal_form: "**Related**: `prov:Agent` - PROV-O agent responsible for production"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -174,13 +174,13 @@ classes:
in_language: zh in_language: zh
- literal_form: value: PRIMARY - literal_form: "value: PRIMARY"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: CO_ORGANIZER - literal_form: "value: CO_ORGANIZER"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
@ -192,43 +192,43 @@ classes:
in_language: zh in_language: zh
- literal_form: PRIMARY: Main organizing institution - literal_form: "PRIMARY: Main organizing institution"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: CO_ORGANIZER: Partner institution with significant organizational role - literal_form: "CO_ORGANIZER: Partner institution with significant organizational role"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: SPONSOR_ORGANIZER: Sponsor with curatorial/organizational input - literal_form: "SPONSOR_ORGANIZER: Sponsor with curatorial/organizational input"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: LENDING_INSTITUTION: Institution lending objects with exhibition involvement - literal_form: "LENDING_INSTITUTION: Institution lending objects with exhibition involvement"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: HOST_VENUE: Venue hosting a traveling exhibition - literal_form: "HOST_VENUE: Venue hosting a traveling exhibition"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Primary**: `schema:Role` - Schema.org role - literal_form: "**Primary**: `schema:Role` - Schema.org role"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: **Close**: `prov:Role` - PROV-O role in activity - literal_form: "**Close**: `prov:Role` - PROV-O role in activity"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -380,163 +380,163 @@ classes:
in_language: zh in_language: zh
- literal_form: value: https://nde.nl/ontology/hc/aux/kroller-muller-sculpture - literal_form: "value: https://nde.nl/ontology/hc/aux/kroller-muller-sculpture"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Kroller-Muller Beeldentuin - literal_form: "value: Kroller-Muller Beeldentuin"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Paleis Het Loo Tuinen - literal_form: "value: Paleis Het Loo Tuinen"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: Archeologisch Park Matilo - literal_form: "value: Archeologisch Park Matilo"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: One of Europe's largest sculpture gardens with 160 works set in 25 hectares of park landscape within De Hoge Veluwe National Park. - literal_form: "value: One of Europe's largest sculpture gardens with 160 works set in 25 hectares of park landscape within De Hoge Veluwe National Park."
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: range: OutdoorSiteTypeEnum - literal_form: "range: OutdoorSiteTypeEnum"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: range: FeatureType - literal_form: "range: FeatureType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: SCULPTURE_GARDEN - literal_form: "value: SCULPTURE_GARDEN"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: ARCHAEOLOGICAL_SITE - literal_form: "value: ARCHAEOLOGICAL_SITE"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: FORMAL_GARDEN - literal_form: "value: FORMAL_GARDEN"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: BotanicalInstitutionClassification - literal_form: "value: BotanicalInstitutionClassification"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: ZoologicalInstitutionClassification - literal_form: "value: ZoologicalInstitutionClassification"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: 160 - literal_form: "value: 160"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: 2500 - literal_form: "value: 2500"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 25.0 - literal_form: "area_value: 25.0"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Included with museum ticket - literal_form: "has_label: Included with museum ticket"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Paved paths - literal_form: "has_label: Paved paths"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Wheelchair routes available - literal_form: "has_label: Wheelchair routes available"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 650.0 - literal_form: "area_value: 650.0"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Included with palace ticket - literal_form: "has_label: Included with palace ticket"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: - literal_form: "value:"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: area_value: 3.5 - literal_form: "area_value: 3.5"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: has_label: Free - literal_form: "has_label: Free"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -200,13 +200,13 @@ classes:
in_language: zh in_language: zh
- literal_form: value: hc:ArchiveOrganizationType - literal_form: "value: hc:ArchiveOrganizationType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM
in_language: zh in_language: zh
- literal_form: value: hc:HolySacredSiteType - literal_form: "value: hc:HolySacredSiteType"
predicate: EXACT_SYNONYM predicate: EXACT_SYNONYM

View file

@ -538,6 +538,9 @@ imports:
- ./outbound_to - ./outbound_to
- ./overlap_with - ./overlap_with
- ./owned_by - ./owned_by
- ./paid_amount
- ./paid_from
- ./paid_to
- ./part_of - ./part_of
- ./participate_in - ./participate_in
- ./performed_by - ./performed_by
@ -628,6 +631,7 @@ imports:
- ./threatened_by - ./threatened_by
- ./track - ./track
- ./transferred - ./transferred
- ./transferred_from
- ./transferred_to - ./transferred_to
- ./transmission - ./transmission
- ./transmit_through - ./transmit_through

View file

@ -31,6 +31,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -96,6 +97,7 @@ slots:
- schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically accessioning. - schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically accessioning.
related_mappings: related_mappings:
- crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of accessioning. - crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of accessioning.
- la:added_member # Linked Art extensions: member added to a Set via an Addition activity
aliases: aliases:
- objects_added - objects_added
examples: examples:

View file

@ -8,6 +8,7 @@ prefixes:
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
foaf: http://xmlns.com/foaf/0.1/ foaf: http://xmlns.com/foaf/0.1/
rdau: http://rdaregistry.info/Elements/u/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
prov: http://www.w3.org/ns/prov# prov: http://www.w3.org/ns/prov#
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
@ -44,6 +45,7 @@ slots:
close_mappings: close_mappings:
- crm:P7_took_place_at - crm:P7_took_place_at
- rico:birthPlace - rico:birthPlace
- rdau:P60593 # RDA Registry (Unconstrained): has place of birth
comments: comments:
- MIGRATED from birth_place slot (Rule 53) - MIGRATED from birth_place slot (Rule 53)
- Supports historical vs. modern place names - Supports historical vs. modern place names

View file

@ -24,6 +24,7 @@ prefixes:
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
owl: http://www.w3.org/2002/07/owl# owl: http://www.w3.org/2002/07/owl#
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -87,6 +88,7 @@ slots:
close_mappings: close_mappings:
- owl:sameAs # W3C OWL 2 standard - Identity assertion (stronger claim than semantic equivalence). - owl:sameAs # W3C OWL 2 standard - Identity assertion (stronger claim than semantic equivalence).
- schema:sameAs # schemaorg.owl:34129-34148 - "URL unambiguously indicating the item's identity." - schema:sameAs # schemaorg.owl:34129-34148 - "URL unambiguously indicating the item's identity."
- la:equivalent # Linked Art extensions: equivalent instance (skos:exactMatch-like without Concept inference)
aliases: aliases:
- is_or_was_equivalent_to - is_or_was_equivalent_to
- wikidata_equivalent - wikidata_equivalent

View file

@ -25,6 +25,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
la: https://linked.art/ns/terms/
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
default_prefix: hc default_prefix: hc
@ -82,6 +83,8 @@ slots:
- crm:P49_has_former_or_current_keeper # CIDOC_CRM_v7.1.3.rdf:2383-2408 - includes former keepers (broader temporal scope) - crm:P49_has_former_or_current_keeper # CIDOC_CRM_v7.1.3.rdf:2383-2408 - includes former keepers (broader temporal scope)
- crm:P50_has_current_keeper # CIDOC_CRM_v7.1.3.rdf:2410-2424 - "current keeper" but domain E18 Physical Thing / range E39 Actor (typed objects) - crm:P50_has_current_keeper # CIDOC_CRM_v7.1.3.rdf:2410-2424 - "current keeper" but domain E18 Physical Thing / range E39 Actor (typed objects)
- rico:hasOrHadHolder # RiC-O_1-1.rdf:6436-6475 - "has or had holder" — archival holding context, domain RecordResource/Instantiation - rico:hasOrHadHolder # RiC-O_1-1.rdf:6436-6475 - "has or had holder" — archival holding context, domain RecordResource/Instantiation
related_mappings:
- la:current_permanent_custodian # Linked Art extensions: normal/permanent custodian of a physical object (E19->E39)
comments: comments:
- | - |
MIGRATED 2026-02-03 from has_or_had_custodian for conciseness. MIGRATED 2026-02-03 from has_or_had_custodian for conciseness.

View file

@ -23,6 +23,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
dcat: http://www.w3.org/ns/dcat# dcat: http://www.w3.org/ns/dcat#
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
ardo: https://w3id.org/ardo/2.0/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -80,6 +81,8 @@ slots:
- dcat:keyword # dcat3.ttl:1208-1231 - "A keyword or tag describing a resource" - dcat:keyword # dcat3.ttl:1208-1231 - "A keyword or tag describing a resource"
close_mappings: close_mappings:
- dcterms:subject # dcterms.rdf:1968-1988 - "A topic of the resource" - dcterms:subject # dcterms.rdf:1968-1988 - "A topic of the resource"
related_mappings:
- ardo:has_keyword # ArDO 2.0: links a thematic subcategory to a keyword (object property)
comments: comments:
- "Used for discovery and classification." - "Used for discovery and classification."
annotations: annotations:

View file

@ -25,6 +25,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
org: http://www.w3.org/ns/org# org: http://www.w3.org/ns/org#
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
default_prefix: hc default_prefix: hc
imports: imports:
@ -80,5 +81,7 @@ slots:
exact_mappings: exact_mappings:
- org:hasMember # org.rdf:427-446 - "Indicates a person who is a member of the subject Organization." Domain: Organization, Range: Agent. Organization membership only; this slot also covers collection elements. - org:hasMember # org.rdf:427-446 - "Indicates a person who is a member of the subject Organization." Domain: Organization, Range: Agent. Organization membership only; this slot also covers collection elements.
- schema:member # schemaorg.owl:26055-26085 - "A member of an Organization or a ProgramMembership." Domain: Organization/ProgramMembership. Does not cover collection elements. - schema:member # schemaorg.owl:26055-26085 - "A member of an Organization or a ProgramMembership." Domain: Organization/ProgramMembership. Does not cover collection elements.
related_mappings:
- la:has_member # Linked Art extensions: membership (Set→Entity)
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -19,6 +19,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pca: http://rds.posccaesar.org/ontology/plm/rdl/
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -82,3 +83,5 @@ slots:
custodian_types: '["*"]' custodian_types: '["*"]'
close_mappings: close_mappings:
- dcterms:conformsTo # dcterms.rdf:987-1010 - "An established standard to which the described resource conforms." Conformance relationship ≠ having a standard. - dcterms:conformsTo # dcterms.rdf:987-1010 - "An established standard to which the described resource conforms." Conformance relationship ≠ having a standard.
related_mappings:
- pca:PCA_100003538 # POSC Caesar RDL (PCA PLM core): Standard (class)

View file

@ -24,6 +24,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pav: http://purl.org/pav/2.3#
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -81,6 +82,7 @@ slots:
multivalued: false multivalued: false
related_mappings: related_mappings:
- dcterms:hasVersion # dcterms.rdf:1371-1395 — "A related resource that is a version, edition, or adaptation." Relates resources to each other, not a version identifier. - dcterms:hasVersion # dcterms.rdf:1371-1395 — "A related resource that is a version, edition, or adaptation." Relates resources to each other, not a version identifier.
- pav:hasVersion # PAV 2.3 (used by ArDO): links a resource to a version resource
aliases: aliases:
- has_or_had_version - has_or_had_version
- api_ver - api_ver

View file

@ -27,6 +27,7 @@ prefixes:
schema: http://schema.org/ schema: http://schema.org/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -115,6 +116,7 @@ slots:
custodian_types: '["*"]' custodian_types: '["*"]'
related_mappings: related_mappings:
- schema:owns # schemaorg.owl:28732-28760 — "Things owned by the organization or person." Ownership ≠ custody/holding. - schema:owns # schemaorg.owl:28732-28760 — "Things owned by the organization or person." Ownership ≠ custody/holding.
- la:current_permanent_custodian_of # Linked Art extensions: inverse of current_permanent_custodian (Actor->Physical Object)
close_mappings: close_mappings:
- crm:P49i_is_former_or_current_keeper_of # CIDOC_CRM:2410-2435 — "is former or current keeper of." Custody relationship. - crm:P49i_is_former_or_current_keeper_of # CIDOC_CRM:2410-2435 — "is former or current keeper of." Custody relationship.
- rico:isOrWasHolderOf # RiC-O_1-1.rdf:6436-6470 — "has or had holder" (inverse). Archives holding. - rico:isOrWasHolderOf # RiC-O_1-1.rdf:6436-6470 — "has or had holder" (inverse). Archives holding.

View file

@ -32,6 +32,7 @@ prefixes:
rico: https://www.ica.org/standards/RiC/ontology# rico: https://www.ica.org/standards/RiC/ontology#
org: http://www.w3.org/ns/org# org: http://www.w3.org/ns/org#
foaf: http://xmlns.com/foaf/0.1/ foaf: http://xmlns.com/foaf/0.1/
la: https://linked.art/ns/terms/
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -98,6 +99,7 @@ slots:
- rico:isOrWasMemberOf # RiC-O_1-1.rdf:14505-14550 - Person→Group (restricted domain) - rico:isOrWasMemberOf # RiC-O_1-1.rdf:14505-14550 - Person→Group (restricted domain)
related_mappings: related_mappings:
- foaf:member # foaf.ttl:410-417 - INVERSE: Group→Agent (not Agent→Group) - foaf:member # foaf.ttl:410-417 - INVERSE: Group→Agent (not Agent→Group)
- la:member_of # Linked Art extensions: membership (Entity→Set)
annotations: annotations:
inverse_slot: has_or_had_member inverse_slot: has_or_had_member
deprecates: is_member_of deprecates: is_member_of

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_amount
# ==============================================================================
# Monetary amount paid in a payment/transfer context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|------------------|---------|------------------------------------------------------|
# | **Linked Art** | `la:paid_amount` | exact | Payment -> Monetary Amount in Linked Art extensions. |
# | **Schema.org** | `schema:price` | close | Price/value expression, broader commerce usage. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_amount
name: paid_amount
title: Paid Amount
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_amount:
slot_uri: hc:paidAmount
description: >-
Specifies the amount that was paid as part of a payment or transfer.
range: string
multivalued: false
exact_mappings:
- la:paid_amount
close_mappings:
- schema:price
aliases:
- is_or_was_paid_amount
annotations:
custodian_types: '["*"]'

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_from
# ==============================================================================
# Paying party/source in a payment context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|----------------|---------|-----------------------------------------------------------|
# | **Linked Art** | `la:paid_from` | exact | Payment source actor in Linked Art extensions. |
# | **Schema.org** | `schema:buyer` | related | Buyer role; related commercial payer perspective. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_from
name: paid_from
title: Paid From
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_from:
slot_uri: hc:paidFrom
description: >-
Identifies the party or source from which a payment originated.
range: string
multivalued: false
exact_mappings:
- la:paid_from
related_mappings:
- schema:buyer
aliases:
- is_or_was_paid_from
annotations:
custodian_types: '["*"]'

View file

@ -0,0 +1,41 @@
# ==============================================================================
# LinkML Slot Definition: paid_to
# ==============================================================================
# Receiving party/destination in a payment context.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|-----------------|---------|-----------------------------------------------------------|
# | **Linked Art** | `la:paid_to` | exact | Payment recipient actor in Linked Art extensions. |
# | **Schema.org** | `schema:seller` | related | Seller role; related commercial payee perspective. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/paid_to
name: paid_to
title: Paid To
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
paid_to:
slot_uri: hc:paidTo
description: >-
Identifies the party or destination to which a payment was made.
range: string
multivalued: false
exact_mappings:
- la:paid_to
related_mappings:
- schema:seller
aliases:
- is_or_was_paid_to
annotations:
custodian_types: '["*"]'

View file

@ -35,6 +35,7 @@ prefixes:
time: http://www.w3.org/2006/time# time: http://www.w3.org/2006/time#
schema: http://schema.org/ schema: http://schema.org/
dcterms: http://purl.org/dc/terms/ dcterms: http://purl.org/dc/terms/
pav: http://purl.org/pav/2.3#
default_prefix: hc default_prefix: hc
imports: imports:
- linkml:types - linkml:types
@ -110,6 +111,7 @@ slots:
- schema:predecessorOf # schemaorg.owl:30406-30420 - "Previous variant of product; ProductModel domain" - schema:predecessorOf # schemaorg.owl:30406-30420 - "Previous variant of product; ProductModel domain"
- schema:previousItem # schemaorg.owl:30559-30575 - "Preceding ListItem; ListItem domain" - schema:previousItem # schemaorg.owl:30559-30575 - "Preceding ListItem; ListItem domain"
- dcterms:replaces # dcterms.rdf:1827-1846 - "Supplants/supersedes described resource; implies replacement" - dcterms:replaces # dcterms.rdf:1827-1846 - "Supplants/supersedes described resource; implies replacement"
- pav:previousVersion # PAV 2.3 (used by ArDO): previous version link (version chain)
aliases: aliases:
- previous_observation - previous_observation
examples: examples:

View file

@ -32,6 +32,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
crm: http://www.cidoc-crm.org/cidoc-crm/ crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
imports: imports:
- linkml:types - linkml:types
default_prefix: hc default_prefix: hc
@ -98,6 +99,7 @@ slots:
- schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically deaccessioning. - schema:object # schemaorg.owl:27871-27890 - "The object upon which the action is carried out." Broader: object of any action, not specifically deaccessioning.
related_mappings: related_mappings:
- crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of deaccessioning/disposal. - crm:P24_transferred_title_of # CIDOC_CRM_v7.1.3.rdf:1738-1750 - "Identifies the E18 Physical Thing involved in an E8 Acquisition." Legal transfer aspect of deaccessioning/disposal.
- la:removed_member # Linked Art extensions: member removed from a Set via a Removal activity
aliases: aliases:
- objects_removed - objects_removed
examples: examples:

View file

@ -22,6 +22,7 @@ prefixes:
linkml: https://w3id.org/linkml/ linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
la: https://linked.art/ns/terms/
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
@ -83,5 +84,6 @@ slots:
- is_or_was_transferred - is_or_was_transferred
related_mappings: related_mappings:
- schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects" - schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects"
- la:transferred # Linked Art extensions: what was transferred (Transfer->Entity). Note: this slot is boolean, so mapping is conceptual only.
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -0,0 +1,45 @@
# ==============================================================================
# LinkML Slot Definition: transferred_from
# ==============================================================================
# Source party/place from which something was transferred.
#
# ONTOLOGY ALIGNMENT (verified against linked.art terms):
#
# | Ontology | Property | Mapping | Notes |
# |----------------|-----------------------|---------|-------------------------------------------------------------|
# | **Linked Art** | `la:transferred_from` | exact | Source entity in a transfer in Linked Art extensions. |
# | **CIDOC-CRM** | `crm:P27_moved_from` | narrow | Location-only origin (place), narrower than general source. |
# | **Schema.org** | `schema:fromLocation` | narrow | Location-only source in action logistics. |
#
# CREATED: 2026-02-18
# ==============================================================================
id: https://nde.nl/ontology/hc/slot/transferred_from
name: transferred_from
title: Transferred From
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
la: https://linked.art/ns/terms/
crm: http://www.cidoc-crm.org/cidoc-crm/
schema: http://schema.org/
imports:
- linkml:types
default_prefix: hc
slots:
transferred_from:
slot_uri: hc:transferredFrom
description: >-
Identifies the source party, owner, custodian, or location from which
something was transferred.
range: string
multivalued: false
exact_mappings:
- la:transferred_from
narrow_mappings:
- crm:P27_moved_from
- schema:fromLocation
aliases:
- is_or_was_transferred_from
annotations:
custodian_types: '["*"]'

View file

@ -24,6 +24,7 @@ prefixes:
hc: https://nde.nl/ontology/hc/ hc: https://nde.nl/ontology/hc/
schema: http://schema.org/ schema: http://schema.org/
odrl: http://www.w3.org/ns/odrl/2/ odrl: http://www.w3.org/ns/odrl/2/
la: https://linked.art/ns/terms/
skos: http://www.w3.org/2004/02/skos/core# skos: http://www.w3.org/2004/02/skos/core#
xsd: http://www.w3.org/2001/XMLSchema# xsd: http://www.w3.org/2001/XMLSchema#
@ -86,5 +87,6 @@ slots:
- is_or_was_transferred_to - is_or_was_transferred_to
related_mappings: related_mappings:
- schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects" - schema:TransferAction # schemaorg.owl:5808-5812 - "act of transferring animate or inanimate objects"
- la:transferred_to # Linked Art extensions: transferred to (Transfer→Entity)
annotations: annotations:
custodian_types: '["*"]' custodian_types: '["*"]'

View file

@ -0,0 +1,282 @@
#!/usr/bin/env python3
"""Verify external ontology mappings used in LinkML YAML files.
Default behavior targets changed/untracked YAML files under:
schemas/20251121/linkml/
It validates mapping CURIEs under mapping keys:
exact_mappings, close_mappings, broad_mappings, narrow_mappings, related_mappings
Supported prefixes:
- la (Linked Art)
- rdac (RDA classes)
- rdau (RDA unconstrained properties)
- pav (PAV 2.3)
- ardo (ArDO)
- pca (POSC Caesar RDS)
"""
from __future__ import annotations
import argparse
import json
import re
import subprocess
import sys
import urllib.error
import urllib.request
import xml.etree.ElementTree as ET
from pathlib import Path
MAPPING_KEYS = {
"exact_mappings",
"close_mappings",
"broad_mappings",
"narrow_mappings",
"related_mappings",
}
SUPPORTED_PREFIXES = {"la", "rdac", "rdau", "pav", "ardo", "pca"}
CURIE_RE = re.compile(r"^(?P<prefix>[a-z][a-z0-9_-]*):(?P<local>[A-Za-z0-9_./-]+)$")
def fetch_text(url: str, timeout: int = 60) -> str:
with urllib.request.urlopen(url, timeout=timeout) as resp:
return resp.read().decode("utf-8", errors="ignore")
def fetch_bytes(url: str, timeout: int = 60) -> bytes:
with urllib.request.urlopen(url, timeout=timeout) as resp:
return resp.read()
def parse_mapping_curies(file_path: Path) -> list[tuple[int, str, str]]:
"""Return (line_number, prefix, local) mapping CURIEs from mapping blocks."""
out: list[tuple[int, str, str]] = []
lines = file_path.read_text(encoding="utf-8", errors="ignore").splitlines()
in_block = False
block_indent = -1
for idx, line in enumerate(lines, start=1):
stripped = line.strip()
indent = len(line) - len(line.lstrip(" "))
if not in_block:
if not stripped or stripped.startswith("#"):
continue
if ":" in stripped:
key = stripped.split(":", 1)[0].strip()
if key in MAPPING_KEYS and stripped.endswith(":"):
in_block = True
block_indent = indent
continue
# Exit mapping block on dedent to same or lower level and non-list content
if stripped and not stripped.startswith("#"):
if indent <= block_indent and not stripped.startswith("-"):
in_block = False
block_indent = -1
# re-process this line as potential new key
if ":" in stripped:
key = stripped.split(":", 1)[0].strip()
if key in MAPPING_KEYS and stripped.endswith(":"):
in_block = True
block_indent = indent
continue
if stripped.startswith("-"):
item = stripped[1:].strip()
# remove inline comment
if " #" in item:
item = item.split(" #", 1)[0].strip()
m = CURIE_RE.match(item)
if m:
pfx = m.group("prefix")
local = m.group("local")
out.append((idx, pfx, local))
return out
def changed_yaml_files(repo_root: Path, scope: Path) -> list[Path]:
"""Collect changed and untracked YAML files inside scope."""
files: set[Path] = set()
def run(cmd: list[str]) -> list[str]:
try:
out = subprocess.check_output(cmd, cwd=repo_root)
return [x for x in out.decode().splitlines() if x]
except subprocess.CalledProcessError:
return []
tracked = run(["git", "diff", "--name-only"])
untracked = run(["git", "ls-files", "--others", "--exclude-standard"])
for rel in tracked + untracked:
if not rel.endswith(".yaml"):
continue
p = (repo_root / rel).resolve()
try:
p.relative_to(scope.resolve())
except ValueError:
continue
if p.is_file():
files.add(p)
return sorted(files)
def load_linked_art_terms() -> tuple[set[str], set[str]]:
xml_data = fetch_bytes("https://linked.art/ns/terms/")
root = ET.fromstring(xml_data)
ns = {
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
}
props: set[str] = set()
classes: set[str] = set()
for p in root.findall("rdf:Property", ns):
uri = p.attrib.get("{http://www.w3.org/1999/02/22-rdf-syntax-ns#}about", "")
if uri.startswith("https://linked.art/ns/terms/"):
props.add(uri.rsplit("/", 1)[-1])
for c in root.findall("rdfs:Class", ns):
uri = c.attrib.get("{http://www.w3.org/1999/02/22-rdf-syntax-ns#}about", "")
if uri.startswith("https://linked.art/ns/terms/"):
classes.add(uri.rsplit("/", 1)[-1])
return props, classes
def load_rda_ids(path: str, marker: str) -> set[str]:
txt = fetch_text(f"https://www.rdaregistry.info/jsonld/Elements/{path}.jsonld")
return set(re.findall(marker, txt))
def main() -> int:
parser = argparse.ArgumentParser(description="Verify LinkML external mappings")
parser.add_argument(
"files",
nargs="*",
help="YAML files to verify (defaults to changed/untracked files under scope)",
)
parser.add_argument(
"--scope",
default="schemas/20251121/linkml",
help="Default scope used when no files are provided",
)
parser.add_argument(
"--all",
action="store_true",
help="Scan all YAML files under --scope (instead of changed/untracked files)",
)
args = parser.parse_args()
repo_root = Path(__file__).resolve().parents[1]
scope = (repo_root / args.scope).resolve()
if args.files:
files = [Path(f).resolve() for f in args.files]
elif args.all:
files = sorted(scope.rglob("*.yaml"))
else:
files = changed_yaml_files(repo_root, scope)
if not files:
print("No target YAML files found. Nothing to verify.")
return 0
occurrences: dict[str, list[tuple[Path, int, str]]] = {}
for file_path in files:
if not file_path.exists() or file_path.suffix != ".yaml":
continue
for line_no, pfx, local in parse_mapping_curies(file_path):
if pfx not in SUPPORTED_PREFIXES:
continue
occurrences.setdefault(pfx, []).append((file_path, line_no, local))
if not occurrences:
print("No supported external mapping CURIEs found in selected files.")
return 0
failures: list[str] = []
la_props: set[str] = set()
la_classes: set[str] = set()
rdac_ids: set[str] = set()
rdau_ids: set[str] = set()
pav_text = ""
try:
la_props, la_classes = load_linked_art_terms()
except Exception as e: # pragma: no cover - network failures
failures.append(f"[load] Linked Art: {e}")
try:
rdac_ids = load_rda_ids("c", r"Elements/c/(C\d+)")
except Exception as e: # pragma: no cover
failures.append(f"[load] RDA c.jsonld: {e}")
try:
rdau_ids = load_rda_ids("u", r"Elements/u/(P\d+)")
except Exception as e: # pragma: no cover
failures.append(f"[load] RDA u.jsonld: {e}")
try:
pav_text = fetch_text("https://purl.org/pav/2.3")
except Exception as e: # pragma: no cover
failures.append(f"[load] PAV 2.3: {e}")
print("Verifying mapping CURIEs:")
for prefix in sorted(occurrences):
locals_unique = sorted({x[2] for x in occurrences[prefix]})
print(f"- {prefix}: {', '.join(locals_unique)}")
# prefix-specific verification
for file_path, line_no, local in occurrences.get("la", []):
if local not in la_props and local not in la_classes:
failures.append(f"{file_path}:{line_no} la:{local} not found in linked.art/ns/terms")
for file_path, line_no, local in occurrences.get("rdac", []):
if local not in rdac_ids:
failures.append(f"{file_path}:{line_no} rdac:{local} not found in RDA Elements/c.jsonld")
for file_path, line_no, local in occurrences.get("rdau", []):
if local not in rdau_ids:
failures.append(f"{file_path}:{line_no} rdau:{local} not found in RDA Elements/u.jsonld")
for file_path, line_no, local in occurrences.get("pav", []):
if local not in pav_text:
failures.append(f"{file_path}:{line_no} pav:{local} not found in PAV 2.3 ontology")
for file_path, line_no, local in occurrences.get("ardo", []):
url = f"https://w3id.org/ardo/2.0/{local}"
try:
txt = fetch_text(url)
if local not in txt:
failures.append(f"{file_path}:{line_no} ardo:{local} not found at {url}")
except urllib.error.URLError as e:
failures.append(f"{file_path}:{line_no} ardo:{local} fetch error: {e}")
for file_path, line_no, local in occurrences.get("pca", []):
url = f"https://rds.posccaesar.org/ontology/plm/rdl/{local}"
try:
txt = fetch_text(url)
if local not in txt:
failures.append(f"{file_path}:{line_no} pca:{local} not found at {url}")
except urllib.error.URLError as e:
failures.append(f"{file_path}:{line_no} pca:{local} fetch error: {e}")
if failures:
print("\nFAIL")
for f in failures:
print(f"- {f}")
return 1
print("\nOK: all checked mapping CURIEs were verified against source ontologies.")
return 0
if __name__ == "__main__":
sys.exit(main())