TOML Processing

Content:

  1. Introduction
  2. Object tree
  3. Class binding

Introduction:

TOML (Tom's Obvious Minimal Language, previously Tom's Own Markup Language) is a format that was invented in 2013 and it has some usage.

TOML is somewhat similar to the old INI file format and Java properties files, but TOML has more capabilities.

The TOML used in this article will be extremely basic.

The examples will focus on reading of configuration files since that is a very relevant use case.

Most examples will be using demo.toml:

c = 3
f = "GHI"
[ab]
a = 1
b = 2
[de]
d = "ABC"
e = "DEF"
[m]
ia = [ 1, 2, 3 ]
sa = [ "X", "Y", "Z" ]

Object tree:

One type of TOML libraries work on generic types and access data via named fields.

This sort of representation does not require any known classes to be defined, but tend to be a bit cumbersome to write.

Open source under Apache license.

TomljTree.java:

package tomlproc;

import java.io.IOException;
import java.nio.file.Paths;

import org.tomlj.Toml;
import org.tomlj.TomlArray;
import org.tomlj.TomlParseResult;

public class TomlJTree {
    public static void main(String[] args) throws IOException {
        TomlParseResult result = Toml.parse(Paths.get("/Work/demo.toml"));
        long a = result.getLong("ab.a");
        long b = result.getLong("ab.b");
        long c = result.getLong("c");
        String d = result.getString("de.d");
        String e = result.getString("de.e");
        String f = result.getString("f");
        System.out.printf("%d %d %d %s %s %s\n", a, b, c, d, e, f);
        TomlArray ia = result.getArrayOrEmpty("m.ia");
        for(int i = 0; i < ia.size(); i++) {
            System.out.printf(" %d",  ia.getLong(i));
        }
        System.out.println();
        TomlArray sa = result.getArrayOrEmpty("m.sa");
        for(int i = 0; i < ia.size(); i++) {
            System.out.printf(" %s",  sa.getString(i));
        }
        System.out.println();
    }
}

Open source under BSD 2 clause license.

Program.cs:

using System;
using System.IO;

using Tomlyn;
using Tomlyn.Model;

namespace TomlynTree
{
    public class Program
    {
        public static void Main(string[] args)
        {
            TomlTable cfg = Toml.Parse(File.ReadAllText(@"C:\Work\demo.toml")).ToModel();
            TomlTable ab = (TomlTable)cfg["ab"];
            long a = (long)ab["a"];
            long b = (long)ab["b"];
            long c = (long)cfg["c"];
            TomlTable de = (TomlTable)cfg["de"];
            string d = (string)de["d"];
            string e = (string)de["e"];
            string f = (string)cfg["f"];
            Console.WriteLine("{0} {1} {2} {3} {4} {5}", a, b, c, d, e, f);
            TomlTable m = (TomlTable)cfg["m"];
            TomlArray ia = (TomlArray)m["ia"];
            for(int i = 0; i < ia.Count; i++)
            {
                if (i > 0) Console.Write(" ");
                Console.Write(ia[i]);
            }
            Console.WriteLine();
            TomlArray sa = (TomlArray)m["sa"];
            for (int i = 0; i < sa.Count; i++)
            {
                if (i > 0) Console.Write(" ");
                Console.Write(sa[i]);
            }
            Console.WriteLine();
        }
    }
}

Open source under MIT license.

It is header only and require a modern C++ compiler.

tomlpp_tree.cpp:

#include <iostream>
#include <string>
#include <vector>
#include <optional>

#include "toml.hpp"

int main()
{
    toml::table tbl = toml::parse_file("/Work/demo.toml");   
    std::optional<long long int> a = tbl["ab"]["a"].value<long long int>();
    std::optional<long long int> b = tbl["ab"]["b"].value<long long int>();
    std::optional<long long int> c = tbl["c"].value<long long int>();
    std::optional<std::string> d = tbl["de"]["d"].value<std::string>();
    std::optional<std::string> e = tbl["de"]["e"].value<std::string>();
    std::optional<std::string> f = tbl["f"].value<std::string>();
    std::cout << *a << " " << *b << " " << *c << " " << *d << " " << *e << " " << *f << std::endl;
    bool first;
    toml::array *ia = tbl["m"]["ia"].as_array();
    first = true;
    ia->for_each([&first](auto&& elm)
    {
        if(!first) std::cout << " "; else first = false;
        long long int iv = elm.as_integer()->get();
        std::cout << iv;
    });
    std::cout << std::endl;
    toml::array *sa = tbl["m"]["sa"].as_array();
    first = true;
    sa->for_each([&first](auto&& elm)
    {
        if(!first) std::cout << " "; else first = false;
        std::string sv = elm.as_string()->get();
        std::cout << sv;
    });
    std::cout << std::endl;
    return 0;
}

