Status: Experimental. Namespace
atlas.adapter.yaml-ld(core/src/atlas/adapter/yaml_ld.clj). Export-only. Requiresclojure.data.json(already a core dep).
Export an Atlas registry to JSON-LD and its YAML serialization YAML-LD — W3C linked data. This makes Atlas registries consumable by the entire semantic-web ecosystem (triple stores, SPARQL, RDF tooling, existing vocabularies).
Atlas already is a linked-data graph — it just uses EDN instead of RDF syntax:
| Atlas | → | Linked data |
|---|---|---|
:atlas/dev-id | → | @id (a CURIE / IRI) |
:atlas/type | → | @type (rdf:type) |
| compound-id aspects | → | atlas:aspect (each an @id resource) |
| qualified-keyword namespaces | → | @context prefix → IRI mappings |
type-refs (property + :type-ref/datalog-verb) | → | @context term defs: property CURIE → the verb IRI, {@type: @id, @container: @set} |
| ref edges (deps / consumes / produces) | → | RDF triples on the verb predicate |
JSON-LD/YAML-LD is the standard name for the model Atlas already implements, so this adapter is a near 1:1 projection, not a translation.
This is the elegant part. A type-ref like
{:type-ref/source :atlas/interface-endpoint, :type-ref/property :interface-endpoint/deps, :type-ref/datalog-verb :entity/depends} becomes a @context entry:
interface-endpoint:deps:
"@id": entity:depends # the semantic predicate
"@type": "@id" # values are resources, not strings
"@container": "@set"
Because multiple properties share a verb, they unify to one predicate:
execution-function/deps and interface-endpoint/deps both expand to
entity:depends in the resulting RDF. The same meta-model that drives
the Overarch adapter's edges drives the JSON-LD context here.
atlas:aspect predicate (each an
@id resource), not extra @type values — this preserves Atlas's
type-vs-aspect distinction and round-trips cleanly. (:atlas/* meta-aspects
are dropped.)@type.entity:depends/consumes/produces), so
the RDF is semantically deduplicated across property names.@context prefix under a base
IRI (default https://semantic-namespace.org/atlas/), so :domain/auth →
domain:auth.(require '[atlas.adapter.yaml-ld :as yld]
'[clojure.edn :as edn])
(def reg (edn/read-string (slurp "snapshot.edn"))) ; a registry map
;; Pure projection → {"@context" {…} "@graph" [nodes…]}
(yld/registry->jsonld reg {:select (yld/aspect-selector :domain/orders)})
;; Write <path>.jsonld + <path>.yaml
(yld/emit! reg "/tmp/orders"
{:select (yld/aspect-selector :domain/orders
#{:atlas/execution-function :atlas/interface-endpoint})})
;; => {:nodes N :namespaces M :context-terms K}
Selectors mirror the other adapters: aspect-selector (one aspect, optional
type set) and aspects-selector (any of several aspects). :base overrides the
base IRI. Serializers: ->jsonld and ->yaml.
Note: JSON is a subset of YAML, so the emitted .jsonld is itself valid
YAML-LD; ->yaml additionally renders the friendlier YAML block form (with the
@-keywords quoted, as YAML requires).
The prototype was verified end-to-end against a real production registry (~1000 entities), sliced to one domain's functions + endpoints (21 nodes, 50 namespace prefixes, 65 context terms):
yaml.safe_load(out.yaml) == json.load(out.jsonld) ✓rdflib): the JSON-LD expands to 610 valid RDF
triples, with predicates atlas/aspect, entity/depends (57 triples),
entity/consumes, entity/produces, and rdf:type — confirming the
type-ref-generated @context resolves correctly and the verb unification
works (e.g. execution-function/deps and interface-endpoint/deps both →
entity:depends).Example node (YAML-LD):
- "@id": interface-endpoint:place-order
"@type": atlas:interface-endpoint
atlas:aspect:
- domain:orders
- tier:api
entity:depends:
- execution-function:create-order
The canonical C4 Internet Banking System is coded as an
Atlas registry in test/app/internet_banking.clj.
Exporting it produces adapter-yaml-ld/banking.jsonld
and adapter-yaml-ld/banking.yaml — 13 nodes
that expand to 62 RDF triples (atlas/aspect, entity/depends, rdf:type).
Note: the core ontologies declare only
depsas type-refs, so the banking export showsentity:dependsedges.entity:consumes/entity:producesappear when a registry also declares context/response as type-refs (as the validation registry above does) — the adapter faithfully reflects whatever the type-ref meta-model declares.
@type + atlas:aspect; deferred.endpoint/deps vs
endpoint/serialisation both become entity:depends). If per-property
predicates are wanted, map each property term to its own IRI instead of the
verb.core
(it pulls data.json, and a real YAML lib if the hand-rolled emitter is
replaced).Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |