Home > OS >  XML attribute for ignoring class tag when serializating object c#
XML attribute for ignoring class tag when serializating object c#

Time:10-03

I need to get an xml output like this:

<Partners>
   <Partner>
      <PartnerType>SomeStringValue</PartnerType>
      <PartnerID>SomeStringValue</PartnerID>
      <PartnerIDType>SomeStringValue</PartnerIDType>
      <PartnerID>BTW BEXXXXXXXXXX</PartnerID>
      <PartnerIDType>SomeStringValue</PartnerIDType>
   </Partner>
   <Partner>
      <PartnerType>SomeStringValue</PartnerType>
      <PartnerID>SomeStringValue</PartnerID>
      <PartnerIDType>SomeStringValue</PartnerIDType>
      <PartnerID>BTW BEXXXXXXXXXX</PartnerID>
      <PartnerIDType>SomeStringValue</PartnerIDType>
   </Partner>
</Partners>

It has to be possible to add multiple PartnerID tags and multiple PartnerIDType tags in the parner tag. To get this result I was using a list of PartnerIdInfo. I had my classes like this:

public class Someclass
{
    public List<Partner> Partners {get; set;}
}

public class Partner
{
    public string PartnerType { get; set; }

    [XmlElement("PartnerIdInfo")]
    public List<PartnerIdInfo> PartnerIDInfos { get; set; }
}

public class PartnerIdInfo
{
    public string PartnerID { get; set; }
    public string PartnerIDType { get; set; }
}

The [XmlElement("PartnerIdInfo")] tag is for not showing the tag from the list property in the partner class. But it is still showing the tag :

<Partners>
   <Partner>
      <PartnerType>SomeStringValue</PartnerType>
      <PartnerIdInfo>
         <PartnerID>SomeStringValue</PartnerID>
         <PartnerIDType>SomeStringValue</PartnerIDType>
      </PartnerIdInfo>
      <PartnerIdInfo>
         <PartnerID>BTW BEXXXXXXXXXX</PartnerID>
         <PartnerIDType>SomeStringValue</PartnerIDType>
      </PartnerIdInfo>
   </Partner>
</Partners>

Is there an attibute (or another solution) to do this? I prefer not to rewrite my code and fill everything in the code through the use of XmlDocument and XmlNode... Or will this be the only possible solution for this outcome?

CodePudding user response:

Your problem is that you want the serializer to combine the value of Partner.PartnerType with the repeating values of Partner.PartnerIDInfos[*].PartnerID and Partner.PartnerIDInfos[*].PartnerIDType into a single omnibus <Partner> element. Unfortunately, this simply is not implemented. The content of each PartnerIdInfo will always be serialized within its own element.

Several workarounds can be found in the answers to the questions Keep sort when deserialize and serialize XML using XmlSerializer and Xml Deserialization - Merging two elements into a single List<T> object. In particular using a polymorphic array of simple elements with two possible types corresponding to <PartnerID> and <PartnerIDType> should meet your needs. You will need to modify Partner to mark the PartnerIDInfos as ignored and use a surrogate array for the elements:

public class Partner
{
    [XmlElement(Order = 1)]
    public string PartnerType { get; set; }

    [XmlIgnore]
    public List<PartnerIdInfo> PartnerIDInfos { get; set; }

    [XmlElement(typeof(PartnerID), Order = 2), XmlElement(typeof(PartnerIDType), Order = 2)]
    public StringElementBase [] XmlPartnerIDInfos 
    {
        get => PartnerIDInfos?.SelectMany(p => new StringElementBase [] { new PartnerID { Value = p.PartnerID }, new PartnerIDType { Value = p.PartnerIDType } }).ToArray();
        set => PartnerIDInfos = value?.OfType<PartnerID>().Zip(value.OfType<PartnerIDType>(), (id, type) => new PartnerIdInfo { PartnerID = id.Value, PartnerIDType = type.Value }).ToList();
    }
}

public abstract class StringElementBase { [XmlText] public string Value { get; set; } } // From https://stackoverflow.com/a/48130816/3744182
public class PartnerID : StringElementBase { }
public class PartnerIDType : StringElementBase { }

Notes:

  • Marking StringElementBase.Value with [XmlText] causes the value to be serialized as text rather than nested markup.

  • StringElementBase [] XmlPartnerIDInfos should be an array rather than a List<StringElementBase> because XmlSerializer will not set back the value of a resizable collection such as List<T> after populating it.

  • Setting XmlElement.Order is optional but does indicate that <PartnerType> not come between any of the <PartnerID> and <PartnerIDType> elements.

  • In the setter for XmlPartnerIDInfos I don't attempt to validate that there are an equal number of PartnerID and PartnerIDType elements, or that the values alternate. You could add that, if you wish.

Demo fiddle here.

  • Related