tomllib is built into Python since version 3.11.

tree.py:

import tomllib

with open("/work/demo.toml", "rb") as f:
    cfg = tomllib.load(f)
    a = cfg['ab']['a']
    b = cfg['ab']['b']
    c = cfg['c']
    d = cfg['de']['d']
    e = cfg['de']['e']
    f = cfg['f']
    print('%d %d %d %s %s %s' % (a,b,c,d,e,f))
    ia = cfg['m']['ia']
    print(' '.join(str(iv) for iv in ia))
    sa = cfg['m']['sa']
    print(' '.join(str(sv) for sv in sa))

Open source under MIT license.

toml_tree.php:

<?php

require 'vendor/autoload.php';

$cfg = toml_decode(file_get_contents("/Work/demo.toml"), asArray: true);
$a = $cfg['ab']['a'];
$b = $cfg['ab']['b'];
$c = $cfg['c'];
$d = $cfg['de']['d'];
$e = $cfg['de']['e'];
$f = $cfg['f'];
echo sprintf("%d %d %d %s %s %s\r\n", $a, $b, $c, $d, $e, $f);
$ia = $cfg['m']['ia'];
echo implode(' ', $ia) . "\r\n";
$sa = $cfg['m']['sa'];
echo implode(' ', $sa) . "\r\n";

?>

Class binding:

Another type of TOML libraries work by binding (mapping) class definitions to TOML structures.

This sort of representation require use of defined classes to be defined (for static typed languages), but is very convenient to use.

Open source under BSD 2 clause license.

Program.cs:

using System;
using System.IO;
using System.Linq;

using Tomlyn;

namespace TomlynBind
{
    public class AB
    {
        public long A { get; set; }
        public long B { get; set; }
    }
    public class DE
    {
        public string D { get; set; }
        public string E { get; set; }
    }
    public class M
    {
        public long[] IA { get; set; }
        public string[] SA { get; set; }
    }
    public class Config
    {
        public long C { get; set; }
        public string F { get; set; }
        public AB AB { get; set; }
        public DE DE { get; set; }
        public M M { get; set; }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Config cfg = Toml.Parse(File.ReadAllText(@"C:\Work\demo.toml")).ToModel<Config>();
            long a = cfg.AB.A;
            long b = cfg.AB.B;
            long c = cfg.C;
            string d = cfg.DE.D;
            string e = cfg.DE.E;
            string f = cfg.F;
            Console.WriteLine("{0} {1} {2} {3} {4} {5}", a, b, c, d, e, f);
            long[] ia = cfg.M.IA;
            Console.WriteLine(string.Join(" ", ia.Select(iv => iv.ToString())));
            string[] sa = cfg.M.SA;
            Console.WriteLine(string.Join(" ", sa));
            Console.WriteLine();
        }
    }
}

Open source under MIT license.

toml_class.php:

<?php

require 'vendor/autoload.php';

$cfg = toml_decode(file_get_contents("/Work/demo.toml"), asArray: false);
$a = $cfg->ab->a;
$b = $cfg->ab->b;
$c = $cfg->c;
$d = $cfg->de->d;
$e = $cfg->de->e;
$f = $cfg->f;
echo sprintf("%d %d %d %s %s %s\r\n", $a, $b, $c, $d, $e, $f);
$ia = $cfg->m->ia;
echo implode(' ', $ia) . "\r\n";
$sa = $cfg->m->sa;
echo implode(' ', $sa) . "\r\n";

?>

Note that this PHP library do not bind TOML to an existing class, but generate a new class for the structure.

Article history:

Version Date Description
1.0 February 25th 2026 Initial version

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj