File formats

Four ways the fact-based modelling community exchanges models — and where Factum sits among them.

The landscape

There is no agreed exchange standard for fact-based models. There are four serious formats, and the first thing to notice is that they do not all describe the same kind of thing. Two are conceptual — they talk about object types, fact types and roles. Two are logical — they talk about tables, columns and keys, with the fact-based content surviving as annotations.

That distinction decides everything about which format can losslessly hold a model and which can only receive one.

FormatLevelSyntaxMachine-readable contractOrigin
Factum .orm.jsonConceptualJSONJSON Schema 2020-12This project
NORMA .ormConceptualXMLXSDORM Foundation / NORMA
FBM Exchange MetaModel .fbmConceptualXMLXSD + .NET classesFactEngine community
Unified Modelling SchemaLogicalYAMLJSON Schema 2020-12 + Delphi / VB.NET classesFactEngine community
Apache OssieLogical core, conceptual ontologyYAML / JSONJSON Schema 2020-12Apache Software Foundation (incubating)

NORMA .orm

The ORM 2 XML written by NORMA, and the de-facto archive format for the community. It is the most faithful ORM 2 metamodel of the four: everything the notation can draw is in there, including the join paths of external constraints and the full diagram geometry.

Its costs are verbosity, a strong tie to Visual Studio, and a great deal of tool state stored alongside the model. Factum reads it — ORM: Import NORMA (.orm) File — and keeps the NORMA element GUIDs as its own ids, so a model imported from NORMA keeps its cross-tool identity.

FBM Exchange MetaModel

An XML format published by the FactEngine community as a deliberate exchange standard for fact-based models — Object-Role Modeling and FCO-IM alike — with an XSD and ready-made .NET classes. It is markedly simpler than NORMA's format while covering the same conceptual ground.

It carries value and entity types, fact types with role groups, readings decomposed into predicate parts, role constraints with join paths, subtype relationships, model notes, synonyms, sample populations, and a multi-page diagram section where each page has a language.

Four of its per-element attributes are the reason Factum's format grew a meta and a hints object: GUID (an identity separate from the readable id), DBName (a physical name for relational generation), GraphLabel (a label for property graph generation), and LongDescription / ShortDescription.

Unified Modelling Schema

A YAML format, also from the FactEngine community, with a JSON Schema and generated Delphi and VB.NET classes. Unlike the other three it is logical rather than conceptual: the unit is a type with properties, primary keys and relationships, and the fact-based content survives as FactTypeReadings attached to those properties and relationships.

That makes it a good target for generation and a lossy source. By the time a model is expressed as types with properties, the attributes have already been formed — the design decisions ORM exists to postpone have been taken, and you cannot recover which ones they were.

Apache Ossie

An incubating ASF specification for exchanging semantic metadata across analytics, AI and BI platforms, defined as YAML with a published JSON Schema and a growing set of vendor converters.

Its core specification is a logical semantic model — datasets, fields, relationships, metrics — but its ontology section is conceptual, and it is ORM in all but name:

  • concepts typed EntityType or ValueType — object types and value types;
  • relationships with ordered roles and optionally named role players — fact types with role names;
  • multiplicity of ManyToOne or OneToOne — uniqueness constraints;
  • identify_by — the preferred identifier;
  • extends — subtyping;
  • requires — value and other constraints, as expressions;
  • derived_by — derivation rules;
  • verbalizes — readings, complete with the hyphen-binding convention (has description- {String}) that ORM uses when a reading binds tightly to its role player.

Its ontology_mappings then bind concepts and relationships down to fields of a logical dataset — the same job Factum's relational and graph mappings do, expressed as data rather than as code.

Ossie is the most likely of the three to be widely adopted, because it has an ASF home and vendor converters rather than a single implementer. It is also the only one of the four that treats the conceptual model and its mapping to physical storage as two separate, linked artifacts — which is the same separation Factum draws between the model and its hints.

