Without a looping or sequence construct, this will be hard to avoid, and once you go that route, you might as well adopt a Lisp as your config syntax.
Before there was XML, there was SGML, and SGML has DSSSL, which was a Scheme dialect, and that was a brilliant idea which has been ditched for XML and its surrounding specs. S-Expressions are natural for the task. There are still prominent uses of S-Expressions, even in the OCaml world, where Jane Street uses it for configuration and serialization.
The full power of a Lisp may be too much and risky, but you can restrict the spec and allow only certain constructs, so that you can ensure it will evaluate to a result in a quick and deterministic way.
The little "templating" feature used in gitlab-ci.yml is a huge benefit, and as long as parsers limit the feature, it's a good compromise between complexity and comfort.
There is a lot of experience with using Lisp for configuration, and that experience can be leveraged to come up with a good S-Expressions based config format that's flexible, deterministic, and known to terminate in constant time. If you're careful with the spec, you could even validate the config fully.
So, I'm actually surprised no Lisp dialect has gained popularity in the modern web stacks for configuration. Maybe if Clojure were more popular and less XML-influenced from the JVM world. Just thinking out loud.
Without a looping or sequence construct, this will be hard to avoid, and once you go that route, you might as well adopt a Lisp as your config syntax.
Before there was XML, there was SGML, and SGML has DSSSL, which was a Scheme dialect, and that was a brilliant idea which has been ditched for XML and its surrounding specs. S-Expressions are natural for the task. There are still prominent uses of S-Expressions, even in the OCaml world, where Jane Street uses it for configuration and serialization.
The full power of a Lisp may be too much and risky, but you can restrict the spec and allow only certain constructs, so that you can ensure it will evaluate to a result in a quick and deterministic way.
The little "templating" feature used in gitlab-ci.yml is a huge benefit, and as long as parsers limit the feature, it's a good compromise between complexity and comfort.
There is a lot of experience with using Lisp for configuration, and that experience can be leveraged to come up with a good S-Expressions based config format that's flexible, deterministic, and known to terminate in constant time. If you're careful with the spec, you could even validate the config fully.