Type Mapping Configuration¶
All converters support a --type-mapping YAML file to override how source notation
types map to ontology IRIs.
Substitution, not alignment¶
A mapping entry replaces a type; it does not relate two types
A --type-mapping entry replaces the type a converter would otherwise emit. Mapping
userTask to myont:HumanActivity makes the output say a myont:HumanActivity instead of
a bpmn:UserTask — it does not state any relationship between the two classes, and no
skos:exactMatch, skos:closeMatch or owl:equivalentClass triple is produced.
That distinction matters when the substituted type belongs to a vocabulary a consumer also
knows by another name. The shipped type-mapping-bpmn-lite.yml is the clear case: it swaps
bpmn:UserTask for bpmnl:UserTask, and the fact that those two denote the same concept is
asserted in the published BPMN Lite ontology, which carries skos:exactMatch on each of
its classes — not by the mapping file and not in the converter output.
So: use --type-mapping to choose which vocabulary the output speaks. To state that one
vocabulary's concepts correspond to another's, author a cross-language mapping document
instead — see
Authoring cross-language mappings.
Converters never emit correspondence triples of their own; mappings are editorial judgements,
not derivations.
Retyping a relationship carries its predicates with it¶
Because a relationships: entry replaces the class, it also invalidates the predicates that were
declared against the class it replaced. A LeanIX edge retyped from lmm:Requiring to am:Serving
no longer answers to lmm:qualifiedRequires, whose rdfs:range names lmm:Requiring.
This is not a cosmetic mismatch. rdfs:range is an entailment, not a constraint, so a reasoner
reading {src} lmm:qualifiedRequires {rel} will infer rel a lmm:Requiring — putting back exactly
the class the mapping set out to replace, without anything reporting a conflict.
So a converter will not reuse a published predicate once you have retyped the class it belongs to:
qualifiedPredicates:named — your predicate is used.- not named — the relationship falls back to
arch:hasQualifiedRelationship, whose range isarch:QualifiedRelationshipand so always holds. The run warns and names the key to add. The relationship is still reachable; it just no longer says of what kind on the way in. predicates:not named — there is no generic core predicate for a shortcut triple, so the direct triple is omitted entirely rather than written with a term that contradicts the new type. Nothing is lost: the relationship resource carries the statement either way.
The practical rule is one predicates: and one qualifiedPredicates: entry per relationships:
entry. The vocabulary you are retyping into will normally publish both — ArchiMate declares a
qualified form for every relationship class, for instance — so this is naming existing terms rather
than inventing them. playground/config/type-mapping-leanix.yml is a worked example.
Which key a lookup matches¶
elements: keys are the element or fact sheet type name as your source spells it.
relationships:, predicates: and qualifiedPredicates: keys are matched against the relationship
name your source declares first — relApplicationToITComponent, sequenceFlow — and against the
canonical name the converter resolved from it second, such as Requiring. Prefer the declared name:
it is the one visible in your export. All three sections resolve the same way, so a mapping keyed
consistently cannot retype a relationship while leaving its predicates behind.
YAML structure¶
# Declare namespace prefixes for output readability
namespaces:
ont: https://custom.linked.archi/ont#
# Override vocabulary IRIs (BPMN only)
vocab:
arch:Element: https://custom.linked.archi/ont#Element
# Override element type IRIs
elements:
BusinessActor: https://custom.linked.archi/ont#BusinessActor
userTask: https://custom.linked.archi/ont#HumanActivity
class: https://custom.linked.archi/ont#DomainEntity
# Override relationship type IRIs
relationships:
Serving: https://custom.linked.archi/ont#Serving
sequenceFlow: https://custom.linked.archi/ont#Triggers
# Direct predicate, for the {src} {pred} {tgt} shortcut under --emit-direct-rel-triples
predicates:
Serving: https://custom.linked.archi/ont#serves
sequenceFlow: https://custom.linked.archi/ont#triggers
# Qualified predicate, from the source element to the relationship resource. Always
# emitted — arch:hasQualifiedRelationship where you name none. See below.
qualifiedPredicates:
Serving: https://custom.linked.archi/ont#qualifiedServes
# View type overrides (ArchiMate only)
views:
Diagram: https://custom.linked.archi/ont#ArchView
# Metadata predicate overrides (BPMN only)
metadata-predicates:
title: http://purl.org/dc/terms/title
# Property keys whose value is a reference, not a string (ArchiMate only)
object-properties:
- arch:architectureState
- ':realizes'
# House spec fields to read as relationships, and the default kind of a bare
# reference in each (Backstage only)
spec-relations:
deployedTo: Resource
# House spec fields whose value is a literal (Backstage only)
spec-literals:
- tier
# House metadata fields whose value is a literal (Backstage only)
metadata-literals:
- costCentre
Property keys whose value is a link¶
Every other section maps a type to an IRI. This one is about a value.
A promoted property key normally carries a literal, which is right for a cost centre and wrong for anything naming another resource. Listing a key here says its values are references, so they are resolved to IRIs:
An ArchiMate property arch:architectureState = arch:Target then reaches the graph as
arch:architectureState arch:Target rather than as the string "arch:Target" — which is what lets a
model populate a published owl:ObjectProperty instead of forking the term into a local datatype
property.
Values resolve as an absolute IRI, a prefixed name against namespaces: (falling back to --ns-vocab),
or a bare local name against --ns-vocab. A value that resolves to none of those emits no link: it is
kept as a schema:additionalProperty pair and reported, rather than emitted as a literal that would
contradict the property's range.
Keys are matched as authored in the model, so a key written :realizes is declared ':realizes' —
quoted, because a leading colon starts a YAML alias otherwise.
Read by archimate2linkedarchi today. See
ArchiMate → Making a property value a link
for the full rules and for why this is declared rather than detected from the ontology.
House fields in a Backstage descriptor¶
spec-relations:, spec-literals: and metadata-literals: are the same idea one level up: they name
keys the Backstage descriptor format does not declare, and say what the value of each one is.
namespaces:
example: https://vocab.example.org/id/
spec-relations: # the value names another resource
deployedTo: Resource # …and a bare reference defaults to kind Resource
spec-literals: # the value is a value
- tier
metadata-literals: # a house key in metadata rather than in spec
- costCentre
predicates:
deployedTo: https://vocab.example.org/arch#deployedTo # the predicate to write
tier: https://vocab.example.org/arch#tier
costCentre: https://vocab.example.org/arch#costCentre
relationships:
deployedTo: https://vocab.example.org/arch#Deployment # optional; makes it a qualified edge
The split matters because the two are indistinguishable in the file: deployedTo: prod-cluster and
tier: gold are one YAML shape, and only the author knows which names an entity. This is
object-properties: above applied to a field rather than a property key, and for the same stated
reason — links and literals are declared, not detected.
spec-relations: is a map because a reference needs a default kind, playing the part the descriptor
format plays for spec.owner (Group). spec-literals: is a list because a literal needs nothing per
key: its datatype comes from the catalog, since the YAML loader has already resolved 3 to an
integer and gold to a string, and the emitter maps that onto XSD. Declaring the datatype here would
let the configuration disagree with the file.
The kind is only the default segment of an entity reference, not a type declaration, so it is ignored
by a value that resolves as an IRI — a prefixed name against namespaces:, or an absolute IRI — which is
how a field points at something the catalog does not describe. The entry is still what makes the field
readable at all. A kind outside the seven the ontology models is accepted too; give it a class under
elements:, keyed on the lowercased kind.
Without an entry in relationships: a relation field is emitted as a direct triple only, since a
qualified relationship with no class would be an untyped node — and the Backstage converter will not
invent a class in bs:, a namespace it reads and does not own. The section has no effect on a literal
field, which is a property rather than an edge.
metadata-literals: is the metadata counterpart of spec-literals:, with identical predicate and
datatype handling. It is a separate list rather than a shared one because metadata.tier and spec.tier
are two different statements, and one declaration must not silently answer for both. It has no relation
counterpart: metadata is where Backstage puts descriptive fields, and a reference belongs in spec or
in metadata.labels — the latter being read with no declaration at all.
A declared key a descriptor does not carry is silent. An undeclared key found in a descriptor is
reported, as is a key declared in both spec sections, which is contradictory and so emits nothing.
elements: matters here too. A kind outside the seven the ontology models — Template, Location, or
one of your own — takes its class from elements: keyed on the lowercased kind, or from --ns-vocab.
Nothing is minted in bs:, so with neither the entity is emitted as an arch:Element carrying no
notation class, and the run reports it.
None of these sections causes an OWL axiom to be emitted. The predicate is used; whether it is an
owl:ObjectProperty or an owl:DatatypeProperty, and what its domain and range are, belongs to the
ontology you publish and load alongside the output.
Read by backstage2linkedarchi only. See
Backstage → Custom spec fields for value resolution,
the two output shapes and what gets reported.
How overrides work¶
Each converter has a default type resolution strategy:
| Converter | Default behaviour | Override trigger |
|---|---|---|
| ArchiMate | xsi:type → {nsArchimate}{TypeName} |
Entry in elements: or relationships: |
| BPMN | CMOF class → {BPMN_BASE}{ClassName} |
Entry in elements: or relationships: |
| PlantUML | Stereotype → UmlTypeDefaults lookup |
Entry in elements: or relationships: |
When an entry exists in the YAML, it takes precedence over the default. When no entry exists, the default is used.
Example configs¶
See playground/config/ for working examples:
type-mapping-archimate.yml— ArchiMate reference with predicate mappingstype-mapping-bpmn-full.yml— BPMN full reference (documents defaults)type-mapping-bpmn-lite.yml— BPMN → BPMN Lite ontology overridetype-mapping-plantuml.yml— PlantUML → UML reference (documents defaults)type-mapping-plantuml-custom.yml— PlantUML → custom domain ontology