Skip to content

XmiElementCache

samatstarion edited this page Oct 4, 2026 · 2 revisions

Introduction

XmiElementCache (interface IXmiElementCache, namespace uml4net) is the registry of every XmiElement that has been read, across all the documents of one read operation. It has one job: to let a reference — an xmi:idref, an href, an xmi:uuid pointer — be turned into the object it refers to. The Assembler is its main consumer; the generated readers are its main producer.

There is one cache per IXmiReader. It is created by the reader's dependency-injection scope (XmiReaderScope), handed to every generated IXmiElementReader and to the Assembler, and cleared when the reader is disposed.

Keys

Elements are stored under their FullyQualifiedIdentifier, {DocumentName}#{XmiId}:

Element read from Key
Class with xmi:id="_c" in the file Model.xmi Model.xmi#_c
PrimitiveType Boolean reached through href="http://www.omg.org/spec/UML/20131001/PrimitiveTypes.xmi#Boolean" http://www.omg.org/spec/UML/20131001/PrimitiveTypes.xmi#Boolean
Class reached through href="../lib/types.xmi#T" ../lib/types.xmi#T

The document part is the href as written in the referencing document, not the path the file was eventually loaded from. That is what makes the key of the element and the key derived from the reference identical, whatever LocalReferenceBasePath or the referencing document's location the ExternalReferenceResolver used to find the file.

Elements without xmi:id

xmi:id is optional (XMI 2.5.1 clause 7.6.1). An element without one cannot be referenced, but its own references, hrefs and extensions still have to be processed, so TryAdd stores it under a synthetic key {DocumentName}#<anonymous:n> that cannot clash with an xmi:id. It is enumerated and assembled like any other element.

Duplicate xmi:id

TryAdd returns false when the key is already present; the element that was read first stays in the cache and is the one that references resolve to. The generated readers log an error with the element and line position in that case. It is deliberately not rejected, even in strict mode: the normative UML.xmi itself contains the xmi:id State-isConsistentWith twice.

Look-up

TryGetValue(key, out element) looks the key up as-is. When that fails and the fragment of the key has the XPointer uuid form defined by XMI 2.5.1 clause 7.10.2,

Co.xmi#xpointer((//*[@xmi:uuid='DCE:emp-3'])[1])

the element is looked up in a secondary index by {DocumentName}#{XmiGuid}. TryAdd fills that index with the first element of a document that carries a given xmi:uuid, which is what the [1] of the XPointer selects. XmiElementCache.TryParseXPointerUuid exposes the parsing of the fragment (single or double quotes are accepted; other XPointer schemes, [2], or xmi:label are not).

An element without xmi:id but with an xmi:uuid is therefore still reachable — by uuid.

The cache is also enumerable (Keys, Values, Count, GetEnumerator), which the Assembler and the ExternalReferenceResolver use to walk every element that has been read.

Extenders

AddExtender(xmiElement, extender) and TryGetExtenders(xmiElement, out extenders) associate arbitrary objects with an element. This is used by the extension mechanism: an xmi:Extension that a registered extender reader understands (for example the Enterprise Architect extension) produces objects that are attached to the extended element without becoming part of the UML model.

Stereotype applications

AddStereoTypeApplication(xmiElement, stereoTypeApplication) and TryGetStereoTypeApplications(xmiElement, out stereoTypeApplications) register the stereotype applications of a document with the element they extend, once they are resolved. The extension methods QueryStereoTypeApplications() and QueryStereoTypeApplication(name) on an element read them through its Cache; see Profiles and StereoTypes.

Where it is used

  • Generated readers call TryAdd for every element as soon as its identity attributes are read, before its children — so that a child can refer back to its owner.
  • ExternalReferenceResolver walks the cache to collect every recorded href and load the documents they point to.
  • Assembler walks the cache to resolve every recorded identifier.
  • Derived-property emulation of allInstances(): Class::extension and Vertex::incoming/outgoing are defined in the metamodel over all instances of a metaclass; uml4net emulates allInstances() over every element of the read: the elements in the cache, which holds the document and the external documents it references, together with the containment trees of those elements, so that elements created in code are included as well.
  • XmiReaderResult: after reading, the elements of the document that was read and of the external documents are all in the cache; QueryRootElement<T>(xmiId) resolves through it.

Notes for callers

  • The cache is not thread-safe.
  • Clear() empties everything, including the uuid index and the extenders, and resets the anonymous-key counter. XmiReader clears it when disposed; a reader instance is meant to be used for one read.
  • Building a model in code does not require a cache; Cache on such elements is null, and the queries that emulate allInstances() fall back to walking the containment tree.

See also

  • XmiElement — the identity properties that make up the key
  • Assembler — resolves references through the cache
  • uml4net.xmi project — external references and the ExternalReferenceResolver

Clone this wiki locally