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.Valuewith[XmlText]causes the value to be serialized as text rather than nested markup.StringElementBase [] XmlPartnerIDInfosshould be an array rather than aList<StringElementBase>becauseXmlSerializerwill not set back the value of a resizable collection such asList<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
XmlPartnerIDInfosI don't attempt to validate that there are an equal number ofPartnerIDandPartnerIDTypeelements, or that the values alternate. You could add that, if you wish.
Demo fiddle here.
