Edifact.Projection
1.0.0-preview.6
dotnet add package Edifact.Projection --version 1.0.0-preview.6
NuGet\Install-Package Edifact.Projection -Version 1.0.0-preview.6
<PackageReference Include="Edifact.Projection" Version="1.0.0-preview.6" />
<PackageVersion Include="Edifact.Projection" Version="1.0.0-preview.6" />
<PackageReference Include="Edifact.Projection" />
paket add Edifact.Projection --version 1.0.0-preview.6
#r "nuget: Edifact.Projection, 1.0.0-preview.6"
#:package Edifact.Projection@1.0.0-preview.6
#addin nuget:?package=Edifact.Projection&version=1.0.0-preview.6&prerelease
#tool nuget:?package=Edifact.Projection&version=1.0.0-preview.6&prerelease
Edifact.Projection
Projects a matched message into JSON or XML, either as the document it describes or as a linked form in which every value still points at the directory definition it was read against.
Two different projections, for two different jobs:
MessageDocument— one message as data, for anything that consumes it: a mapper, a queue, an API response. It is lossless, and turning it back into the interchange it came from gives the same characters.LinkedMessage— a message type and everything it names: 42 segments, 63 composites, 201 elements and 101 code lists for D.96A INVOIC, gathered in one document so a form builder does one fetch instead of walking a graph five levels deep.
Install
dotnet add package Edifact.Projection --prerelease
net8.0 and net10.0, no external dependencies.
You supply the directory
No directory data ships in this package. A compiled pack is a derivative of the UN Directory, and shipping one would make every consumer a redistributor of it. Download a release from UNECE (https://unece.org/trade/uncefact/unedifact/download) and ingest it once:
dotnet tool install --global Edifact.Cli --prerelease
edifact ingest ~/Downloads/D96A --out ~/edifact/packs/compiled
That writes the pack to ~/edifact/packs/compiled/untdid-d96a, and puts the four ISO 9735 syntax
definitions in ~/edifact/packs/syntax beside it. Those four are the one input no ingestion can
produce — the UNTDID omits the service definitions — so they reach a machine only because the tool
ships them. Files already in that directory are left alone.
A message as a document, and back
using Edifact.Core.Syntax;
using Edifact.Projection;
using Edifact.Projection.Serialization;
using Edifact.Schema.Serialization;
using Edifact.Validation;
var syntax = new SyntaxPackSet("/home/me/edifact/packs/syntax");
var pack = PackReader.Read("/home/me/edifact/packs/compiled/untdid-d96a", syntax.For);
var text = File.ReadAllText("invoice.edi");
var tokens = EdifactTokenizer.Tokenize(text);
var report = new EdifactValidator(pack, syntax.For).Validate(tokens);
// One document per message. The syntax argument is what lets the interchange be rebuilt exactly;
// the pack is optional and names the elements.
var document = MessageProjection.ToDocument(report.Trees[0], tokens.Syntax, pack);
File.WriteAllText("invoice.json", ProjectionJson.Serialise(document));
File.WriteAllText("invoice.xml", ProjectionXml.Serialise(document));
// And back — the property this package is built around.
var read = ProjectionJson.Deserialise(File.ReadAllText("invoice.json"), "invoice.json");
var rebuilt = EdifactWriter.Write(MessageProjection.ToSegments(read), tokens.Syntax);
// MessageProjection.ToTree(read, pack) puts the message tree back, for walking it again.
ToSegments needs no directory and no message definition: writing an interchange back out is a
question about characters, and the one caller who most often has neither — an inspector showing
somebody the file they sent — still has to be able to do it.
A MessageDocument that names a message type the directory does not define still round-trips; its
segments come back as orphans rather than as an error. ProjectionJson.Deserialise throws
ProjectionFormatException for a document that is not one.
A message type, linked
using Edifact.Projection;
using Edifact.Projection.Serialization;
using Edifact.Schema.Model;
var linked = LinkedMessageProjection.Gather(pack, new MessageKey("INVOIC", "D", "96A"));
Console.WriteLine(LinkedMessageJson.Serialise(linked));
// With a trading partner's guide applied, so a builder never offers a field the agreement forbids:
// var linked = LinkedMessageProjection.Gather(effective); // an Edifact.Overlays EffectiveMessage
The guided form carries the restrictions as data — which positions are excluded, which code lists were narrowed and by whom — rather than silently presenting a narrowed directory as the directory.
The constraint everything else follows from
A projection that cannot be turned back into the interchange it came from is a report, not a projection. So the property held under test is not "the JSON looks right", it is:
text → tokenize → match → tree → document → JSON → document → tree → write == text
character for character, over 2000 generated invoices. Looking right is exactly what a projection that has silently dropped a trailing empty element does.
Where this sits
Edifact.Projection → Edifact.Overlays,
Edifact.Structure. It needs a MessageTree,
which normally comes from
Edifact.Validation or from
StructureMatcher directly.
The design notes are in DESIGN.md. Full documentation: https://github.com/101-semaphore/EDIFACT.
Licence
Apache-2.0. See the NOTICE in this package for what the wider project is derived from and under
what terms.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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 is compatible. 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. |
-
net10.0
- Edifact.Overlays (>= 1.0.0-preview.6)
- Edifact.Structure (>= 1.0.0-preview.6)
-
net8.0
- Edifact.Overlays (>= 1.0.0-preview.6)
- Edifact.Structure (>= 1.0.0-preview.6)
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-preview.6 | 55 | 10/11/2026 |
| 1.0.0-preview.5 | 72 | 9/19/2026 |
| 1.0.0-preview.4 | 70 | 9/17/2026 |
| 1.0.0-preview.3 | 97 | 9/7/2026 |
| 1.0.0-preview.2 | 88 | 9/6/2026 |
| 1.0.0-preview.1 | 83 | 9/6/2026 |