One fact type, four ways

Person works for Company, each role mandatory on the Person side and functional — one elementary fact, written in each format.

Factum .orm.json — roles and readings are separate, and the uniqueness constraint that makes the fact type functional is its own addressable element:

{
  "id": "ft_works",
  "roles": [
    { "id": "r1", "objectTypeId": "ot_person" },
    { "id": "r2", "objectTypeId": "ot_company" }
  ],
  "readings": [
    { "id": "rd1", "roleOrder": ["r1", "r2"], "text": "{0} works for {1}", "isPrimary": true },
    { "id": "rd2", "roleOrder": ["r2", "r1"], "text": "{0} employs {1}" }
  ]
}
// elsewhere, in constraints:
{ "id": "uc1", "kind": "uniqueness", "roles": ["r1"] }
{ "id": "mc1", "kind": "mandatory",  "roles": ["r1"] }

FBM Exchange MetaModel — the same content, with readings broken into predicate parts and constraints in a separate RoleConstraints collection:

<FactType Id="WorksFor" GUID="_64A69DFB-..." Name="PersonWorksForCompany" DBName=""
          IsObjectified="false" IsDerived="false" LongDescription="">
  <GraphLabel />
  <RoleGroup>
    <Role Id="_3678ED9A-..." SequenceNr="1" Mandatory="true"  JoinedObjectTypeId="Person" />
    <Role Id="_785CF2B5-..." SequenceNr="2" Mandatory="false" JoinedObjectTypeId="Company" />
  </RoleGroup>
  <FactTypeReadings>
    <FactTypeReading Id="...">
      <PredicateParts>
        <PredicatePart SequenceNr="1" Role_Id="_3678ED9A-...">
          <PredicatePartText>works for</PredicatePartText>
        </PredicatePart>
        <PredicatePart SequenceNr="2" Role_Id="_785CF2B5-..." />
      </PredicateParts>
    </FactTypeReading>
  </FactTypeReadings>
</FactType>

Unified Modelling Schema — already a foreign key. The fact is recoverable only from the readings:

- Type: Person
  Labels: [Person]
  PrimaryKey: [Person_Id]
  Properties:
    - Name: Company_Id
      DataType: Integer
      Constraints: [NotNull]
      FactTypeReadings:
        - Language: Not Defined
          Readings: [Person works for Company]
  Relationships:
    - Name: WORKS_FOR
      Source: Person
      Target: Company
      From: [Company_Id]
      To:   [Company_Id]
      Readings: [Person works for Company, Company employs Person]
  IsRelationshipType: false

Apache Ossie ontology — conceptual again, with the relationship grouped under the concept that plays its first role:

- concept: Person
  type: EntityType
  identify_by: [nr]
  relationships:
    - name: works_for
      roles:
        - concept: Company
      multiplicity: ManyToOne
      verbalizes:
        - '{Person} works for {Company}'
        - '{Company} employs {Person}'

Read those four in order and the trade-off is visible. FBM says the most per element and costs the most to write. UMS has already decided that Company is a foreign key on Person. Ossie says almost exactly what Factum says, in half the space, by hanging relationships off concepts and folding the uniqueness constraint into a multiplicity keyword.

What each format carries

ConceptFactumNORMAFBMUMSOssie
Object types and value typesyesyesyespartialyes
N-ary fact typesyesyesyesnoyes
Multiple readings per fact typeyesyesyesyesyes
Full constraint familyyesyesyesnoas expressions
Join paths on set-comparison constraintsnoyesyesnoas expressions
Subtyping and objectificationyesyesyesnosubtyping only
Derivation rulesstored, not evaluatedyesyesnoyes
Diagram geometryyesyesyes, multi-pagenono
Stable GUIDsmeta.guidyesyesnonames are the identity
Descriptions per elementmeta.descriptionnotesyesnoyes
Synonymsmeta.synonymsnoyesAliasai_context.synonyms
Physical name for generationhints.relational.tableNamenoDBNameLabelsmappings
Graph label for generationhints.graph.labelnoGraphLabelLabel / Labelsno
Guidance for AI toolsmeta.aiContextnononoai_context
Multilingual readingslangnopage languageper readingno
Sample populationsnoyesyesyesno
Vendor extension namespacex-nononocustom_extensions

