Text::KDL::XS

A fast Perl XS binding to ckdl for parsing and emitting KDL documents. Supports KDL 2.0.0 and the legacy KDL 1.0.0 with automatic version detection.

The full documentation is in the POD: perldoc Text::KDL::XS for the API reference and perldoc Text::KDL::XS::Cookbook for a tour of every KDL feature with Perl examples. This file is the short version.

What is KDL?

KDL ("cuddle", the KDL Document Language) is a small configuration and data language. A document is a tree of nodes; each node has a name, optional arguments, optional properties (key=value) and an optional block of child nodes:

package "kdl-rs" {
    version "0.4.0"
    author "Kat Marchán" email="kat@example.com"
    keywords "config" "data" "structured"
    license "MIT" {
        url "https://opensource.org/licenses/MIT"
    }
}

Values are strings, numbers, #true/#false, #null or the special numbers #inf, #-inf and #nan, and any value or node can carry a (type) annotation. Comments, multi-line and raw strings, hexadecimal/octal/binary numbers and /- "slashdash" comments round out the language. The Cookbook shows all of them.

Synopsis

use Text::KDL::XS qw(parse_kdl emit_kdl);

my $doc = parse_kdl(<<'KDL');
server "web-1" port=8080 {
    tls #true
    upstream name="app" weight=3
}
KDL

for my $node (@{ $doc->nodes }) {
    print $node->name, "\n";                          # server
    print $node->args->[0]->as_string, "\n";          # web-1
    print $node->prop('port')->as_number, "\n";       # 8080
    for my $child (@{ $node->children }) {
        print "  ", $child->name, "\n";               # tls, upstream
    }
}

print emit_kdl($doc);                                 # round trip

print emit_kdl({                                      # plain data
    server => { host => 'localhost', port => 8080 },
    tags   => [ 'a', 'b' ],
});
# server {
#     host localhost
#     port 8080
# }
# tags a b

parse_kdl accepts a Perl character string, a filehandle (any PerlIO layer), or a code reference returning chunks of UTF-8. emit_kdl accepts a parsed document, a node, a list of nodes, or plain hashes and arrays, and returns a character string, so parse_kdl(emit_kdl($data)) round-trips.

For SAX-style streaming without building a tree:

use Text::KDL::XS::Parser;

open my $fh, '<', 'huge.kdl' or die $!;
my $p = Text::KDL::XS::Parser->new($fh);
while (my $ev = $p->next_event) {
    print $ev->{name}, "\n" if $ev->{event} eq 'start_node';
}

Modules

| Module | Role | |------------------------------------------------------------|--------------------------------------------------------| | Text::KDL::XS | parse_kdl, emit_kdl, options, encoding, errors | | Text::KDL::XS::Cookbook | Every KDL feature with KDL and Perl examples; recipes | | Text::KDL::XS::Parser | Streaming event parser | | Text::KDL::XS::Document | Container for the top-level nodes | | Text::KDL::XS::Node | A node: name, type annotation, args, props, children | | Text::KDL::XS::Value | A typed value: null, bool, number, string | | Text::KDL::XS::Emitter | Internal emitter helpers |

Features

Known issues

The remaining limitations come from the underlying ckdl library: parse errors carry a reason but no line or column, detection mode is not a complete KDL v1 parser, a few lenient spots in ckdl's parser (such as \u{} escapes without digits), and a small memory leak in ckdl for every parsed property (about 32 bytes, relevant only to long-running processes that parse many documents). Strings that would be written bare but read back as keywords or numbers (true, -1) make emit_kdl quote the whole document. All of them are listed in perldoc Text::KDL::XS, section "KNOWN ISSUES AND LIMITATIONS".

Upgrading from 0.001: a string passed to parse_kdl is now read as Perl characters. Code that passed UTF-8 byte strings must decode them first (utf8::decode, Encode::decode) or pass the filehandle instead; see Changes for the complete list.

Installation

perl Makefile.PL
make
make test
make install

Text::KDL::XS links statically against ckdl through Alien::ckdl, which builds the C library from source. No system package is needed; a C11 compiler and a perl with 64-bit integers are.

Status

Version 0.002 fixes the defects found in 0.001 (see Changes; what remains are the upstream limitations above) and changes one behaviour on purpose: string sources are character strings. The API (parse_kdl, emit_kdl, Parser, Document, Node, Value) is otherwise stable; Value gained as_bignum.

See also

License

Copyright (C) 2026 Davenonymous.

This Perl distribution is released under the same terms as Perl itself. The bundled ckdl library (linked statically through Alien::ckdl) is MIT-licensed.