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 aList<StringElementBase>
becauseXmlSerializer
will 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
XmlPartnerIDInfos
I don't attempt to validate that there are an equal number ofPartnerID
andPartnerIDType
elements, or that the values alternate. You could add that, if you wish.
Demo fiddle here.