Reputation: 9037
I am creating a converter to SEPA XML in F# using the .NET XML Serializer:
[<CLIMutable>]
[<XmlRoot(ElementName="InitgPty", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type InitiatingParty = {
[<XmlElement(ElementName="Nm", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Name: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="GrpHdr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type GroupHeader = {
[<XmlElement(ElementName="MsgId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
MessageId: string
[<XmlElement(ElementName="CreDtTm", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreationDateTime: string
[<XmlElement(ElementName="NbOfTxs", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
TransactionCount: string
[<XmlElement(ElementName="CtrlSum", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ControlSum: string
[<XmlElement(ElementName="InitgPty", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
InitiatingParty: InitiatingParty
}
[<CLIMutable>]
[<XmlRoot(ElementName="SvcLvl", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type ServiceLevel = {
[<XmlElement(ElementName="Cd", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Code: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="PmtTpInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type PaymentTypeInformation = {
[<XmlElement(ElementName="SvcLvl", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ServiceLevel: ServiceLevel
}
[<CLIMutable>]
[<XmlRoot(ElementName="Dbtr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type Debtor = {
[<XmlElement(ElementName="Nm", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Name: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="Id", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type Id = {
[<XmlElement(ElementName="IBAN", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Iban: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="DbtrAcct", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type DebtorAccount = {
[<XmlElement(ElementName="Id", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Id: Id
[<XmlElement(ElementName="Ccy", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Currency: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="FinInstnId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type FinancialInstitutionId = {
[<XmlElement(ElementName="BIC", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Bic: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="DbtrAgt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type DebtorAgent = {
[<XmlElement(ElementName="FinInstnId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
FinancialInstitutionId: FinancialInstitutionId
}
[<CLIMutable>]
[<XmlRoot(ElementName="PmtId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type PaymentIdentification = {
[<XmlElement(ElementName="EndToEndId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
EndToEndId: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="InstdAmt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type InstructedAmount = {
[<XmlAttribute(AttributeName="Ccy")>]
Currency: string
[<XmlText>]
Text: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="Amt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type Amount = {
[<XmlElement(ElementName="InstdAmt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
InstructedAmount: InstructedAmount
}
[<CLIMutable>]
[<XmlRoot(ElementName="CdtrAgt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type CreditorAgent = {
[<XmlElement(ElementName="FinInstnId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
FinancialInstitutionId: FinancialInstitutionId
}
[<CLIMutable>]
[<XmlRoot(ElementName="Cdtr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type Creditor = {
[<XmlElement(ElementName="Nm", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Name: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="CdtrAcct", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type CreditorAccount = {
[<XmlElement(ElementName="Id", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Id: Id
}
[<CLIMutable>]
[<XmlRoot(ElementName="RmtInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type RemittanceInformation = {
[<XmlElement(ElementName="Ustrd", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Unstructured: string
}
[<CLIMutable>]
[<XmlRoot(ElementName="CdtTrfTxInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type CreditTransferTransactionInformation = {
[<XmlElement(ElementName="PmtId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentIdentification: PaymentIdentification
[<XmlElement(ElementName="Amt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Amount: Amount
[<XmlElement(ElementName="CdtrAgt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditorAgent: CreditorAgent
[<XmlElement(ElementName="Cdtr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Creditor: Creditor
[<XmlElement(ElementName="CdtrAcct", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditorAccount: CreditorAccount
[<XmlElement(ElementName="RmtInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
RemittanceInformation: RemittanceInformation
}
[<CLIMutable>]
[<XmlRoot(ElementName="PmtInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type PaymentInformation = {
[<XmlElement(ElementName="PmtInfId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentInformationId: string
[<XmlElement(ElementName="PmtMtd", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentMethod: string
[<XmlElement(ElementName="NbOfTxs", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
TransactionCount: string
[<XmlElement(ElementName="CtrlSum", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ControlSum: string
[<XmlElement(ElementName="PmtTpInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentTypeInformation: PaymentTypeInformation
[<XmlElement(ElementName="ReqdExctnDt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
RequestedExecutionDate: string
[<XmlElement(ElementName="Dbtr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Debtor: Debtor
[<XmlElement(ElementName="DbtrAcct", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
DebtorAccount: DebtorAccount
[<XmlElement(ElementName="DbtrAgt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
DebtorAgent: DebtorAgent
[<XmlElement(ElementName="ChrgBr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ChargeBearer: string
[<XmlElement(ElementName="CdtTrfTxInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditTransferTransactionInformation: List<CreditTransferTransactionInformation>
}
[<CLIMutable>]
[<XmlRoot(ElementName="CstmrCdtTrfInitn", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type CustomerCreditTransferInitialization = {
[<XmlElement(ElementName="GrpHdr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
GroupHeader: GroupHeader
[<XmlElement(ElementName="PmtInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentInformation: PaymentInformation
}
[<CLIMutable>]
[<XmlRoot(ElementName="Document", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type Document = {
[<XmlElement(ElementName="CstmrCdtTrfInitn", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CustomerCreditTransferInitialization: CustomerCreditTransferInitialization
[<XmlAttribute(AttributeName="xsi", Namespace="http://www.w3.org/2000/xmlns/")>]
Xsi: string
[<XmlAttribute(AttributeName="xmlns")>]
Xmlns: string
}
When using the serializer it crash:
[<EntryPoint>]
let main argv =
let xmlSerializer = new XmlSerializer(typeof<Document>)
return 0
The exception I have:
System.InvalidOperationException: There was an error reflecting type 'Program.Document'. ---> System.InvalidOperationException: There was an error reflecting property 'CustomerCreditTransferInitialization'. ---> System.InvalidOperationException: There was an error reflecting type 'Program.CustomerCreditTransferInitialization'. ---> System.InvalidOperationException: There was an error reflecting property 'PaymentInformation'. ---> System.InvalidOperationException: There was an error reflecting type 'Program.PaymentInformation'. ---> System.InvalidOperationException: There was an error reflecting property 'CreditTransferTransactionInformation'. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source, Boolean directReference, Boolean throwOnError)
at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, String ns, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type)
at Program.main(String[] argv) in C:\Users\eperret\Desktop\SepaConversion\SepaConversion\Program.fs:line 221
Upvotes: 1
Views: 108
Reputation: 9037
I found out the issue:
List<Whatever>
does not work for the serialization of a collection of elements in :
[<CLIMutable>]
[<XmlRoot(ElementName="PmtInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
type PaymentInformation = {
[<XmlElement(ElementName="PmtInfId", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentInformationId: string
[<XmlElement(ElementName="PmtMtd", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentMethod: string
[<XmlElement(ElementName="NbOfTxs", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
TransactionCount: string
[<XmlElement(ElementName="CtrlSum", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ControlSum: string
[<XmlElement(ElementName="PmtTpInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
PaymentTypeInformation: PaymentTypeInformation
[<XmlElement(ElementName="ReqdExctnDt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
RequestedExecutionDate: string
[<XmlElement(ElementName="Dbtr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
Debtor: Debtor
[<XmlElement(ElementName="DbtrAcct", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
DebtorAccount: DebtorAccount
[<XmlElement(ElementName="DbtrAgt", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
DebtorAgent: DebtorAgent
[<XmlElement(ElementName="ChrgBr", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
ChargeBearer: string
[<XmlElement(ElementName="CdtTrfTxInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditTransferTransactionInformation: List<CreditTransferTransactionInformation>
}
In particular:
[<XmlElement(ElementName="CdtTrfTxInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditTransferTransactionInformation: List<CreditTransferTransactionInformation>
Which needed to be converted to an actual array:
[<XmlElement(ElementName="CdtTrfTxInf", Namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")>]
CreditTransferTransactionInformation: CreditTransferTransactionInformation[]
Then it works like a charm!
Upvotes: 1