Repository navigation
feat(rdf): give declared annotation values and native metadata the term of their range - #58
Open
jdsika wants to merge 1 commit into
Conversation
jdsika
force-pushed
the
feat/declared-annotation-terms
branch
from
October 21, 2026 20:38
4b97442 to
9020d54
Compare
This was referenced Oct 21, 2026
jdsika
force-pushed
the
feat/declared-annotation-terms
branch
from
October 21, 2026 20:54
9020d54 to
cb6a6f1
Compare
jdsika
force-pushed
the
fix/string-derived-anyuri-types-stay-literals
branch
from
October 22, 2026 20:16
373df7a to
88e231b
Compare
jdsika
force-pushed
the
feat/declared-annotation-terms
branch
from
October 23, 2026 08:47
cb6a6f1 to
6fe02bc
Compare
…rm of their range An annotation whose tag a metaclass declares through instantiates gets the RDF term that the slot's range gives a slot value (linkml_runtime.utils.rdf_terms): nodeidentifier, uri and uriorcurie values are IRIs or blank nodes, string values are text with the resolved language, curie values are xsd:string literals, and an enum-ranged slot writes the permissible value's text. gen-owl and gen-shacl share the rule through linkml.generators.common.annotations; without a declaration both keep their earlier behaviour, and metaclasses that declare a tag with different terms are an error. gen-owl applies the same rule to native metadata, so see_also, source and the mappings are IRIs by the metamodel's ranges rather than by a name check, and created_on is an xsd:dateTime literal. A link value that is neither an IRI nor a CURIE, such as a bare element name in see_also, is written as a plain literal with a warning: a relative IRI would make the whole graph non-standard RDF and push it onto the canonicalizer's rdflib fallback. OWL 2 §10.1 admits IRIs, anonymous individuals and literals as annotation values. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
jdsika
force-pushed
the
feat/declared-annotation-terms
branch
from
October 23, 2026 11:55
6fe02bc to
0fa8f65
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mirror of linkml#4157, same head. Review there; this PR tracks the fork stack.
An annotation whose tag a metaclass declares through
instantiatesnow gets the RDF term that the slot's range gives a slot value, by the rule of linkml#4156 (linkml_runtime.utils.rdf_terms). gen-owl and gen-shacl (--include-annotations) share it throughlinkml.generators.common.annotations, and gen-owl applies the same rule to native metadata such assee_also.Example
mainreviewer"ex:alice"@en<https://example.org/alice>review"well defined"@enOn
mainthe declared range is ignored: every annotation value is a string, and with--default-languageevery value is language-tagged, identifiers included. This is the pattern of the annotations guide; the metaclass needs no further declaration.The rule
nodeidentifier,urianduriorcuriegive IRIs, or a blank node for a_:label;stringgives text, with the language;curiegives anxsd:stringliteral; a string-derivedxsd:anyURItype gives anxsd:anyURIliteral.see_also,source,created_byand the mappings are IRIs, with CURIEs expanded through the schema's prefixes;license,descriptionandtitleare strings;created_onis anxsd:dateTimeliteral.Standards and LinkML contract
instantiatesmakes a metaclass's slots the declarations of an element's annotations.rangeIncludesis a recommendation, andrdfs:Resourceincludes literals, so a property name cannot decide the term.Behaviour changes
created_onandlast_updated_onbecomexsd:dateTimeliterals (were plain strings). Mappeduriorcuriemetaslots stay IRIs, now by the shared rule instead of a name check.uriannotation value that is a relative reference or a_:label is an error.see_also, is written as a plain literal, with a warning naming the element and metaslot. A relative IRI would make the whole graph non-standard RDF, andmainwrites one.Not in this PR
implements: [owl:AnnotationProperty]already declares the role, but the class restrictions are still emitted (Missing support for OWL annotation properties linkml/linkml#3249). Next PR.licenseas an IRI (gen-owl emits rdfs:isDefinedBy and dcterms:license as string literals instead of URIs linkml/linkml#3546): the metamodel declares it a string; a linkml-model question.Testing
test_declared_annotations.py(44): both generators; every range kind; tag as name, CURIE or IRI; annotated classes, slots, enums, permissible values and types; inherited and imported metaclasses; blank nodes; conflicting declarations; wrong-kind negatives; native metadata; the documented DCMI example; a pyshacl check that shape annotations do not constrain data.Draft, stacked on linkml#4156: this PR's own change is its last commit; the first is linkml#4156. It will be rebased when linkml#4156 lands. Fork review: #58. Refs linkml#2892, linkml#3543, linkml#3546.