ISO20022.Suite
Parsing, schema conversion, generation and validation in one package.
ISO20022.Suite combines the capabilities of ISO20022.XSD and ISO20022.Parser into a single .NET package. It handles XSD-to-JSON conversion, message validation, and the parsing and generation of ISO 20022 messages — so a team working with both complex XML schemas and form data has one dependency rather than three.
What it does
- Parse ISO 20022 XML messages with pre-defined rules
- Convert ISO 20022 XSD to a JSON form model
- Convert form output JSON back into a valid ISO 20022 message
Install
dotnet add package ISO20022.SuiteInstall-Package ISO20022.SuiteExtract information from ISO 20022 messages
Parsing works exactly as it does in ISO20022.Parser — the Suite bundles it. Each message in a file is returned through the callback with its own identifier.
using System.Data;
using ISO20022.Parser;
IParsingService parsingService = new ParsingService(
new ParsingJsonRules(@"data\parsing_rules.json"), "Document");
await parsingService.ParseXmlAsync(@"data\pacs.008.xml",
(DataSet ds, Guid messageUniqueId, Guid uniqueId) =>
{
return Task.Run(() =>
{
foreach (DataTable dt in ds.Tables)
{
// Transform to CSV/Excel, or bulk-insert into a database.
ExportDataTableToCsv(dt,
@$"export\{messageUniqueId}_{dt.TableName}_{uniqueId}.csv");
}
});
});Parsing rules
Follow the parsing rules example in the data directory of the repository. Mapping rules should follow the model class structure below.
public class MappingRules
{
public string Namespace { get; set; }
public List<MappingTable> Mappings { get; set; }
}
public class MappingTable
{
public string NodeName { get; set; }
public string XPath { get; set; }
public IList<MappingColumn> Columns { get; set; }
}
public class MappingColumn
{
public int OrderNumber { get; set; }
public string NodeName { get; set; }
public string XPath { get; set; }
public string DataType { get; set; }
public int MinLength { get; set; }
public int MaxLength { get; set; }
public int fractionDigits { get; set; }
public int totalDigits { get; set; }
}Override the parsing rules
The supplied example reads rules from a JSON file. To store them somewhere else — a database, say — override the ParsingRules class method DeserializeRules.
public class ParsingDatabaseRules : ParsingRules
{
public override void DeserializeRules()
{
// MapParsingRules is of type IList<MappingRules>?
MapParsingRules = GetMyRulesFromDB();
}
}Convert ISO 20022 XSD to JSON
Turn an ISO 20022 schema into the JSON form model that xsd-ui and ngx-xml-message render directly.
using ISO20022.XSD;
string xsdFileName = "pacs.008.001.10.xsd";
var fileInfo = new FileInfo(xsdFileName);
if (File.Exists(xsdFileName) && fileInfo.Extension.Equals(".xsd"))
{
XsdToJson xsdLib = new(xsdFileName);
xsdLib.Convert();
File.AppendAllText(fileInfo.FullName.Replace(".xsd", ".json"), xsdLib.SchemaJson);
}Convert JSON to an ISO 20022 message, and validate it
The JSON here is the output of the form components — hand it back with the target namespace and the schema, and you get a validated message.
The original swiftmx.co example declared a pacs.008 namespace while its payloads were pain.001 customer credit transfers. The namespace below matches the payload.
using ISO20022.Suite;
string targetNamespace = "urn:iso:std:iso:20022:tech:xsd:pain.001.001.12";
string jsonData = File.ReadAllText(@jsonPath);
string xsdContent = File.ReadAllText(@xsdFilePath);
XElement xml = MxMessage.Create(jsonData, targetNamespace)
?? throw new Exception("Conversion failed");
if (MxMessage.ValidateMXMessage(xsdContent, xml.ToString(), out string validationMessage))
{
if (string.IsNullOrEmpty(validationMessage))
{
Console.WriteLine(xml?.ToString());
}
else
{
Console.Error.WriteLine(validationMessage);
}
}{
"Document": {
"CstmrCdtTrfInitn": {
"GrpHdr": {
"MsgId": "123456",
"CreDtTm": "2025-03-27T10:00:00",
"NbOfTxs": "1",
"CtrlSum": "1000",
"InitgPty": { "Nm": "Sender Company", "CtryOfRes": "US" }
},
"PmtInf": [
{
"PmtInfId": "PAY001",
"PmtMtd": "TRF",
"BtchBookg": "false",
"Dbtr": { "Nm": "John Doe" },
"DbtrAcct": { "Nm": "DE89370400440532013000" },
"DbtrAgt": { "FinInstnId": { "BICFI": "DEUTDEFFXXX" } },
"CdtTrfTxInf": [
{
"PmtId": { "EndToEndId": "TX123" },
"Amt": { "InstdAmt": { "Ccy": "USD", "Amt": "1000" } },
"CdtrAgt": { "FinInstnId": { "BICFI": "BNPAFRPPXXX" } },
"Cdtr": { "Nm": "Jane Smith" },
"CdtrAcct": { "Id": { "IBAN": "FR7630006000011234567890189" } }
}
]
}
]
}
}
}<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.12">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>123456</MsgId>
<CreDtTm>2025-03-27T10:00:00</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>1000</CtrlSum>
<InitgPty>
<Nm>Sender Company</Nm>
<CtryOfRes>US</CtryOfRes>
</InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>PAY001</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<Dbtr>
<Nm>John Doe</Nm>
</Dbtr>
<DbtrAcct>
<Nm>DE89370400440532013000</Nm>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BICFI>DEUTDEFFXXX</BICFI>
</FinInstnId>
</DbtrAgt>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>TX123</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="USD">1000</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BICFI>BNPAFRPPXXX</BICFI>
</FinInstnId>
</CdtrAgt>
<Cdtr>
<Nm>Jane Smith</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>FR7630006000011234567890189</IBAN>
</Id>
</CdtrAcct>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>Running this in production?
We wrote these libraries and we run them. If you are planning an ISO 20022 migration, we can tell you quickly where the hard parts actually are.