Façade-X Concepts and Metamodel Specification
Copyright
©
2026
the Contributors to the Façade-X Concepts and Metamodel Specification
Specification, published by the
Data Façades Community Group under the
W3C Community Contributor License Agreement (CLA). A human-readable
summary
is available.
This document specifies the Façade-X concepts and metamodel.
This specification was published by the Data Façades Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.
This is version 0.1 of this document, released on 2026-10-06, at https://w3c-facade-x.github.io/facade-x-specs/0.1/metamodel.html. This version will not change. The latest release is always at https://w3c-facade-x.github.io/facade-x-specs/metamodel.html. The editor's draft, which may include changes made after this release, is at https://w3c-facade-x.github.io/facade-x-specs/dev/metamodel.html. The issues addressed in this release, and those still open, are listed in the release notes.
This document is currently in active development.
GitHub Issues are preferred for discussion of this specification.
This document is one of seven Façade-X specification documents produced by the Data Façades Community Group:
This section is non-normative.
Façade-X is the (meta-)model resulting from the abstraction of all the basic data structures used to represent source data formats, combined into a unified model. RDF languages can implement it to provide users direct access to external, heterogeneus data formats. The Figure below provide an intuive overview of Façade-X. The related RDF vocabulary is [under preparation].
(Comment made by @kvistgaard)
Each container cannot recursively contain itself through a sequence of slots and containers.
What's the practical application of this?
By @kvistgaard
The framework introduces the notion of Container as an abstraction of both lists and maps through the notion of Slots. A Slot is an allotted place for an object, namely a primitive value or another container, “contained” in a Container.
Do we really need the notion of "Slot"? One way to avoid it is:
Façade-X interprets every data source as a container, containing key-value pairs. The keys are either generic containment relations or specific properties. The values are either other containers or literals (strings, numbers, dates etc).
A saw later that "Nothing can be both a container and a slot." but isn't that simply dependant on how container is defined?
I find it difficult to see Facade-X as a meta-model. Since it is not meta, neither in about, nor in for sense, what are the grounds for such classification?
Resources can have more than one data source. For example, a spreadsheet has multiple sheets. We can query both by assigning each one to a different named graph. This is clearly outside of the facade vocabulary itself, but it makes sense to specify it together in the same document.
Besides describing the model with natural language it must be specified by using a formal language.
Currently, it has been formally described in predicate logic in TOIT paper but relational algebra or other languages could also be considered.
We rely on the generic notion of resource to refer to a digital artifact that wraps some data (to not be confused with the concept of Resource in RDFS). We say that a resource contains one or more data sources, to refer to actual data contained in them.
Intuitively, a CSV is a file (then, a resource) that includes some tabular data (hence, a single data source). A Spreadsheet is a file (then, a resource) containing many tabs, each one of them including tabular data (hence, possibly multiple data sources).
Predicate Definition
Resource(x) denotes a digital artifact (e.g., a file or service).
DataSource(x) denotes a collection of data contained in a resource.
includes(r, ds) means that resource r contains data source ds.
Every resource must contain at least one data source.
The first argument of the includes predicate is a resource and the second is a data source.
Every data source must belong to some resource.
A data source cannot belong to two different resources; it is included in one at most.
The framework introduces the notion of Container as an abstraction of both lists and maps through the notion of Slots. A Slot is an allotted place for an object, namely a primitive value or another container, “contained” in a Container.
Containers are collections of unique key/value pairs (slots) where:
the key of the slot is unique in the collection and can be either a number (i.e. NumberSlot)
or a sequence of alphanumeric characters (i.e. StringSlot);
the value can be either a primitive value or another container.
We say that a container c contains a slot s if
(c,s) is in the interpretation of the predicate
hasSlot.
Moreover, we say that a slot s holds a value
v (or a container c) if
(s,v) (resp. (s,c)) is in the interpretation of
hasValue (resp. hasContainer).
In this case we can also say that v (resp. c) is assigned to a slot.
Finally, we say that a container hasSlot and
hasContainer.
Predicate Definition
Container(x) represents a collection of slots (list or map).
Slot(x) is an allotted place for an object within a container.
NumberSlot(x) and StringSlot(x) identify the type of the slot.
Value(x) denotes a primitive datum.
hasSlot(c,s) links a container to a slot.
hasValue(s,v) links a slot to a value.
hasContainer(s,c) links a slot to a nested container.
includesContainer(ds,c) associates a data source with its containers.
The first argument of hasSlot is a Container and the second is a Slot.
The first argument of hasValue is a slot and the second is a value.
The first argument of hasContainer is a slot and the second is a container.
The first argument of includesContainer is a data source and the second is a container.
Every NumberSlot is a slot.
Every StringSlot is a slot.
A slot identified by a string cannot also be a NumberSlot.
Every slot must be either a NumberSlot or a StringSlot.
Every container must belong to some data source.
A container cannot belong to more than one data source.
Values must be assigned to a slot. Slots must be contained by a single container. Slots must hold either a single container or a single value. There cannot exist a container c and a slot s such that c contains s and s holds c. Each container cannot recursively contain itself through a sequence of slots and containers.
Every value must be assigned to some slot.
Every slot must be contained in some container.
Each slot belongs to exactly one container.
Every slot must hold either a container or a value.
A slot cannot simultaneously hold a container and a value.
A slot can hold at most one container.
A slot can hold at most one value.
A container cannot directly contain itself via one of its slots.
No container may (even indirectly) contain itself, namely, the containment graph is acyclic.
Each container can only be held by a single slot (it is not possible for two slots to hold the same container).
Containers can have types.
Every type must be assigned to a container.
To this end we introduce the unary predicate Type and the binary predicate hasType.
Predicate Definition
Type(x) denotes a classification assigned to containers.
hasType(c,t) links a container to a type.
The first argument of hasType is a container and the second is a type.
Every type must be assigned to at least one container.
For each data source, there exists one and only one Root container.
The Root container cannot be assigned to a slot.
Containers that are not root must be assigned to a slot.
To identify the root container we introduce the unary predicate Root as a specialisation of Container
and the binary predicate hasRoot that connects a data source to its root container.
Predicate Definition For each data source there is a distinguished top-level container, the root. The root is the entry point of the container hierarchy and cannot be nested in any slot. All other containers must be reachable from it.
Every data source must have at least one root container.
The first argument of hasRoot is a data source and the second is a root.
Every root container is the root of some data source.
The root container of a data source is included in that data source.
Every root is also a container.
A root container cannot be nested inside any slot.
Each data source cannot have more than one root container.
Every non-root container must be contained in some slot.
The unary predicates Container, Slot, Value, and Type are pairwise disjoint. The unary predicates DataSource and Resource are disjoint from Container, Slot, Value, and Type. The unary predicate Root is disjoint from Type, Slot, Value, DataSource, and Resource. The binary predicates includes, includesContainer, hasType, hasSlot, hasContainer, and hasValue are pairwise disjoint.
Nothing can be both a container and a slot.
Nothing can be both a container and a value.
Nothing can be both a container and a type.
Nothing can be both a slot and a container.
Nothing can be both a slot and a value.
Nothing can be both a slot and a type.
Nothing can be both a value and a container.
Nothing can be both a value and a slot.
Nothing can be both a value and a type.
Nothing can be both a type and a container.
Nothing can be both a type and a slot.
Nothing can be both a type and a value.
Nothing can be both a data source and a container.
Nothing can be both a data source and a slot.
Nothing can be both a data source and a value.
Nothing can be both a data source and a type.
Nothing can be both a resource and a container.
Nothing can be both a resource and a slot.
Nothing can be both a resource and a value.
Nothing can be both a resource and a type.
Nothing can be both a root and a type.
Nothing can be both a root and a slot.
Nothing can be both a root and a value.
Nothing can be both a root and a data source.
Nothing can be both a root and a resource.
No pair can be related by both includes and includesContainer.
No pair can be related by both includes and hasType.
No pair can be related by both includes and hasSlot.
No pair can be related by both includes and hasContainer.
No pair can be related by both includes and hasValue.
No pair can be related by both includesContainer and hasType.
No pair can be related by both includesContainer and hasSlot.
No pair can be related by both includesContainer and hasContainer.
No pair can be related by both includesContainer and hasValue.
No pair can be related by both hasType and hasSlot.
No pair can be related by both hasType and hasContainer.
No pair can be related by both hasType and hasValue.
No pair can be related by both hasSlot and hasContainer.
No pair can be related by both hasSlot and hasValue.
No pair can be related by both hasContainer and hasValue.