https://kdl.dev/
KDL: A cuddly document language
KDL is a document language with xml-like semantics that looks like
you're invoking a bunch of CLI commands! It's meant to be used both
as a serialization format and a configuration language, much like
JSON, YAML, or XML.
There's a living specification, as well as various implementations.
You can also check out the FAQ to answer all your burning questions!
In addition to a spec for KDL itself, there are also standard specs
for a KDL Query Language based on CSS selectors, and a KDL Schema
Language loosely based on JSON Schema.
The language is based on SDLang, with a number of modifications and
clarifications on its syntax and behavior.
The current version of the KDL spec is 1.0.0.
Play with it in your browser!
Overview
Basics
A KDL node is a node name, followed by zero or more "arguments", and
children.
title "Hello, World"
You can also have multiple values in a single node!
bookmarks 12 15 188 1234
Nodes can have properties.
author "Alex Monad" email="alex@example.com" active=true
And they can have nested child nodes, too!
contents {
section "First section" {
paragraph "This is the first paragraph"
paragraph "This is the second paragraph"
}
}
Nodes without children are terminated by a newline, a semicolon, or
the end of a file stream:
node1; node2; node3;
Values
KDL supports 4 data types:
* Strings: "hello world"
* Numbers: 123.45
* Booleans: true and false
* Null: null
Strings
It supports two different formats for string input: escaped and raw.
node "this\nhas\tescapes"
other r"C:\Users\zkat\"
Both types of string can be multiline as-is, without a different
syntax:
string "my
multiline
value"
And for raw strings, you can add any number of # after the r and the
last " to disambiguate literal " characters:
other-raw r#"hello"world"#
Numbers
There's 4 ways to represent numbers in KDL. KDL does not prescribe
any representation for these numbers, and it's entirely up to
individual implementations whether to represent all numbers with a
single type, or to have different representations for different
forms.
KDL has regular decimal-radix numbers, with optional decimal part, as
well as an optional exponent.
num 1.234e-42
And using the appropriate prefix, you can also enter hexadecimal,
octal, and binary literals:
my-hex 0xdeadbeef
my-octal 0o755
my-binary 0b10101101
Finally, all numbers can have underscores to help readability:
bignum 1_000_000
Comments
KDL supports C-style comments, both line-based and multiline.
Multiline comments can be nested.
// C style
/*
C style multiline
*/
tag /*foo=true*/ bar=false
/*/*
hello
*/*/
On top of that, KDL supports /- "slashdash" comments, which can be
used to comment out individual nodes, arguments, or children:
// This entire node and its children are all commented out.
/-mynode "foo" key=1 {
a
b
c
}
mynode /-"commented" "not commented" /-key="value" /-{
a
b
}
Type Annotations
KDL supports type annotations on both values and nodes. These can be
arbitrary, but can be used by individual implementations or use-cases
to constrain KDL's basic types. A number of type names are also
reserved to have specific meanings.
numbers (u8)10 (i32)20 myfloat=(f32)1.5 {
strings (uuid)"123e4567-e89b-12d3-a456-426614174000" (date)"2021-02-03" filter=(regex)r"$\d+"
(author)person name="Alex"
}
More Details
// Nodes can be separated into multiple lines
title \
"Some title"
// Files must be utf8 encoded!
smile ""
// Instead of anonymous nodes, nodes and properties can be wrapped
// in "" for arbitrary node names.
"!@#$@$%Q#$%~@!40" "1.2.3" "!!!!!"=true
// The following is a legal bare identifier:
foo123~!@#$%^&*.:'|?+ "weeee"
// And you can also use unicode!
nodo oMing Qian ="(;wa;)"
// kdl specifically allows properties and values to be
// interspersed with each other, much like CLI commands.
foo bar=true "baz" quux=false 1 2 3
Implementations
* Rust: kdl-rs, knuffel (latter includes derive macro), and kaydle
(serde-based)
* JavaScript: kdljs, @virtualstate/kdl (query only, JSX based)
* Ruby: kdl-rb
* Dart: kdl-dart
* Java: kdl4j
* PHP: kdl-php
* Python: kdl-py, cuddle, ckdl
* Elixir: kuddle
* XSLT: xml2kdl
* Haskell: Hustle
* .NET: Kadlet
* C: ckdl
* C++: kdlpp (part of ckdl, requires C++20)
* OCaml: ocaml-kdl
* Nim: kdl-nim
* Common Lisp: kdlcl
Editor Support
* VS Code
* Sublime Text
* Intellij IDEA
* vim
Design and Discussion
KDL is still extremely new, and discussion about the format should
happen over on the discussions page in the Github repo. Feel free to
jump in and give us your 2 cents!
Design Principles
1. Maintainability
2. Flexibility
3. Cognitive simplicity and Learnability
4. Ease of de/serialization
5. Ease of implementation
Compatibility with JSON and XML
There are two specifications for writing KDL that can be losslessly
translated between it and JSON or XML. These specifications define a
stricter subset of KDL that, even if not entirely idiomatic, is still
valid and fits into the data models of the other two languages:
* JSON in KDL
* XML in KDL
FAQ
How do you pronounce KDL?
Same as "cuddle".
Why yet another document language?
Because nothing out there felt quite right. The closest one I found
was SDLang, but that had some design choices I disagreed with.
Ok, then, why not SDLang?
SDLang is designed for use cases that are not interesting to me, but
are very relevant to the D-lang community. KDL is very similar in
many ways, but is different in the following ways:
* The grammar and expected semantics are well-defined and specified
.
* There is only one "number" type. KDL does not prescribe
representations.
* Slashdash (/-) comments are great and useful!
* I am not interested in having first-class date types, and
SDLang's are very non-standard.
* Values and properties can be interspersed with each other, rather
than one having to follow the other.
* KDL does not have a first-class binary data type. Just use
strings with base64.
* All strings in KDL are multi-line, and raw strings are written
with Rust-style syntax (r"foo"), instead of backticks.
* KDL identifiers can use UTF-8 and are much more lax about symbols
than SDLang.
* KDL does not support "anonymous" nodes.
* Instead, KDL supports arbitrary identifiers for node names and
attribute names, meaning you can use arbitrary strings for those:
"123" "value"=1 is a valid node, for example. This makes it
easier to use KDL for representing arbitrary key/value pairs.
Have you seen that one XKCD comic about standards?
Yes. I have. Please stop linking me to it.
What about YAML?
YAML is a great, widespread language. Unlike KDL, which is node-based
(like XML or HTML), it's based on map and array data structures,
which can provide an easier serialization experience in some cases.
At the same time, YAML can be ambiguous about what types the data
written into it is. There's also a persistent issue where very large
YAML files become unmanageable, especially due to the significant
indentation feature.
KDL is designed to avoid these particular pitfalls by always being
explicit about types, and having clearly-delimited scope (and the
ability to auto-indent/auto-format). Syntax errors are easier to
catch, and large files are (hopefully!) much more manageable.
What about JSON?
JSON is a great serialization language, but it can be very difficult
to use as a human configuration language. This is largely due to its
very specific, very strict syntax, as well as its lack of support for
comments.
KDL, on the other hand, has great comment support, and has a much
more forgiving syntax without being so flexible as to allow certain
classes of unfortunate mistakes. It also has much more flexibility
around how to represent data.
If you need to interoperate with a service that consumes or emits
JSON, or for some other reason have need to write "JSON in KDL", we
have JiK, an official microsyntax for losslessly encoding JSON.
What about TOML?
It nests very poorly. It doesn't fare well with large files.
What about XML?
XML is actually pretty fantastic, and has long been a standard for
data exchange across many industries. At the same time, XML is known
to be very verbose, and editing it involves writing (and updating)
matching tags. Another large pitfall with XML is its lack of direct
support for arbitrary string key/value pairs, so what would be a
simple foo: x in some languages has to be represented as or something similar. XML also functions great as
a markup language. That is, it is easy to intersperse with text, like
HTML.
KDL, just like XML, is a node/element-based language, but with much
more lightweight syntax. It also adds the ability to apply anonymous
values directly to a node, rather than as children. That is, nodename
1 2 3 instead of 12(etc)
element>. This can make it much more manageable and readable as a
human configuration language, and is also less verbose when
exchanging documents across APIs!
Finally, KDL is not a markup language. XML or HTML do a much better
job of "marking up" a text document with special tags, although KDL
can still be useful for templating engines that want to be more
strict about text fragments.
If you need to interoperate with a service that consumes or emits
XML, or for some other reason have need to write "XML in KDL", we
have XiK, an official microsyntax for losslessly encoding XML.