3

I try to deserialize this xml:

<AccountInfo ID="accid1" Currency="EUR">
  <AccountNumber international="false">10000</AccountNumber>
  <AccountNumber international="true">DE10000</AccountNumber>
  <BankCode international="false">22222</BankCode>
  <BankCode international="true">BC22222</BankCode>
  <AccountHolder>Some Dude</AccountHolder>
</AccountInfo>

into following class:

public class AccountInfo 
{
  public int ID {get; set;}
  public string Currency {get; set;}
  public long AccountNumber {get; set;} //this should be filled if international == false
  public string BankCode {get; set;}
  public long AccountNumberInternational {get; set;} //this should be filled if internation == true
  public string BankCodeInternational {get; set;}
  public string AccountHolder {get; set;}
}

but i stuck in the part how to tell the Deserializer (System.Xml.Serialization, .NET 4.6.1) to fill the Properties AccountNumber/BankCode of the class depending on the Attribute "international" from AccountNumber/BankCode from the xml.

I tried using this "Serialisation" classes so far:

    [XmlRoot("AccountInfo")]
    public class AccountInfo
    {
        [XmlAttribute]
        public int ID { get; set; }

        [XmlAttribute]
        public string Currency { get; set; }

        [XmlElement]
        public BankAccount BankAccount { get; set; }

        public string AccountHolder { get; set; }
    }

    public class BankAccount
    {
        public long AccountNumber { get; set; }

        public int BankCode { get; set; }
    }

but this don't even lead near to the structure that i need.

Completely wrong xml

How do i need to declare the classes for Serialisation?

Kris
  • 512
  • 7
  • 16
  • You can check the msdn doc https://learn.microsoft.com/en-us/dotnet/standard/serialization/custom-serialization – Cleptus Jan 09 '18 at 11:10
  • 1
    You can put the XML in your clipboard and then choose paste special -> paste XML as classes and Visual Studio will create some classes that match the XML – Hans Kilian Jan 09 '18 at 11:12
  • The XML serialization code being variable/mutable points to a bad schemma / class design. Perhaps you should not have that XML & class but something slightly different (a new base class named Account with the long property and a child class named InternationalAccount that inherits Account and has the country string). – Cleptus Jan 09 '18 at 11:17
  • Neat Trick @HansKilian, thank you. Did not know this. – Kris Jan 09 '18 at 11:38

1 Answers1

5

XmlSerializer is designed to deserialize data into a DTO model that is basically the same shape as the XML, so something like:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

static class Program
{
    static void Main()
    {
        var xml = @"<AccountInfo ID=""accid1"" Currency=""EUR"">
  <AccountNumber international=""false"">10000</AccountNumber>
  <AccountNumber international=""true"">DE10000</AccountNumber>
  <BankCode international=""false"">22222</BankCode>
  <BankCode international=""true"">BC22222</BankCode>
  <AccountHolder>Some Dude</AccountHolder>
</AccountInfo>";
        var ser = new XmlSerializer(typeof(AccountInfo));
        var obj = ser.Deserialize(new StringReader(xml));

        // ...
    }
}

public class AccountInfo
{
    [XmlElement]
    public List<BankAccount> AccountNumber { get; } = new List<BankAccount>();
    [XmlElement]
    public List<BankAccount> BankCode { get; } = new List<BankAccount>();

    public string AccountHolder { get; set; }

    [XmlAttribute("ID")]
    public string Id {get;set;}

    [XmlAttribute]
    public string Currency {get;set;}
}
public class BankAccount
{
    [XmlAttribute("international")]
    public bool International { get; set; }
    [XmlText]
    public string Number { get; set; }
}

Which values from that you want to select and push into your domain model should be done afterwards, by you - for example by only selecting the international or non-international items from the lists.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Note that the `[XmlElement]` on the array properties is what actually tells the serializer that the items in the XML are flat and not grouped. – caesay Jan 09 '18 at 11:17
  • to expand on what @caesay notes - without that, it would be `......` (and the same for `BankCode`) - the list gets a wrapper element – Marc Gravell Jan 09 '18 at 11:28
  • Thank you! This solution is nearly perfect. The fields Id and Currency are never filled and the "Internation" bool is always false. Any idea for that? I'm fine with Select(LINQ) the right class afterwards... the deserialisation would perfectly fit my needs. – Kris Jan 09 '18 at 11:36
  • @Kris I've tested it; the code works perfectly and loads the values as specified. If it works differently for you, then either your xml is not quite as you have presented it (I copied it from the question), or you have changed the code that I posted slightly. To test this *with the code in my answer*, simply add: `ser.Serialize(Console.Out, obj);` - this will show *all* the data back again, including the correct values of `@international`, `@ID` and `@Currency`. To *write them* correctly, it must have *read them* correctly. – Marc Gravell Jan 09 '18 at 11:49
  • @MarcGravell Sorry, i debugged the wrong element :). Thank you very much! – Kris Jan 09 '18 at 11:56