Ison.Parser 1.1.0

dotnet add package Ison.Parser --version 1.1.0
                    
NuGet\Install-Package Ison.Parser -Version 1.1.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="Ison.Parser" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ison.Parser" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Ison.Parser" />
                    
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 Ison.Parser --version 1.1.0
                    
#r "nuget: Ison.Parser, 1.1.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 Ison.Parser@1.1.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=Ison.Parser&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Ison.Parser&version=1.1.0
                    
Install as a Cake Tool

ison-cs: ISON for C# — Official Implementation

The official C# implementation of ISON (Interchange Simple Object Notation), from the authors of the ISON format.

This is part of the original ISON family — developed in the ISON-format/ison monorepo and released and versioned alongside every other first-party implementation:

Language Package Registry
Python ison-py PyPI
JavaScript ison-parser npm
TypeScript ison-ts npm
Rust ison-rs crates.io
Go ison-go Go modules
C++ ison-cpp header-only
C# Ison.Parser NuGet

Because all seven are developed together against a shared cross-language golden fixture, they produce byte-identical ISONCS canonical output.

Installation

dotnet add package Ison.Parser

Usage

using IsonParser;

// Parse
var doc = Ison.Loads(@"
table.users
id:int name:string active:bool
1 Alice true
2 Bob false
");

Block? users = doc["users"];
Console.WriteLine(users!.Rows[0]["name"]);   // Alice
Console.WriteLine(users.GetFieldType("id")); // int

// Serialize
string ison      = Ison.Dumps(doc);              // compact, token-efficient
string aligned   = Ison.Dumps(doc, alignColumns: true);
string canonical = Ison.DumpsCanonical(doc);     // ISONCS, byte-identical across languages

// ISONL (one record per line)
string isonl = Ison.DumpsIsonl(doc);
var back     = Ison.LoadsIsonl(isonl);

// Conversion and JSON interop
string asIsonl = Ison.IsonToIsonl(ison);
var fromJson   = Ison.FromJson(@"{""users"": [{""id"": 1, ""name"": ""Alice""}]}");
string asJson  = Ison.ToJson(doc);

Streaming large ISONL files a line at a time:

using var reader = File.OpenText("events.isonl");
foreach (IsonlRecord record in new IsonlParser().Stream(reader))
{
    Process(record.Values);
}

Parse and Stringify are provided as .NET-idiomatic aliases for Loads and Dumps.

API

Member Purpose
Ison.Loads / Parse / Load Parse ISON from a string or file
Ison.Dumps / Stringify / Dump Serialize to ISON
Ison.DumpsCanonical Canonical ISON (ISONCS)
Ison.LoadsIsonl / LoadIsonl Parse ISONL
Ison.DumpsIsonl / DumpIsonl Serialize to ISONL
Ison.DumpsCanonicalIsonl Canonical ISONL
Ison.IsonToIsonl / IsonlToIson Convert between the two forms
Ison.FromJson / ToJson JSON interop
IsonlParser.Stream Line-at-a-time streaming
Document, Block, Reference, FieldInfo Data model
IsonException, IsonSyntaxException, IsonNameException Errors

Staying current

ISON is an evolving specification. Parser fixes, canonical-form corrections, edge-case hardening, hotfixes, and security patches are released here in lockstep with the spec itself — usually the same day they land across the rest of the family.

Practically, that means a routine package update picks up every correction, instead of you having to track spec changes and decide whether they affect you.

A concrete example of the kind of fix that ships this way: canonical field ordering must sort by UTF-8 bytes, not UTF-16 code units. In C# that distinction is easy to get wrong — CompareOrdinal compares UTF-16 code units and silently produces a different field order than every other implementation for non-BMP field names. That is a cross-language divergence bug, and pinning to a version from before the fix keeps it.

  • Watch releases for update notifications
  • Read the changelog before upgrading
  • Report a problem via issues — fixes land in the whole family, not just C#

Third-party ports of ISON exist and are genuinely welcome; a format is healthier for having them. Just be aware they track the spec on their own schedule, so the fixes above may reach them later, or not at all.

Features

  • ISONCS Canonical Serialization: Produces byte-identical output across all implementations
  • UTF-8 Byte Comparison: Field sorting uses UTF-8 bytes, not UTF-16 code units
  • Field Hoisting: id field is hoisted to first position in canonical form
  • Row Sorting: Rows are sorted ordinal-string by the key field
  • Comprehensive Tests: Golden fixture testing with shared test data

Implementation Notes

UTF-16 vs UTF-8 Divergence

C# strings are UTF-16 internally. To ensure byte-identical output across all implementations, the canonical serialization uses System.Text.Encoding.UTF8.GetBytes() for field sorting, NOT string.CompareTo() or StringComparer.Ordinal.

Critical Test Case: Afield (U+FF21, UTF-8: 0xEF...) vs 😀field (U+1F600, UTF-8: 0xF0...)

  • Expected order: Afield, 😀field (0xEF < 0xF0 in UTF-8)
  • WRONG (using CompareTo or CompareOrdinal): 😀field, Afield (UTF-16 code units)

Field Sorting Algorithm

private static List<string> SortFieldsCanonical(List<string> fields)
{
    // Step 1: Partition fields into [id] and [others]
    var idFields = fields.Where(f => f == "id").ToList();
    var otherFields = fields.Where(f => f != "id").ToList();

    // Step 2: Sort others by UTF-8 bytes, NOT UTF-16 code units
    var sortedOthers = otherFields
        .OrderBy(f => Encoding.UTF8.GetBytes(f), new ByteArrayComparer())
        .ToList();

    // Step 3: Concatenate: id first, then sorted others
    var result = new List<string>(idFields);
    result.AddRange(sortedOthers);
    return result;
}

ByteArrayComparer

Compares byte arrays lexicographically (byte-by-byte):

private class ByteArrayComparer : IComparer<byte[]>
{
    public int Compare(byte[] a, byte[] b)
    {
        int minLen = Math.Min(a.Length, b.Length);
        for (int i = 0; i < minLen; i++)
        {
            if (a[i] != b[i])
                return a[i] - b[i];  // Unsigned comparison
        }
        return a.Length - b.Length;  // Shorter comes first
    }
}

Building

dotnet build ison-cs.sln

Testing

dotnet test tests/IsonParser.Tests.csproj

Test Coverage

  • TestGoldenFixtureFieldSort: Validates against shared golden fixture (JSON input, expected ISON output)
  • TestUTF16Divergence: Verifies Afield vs 😀field produces correct UTF-8 byte order
  • TestIdHoisting: Confirms id field is hoisted to first position
  • TestRowSorting: Validates ordinal-string row sorting by key field

References

Absolute links, so they resolve on the NuGet package page as well as on GitHub:

License

MIT — Copyright (c) 2025 Mahesh Vaikri

Version

Compatible with ISON v1.0.4+

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • 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.1.0 33 8/7/2026
1.0.1 36 8/5/2026
1.0.0 85 8/2/2026