Axiom Specification 0.2 DRAFT

Last modified 12 Mar 2021 10:22 +01:00
This is draft specification, only a part of described functionality is available. This is all experimental. The language design and concepts are still subject to change.

Axiom is data modeling language used to model data (and metadata) in an abstract, representation-independent way.

This document describes the syntax and semantics of version 0.2-DRAFT of Axiom language. This document will also describe how a data model defined in Axiom model is encoded in XML, JSON, YAML and Axiom language.


Axiom is representation-independent data modeling language. Axiom can be used to model data in their abstract form. Unlike other modeling languages, Axiom is not bound to specific data representation from such as JSON or XML. Data modeled in Axiom can be represented (serialized and parsed) in many representation formats. Simply speaking, the same data can be expressed in XML, JSON, YAML and possibly also in other formats, including Axiom itself.


The following terms are used in Axiom:


Axiom model defines set of type, item, value and metadata definitions. Model is a basic "packaging" mechanism for Axiom definitions.


Set of one or several models that are used together. Schema is usually set of models that are loaded and active in an application. Schema is a "soft" concept, it is not formally defined anywhere in Axiom definitions.


Data item which can have one or more values. It is identified by item name.

item name

Name of data item. Item name can be local (if item is native to the data type) or fully qualified name (if item is external/ augmented to the data type).


Represents a type of value. It can be simple type or structured type, and may its instance (value) may have value metadata attached.

simple type

A type, which has simple value (eg. integer, string), does not have nested items.

structured type

A type, which has structured value - value consisting of multiple named items.


Represents concrete instance of type. The value is instance of type and may have value metadata attached.


Data about data. Metadata may describe origin of the data, trustworthiness and so on.

value metadata

Represents metadata attached to value. Each individual value of an item may have different metadata.


Mechanism for declaring additional items to already defined objects.

representation format

(also serialization format) Specific data format used to store the data. JSON, XML and YAML are examples of representation formats.

Design Principles

Axiom design is based on several principles, requirements and early design decisions.

The goal of Axiom is modeling of data in extensible, web-friendly applications. Axiom can be used to create a data model of a particular application, usually a reusable software product. Axiom is designed for reuse of existing data model components inside an application. Axiom data models can be made extensible by third parties, allowing customization of the data model by application users. Axiom is designed for use in applications that are completely schema-aware, applications that can iterate over the data, interpret them dynamically while being aware of data types and definition of all the items. Axiom is designed quite specifically for application developers. It is not meant to be yet another universal "schema language" for the web.

Axiom is used to model (abstract) data structures. Axiom is format-independent. Data modeled by Axiom can be represented in several data languages, such as JSON or XML. But Axiom is not bound to any such language.

Data modeled in Axiom can be expressed in several representation languages. But this does not work both ways. There is no ambition to be able to model any arbitrary JSON data in Axiom. There is no ambition to parse any arbitrary XML file. Only "Axiom-compliant" data structures can be processed.

Axiom is web-friendly, it is designed with World Wide Web in mind. That means, Axiom should be easy to use for data on the web such as RESTful interfaces, semantic web and linked data. Axiom is using namespaces identified by URIs. Axiom is using qualified names (QName) for data types and items, providing mapping of QNames to URIs. Overall, Axiom is trying to reuse existing web concepts as much as possible to fit into the WWW environment.

Axiom is built to be human-friendly - to a reasonable degree. Axiom should be easy to read, write and understand by humans, at least those humans that have spent some time learning Axiom. Axiom tries to limit the boilerplate and ceremony to necessary minimum. Of course, the primary goal for Axiom is to be machine-processable. Therefore it must be unambiguous, as close to minimalism as possible and so on. But humans are going to read and write Axiom models and data. Therefore the language should also be pleasant, readable and elegant. Axiom should consider human aspects of data modeling, e.g. support for integrated documentation. We have no ambition to make Axiom super efficient for binary processing, we do not optimize the language for parsing speed and so on. We create Axiom for human users.

Axiom natively support concepts of data model evolution. Data models are not static. They evolve, change in time. Some changes are compatible, other are not. Axiom is built to allow for such evolution.

Axiom is designed to create cross-domain schemas. Which means that Axiom schemas can be composed of models that originated in different domains, authored by different organizations. Axiom supports reuse and extension of schemas that are created by others.

However, Axiom is not designed for applications that adopt an open world paradigm. I.e. applications that work with data models that can be extended in any way, at any time, without requiring human intervention. Semantic web applications are a prime example of such approach. Axiom design trade-offs are made in favor of extensible applications, e.g. the ability to generate code from data model is much more important than smooth support for open world. We hope that Axiom could still be used in open world systems or at least for interaction with such systems. But such use may not be entirely easy or comfortable.

Axiom is a data language. However, it is designed to support generation of type-safe code. For example, it should be possible to express Axiom data types using Java classes. The generated code should look reasonably natural in wide range of programming languages, but the primary focus are statically-typed object-oriented languages.

Axiom is designed to support metadata and other cross-cutting concerns in data modeling. For example Axiom supports annotations for incomplete or unknown data.

Axiom is designed to be extensible language. Frameworks can extend the language capabilities to introduce their own data modeling concepts, add annotations and so on.

Axiom assumes that all models for all data will be available eventually. But that does not mean that all the models are available at the time when data are parsed. Some parts of the data are dynamic, they may be parsed without knowledge of the model. The model may be determined at runtime using complex algorithms based on parsed data and environment. The models may also be retrieved on demand. Therefore Axiom processors should be able to parse data partially (or as raw data as we call it) and apply model definitions later. However, Axiom assumes that such raw data will not be used until appropriate model is applied. All that Axiom can do with raw data is parsing them and storing them in their original form (without any modification). Full model is needed to use the data, interpret them and modify them.

Axiom is developed in an incremental fashion. The focus is on practical use and overall usefulness of Axiom. We are paying a lot of attention to make sure that the basic principles of Axiom are correct and consistent and that Axiom can evolve in the future. However, first versions of Axiom are not going to be perfect. It will be limited and there may be mistakes that need to be corrected in the future. However, Axiom can be validated only by practical use of the language in prototypes and real-world implementations. Therefore the primary goal of Axiom effort is to allow for such implementations to allow Axiom to continually improve.

