Using Xmlarrayitem Attribute Without Xmlarray on Serializable C# Class

using XmlArrayItem attribute without XmlArray on Serializable C# class

The following should serialize properly the way you want. The clue being [XmlElement("credentials")] on the list. I did this by taking your xml, generating a schema (xsd) from it in Visual Studio. Then running xsd.exe on the schema to generate a class. (And some small edits)

public class CredentialsSection
{
public string Username { get; set; }
public string Password { get; set; }
}

[XmlRoot(Namespace = "", IsNullable = false)]
public class configuration
{
/// <remarks/>
public string logging { get; set; }

/// <remarks/>
[XmlElement("credentials")]
public List<CredentialsSection> credentials { get; set; }

public string Serialize()
{
var credentialsSection = new CredentialsSection {Username = "a", Password = "b"};
this.credentials = new List<CredentialsSection> {credentialsSection, credentialsSection};
this.logging = "log this";
XmlSerializer s = new XmlSerializer(this.GetType());
StringBuilder sb = new StringBuilder();
TextWriter w = new StringWriter(sb);
s.Serialize(w, this);
w.Flush();
return sb.ToString();
}
}

give the following output

<?xml version="1.0" encoding="utf-16"?>
<configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<logging>log this</logging>
<credentials>
<Username>a</Username>
<Password>b</Password>
</credentials>
<credentials>
<Username>a</Username>
<Password>b</Password>
</credentials>
</configuration>

XmlArray Serialization - How can I make the serializer ignore the class name of items in a list?

So, I did something pretty hacky, but it works and I suppose that's all that matters. I changed PropA to be an int, since it was always a number, and used the following tags to set up the special property I wanted the XML serializer to use. I used some of Selman22's suggestion to make that easier. (Thank you!)

This solution will not work if your properties are all the same type, unfortunately, but it meets my needs at present and we do not foresee any potential for change (rare as that is).

[XmlIgnore]
public List<MyObject> Objects{ get; set; }

[XmlArray(ElementName = "OBJECT")]
[XmlArrayItem(Type = typeof(int), ElementName = "PROPA")]
[XmlArrayItem(Type = typeof(string), ElementName = "PROPB")]
public List<object> XmlObjects
{
get
{
var xmlObjects = new List<object>();

if (Objects != null)
{
xmlObjects.AddRange(Objects.SelectMany(x => new List<object>
{
x.PropA,
x.PropB
}));
}

return xmlObjects;
}
set { }
}

XmlArray with multiple names

Given that the answer from How to define multiple names for XmlElement field? works primarily for elements not arrays, the easiest solution would seem to be to introduce a surrogate property for one of the image elements, say <smallImages>:

public class root 
{
[XmlArray("largeImages")]
[XmlArrayItem("largeImage")]
public List<image> Images { get; set; } = new List<image>();

[XmlArray("smallImages")]
[XmlArrayItem("smallImage")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<image> SmallImagesSurrogate { get { return Images; } }

public bool ShouldSerializeSmallImagesSurrogate() { return false; }
}

Notes:

  • When deserializing to a pre-allocated List<T>, XmlSerializer will simply append deserialized elements to the existing list. That allows elements from both <largeImages> and <smallImages> to be concatenated into the same collection without data loss.

  • The surrogate property must be public but can be made "less visible" by setting attributes such as [Browsable(false)].

  • XmlSerializer can successfully deserialize get-only collection properties as long as the collection is pre-allocated. I took advantage of this to avoid adding a setter for the surrogate.

  • In case you need to re-serialize your root, the method ShouldSerializeSmallImagesSurrogate() will prevent the images array from being double-serialized. (For an explanation of why, see ShouldSerialize*() vs *Specified Conditional Serialization Pattern.) Instead all the images will serialize under <largeImages>. This method does not affect deserialization.

Sample working .Net fiddle.

How do I Set XmlArrayItem Element name for a ListCustom implementation?

Assuming you are using XmlSerializer, if all you want to do is change how your HotelBasic class is serialized, you can use XmlTypeAttribute:

[XmlType(TypeName = "Hotel")]
public class HotelBasic
{
public string Name { get; set; }
}

When used with your HotelList class it will be serialized as:

<Hotels xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Hotel>
<Name>One</Name>
</Hotel>
<Hotel>
<Name>Two</Name>
</Hotel>
</Hotels>

Xml serialize array of different classes with custom tag names

I found a solution for your problem which is nearly what you need:

  [XmlRoot(ElementName = "node")]
public class Node
{
[XmlArrayItem(typeof(CustomNode), ElementName = "custom-node")]
[XmlArrayItem(typeof(CustomNode2), ElementName = "custom-node-2")]
public List<Node> Children { get; set; }
}
[XmlRoot(ElementName = "custom-node")]
public class CustomNode : Node { }
[XmlRoot(ElementName = "custom-node-2")]
public class CustomNode2 : Node { }

results in:

<node xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Children>
<custom-node />
<custom-node-2 />
</Children>
</node>

Hope that helps a bit.

Deserialization of xml file by using XmlArray?

You need a common type to be able to deserialize your XML, and with that you can define with the [XmlElement] namespace what type to instantiate depending on the name of the element, as shown below.

public class StackOverflow_15907357
{
const string XML = @"<?xml version=""1.0""?>
<DietPlan>
<Health>
<Fruit>Test</Fruit>
<Fruit>Test</Fruit>
<Veggie>Test</Veggie>
<Veggie>Test</Veggie>
</Health>
</DietPlan>";

[XmlRoot(ElementName = "DietPlan")]
public class TestSerialization
{
[XmlArray("Health")]
[XmlArrayItem("Fruit", Type = typeof(Fruit))]
[XmlArrayItem("Veggie", Type = typeof(Veggie))]
public Food[] Foods { get; set; }
}

[XmlInclude(typeof(Fruit))]
[XmlInclude(typeof(Veggie))]
public class Food
{
[XmlText]
public string Text { get; set; }
}

public class Fruit : Food { }
public class Veggie : Food { }

public static void Test()
{
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(XML));
XmlSerializer xs = new XmlSerializer(typeof(TestSerialization));
TestSerialization obj = (TestSerialization)xs.Deserialize(ms);
foreach (var food in obj.Foods)
{
Console.WriteLine("{0}: {1}", food.GetType().Name, food.Text);
}
}
}

XmlSerializer and XmlArrayItem

Found the answer here:

using XmlArrayItem attribute without XmlArray on Serializable C# class

For those following along at home:

[<XmlElement>] member this.PublisherID with get() = this._publisherIds and set(v) = this._publisherIds <- v 


Related Topics



Leave a reply



Submit