KdlFramework 0.1.0
dotnet add package KdlFramework --version 0.1.0
NuGet\Install-Package KdlFramework -Version 0.1.0
<PackageReference Include="KdlFramework" Version="0.1.0" />
<PackageVersion Include="KdlFramework" Version="0.1.0" />
<PackageReference Include="KdlFramework" />
paket add KdlFramework --version 0.1.0
#r "nuget: KdlFramework, 0.1.0"
#:package KdlFramework@0.1.0
#addin nuget:?package=KdlFramework&version=0.1.0
#tool nuget:?package=KdlFramework&version=0.1.0
KdlFramework

Important:
This project is a fork of the amazing KdlSharp library, intended to work with .NET Framework.
While all tests pass, some functionality has been removed. This library should only be used as a last resort - use KdlSharp first.
Most notable changes:
- File-based async functions removed
- TryParse functions removed
This library hasn't yet proved itself in production, and is totally experimental. Use at your own risk!
KdlSharp README
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
refresolution support - Special Numbers: Full support for
#inf,#-inf, and#nanwith 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 KdlFramework;
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 KdlFramework.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 KdlFramework.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 KdlFramework.Schema;
using KdlFramework.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 KdlFramework.Formatting;
using KdlFramework.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 KdlFramework.Formatting;
using KdlFramework.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
KdlStringvalues programmatically (not from parsing), they default toKdlStringType.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 NOT available.
Token-by-Token Reading
For scenarios requiring token-level control over parsing, use KdlReader:
using KdlFramework.Parsing;
using var reader = new StringReader(kdlText);
using var kdlReader = new KdlReader(reader);
while (kdlReader.Read())
{
Console.WriteLine($"[{kdlReader.Line}:{kdlReader.Column}] {kdlReader.TokenType}");
}
Requirements
- .NET Standard 2.0 or higher
More Resources
- KDL Website - Official KDL documentation
- AGENTS.md - Development guide and contributing
License
MIT License - see LICENSE for details.
| Product | Versions 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 | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.5)
- Microsoft.Bcl.HashCode (>= 6.0.0)
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 |
|---|---|---|
| 0.1.0 | 99 | 4/12/2026 |