Axiom Overview

A Axiom model defines data objects and their nested data item hierarchies. This allows a complete human and machine-readable description of the data.

Axiom models data structures using items and values that are combined to specify data types. Axiom provides clear and concise descriptions of the items, as well as relations between those items and their composition in data types.

Axiom definitions are grouped into models. A model can import definitions from other external models. Models can be extended, allowing one model to add items to the extension point defined in another model.

Axiom data models can describe constraints to be applied to the data.

Axiom defines a set of built-in types and has a type mechanism through which additional types may be defined. Derived types can restrict their base type’s set of valid values using mechanisms like range or pattern restrictions and extend their base type by addition of additional items in case of structured types.

Axiom is a self-descriptive language. Axiom modeling language could be also modeled using Axiom.


Axiom definitions are grouped into models. A model contains collection of related definitions that form a consistent group of data types for a specific use.

Models are defined using model statement. Each model needs a name and namespace declaration.

model my-model {
    namespace "";

Model is identified by its namespace. Namespace is a globally-unique identifier in URI form.

Model name is a short string that is used mostly for diagnostic reasons. Model name can be displayed in error messages, diagnostic output and it can be used for similar purposes.

There is no strict requirement for model name to be unique. However, there is a benefit in making the name unique with reasonable probability. Model name is used as a default prefix for the model namespace, therefore it is recommended to keep model name short. It is recommended to use kebab-case for model names.

Types, Items and Values

Axiom defines basic concepts for data modeling - items, values and data types.


Item is named collection of values. There are three basic types of items in Axiom:

Identifier-less item

Item which does not have value identifiers specified.

Map item

Item which has value identifiers specified, and values could be retrieved by their identifier.

Substitution item

Item with different name and different value type which subsitutes other less-specific item.

Value ordering is not defined for item. Use explicitly modeled ordering (eg. order item) for values, which requires order.
Item Name

Each item (in actual data or in model) has name. This name can be local (to the value type) or fully qualified name (if item is augmented into type).

Item names (local) by conventions use lower camel case (as is common for elements in XML or keys in JSON/YAML).

Item Defitions

Axiom models defines structure, behaviour and restrictions imposed on items by item definitions. Item definitions are part of type definitions for nested data, or as root item definitions for models.

Item definitions in types could be:


Type is specification of value structure (for structured types) or possible set of values (for simple types).

Simple type

A type, which has simple value (eg. integer, string) and does not have nested items.

Simple type must be subtyped from one of built-in types.

An instance of simple type is simple unstructured value.

An simple type may be:

  • derived from super type Simple Type Subtyping

    • restricting possible value set

    • expanding possible value set

    • adding semantic information

Structured type

Type, which has structured value - does allows nested items and contains their definition. An instance of structured type is structured value, which consists of items.

A structured type could be: * derived - type is derived from other structured type by Structured Type Subtyping * augmented - type definition is expanded by external model Augmentation


Actual data value, which has its type and represents instance of that type. Value must conform to definition of the type.

Structured Value

Instance of structured type. Consists of items and their values, which conforms to item definitions present in its type definition.


Item ordering is undefined and may not be preserved.

Built-in Simple Types

This list represents set of current built-in types, in following versions of draft additional base types will be introduced.

Axiom provides following built-in simple types:


Character sequence. Equivalent XSD type is string


Boolean value. Equivalent XSD type is boolean




Number. This type is abstract and is supertype for all number types.


Whole number. Equivalent type is integer.


Variable length binary data. In text format data are serialized using Base64 encoding. Equivalent XSD type is


Time-zone qualified date time. Type is serialized as ISO8601 date time with time zone offset. Equivalent XSD type is dateTimeStamp.


Namespace qualified name - an URI identifying Axiom concept such as item or type. This type adds semantic meaning to URI and allows for additional serialization format as prefixed name.

Model Imports

One model can be referenced from another model for reuse or extension. Models can be references by import statement:

model base {
    namespace "";
    type Foo { ... }

model extended {
    namespace "";
    import {
        namespace "";
        prefix "base";

Import statement prepares the base model for use in extended model. The statement also sets prefix for the base model. Types and items from the base model may be referenced by using base: prefix. For example, type Foo from the base model can be used in the extended model by referring to it as base:Foo.

Model name will be used as a default prefix when model is imported. Therefore the import statement above can be shortened as:

model extended {
    namespace "";
    import "";

Import of a model creates a dependency on that model. Consequences of that dependency depend on specifics of reuse. For example, subtyping creates a strong dependency, while augmentation creates a weak one. But import and reuse always create a dependency - at the very least a dependency that the imported model exists.

Model imports may be circular. However, great care must be taken when working with circular dependencies. As a rule of thumb it is strongly recommended to avoid circular dependencies whenever possible.


Axiom allows subtyping (type derivation) for both simple and structured types. Derived simple type may limit possible value set by imposing restrictions. Derived structured type may introduce additional items (properties, container, object references).

Simple Type Subtyping

New simple types could be created by using built-in types as super type.

Adding semantic simple type
type TypeName {
  supertype Uri;
  documentation """
    An URI representing type name qualified by model URI and type local name.

Simple type subtyping is useful for adding additional semantic layer to types and to modifying possible value set by restricting or extending it.

Current value restriction / extension concepts are still work-in-progress and will de defined in later revision of draft.
Extending value set
// Note This is proposed syntax only
type OccurenceLimit {
  union Integer;
  union Enum {
    enum unbounded;

Structured Type Subtyping

Structured type subtyping is extending the set of items that are defined for the type:

type IdentifiableObject {
  item oid {
    type uuid;

type User {
  supertype IdentifiableObject;
  item username {
    type string;

Subtyping creates new data type in a smooth and natural way. For example, the new data type will use the same namespace for all the items, even if the supertype is defined in a different model. The purpose of subtyping is to facilitate reuse of data structures and hence support reuse of code in the data processing implementations.

    oid: 96df17b4-ab26-11ea-859b-cf5a21832c98
    username: foo
Subtyping and inheritance

Subtyping is often confused with inheritance. Axiom is a data modeling language and not a programming language. Therefore it is quite obvious that Axiom is focusing on subtyping instead of inheritance. However, there is also a bit of inheritance involved in structured type subtyping. Subtype automatically "inherits" definitions of all items of a supertype. This is a natural thing to do, as subtype has to satisfy the contract of the supertype and the common method how to do that is to reuse supertype items. However, this is only a default behavior. Subtype is free to provide its own definition of the supertype items - as long as it still satisfies the supertype contract.

However, there is also a downside to subtyping. The subtype has a very tight binding to the supertype. Whenever supertype changes, the changes may affect subtype in a very severe way. The use of subtyping is recommended only in cases that there is a strong coordination of evolution of supertype and subtype, ideally when they are part of the same model.

Simple type subtyping is planned for the future, but it is not supported yet.


Mixin is a data structure designed to be included in other data structures. Use of mixins is similar to inheritance used in subtyping, but it is not bound to subtyping and therefore it does not need to follow type hierarchy.

model example {
    mixin Documented {
        item documentation {
            type string

    type Object {
        item name { ... }
        include Documented;

The mixin is seamlessly integrated into the data type:

    name: foo
    documentation: This is really useless object.

Mixins are used when a set of items is repeated in may data types. It would be possible to just copy definitions of such items. But that would not be really readable and maintainable, especially if the items have structured type definitions, documentation or other annotations. Mixins make it all easier, bundling all the complexity in a single definition and then allowing its reuse. There is also a benefit for platforms that are generating code from the models, as mixins can be translated to native programming language concepts (e.g. Java interfaces).

However, all of that does not change the basic fact that mixin use is just a simple inclusion of items into the data structure. Therefore there are downsides. Data type that is using a mixin is tightly bound to the mixin definition, similarly to subtyping. Therefore great care must be taken when using mixins from different models.


Augmentation is a method how to extend capabilities of an existing data type without definition of a new data type.

model midpoint {
    namespace "";
    type User {
        item fullName { ... }

model custom {
    namespace "";

    import "";

    augmentation ExampleUser {
        target midpoint:User;
        item personIdentifier { ... }

Example model augments midPoint User type with custom property personIdentifier. Whenever the User data structure is used, the personIdentifier property may be used with it.

However, the personIdentifier property needs to be fully qualified with namespace information to distinguish it from any other properties that the midPoint model can have in the future.

@context: ""
    fullName: James Bond
    "": "007"
<user xmlns="">
    <fullName>James Bond</fullName>

Augmentation is usually used to extend capabilities of a different model, a model that we do not control. Therefore it is an ideal tool for customization of data models. For example, midPoint is a product with a fixed data model set when the product was released. But there is often a need to customize and extend the data model at "deployment time", long after the software was released. Augmentation is an ideal mechanism for that. A customer data model can augment fixed data structures of midPoint with custom items.

Augmentation is designed to be safe with respect to data model evolution. As long as the original data model evolves in an compatible way, the augmentation will still work. Both the original data model and the augmentation may evolve independently. The models will not get into conflict. But there is a price to pay. Augmentation data always have to use full namespaces to make the augmentation safe.

Augmentation is a mechanism that realizes the open-closed principle. The original data model is fixed, it is closed to modification. But still the data are open to extension by the means of data model augmentation.

Data Model Documentation

Axiom provides a means for a documentation integrated into the data model specification:

model my-model {
    namespace "";
    documentation """
        Example data model.
        This model should be used for *demonstration* pruposes only.

    type Foo {
        documentation "Foo type, just to have something here.";

Axiom documentation is formatted in AsciiDoc. Only basic asciidoc formatting should be used, formatting that one would use inside of a simple section. Such as character formatting (bold, italics, monospace), paragraphs, bullet lists and so on. Headings and similar "outline" formatting should not be used. Axiom processors will take care of generating document outline, headers and similar document infrastructure.

Metadata, Completeness And Other Underlying Concepts

Unlike most other languages, Axiom goes wider and deeper, working with concepts that are beyond and the data and under the data. Axiom supports concept of metadata, that are data about data. Metadata can be attached to every data value, describing data origin, transformation and so on. Axiom also supports concepts of partial, incomplete or unknown data values.

All of that is allowed by a concept of inframodel, which is model under the data. Inframodel deals with data items and values. E.g. metadata are implemented by extending the inframodel of Axiom value, which allows to attach metadata structures to every value of the data.

Dealing with inframodel is quite an advanced abstraction. However, the inframodel is usually hidden from most Axiom users.

None of the usual representation formats have sufficient support for such abstract "meta" and "infra" concepts. This is, in fact, quite understandable. Such formats originated in different times and they were built for different purposes. The need to support inframodel was not there when XML was created and when JavaScript object notation was (ab)used for general-purpose data representation. Therefore transition to inframodel is usually denoted by use of special characters in representation formats. Whenever you see at character (@) in JSON or element starting with underscore (_) in XML it is most likely an inframodel concept.

Please see Axiom concepts explanation for more details about such advanced topics.

Axiom in Axiom

Axiom is a self-descriptive language in a way that Axiom language can be described by Axiom language.

Axiom Syntax

Axiom syntax closely emulates basic Axiom concepts of item & value.

Language syntax was inspired by YANG modeling language from IETF, which tries to strike balance between readability and authoring. (YANG 1.1: 6.3 Statements)
Basic ABNF
item = itemName value;
infra = "@" itemName value;
value = [argument] (";" / "{" *(item|infra) "}");

Normal data item


Value of item. In case of simple type values, argument represents value. In case of complex values, argument represent value of item based on argument in type definition.


Name of item, expected value is prefixed name (also without prefix).


Infra data item - used to specify inframodel specific data.


value of item in case of simple type item, nested value could be prefixed name, number or string.

This provides basic simple structure for language and allows for simpler parser (See ANTLR4 syntax below.)

The omission of actual item names from grammar allows for addition of keywords and language extensions without need to change grammar definition (and lexer code). Sharing of same concepts with data model also allows Axiom to be used for data serialization / authoring.

Table 1. Syntax example (model and data)
Simple model syntax example
model simple-user {
  namespace "";
  import "" {
    prefix storage;
  root user { (1)
    type User;
    description "user is root item."; (3)
  type User { (2)
    description """
      Represents simple user.
       of the system.
    """; (4)
    argument username; (5)
    item username { (6)
      type string;
    item note {
      type string;
      storage:indexed fulltext; (7)
1 Item root with argument user
2 Item type with argument User. This is declaration of type User
3 Statement description with single-line string argument
4 Statement description with multi-line string argument
5 Item argument with value username (value type is item name)
6 Item item with name username, This is declaration of item username, which is also target of argument
7 Item indexed from model (added via augmentation)
Data written in Axiom
  user {  (1)
    name "administrator"; (2)
    note """ (3)
      Administrator of system.
      Do NOT remove
1 Root item user (of type User, based on simple-user model)
2 Item name with value administrator
3 Item note with multi-line string value
Same data in Axiom using arguments
user admin { (1)
  note """
    Administrator of system.
    Do NOT remove
1 Item user, child item name has value administrator (via argument, based on simple-user model).
Same data in YAML
  name: administrator
  note: >
    Administrator of system.
    Do NOT remove


model "prism-types" {
  version 4.0;

  type PolyString {
    documentation """
      Polymorphic string.
      String that may have more than one representation at
      the same time. The primary representation is the original version that is
      composed of the full Unicode character set. The other versions may be
      normalized to trim it, normalize character case, normalize spaces,
      remove national characters or even transliterate the string.

      There is an alternative syntactic short-cut representation of PolyString. If no
      child element is present then the text entire text content of this element is
      considered as if it was present in the 'orig' element. That's the reason for making
      this type 'mixed'.

      This is considered to be primitive built-in type for prism objects.

    argument orig; // Allows PolyString to be specified as normal string

    property orig {
      type string;
    property norm {
      type string;
      documentation """
        Normalized value of the string.
        The values is processed by the default normalization algorithm defined
        in the system.""";
    container translation {
      type PolyStringTranslation;
      documentation """
        Definition of string value by using localization key and parameters.
      since 4.0;
    container lang {
      type PolyStringLang;
  type PolyStringLang {
    item lang {
      type string;
      documentation "Language code";


Namespace is one of Axiom fundamental mechanisms. Namespaces identify models and provide model isolation. Namespaces are instrumental in supporting evolution of data models.

Technically, namespaces are Uniform Resource Identifiers (URIs). The namespace should be chosen to be globally unique, therefore URIs are a natural choice.

Model Identification

Namespace is a globally-unique identifier of a model. Each namespace specifies exactly one model. Whenever a data file needs to specify the data model that was used to create it, namespace is used to identify that model. Whenever a data model refers to a concepts of another model, namespace of the model is used. Whenever there is may be an ambiguity about appropriate interpretation of an item, namespace is used to resolve the ambiguity by pointing to the correct model.

Isolation of Models to Support Evolution

All data models evolve. They change to implement new features, adapt to changes environment or fix mistakes of the past. Axiom is designed to combine, reuse and extend data models. Each model has its own namespace, therefore it may look like each model can evolve independently. However, there are practical limitations.

Some models are tightly interweaved. They depend on one another and if one of them changes the other has to adapt. This is usually caused by type inheritance. The problem is, that even if the "parent" model evolves in an compatible way, the "child" (dependent) model may still be affected and it may be forced to change in non-compatible way. The bad news is that there is not much that we can about this unless we want to make data structures quite complicated, big and difficult to use. But the good news is that we usually do not need to do anything. Development of models that are such a tight relationship are usually well coordinated. Therefore such conflicts can usually be avoided or resolved by "out of band" means.

Then there are models that need to evolve independently and they are prepared to pay the cost. There are two "safe" methods to use: composition and augmentation. Composition is a mechanism to use data type from a foreign schema in my own data structures. Composition easy to use, it does not complicate the data and it is overall a recommended mechanism. Augmentation is a mechanism to extend data type from foreign schema with custom items. Augmentation ensures safe evolution of the models. But it is using explicit specification of namespaces in the data, therefore it makes the data larger and more complex.

See Cross-model use cases for more details.

QNames and URIs

Axiom, similarly to other languages and platforms is using a concept of qualified name. Known as QName, qualified name is a combination of a local name with the namespace. E.g. an item foo specified in model identified by namespace will have a QName that is a combination of these two values. QNames are used to create globally-unique identifiers for all elements of data models, making sure that they will not be confused.

WWW architecture that states that QNames should be considered equivalent to URIs. But we have gone one step further in Axiom and we consider QNames to by just a special case of URIs. We define a mapping between QNames and URIs, which means that all QNames can be represented in URI form.

The QNames are mapped to URIs by concatenating namespace URI and a local name. If URI does not end with slash (/) or hash (#) character, hash (#) is concatenated to the URI before adding the local name. The URI-QName mapping is the reverse process. Local names must not contain hash or slash characters.

The recommendation is that model namespace name should not end with hash (#) or slash (/) character, so the hash (#) is assumed at the end. All the QNames used in a single model are related and part of one consistent group. We want to be perform a single fetch of the model specification to get definition of all the elements in the model.

Axiom QNames and URIs are almost the same thing. This means that URI can be used anywhere where QName is expected — as long as the URI is well-formed and QName can be derived from it. There is no special format for QName in Axiom. We do not need that. We are using URI format instead.

Axiom is reusing the concept of QName that is also used in other languages, such as XML. However, QNames can be quite a strange animal, especially when used in XML ecosystem. We are not promising that Axiom could deal with all the possible uses of QNames in the XML world, semantic web or in various JSON extensions. That is not our goal as that would complicate the system to the point where it may not be maintainable any more. Our goal is the other way around: QNames and concepts specified in Axiom should be usable in other ecosystems, as long as the ecosystem supports all the necessary concepts. E.g. It should be able to, theoretically, translate Axiom data models into XSD or JSON Schema and used them in XML or JSON worlds. However, if you use the concept of metadata, you are probably out of luck with XML or JSON, as those do not support metadata concepts at all.

Namespace Aliases

Each model should be identified by exactly one namespace. Namespaces are URIs and not URLs, therefore they do not need to change. That is the theory. But in practice the namespaces do change. Even URIs are usually based on domain names that change. URI structure may change in time. Company names change, product names change, people make mistakes that need to be fixed and so on. Therefore namespaces change too.

Axiom models are identified by exactly one primary namespace. This namespace is used for all the usual purposes, especially when data are stored and serialized to representation formats. However, when we read the data, we tolerate other namespaces as well. Those are namespace aliases. Those may be data stored with a namespace before it was changed. We want to be able to read them and process them. But whenever we present or store the data, we will always use primary namespaces.

Namespace aliases are also a nice way how to solve the http vs https confusion.

Namespace Prefixes

Namespace URIs are usually quite long and it may be quite cumbersome to use them in representation data formats. Therefore Axiom has a concept of namespace prefix. Prefix is a short string that identifies the namespace. For example the Axiom model namespace is usually using axiom-model prefix. Prefix can be used at appropriate places instead of full namespace URI. Therefore, given the axiom-model prefix above, the following two notations are usually equivalent:

Namespace prefixes are usually specified in the model. Model name is used as a namespace prefix by default.

Specific syntax of the prefixes, rules about where prefixes can be used or cannot be used and other details depend on specific representation format.

Axiom namespace prefixes are similar to namespace prefixes in other languages (XML, XPath), but there are subtle and important differences. The most notable difference is that prefixes are semantically significant. Which means that if prefix is changed, meaning of the items and values may change as well. This is a critical difference with respect to the XML world. Unlike XML, prefix are usually defined in the model (schema), not in the document. The document may provide prefix declaration, but those are often redundant and may be omitted. The processor may refuse to process a file where prefix declaration is in conflict with the prefixes specified in the model. It is expected that processors will make some effort to process data with conflicting prefixes and try to "fix" them. However, this may not be possible under some circumstances, therefore processors are allowed to refuse such data.

Namespace prefixes are given by the model and they are considered to be immutable. Change of namespace prefix is considered to be an incompatible change. Prefix change is very likely to require data migration process.

Of course, making prefixes significant and immutable results in requirement that prefixes have to be unique. However, Axiom do not require global uniqueness of the prefixes. Prefixes need to be unique only in a particular data set. Axiom assumes that a models for all the data in the system are (eventually) known. As prefixes are controlled by the models, it is feasible to make prefixes unique in the entire schema. Which also makes prefixes unique in the entire data set.

However, prefix names have to be chosen wisely to allow evolution of data models. It is not difficult to make sure that the prefixes are not in the conflict today. But we also need to make sure that the prefixes will not conflict in the future when data models evolve and new models are introduced into the schema. Prefixes of Axiom models start with axiom-, which should be considered to be a reserved segment of prefix namespace. Models built on Axiom should adopt a similar convention to avoid future prefix conflicts. Use of project name in the prefix is a recommended practice. E.g. Prism model prefixes start with prism- and midpoint prefixes start with midpoint-. It is usually not a big issue to choose a longer prefix for primary model namespace, as that prefix is almost never used in the data. The data that are given by the primary model are almost always written without any namespace at all, as the namespace can be determined from the model. The prefixes are significant for metadata models or "extension" models that extend primary data model by using augmentation.

Names that are using the prefix notations are often used in the same place where URIs can be used in the representation formats. Therefore there is slight chance that prefix can be confused with URI scheme. For example, specifying prefixes such as http, https and especially urn are not a good idea. URIs usually have more complex internal structure than simple "qualified" names that use prefixes, therefore a chance to confuse prefix and URI are minimal. But there is still non-zero chance of conflict. Therefore, specifying namespace prefix that matches any of currently used URI schemes is strongly discouraged. Prefixes are specified in the models, as are namespace URI. Therefore model authors can make sure that prefixes and URIs are conflict-free. For data compatibility reasons, in case that a prefix conflicts with URI scheme, the prefix takes precedence.

Prefixes are completely optional. Axiom can be used without prefixes at all, if needed. It will be less efficient and perhaps less elegant, but everything will be strict, correct and fully-qualified. Such representations of Axiom data are called portable formats. Axiom is designed to work inside a single application, processing data for that application only. Portable data extend this notion, as they can be safely passed from one system to another. Portable formats make sure that every value or every item can be unambiguously interpreted in a different system that has the same primary data model, but that may have a different set of additional data models in its schema.

Use of prefixes may be problematic in applications that adopt an open world view. Use of prefixes in such applications that is not recommended.

The decision to make prefixes significant and immutable is based on a decade-long battle with XML and XSD, where the prefixes caused annoying problems. Axiom assumes that all models for all data will be available eventually. But that does not mean that all the models are available at the time when data are parsed. If an model is not available, it is impossible to determine whether foo:val is a simple string, or whether it is qualified name with foo as namespace prefix and val as a local name. Reading the data as string and storing them as string is the best we can do if the model is not available. But doing so may destroy the data in case that namespace prefix foo is renamed to bar. If this is a qualified name we have to store bar:val. But if it is a simple string, we have to store foo:val. The point is that we do not know what it is, therefore we do not know how to store it. Axiom avoids this situation by admitting that prefixes are semantically significant and making prefixes immutable. If prefix cannot change, we can always store foo:val and we can be sure that we have not ruined the data.

Namespace URI Recommendations

Choosing a namespace URI is am important decision. Even though there are namespace aliases and Axiom can tolerate namespace changes, frequent namespace changes are confusing and they should be generally avoided. It is recommended to choose a good namespace URI from the beginning and then stick to it for years or even decades. Following paragraphs provide recommendations for choosing good namespace URI.

Generally, it is recommended to use HTTPS uri based on the DNS domain that you control. We recommend following format:

The best strategy is to keep the namespace URI short. Long namespace URIs are an obstacle for readability. Also, namespace URIs need to be stored together with the data under some circumstances therefore long URIs are increasing storage size of the data.

Strictly speaking, those are URIs, therefore there is no requirement for them to be resolvable URLs. However, we strongly recommend to choose URIs that can be made resolvable in the future. There may be great benefit in simply issuing an HTTPS request to the namespace URI to retrieve an definition or to use that URI as an endpoint for model-related services. Using a dedicated host part of the URI (e.g. is a good strategy. Such host can be implemented as DNS alias to point to an appropriate server that hosts actual definitions or API.

Due to the possibility of future resolvability of the namespaces it is recommended to use https URI scheme instead of http.

Do not end your namespace URIs with slash (/) unless you have very good reasons to do so. Ending the namespaces with a slash will affect the way how QNames are created from the namespace. Do not end your namespace URIs with hash (#) either. Hash character will be automatically used when composing QNames if the URI does not end with a slash. Therefore appending hash character to your URI is redundant. It also makes your URI look strange and confusing.

Do not include model version in your URI. Axiom has a separate versioning mechanism and it does not rely on version numbers in namespaces. On the contrary, version numbers in namespace URI are likely to be an obstacle for organic evolution of your data models.

In case that you need to maintain several models in your project, it is recommended to create a component hierarchy in the namespaces, such as:

Common Namespaces

Following namespaces are used for definition of fundamental Axiom concepts:

Purpose Name/prefix Namespace URI Description

Axiom model


Definition of Axiom modeling language. Contains definition of all the basic "statements" of the language such as model, import and type.

This is the namespace that pure Axiom models are using as their "root" namespace (namespace of the root item). However, this namespace is seldom imported, reused or extended. It needs to be used only for models that build on top of Axiom modeling language (such as Prism).

Axiom data types


Defnition of basic data types that are used in almost all Axiom models. Definition of String and Integer is located in this namespace.

This is the default namespace when specifying data types. Therefore built-in Axiom types can be used without explicit namespace or prefix.

Axiom data


Definition of Axiom data language. Concepts such as item or value are defined here.

The concept of Axiom namespaces is similar to namespace concepts in other ecosystems. Namespaces used by XML, semantic web and JSON-LD are quite similar to Axiom namespaces. This similarity is part of Axiom design, as we hope to be compatible with concepts and data from other ecosystems. However, Axiom namespaces are used in quite a different way. Unlike JSON, the namespaces are integral part of the design. And unlike XML, namespaces are used just where they are needed. We hope that this approach helps Axiom to be both reliable and user-friendly platform.

Item Path

Item path identifies particular item or value in Axiom data structures. For example, item path can be used to reference specific data item to be modified.

Item patch is composed from segments separated by slash (/) character:


Item names are usually used in path segments:


The path refers to item or value in hierarchical Axiom data. Each segment refers to one level in the hierarchy. The path above points to the administrativeStatus item in following data:

  "givenName" : "John",
  "familyName" : "Doe",
  "activation" : {
    "administrativeStatus" : "enabled"

Namespaces In Item Path

Item path fully supports concept of namespaces. There are two ways how to specify namespaces: using full URIs and using namespace prefixes.

URIs in the item path must be enclosed in parenthesis:

Namespace using full URIs

Namespace prefixes can be used in item path instead of URIs:

Namespace using prefixes

The example-custom prefix above represents namespace

Value Keys

Axiom is designed to seamlessly support multi-value data. However, referring to items in hierarchical data structures where multiple values are possible is not entirely straightforward. Let’s consider following data structure:

  "assignment" : [
      "name" : "a1",
      "description" : "first",
      "target" : "t1"
      "name" : "a2",
      "description" : "seqond",
      "target" : "t2"

There is a typo in the description of the second assignment. We want to refer to that specific value to have it fixed (e.g. by using a delta-based modify operation). However, the path assignment/description is ambiguous, as it does not specify which values of assignment it refers to.

Therefore path segments may contain optional identifier:


The way how the identifier is interpreted may be slightly different for every item or data type. The details are specified in the model.

Item Path Root

Item paths are usually relative. The root of the path resolution is usually implicit. For example the activation/administrativeStatus is usually relative to the top of the object.

Root of the path resolution can be specified explicitly by using the dollar sign ($):


This path is an absolute path, its root is specified by symbol focus. Meaning of focus is implementation-specific. It may be identifier of an object, it may be name of the variable or it may be anything else. The root symbol is considered to be qualified name, therefore it may even be an URI or URL of a network service:


Use Of Item Path

There are two principal uses of item path:

  • Referencing items and values in the data. The path points to the data structure, result of path resolution is an item or value.

  • Referencing item definitions in model. The path points to types in the model. Result of path resolution is item definition. Data identifiers in square brackets cannot be used in this case as there are no data to perform resolution on.


When we deal with data, we usually have complete and reliable information about the data. However, there are some unusual cases. Such as:

  • We know that item has values X, Y and Z. It has no other values. This is the common case.

  • We know that item has no value. E.g. we are sure that there are no criminal records for this person.

  • We know nothing about an item.

  • We know that item used to have values X, Y, Z recently. E.g. values that were removed by a particular mapping.

  • We know that the item has some value, but we do not know the value (the value is "unknowable"). E.g. there is a hashed password, we do not even want to disclose the hash, but we want to indicate that the password is already set.

  • We know that the item has some, we do not know the value now, but we can easily find out when needed. E.g. values that are not returned in the query because they are big or expensive. But we can easily construct a query that requests them explicitly. Or values, for which we have an expression that can be used to determine them. But we do not want to execute that expression if the value is not needed.

  • We know that the item has value X, but the item may also have other values that we do not know.

Axiom has concepts of item completeness and value significance to denote such cases:

  • Item completeness. Item can be:

    • Complete (default): we have all the values of the item. We are sure there are no more values than those that we have.

    • Incomplete: we do not have all the values of the item. There may be more values of the item, and we do not know anything about such values.

  • Value significance. Value can be:

    • Positive (default): We know the value, and it is the normal, usual value of the item.

    • Negative: We know that the item used to have the value, but it may no longer have that value. E.g. the value was removed by a mapping.

    • Potential: Item does not have this value, but it might have it. For example, the value was generated by the mapping, but mapping condition (or "strength") prohibited setting the value. This can be significant benefit for diagnostics and troubleshooting. It may also be useful for system administration, e.g. in case we have "value override" in place, this may show that value that would be present if the override was not active.

    • Default: Item does not have this value, but it will have this value (or this value will be assumed) if no other value is explicitly specified. This kind of value can be used by user interface to inform user about the default setting, pre-fill the field by a gray text or by any other similar means. It is very likely to improve the overall user experience. It is different from potential significance above, as the default significance clearly defines a condition when this value can become positive value. Therefore user interface can precisely simulate the behavior.

    • Unknown: We know that the item has a value, but we do not know what the value is. E.g. the value may be hashed or encrypted by an unknown key, the value may be determined by an expression that was not evaluated yet and so on.
      Question: do we need shades of meaning here? E.g. unknowable, expensive, dynamic

Completeness and significance can be combined to describe what we know (and what we do not know) about the item:

Item complete Item incomplete

Value positive

Normal data

We know that item has some values, but it may also have other values that we do not know.

Value negative

Value was removed by the delta. We know all the remaining values (if any).

Value was removed, but we have no information about other values.

Value unknown

We know that the item has a value, but we do not know the value (the value is "unknowable"). E.g. hashed password ("unknowable" value), value that is not returned (expensive value), expression (dynamic value)

We know that the item has (unknown) value, but it may also have other values.

No value or null value

We are sure that item has no value. E.g. "no criminal records"

We do not know anything about the item.


Use case: jpegPhoto was not fetched from repository and we do not know whether it has a value or not.

XML, full namespaces
    <jpegPhoto xsi:nil="true">
XML, minimal namespaces
    <jpegPhoto nil="true">

There is an issue that the completeness is a property of jpegPhoto item, not a particular value. But we cannot express data about an item if there is no value present. Hence the nil. The nil indicates that this value is not really a value.

  "jpegPhoto" : {
    "@value" : null,
    "@completeness" : "incomplete"

The @value=null may be optional, as this is a hash and no value is specified this should be obvious.

Use case: password is present, but we cannot or do not want to disclose the value. However, we want to indicate that there is a password.

XML, full namespaces
    <password xsi:nil="true">
XML, minimal namespaces
    <password nil="true">
  "password" : {
    "@significance" : "unknown"

Metadata Of Incomplete And Negative Values

Value significance is used to denote a negative value, metadata are attached as usual.

Metadata serialized with data:

XML, full namespace
        <axiom:value>This was all wrong, it is gone now</axiom:value>
XML, minimal namespace
        <_value>This was all wrong, it is gone now</_value>
  "description" : {
    "@value" : "This was all wrong, it is gone now",
    "@significance" : "negative",
    "@metadata" : {
        "http://.../midpoint#transformation" : {
          "mapping" : ....,


Metadata are data about data. Metadata often describe how we learned about the data, e.i. metadata describe origin of data. But metadata may also describe trustworthiness of the data (e.g. "level of assurance"), data confidentiality, metadata may record transformation history of data and so on. Metadata are often created automatically by systems that process and transfer the data.

Metadata are often as flexible as the data. As Axiom is used to create a model of the data, it can also be used to create a model of metadata: metadata model. Metadata model is using the very same mechanisms that the data model is using: data types, items, values, subtyping, etc. The only difference is that metadata are not included in the data structures directly. Metadata are automatically attached to every applicable value.

Metadata Specification

Metadata structures are specified using a special metadata keyword:

model example {
    namespace "";
    metadata StorageMetadata {
        itemName: storage;
        item createTimestamp { ... }
        item modificationTimestamp { ... }

This statement defines a new data type StorageMetadata with items createTimestamp and modificationTimestamp. The data type will be registered as value metadata with item name storage. The metadata will appear mixed into the data:

JSON representation of user object without metadata
    "user" : {
      "name" : "foo",
      "fullName" : "Foo Bar"
JSON representation of user object with metadata
    "user" : {
      "name" : {
        "@value" : "foo",
        "@metadata" : {
          "" : {
            "createTimestamp" : "2020-06-10T14:26:42Z",
            "modificationTimestamp" : "2020-06-12T18:14:05Z"
      "fullName" : {
        "@value" : "Foo Bar",
        "@metadata" : {
          "" : {
            "createTimestamp" : "2020-06-10T14:26:42Z",
            "modificationTimestamp" : "2020-06-22T09:30:16Z"

Metadata Of Empty Values

Metadata can be attached even to items without a value.

  "criminalCharges" : {
    "@metadata" : {
        "https://...#loa" : {
          "levelOfAssurance" : "high",

No Metametadata

It would be theoretically possible to have data about metadata, thus creating metametadata. However, Axiom does not have ambitions for this, at least not in its early versions. Axiom assumes just one "meta" level and it does not apply metadata definitions to the metadata.

Model Versioning

Axiom is using semantic versioning principles. As Axiom deals with data and not the code, the semantic versioning is slightly modified to suit the needs of data compatibility.

Each axiom data model has a version:

model example {
    namespace "";
    version "3.5";

Semantic Version Numbers

Recommended format for version number is:


All three parts are usually numeric, e.g. 4.2.1. The parts of version number have specific meaning:

  • Major version number indicates compatibility. Data models with the same major number must be compatible (with the exceptions specified below). Changing major version number indicates that the data model may no longer be compatible with its previous versions. Data created for a model with lower major version number may require significant modification or ever complete rewrite to fit the model with higher major version number. Models with major version number of zero (e.g. 0.1) are considered to be experimental (see below).

  • Minor version number indicate (compatible) revisions of the model. Axiom assumes backward compatibility (see below). Changing minor version number indicates that the data model has evolved in a compatible way. E.g. the model may be extended with new optional items. Data created for a model with lower minor version number should be directly usable in processors built for model with higher minor version number. However, the data may still need some modifications, e.g. removal or rewrite of deprecated or experimental items.

  • Patch version number indicate corrections. Changing patch version number indicates that the data model was updated, but there was no significant change in structure or meaning of the data. Data created for a model with lower patch version number must be directly usable in processors built for model with higher patch version number. The data must not require any modifications, with the exception of experimental items and corrections of previous incorrect behavior.

Version number that are zeros are optional. Therefore version 1.2 is to be considered the same as version 1.2.0. Minor and major version numbers must be numeric. It is strongly recommended for patch version number to be numeric too. However, it is allowed for it not to be numeric to account for hotfixes and other out-of-sequence patches.

In addition to that, version number may have optional suffix:


The suffix indicates that the model version is before or lower than the specified version. E.g. 1.2-SNAPSHOT means that this is a model that is just before version 1.2. Therefore it is considered to be after any 1.1 version, including 1.1.2 and 1.1.98761, but not yet reaching version 1.2. The suffix is usually used for development, milestone or pre-release versions. Ordering of the suffixes is not specified. Therefore it is not specified whether 1.2-M3 is before or after 1.2-RC2.

Backward Compatibility

Axiom requires data compatibility between minor versions of data model. This means that data created for earlier version of the model must be comprehensible for models of later versions. No data migration or transformation should be necessary.

However, there are few exceptions:

  • Experimental items: There is absolutely no compatibility or stability guarantees for experimental items. They can change in any way at any time. Including minor or patch versions.

  • Deprecated items: Deprecated items may be removed in a version that follows the version in which the item was deprecated. It is not yet decided whether deprecated items may be removed only in major versions or they can be removed in minor versions as well.

  • Bugfixes: Bugfixes in the code may require changes in the data model. It is recommended to make these changes compatible if it is possible and practical. However, Axiom does not mandate "compatible bugs" policy. That means that bugs may be fixed in minor and patch versions even if it means that compatibility (in a strict sense) is not maintained. The rationale is that if there is a bug in earlier version, that particular part of the data model was not working properly anyway. The data will need modification to fix the problem anyway. Therefore it is better to correct the model as soon as possible.

Versioned Dependencies

This has to be decided in later versions of Axiom.

TODO: use of version in import

Data Versioning

This has to be decided in later versions of Axiom.

TODO: specification of model version in the data

Data Model Evolution

Axiom is designed to support evolution of data models. There are special tools that support data model versioning and version-aware documentation.

Following markers can be applied to any modeling concept (type, item, etc.)



Version where the specified concept was first introduced.


Marked concept is deprecated. It still works, but it should not be used any more. Do not use it for any new configuration or data. Migrate all existing data to avoid use of deprecated concepts.


Version where the specified item became deprecated.


Marked concept is experimental. It is still being developed and it is unstable. It can change any time in any way, even in minor or patch versions. Experimental concepts usually evolve into ordinary concepts eventually. Experimental concepts may be removed at any time if they prove to be wrong or undesirable.


Version where it is planned to remove the concept.


Version where it is planned to change the concept in a non-compatible way.

Deprecation and Removal

This has to be decided in later versions of Axiom.

TODO: removal of deprecated elements

TODO: deprecation "contract" vs compatibility: when we can remove deprecated items? minor or major version?

Experimental Elements

Experimental concepts of the model can change in any way at any time. Such concepts are being developed. They are unstable. People that are using experimental parts of the model must be prepared to adapt the data after every change of the model, including minor and patch versions of the model.

Experimental concepts usually evolve into ordinary concepts eventually. But that may take several versions.

Experimental concepts may even be removed at any time if they prove to be wrong or undesirable. The developers are not required to provide any replacement functionality for removed experimental concepts.

Models with major version of zero (0) are considered to be completely experimental. Every concepts of such model should be considered experimental. There are no compatibility guarantees for models with zero major version number.

Axiom Background

Axiom is a language originally designed to model data in midPoint project. MidPoint was originally designed with XML and XML Schema Definition (XSD), however those mechanisms were never a perfect fit for project needs. Finally in 2020 it was decided to replace XSD with a new data modeling language that would be a better fit. First step was to use Axiom to represent meta-data schema (meta-schema) for data provenance purposes needed by MidPrivacy initiative.

Axiom was used to model Prism data structures in midPoint. Prism is a Java framework that can be used to maintain object-based data models. Prism specifies basic properties of a data object, it defines data structures that describe object changes (deltas), it specifies query language for objects and so on. Prism evolved in midPoint project where it was used as a basic data framework.

Axiom sytnax was heavily inspired by Statement concepts were inspired by YANG modeling language. Some of Axiom concepts were also inspired by YANG.

Axiom in MidPoint

Axiom is data modeling language used to model data and metadata for Prism and midPrivacy project, with intention to replace XSD as go-to modeling language for Prism.

Axiom is designed with migration path from XSD to Axiom in mind, which is possible thanks to common mapping of concepts via Prism. Axiom maps more directly to Prism concepts and it is intended to be less verbose than same model written in XSD.

Axiom Development

Axiom is developed in an incremental fashion. The focus is on practical use and overall usefulness of Axiom. We have no ambition for Axiom to become a universal language suitable for every situation. Axiom is designed for use in applications.

Axiom is built on solid foundations. We are paying a lot of attention to make sure that the basic principles of Axiom are correct and consistent and that Axiom can evolve in the future. But all the details of Axiom are not laid out yet. However, first versions of Axiom are not going to be perfect. It will be limited and there may be mistakes that need to be corrected in the future. However, Axiom can be validated only by practical use of the language in prototypes and real-world implementations. Therefore the primary goal of Axiom effort is to allow for such implementations to allow Axiom to continually improve. Each new version of Axiom should be better, more detailed, better documented, more polished.

Axiom specification will progress from initial draft to early versions, prototypes, specification improvements, validation using initial implementations, progressing in iterations. Language specifications will go hand in hand with implementations. Primary implementation of Axiom is available under open source license and developed in the open source way.

Axiom may get standardized eventually. But we want to avoid premature standardization. We see standardization as the very last step in Axiom development. Before we get to standardization, we need to make sure that Axiom is good enough and that it works. That has to be proven by several independent implementations and the language needs sufficient time to mature.


Axiom was created and it is maintained by Evolveum.

Initial version of Axiom was developed in MidPrivacy project that was supported by funding from NGI_TRUST program.

This project has received funding from the European Union’s Horizon 2020 research and innovation programme under the NGI_TRUST grant agreement no 825618.

Was this page helpful?
Thanks for your feedback