Why Factum keeps its own format

Adopting one of the others outright was considered and rejected, for four reasons.

A conceptual model must stay conceptual

UMS is out immediately: saving to it would mean deciding, at save time, which fact types become columns and which become tables. That is precisely the decision ORM exists to defer, and it is the decision Factum's two mappings exist to let you make twice, differently, from the same model. A format that cannot hold an unmapped model cannot be the native format of a conceptual modelling tool.

Text that diffs and merges

Factum's premise is that a model is source code: it lives in the repository next to everything else and goes through review. Both XML formats defeat that. A NORMA or FBM document is a single deep tree where an element's identity is its position as much as its id, so a two-line conceptual change produces a diff nobody can read and a merge conflict nobody can resolve.

Factum's structure is deliberately flat and id-addressed for exactly this reason. Adding a constraint appends one object to one array; nothing else in the file moves.

The editor is a custom editor over a text document

The diagram is a VS Code custom editor backed by the file's text. That is what makes the dirty indicator, the undo stack, file watching and source control work without any special handling, and what makes ORM: Open Model Source (JSON) possible at all. It requires a format VS Code can parse, validate and hand back as text — which in practice means JSON.

An exchange format and a working format are different jobs

The last reason is the most important one, and it is why this is not a rejection of the others. The FBM Exchange MetaModel is explicitly an exchange format: its job is to be written once, read once, and lose nothing in between. A working format is edited a hundred times a day by a human and a program in turn, and is judged on how well it diffs and how easy it is to fix by hand at two in the morning.

These are different jobs and they want different shapes. The right relationship between them is a converter, not a merger — and a converter needs the source format to carry what the target format expects. That is the whole reason for meta and hints.

Which standard it is closest to

Two different answers, because two different things are being standardised.

Conceptually: Apache Ossie's ontology

Of everything surveyed, Ossie's ontology section is the closest match to what Factum stores, and the alignment is close to term-for-term:

FactumOssie ontology
objectTypes[].kindconcept.type: EntityType / ValueType
factTypes[].roles[]relationships[].roles[]
roles[].nameroles[].name
readings[].text with {0} placeholdersverbalizes[] with {Concept} placeholders
uniqueness constraint on one rolemultiplicity: ManyToOne
isPreferredIdentifieridentify_by
subtypeRelationsextends
value constraintrequires expression
derivationRulederived_by
meta.aiContextai_context

The differences are real but narrow. Ossie groups each relationship under the concept playing its first role, where Factum keeps fact types in a flat list; Ossie has no diagram, no objectification and no explicit constraint objects, expressing constraints as expressions instead. Everything Factum stores that Ossie also models can be written out; the reverse is nearly true too.

Structurally: the JSON Schema and OpenAPI conventions

For the shape of the file rather than its content, Factum follows the conventions that have actually been adopted across the wider ecosystem, not anything specific to fact-based modelling:

  • JSON Schema 2020-12 as the published contract, referenced from the document by $schema — the same choice UMS and Ossie both made, and the one that gives validation and completion in any editor and a compilable contract in any language.
  • x- prefixed extensions for anything outside the specification, the convention used by OpenAPI, AsyncAPI and CloudEvents. Ossie solves the same problem with a custom_extensions list of vendor blobs; the x- prefix keeps extensions in place, next to what they extend.
  • An additive major version. Version 2 only adds optional keys, so every version 1 file is a valid version 2 file.
The combination is what matters: the schema is strict about unknown keys, except in the x- namespace and in hints, where unknown target keys are legal. A typo is caught; a deliberate extension is not.

