6NF File Format

Filename Extension: .6nf

1. Introduction

6NF File Format is a new bitemporal, sixth-normal-form (6NF)-inspired data exchange format designed for DWH and for reporting. It replaces complex hierarchical formats like XBRL, XML, JSON, and YAML.

2. Design Principles

3. Syntax (EBNF)

6nf             = [version] { entity | reference | attribute | attribute_ref | struct | relationship } ;
version         = "VERSION" number "\n" ;
entity          = "ENTITY" entity_name entity_id "\n" ;
reference       = "REFERENCE" name reference_id value "\n" ;
attribute       = "ATTRIBUTE_OF" entity_name entity_id name value valid_from recorded_at "\n" ;
attribute_ref   = "ATTRIBUTE_REF_OF" entity_name entity_id name reference_id valid_from recorded_at "\n" ;
struct          = "STRUCT_OF" entity_name entity_id name valid_from recorded_at "\n" 
                 { name (value | reference_id) "\n" } ;
relationship    = "RELATIONSHIP" name relationship_id valid_from recorded_at "\n" 
                 { name ( entity_id | reference_id ) "\n" } ;
value           = string | number | iso8601 | "true" | "false" ;
string          = "\"" { character } "\"" ;
number          = [ "-" ] digit { digit } [ "." digit { digit } ] ;
valid_from      = iso8601 ;
recorded_at     = iso8601 ;
entity_name     = ( letter | "_" ) { letter | digit | "_" } ;
name            = ( letter | "_" ) { letter | digit | "_" } ;
entity_id       = 26 * base32_char ;
reference_id    = 26 * base32_char ;
relationship_id = 26 * base32_char ;
base32_char     = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" 
                | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "J" | "K" 
                | "M" | "N" | "P" | "Q" | "R" | "S" | "T" | "V" | "W" | "X" | "Y" | "Z" ;

4. Example

VERSION 7
ENTITY bank 01K3Y0690AJCRFEJ2J49X6ZECY
REFERENCE country_code 01K3Y07Z94DGJWVMB0JG4YSDBV "US"
ATTRIBUTE_OF bank 01K3Y0690AJCRFEJ2J49X6ZECY bank_name "Bank Alpha" 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
ATTRIBUTE_REF_OF bank 01K3Y0690AJCRFEJ2J49X6ZECY country_code 01K3Y07Z94DGJWVMB0JG4YSDBV 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
STRUCT_OF bank 01K3Y0690AJCRFEJ2J49X6ZECY bank_address 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
  country_code 01K3Y07Z94DGJWVMB0JG4YSDBV
  street "123 Main St"
  city "New York"
  zip "10001"
ENTITY account 01K3Y0G45CP4GMGE94BYQ09DFM
ATTRIBUTE_OF account 01K3Y0G45CP4GMGE94BYQ09DFM account_balance 100000.50 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
ATTRIBUTE_OF account 01K3Y0G45CP4GMGE94BYQ09DFM account_expiration 2025-12-31T23:59:59Z 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
RELATIONSHIP bank_x_account 01K3Y0NR1Q3KTA9A6J9KYPK6YB 2023-01-01T00:00:00Z 2023-01-01T12:00:00Z
  bank 01K3Y0690AJCRFEJ2J49X6ZECY
  account 01K3Y0G45CP4GMGE94BYQ09DFM
@SergeyProkhorenko
02.09.2025 15:31 UTC
Первоисточник

Комментарии

@Dair_Targ
03.09.2025 21:12 UTC
+1

Поздравляю: вы почти переизобрели turtle. Осталось добавить namespaces, shacl validation и прочие инструменты из мира графов.

@SergeyProkhorenko
03.09.2025 21:55 UTC
+1

Ну, моя роль гораздо скромнее. Я не разрабатывал универсальный синтаксис для описания всего на свете, а просто решал типовую проблему в хранилищах данных. Данные между информационными системами передаются обычно в денормализованном виде (таблицы с сотнями столбцов - атрибутов). В хранилище данных их нормализуют (исключают дублирование данных в таблицах путем использования ссылок на справочники), чтобы проще было выполнять сложные аналитические запросы к данным. Обычно нормализуют до 3NF и очень редко до 6NF, так как для 6NF до сих пор нет удобного инструментария (см. мой DSL). А затем данные опять денормализуют в витринах данных для формирования отчетов для внешних потребителей. Все эти циклы нормализация - денормализация - нормализация - денормализация обходятся IT-подразделениям очень дорого. Поэтому у меня возникла идея передавать данные между информационными системами непосредственно в нормализованном виде, чтобы больше ничего не приходилось нормализовывать. Прообразом послужили методологии Anchor Modeling и (в гораздо меньшей степени) Data Vault. Кстати, для Anchor Modeling есть очень удобный инструмент создания ER-диаграмм, который действительно сближает мой формат с миром графов.

@SergeyProkhorenko
07.09.2025 21:37 UTC
0
@SergeyProkhorenko
19.09.2025 20:30 UTC
0

The same example in JSON format (JSON-6NF):

[
  {
    "type": "ENTITY",
    "table": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY"
  },
  {
    "type": "REFERENCE",
    "table": "country_code",
    "reference_id": "01K3Y07Z94DGJWVMB0JG4YSDBV",
    "value": "US"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "bank_name",
    "value": "Bank Alpha",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "ATTRIBUTE_REF_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "country_code",
    "reference_id": "01K3Y07Z94DGJWVMB0JG4YSDBV",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "STRUCT_OF",
    "entity_name": "bank",
    "entity_id": "01K3Y0690AJCRFEJ2J49X6ZECY",
    "table": "bank_address",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z",
    "columns": {
      "country_code": "01K3Y07Z94DGJWVMB0JG4YSDBV",
      "street": "123 Main St",
      "city": "New York",
      "zip": "10001"
    }
  },
  {
    "type": "ENTITY",
    "table": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM",
    "table": "account_balance",
    "value": 100000.5,
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "ATTRIBUTE_OF",
    "entity_name": "account",
    "entity_id": "01K3Y0G45CP4GMGE94BYQ09DFM",
    "table": "account_expiration",
    "value": "2025-12-31T23:59:59Z",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z"
  },
  {
    "type": "RELATIONSHIP",
    "table": "bank_x_account",
    "relationship_id": "01K3Y0NR1Q3KTA9A6J9KYPK6YB",
    "valid_from": "2023-01-01T00:00:00Z",
    "recorded_at": "2023-01-01T12:00:00Z",
    "columns": {
      "bank": "01K3Y0690AJCRFEJ2J49X6ZECY",
      "account": "01K3Y0G45CP4GMGE94BYQ09DFM"
    }
  }
]
@SergeyProkhorenko
21.09.2025 08:59 UTC
0

It's better to replace type with element_type to avoid conflict with JSON Schema.

@SergeyProkhorenko
21.09.2025 18:26 UTC
0

The same example in JSON format (JSON-6NF) and JSON Schema

6NF JSON.json

JSON Schema.json