KdlSharp 1.0.0

dotnet add package KdlSharp --version 1.0.0
                    
NuGet\Install-Package KdlSharp -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="KdlSharp" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="KdlSharp" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="KdlSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add KdlSharp --version 1.0.0
                    
#r "nuget: KdlSharp, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package KdlSharp@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=KdlSharp&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=KdlSharp&version=1.0.0
                    
Install as a Cake Tool

KdlSharp

alternate text is missing from this package README image

NuGet License: MIT

A feature-rich C# library for KDL (KDL Document Language) with strong v2.0 specification support.

Features

  • POCO Serialization: Map .NET objects to KDL and back with KdlSerializer
  • KDL v2.0 Support: All string types, number formats, and modern syntax
  • Document Model API: Parse and manipulate KDL documents programmatically
  • Query Language: CSS-selector-like queries for finding nodes
  • Schema Validation: Validate documents against schemas with full ref resolution support
  • Special Numbers: Full support for #inf, #-inf, and #nan with proper round-trip semantics
  • Zero Dependencies: No external dependencies in core library
  • Cross-Platform: .NET Standard 2.1 compatible

Installation

dotnet add package KdlSharp

Examples

1. Parse a KDL Document

using KdlSharp;

var doc = KdlDocument.Parse(@"
    server host=""localhost"" port=8080 {
        database connection=""postgres://localhost/mydb""
    }
");

var server = doc.Nodes[0];
Console.WriteLine(server.GetProperty("host")?.AsString()); // "localhost"
Console.WriteLine(server.GetProperty("port")?.AsInt32());  // 8080

2. Serialize Objects to KDL

using KdlSharp.Serialization;

public record ServerConfig(string Host, int Port, bool UseSsl);

var config = new ServerConfig("localhost", 8080, true);
var serializer = new KdlSerializer(new KdlSerializerOptions
{
    RootNodeName = "server",
    PropertyNamingPolicy = KdlNamingPolicy.KebabCase
});

string kdl = serializer.Serialize(config);
// server host="localhost" port=8080 use-ssl=#true

3. Deserialize KDL to Objects

var kdl = @"server host=""localhost"" port=8080 use-ssl=#true";
var config = serializer.Deserialize<ServerConfig>(kdl);

Note: Circular references are not supported. Serializing an object graph containing cycles (e.g., A → B → A) throws KdlSerializationException. To serialize graphs with cycles, break them first using reference IDs or other patterns.

4. Build Documents Programmatically

var doc = new KdlDocument();
doc.Nodes.Add(
    new KdlNode("package")
        .AddArgument("my-app")
        .AddProperty("version", "1.0.0")
        .AddChild(new KdlNode("author").AddArgument("Alice"))
);

string kdl = doc.ToKdlString();

5. Query Nodes

using KdlSharp.Query;

var doc = KdlDocument.Parse(@"
    package {
        dependencies { lodash ""^4.0"" }
        dev-dependencies { jest ""^29.0"" }
    }
");

// Find all dependency nodes
var deps = KdlQuery.Execute(doc, "package >> dependencies");

6. Validate Against Schema

using KdlSharp.Schema;
using KdlSharp.Schema.Rules;

var schema = new SchemaDocument(
    new SchemaInfo { Title = "Config Schema" },
    nodes: new[] {
        new SchemaNode("server", properties: new[] {
            new SchemaProperty("port", required: true, validationRules: new[] {
                new GreaterThanRule(0), new LessThanRule(65536)
            })
        })
    }
);

var result = KdlSchema.Validate(doc, schema);
if (!result.IsValid)
    foreach (var error in result.Errors)
        Console.WriteLine($"{error.Path}: {error.Message}");

7. Parse Legacy v1 Documents

var settings = new KdlParserSettings { TargetVersion = KdlVersion.V1 };
var doc = KdlDocument.Parse("node true false null", settings);

8. Serializer Options

var options = new KdlSerializerOptions
{
    // Custom root node name (default: "root")
    RootNodeName = "config",

    // Naming policy: CamelCase, PascalCase, SnakeCase, KebabCase, None (default: KebabCase)
    PropertyNamingPolicy = KdlNamingPolicy.KebabCase,

    // Include null values in output (default: false)
    IncludeNullValues = true,

    // Add type annotations like (i32), (string), (bool) (default: false)
    WriteTypeAnnotations = true,

    // Write simple values as arguments vs properties (default: true)
    UseArgumentsForSimpleValues = true,

    // Flatten single-child objects into parent node (default: false)
    FlattenSingleChildObjects = false,

    // Target KDL version: V1 uses bare true/false/null, V2 uses #true/#false/#null (default: V2)
    TargetVersion = KdlVersion.V2
};

9. Version Markers

When formatting KDL documents, you can include a version marker at the start of the output:

using KdlSharp.Formatting;
using KdlSharp.Settings;

var settings = new KdlFormatterSettings
{
    IncludeVersionMarker = true,  // Emit /- kdl-version N at start
    TargetVersion = KdlVersion.V2
};
var formatter = new KdlFormatter(settings);
var kdl = formatter.Serialize(doc);
// Output: /- kdl-version 2
//         node #true ...

10. Preserving String Formatting

By default, all strings are serialized as quoted strings. To preserve the original string format (identifier, quoted, raw, or multi-line) from parsing:

using KdlSharp.Formatting;
using KdlSharp.Settings;

// Parse a document with various string types
var doc = KdlDocument.Parse("node identifier-value #\"raw string\"# \"quoted\"");

// Enable PreserveStringTypes to maintain original formatting
var settings = new KdlFormatterSettings { PreserveStringTypes = true };
var formatter = new KdlFormatter(settings);
var kdl = formatter.Serialize(doc);
// Output: node identifier-value #"raw string"# "quoted"

Raw strings preserve their original hash count delimiter during round-tripping:

// Parse a raw string with multiple hashes
var doc = KdlDocument.Parse("node ##\"contains \"# pattern\"##");

// The hash count is preserved when serializing with PreserveStringTypes
var settings = new KdlFormatterSettings { PreserveStringTypes = true };
var formatter = new KdlFormatter(settings);
var kdl = formatter.Serialize(doc);
// Output: node ##"contains "# pattern"##

Note: When constructing KdlString values programmatically (not from parsing), they default to KdlStringType.Quoted. Specify the string type in the constructor to use other formats: new KdlString("value", KdlStringType.Identifier). For raw strings, use the static helper method for convenience:

// Create a simple raw string (hash count computed automatically)
var raw = KdlString.Raw(@"C:\path\to\file");

// Create a raw string with explicit hash count
var rawWithHashes = KdlString.Raw("contains \"# pattern", hashCount: 2);

// Create a multi-line raw string
var rawMultiLine = KdlString.Raw("line1\nline2", multiLine: true);

Streaming API

Reading from Streams

Parse documents directly from streams with the leaveOpen parameter to control stream lifetime:

using var fileStream = File.OpenRead("config.kdl");

// Parse from stream, closing it after parsing (default)
var doc = KdlDocument.ParseStream(fileStream);

// Or keep the stream open for further operations
var doc = KdlDocument.ParseStream(fileStream, leaveOpen: true);

Async versions are available for all stream operations:

var doc = await KdlDocument.ParseStreamAsync(fileStream, cancellationToken: token);
await doc.WriteToAsync(outputStream, leaveOpen: true);

Token-by-Token Reading

For scenarios requiring token-level control over parsing, use KdlReader:

using KdlSharp.Parsing;

using var reader = new StringReader(kdlText);
using var kdlReader = new KdlReader(reader);

while (kdlReader.Read())
{
    Console.WriteLine($"[{kdlReader.Line}:{kdlReader.Column}] {kdlReader.TokenType}");
}

Async Streaming Serialization

For memory-efficient serialization of large sequences, use SerializeStreamAsync:

// Serialize an async sequence directly to a stream
await serializer.SerializeStreamAsync(GetEventsAsync(), outputStream);

async IAsyncEnumerable<Event> GetEventsAsync()
{
    // Objects are serialized one at a time as they are yielded
    await foreach (var evt in eventSource.ReadAsync())
        yield return evt;
}

The streaming serializer supports cancellation tokens and respects serializer options like TargetVersion.

Note: All parsing methods (including ParseStream, ParseStreamAsync, and KdlReader) read the entire input into memory before tokenizing. The "streaming" APIs provide convenient stream-based interfaces but do not perform incremental parsing. For typical configuration files (under 1MB), this is not a concern. See AsyncOperations.cs for detailed examples.

Requirements

  • .NET Standard 2.1 or higher
  • Compatible with .NET 6+, .NET Framework 4.7.2+, Mono, Xamarin

More Resources

License

MIT License - see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 656 12/1/2025