The bridge to each format

The point of the metadata added in format version 2 is that a converter to any of these three now has somewhere to put what it reads, and somewhere to read what it writes.

FactumFBMUMSOssie
meta.guidGUID
meta.descriptionLongDescriptiondescription
meta.shortDescriptionShortDescription
meta.synonymsSynonymsAliasai_context.synonyms
meta.aiContextai_context
meta.uri
hints.relational.tableNameDBNameLabelsdatasets[].source
hints.graph.labelGraphLabelLabel
hints.graph.labelsLabels
readings[].langPage/@LanguageFactTypeReadings[].Language
hints.<target> (open)concept_mappings

The last row is the one worth planning around. An Ossie concept_mapping binds a concept to a dataset and an expression — a per-element binding to a generation target, which is the shape of a hints entry. An Ossie exporter would read hints.ossie and need no change to the format to do it.

Importing and exporting

Factum reads and writes all four formats. ORM: Import Model takes a .orm, .fbm or .yaml file and writes an .orm.json beside it, picking the reader from the file — the extension where that is decisive, and a marker in the text where it is not, since Ossie and UMS share .yaml. ORM: Export Model As writes any of the four back out.

FormatImportExportWhat survives
NORMA .ormyesyesObject types, fact types, readings, constraints, subtypes. Geometry is read but not written.
FBM .fbmyesyesThe whole conceptual model, plus GUIDs, descriptions and synonyms.
Apache Ossie ontologyyesyesConcepts, relationships, verbalizations, multiplicity, identifiers, subtyping, derivation.
Unified Modelling SchemayesyesExport is faithful. Import recovers the logical schema, not the model behind it.

Both directions return warnings rather than dropping content silently. Exporting a model with an objectified fact type to Ossie tells you that Ossie has no objectification and that the entity type was written plain; importing UMS tells you that what came back is the shape of the data rather than the elementary facts behind it.

What each conversion has to reconcile

The interesting work is never the elements that match. It is the handful that do not.

  • Readings. FBM decomposes a reading into predicate parts, each carrying a role and the text that trails it; Factum uses NORMA's {0} placeholders. Ossie names its placeholders by concept — {Person} works for {Company} — so conversion matches placeholders to roles by player name, falling back to the role name when one concept plays more than one role.
  • Mandatory roles. FBM records mandatory on the role itself; Factum makes it a constraint. Neither the role attribute nor the constraint list alone carries both.
  • Uniqueness. Ossie has no constraint objects. ManyToOne is uniqueness over every role but the last, and OneToOne adds the reverse.
  • Ring types. FBM concatenates them into one attribute, so AsymmetricIntransitive is two constraints' worth of information in one string.
  • Built-in concepts. Every Ossie ontology implicitly includes Integer, String and the rest. Redeclaring them on export would turn extends: [Integer] into a subtype link on the next import.
  • Value constraints. NORMA nests them under the object type or role in a ValueRestriction rather than listing them with the other constraints.
The UMS exporter runs the same property graph mapping the Graph tab shows, because that mapping already answers UMS's question: which value types become properties and which fact types become relationships. See Mapping rules.

Status

All four formats can be read and written. What is still missing is at the edges of each one:

  • FBM sample populations (Instance, Fact) and multi-page diagrams are read but not modelled, so only the first page survives and populations are dropped.
  • Join paths on set-comparison constraints are read as plain role sequences. Both NORMA and FBM can say more here than Factum models.
  • Ossie's ontology_mappings — the binding from concepts down to dataset fields — is neither read nor written. It is the natural home for a hints.ossie target.
  • The NORMA exporter writes no diagram geometry.
Factum is an independent implementation and speaks for none of these projects. If you are working on fact-based model interchange, the gap worth closing first is a shared conceptual core that FBM and Ossie's ontology can both round-trip; the two are much closer to each other than either is to a logical schema.

The .orm.json format in detail