XmlSerializer empty properties in class with interface - c#

I am having an API XML response, that looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<artists itemsPerPage="30">
<artist id="a0d9633b">
<url>http://www.somesite.com/3df8daf.html</url>
</artist>
</artists>
For deserializing it I use classes:
[SerializableAttribute]
[XmlTypeAttribute(TypeName = "result")]
public abstract class Result
{
private int _itemsPerPage;
[XmlAttributeAttribute(AttributeName = "itemsPerPage")]
public int ItemsPerPage
{
get { return this._itemsPerPage; }
set { this._itemsPerPage = value; }
}
}
[SerializableAttribute]
[XmlTypeAttribute(TypeName = "artists")]
[XmlRootAttribute(ElementName = "artists")]
public class Artists : Result, IEnumerable<Artist>
{
private List<Artist> _list;
[XmlElementAttribute(ElementName = "artist")]
public List<Artist> List
{
get { return this._list; }
set { this._list = value; }
}
public Artists()
{
_list = new List<Artist>();
}
public void Add(Artist item)
{
_list.Add(item);
}
IEnumerator IEnumerable.GetEnumerator() { return _list.GetEnumerator(); }
public IEnumerator<Artist> GetEnumerator()
{
foreach (Artist artist in _list)
yield return artist;
}
}
[SerializableAttribute]
[XmlTypeAttribute(TypeName = "artist")]
[XmlRootAttribute(ElementName = "artist")]
public class Artist
{
private string _mbid;
private string _url;
[XmlAttributeAttribute(AttributeName = "mbid")]
public string MBID
{
get { return this._mbid; }
set { this._mbid = value; }
}
[XmlElementAttribute(ElementName = "url")]
public string Url
{
get { return this._url; }
set { this._url = value; }
}
public Artist() { }
}
And this is how I do deserialization:
XmlSerializer serializer = new XmlSerializer(typeof(Artists));
Artists result = (Artists)serializer.Deserialize(new StreamReader("artists.xml"));
So, the problem is, that when I do deserialization, ItemsPerPage doesn't have a needed (30) value (it has default 0). However, if I remove IEnumerable<Artist> interface and deserialize Artists, the value will appear. I can remove interface and leaves Artists with only IEnumerator<Artist> GetEnumerator() method, so everything will be fine, Artists still can be foreach'ed, but will no longer be IEnumerable<Artist>. Which is not what I want.
The problem is not in base class, because I can transfer property ItemsPerPage to Artists class, and deserialization result will be the same.
Any ideas how I can deserialize ItemsPerPage value with Artists still being IEnumerable<Artist>?

Related

c# Serialize a ObservableCollection ignoring a property

I am developing an UWP app using the Creators Update SDK.
I am trying to serialize a ObservableCollection ignoring a property of their class.
Here is my code, it have my class and the methods to serialize, you can see I am using [DataContract] and [IgnoreDataMember] but it's not working.
public class Classes
{
[DataContract]
public class Car : BindableBase
{
[DataMember]
private string _Name;
public string Name
{
get { return _Name; }
set { Set(ref _Name, value); }
}
[DataMember]
private string _Brand;
public string Brand
{
get { return _Brand; }
set { Set(ref _Brand, value); }
}
[IgnoreDataMember]
private bool _Electric;
public bool Electric
{
get { return _Electric; }
set { Set(ref _Electric, value); }
}
[DataMember]
private double _Price;
public double Price
{
get { return _Price; }
set { Set(ref _Price, value); }
}
}
public class Values_Car : ObservableCollection<Car> { }
public static class Garage
{
public static Values_Car Cars = new Values_Car();
static Garage()
{
}
}
[XmlRoot("Root")]
public class GarageDTO
{
[XmlElement]
public Values_Car Cars { get { return Garage.Cars; } }
}
}
public class NewSerialization
{
private static void FillList()
{
Car e_1 = new Car()
{
Name = "element_Name",
Brand = "element_Brand",
Electric = true,
Price = 1,
};
Car e_2 = new Car()
{
Name = "element_Name",
Brand = "element_Brand",
Electric = true,
Price = 2,
};
Garage.Cars.Add(e_1);
Garage.Cars.Add(e_2);
}
public static string Serializer()
{
FillList();
var _Instance = new GarageDTO();
var serializer = new XmlSerializer(typeof(GarageDTO));
using (var stream_original = new MemoryStream())
{
serializer.Serialize(stream_original, _Instance);
string string_original = string.Empty;
stream_original.Position = 0;
using (StreamReader reader = new StreamReader(stream_original, Encoding.Unicode))
{
string_original = reader.ReadToEnd();
}
return string_original;
}
}
}
using NewSerialization.Serializer(); I got:
But in the xml I got the Electric property which is ignored.
<?xml version="1.0" encoding="utf-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Cars>
<Name>element_Name</Name>
<Brand>element_Brand</Brand>
<Electric>true</Electric>
<Price>1</Price>
</Cars>
<Cars>
<Name>element_Name</Name>
<Brand>element_Brand</Brand>
<Electric>true</Electric>
<Price>2</Price>
</Cars>
</Root>
How I can ignoring a property of my ObservableCollection on serialization?
Appreciate your help.
Thanks to the comments of #dbc and #Aluan Haddad I found the exact I was finding, this should be my class to achieve that:
public class Car : BindableBase
{
private string _Name;
public string Name
{
get { return _Name; }
set { Set(ref _Name, value); }
}
private string _Brand;
public string Brand
{
get { return _Brand; }
set { Set(ref _Brand, value); }
}
private bool _Electric;
[XmlIgnore] //<----This!
public bool Electric
{
get { return _Electric; }
set { Set(ref _Electric, value); }
}
private double _Price;
public double Price
{
get { return _Price; }
set { Set(ref _Price, value); }
}
}

How can I serialize this xml array to a property in my class?

[Serializable]
public class CampoAuxiliar
{
private string descripcionAuxiliar;
private DateTime fechaAuxiliar;
private ArrayList opcion;
public CampoAuxiliar() { }
[XmlElement(ElementName = "descripcionAuxiliar", Type = typeof(string))]
public string DescripcionAuxiliar
{
get { return descripcionAuxiliar; }
set { descripcionAuxiliar = value; }
}
[XmlElement(ElementName = "fechaHabilitacion", Type = typeof(DateTime))]
public DateTime FechaAuxiliar
{
get { return fechaAuxiliar; }
set { fechaAuxiliar = value; }
}
[XmlArrayItem(ElementName = "opcion", Type = typeof(Opcion))]
[XmlArray(ElementName = "AuxiliarA")]
public ArrayList Opcion
{
get { return opcion; }
set { opcion = value; }
}
}
And this is my xml
- <auxiliarA>
<descripcionAuxiliar>Campo A</descripcionAuxiliar>
<fechaHabilitacion>2017-04-19</fechaHabilitacion>
+ <opcion>
<codigoOpcion>01</codigoOpcion>
<descripcionOpcion>1</descripcionOpcion>
</opcion>
+ <opcion>
<codigoOpcion>02</codigoOpcion>
<descripcionOpcion>2</descripcionOpcion>
</opcion>
+ <opcion>
<codigoOpcion>03</codigoOpcion>
<descripcionOpcion>3</descripcionOpcion>
</opcion>
</auxiliarA>
My problem is I can't figure out how to serialize the "opcion" array into the ArrayList opcion of the class.
With this case it does work and assigns the other nodes properly except for the ArrayList one which returns me count = 0.
You can modify your CampoAuxiliar class as follows:
[XmlRoot("auxiliarA")]
[XmlType("auxiliarA")]
public class CampoAuxiliar
{
private string descripcionAuxiliar;
private DateTime fechaAuxiliar;
public CampoAuxiliar() { }
[XmlElement(ElementName = "descripcionAuxiliar", Type = typeof(string))]
public string DescripcionAuxiliar
{
get { return descripcionAuxiliar; }
set { descripcionAuxiliar = value; }
}
[XmlElement(ElementName = "fechaHabilitacion", Type = typeof(DateTime))]
public DateTime FechaAuxiliar
{
get { return fechaAuxiliar; }
set { fechaAuxiliar = value; }
}
private ArrayList opcion;
[XmlElement("opcion", Type = typeof(Opcion))]
public ArrayList Opcion
{
get { return opcion; }
set { opcion = value; }
}
}
In addition, you should replace the ArrayList with a List<Opcion>:
private List<Opcion> opcion;
[XmlElement("opcion")]
public List<Opcion> Opcion
{
get { return opcion; }
set { opcion = value; }
}
Notes:
[XmlRoot("auxiliarA")] indicates that the root element name is <auxiliarA> not <CampoAuxiliar>.
[XmlElement("opcion")] indicates that the collection is to be serialized without an outer container element.
See ArrayList vs List<> in C# and c# When should I use List and when should I use arraylist? for some discussion of why to prefer List<T> over ArrayList.
Sample fiddle.

Unable to deserialize XML to List<>

I'm having problems trying to get the following XML code to work. First the exception was saying <items xmlns=''> was not expected. and I seem to have been able to fix that by specifying XmlRootAttribute. Now though, it comes back with an empty List<Items> and I can't figure out why. Any ideas?
XML Example
<?xml version="1.0"?>
<items>
<item>
<version>1.0</version>
<title>Example</title>
<changelog>http://example.com/changelog.txt</changelog>
<url>http://www.example.com/download/</url>
</item>
</items>
XML Deserialize Code
Stream appCastStream = webResponse.GetResponseStream();
UpdateXML updateXml = new UpdateXML();
var rootAttribute = new XmlRootAttribute();
rootAttribute.ElementName = "items";
rootAttribute.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(UpdateXML), rootAttribute);
try
{
using (XmlTextReader reader = new XmlTextReader(appCastStream))
{
if (serializer.CanDeserialize(reader))
{
updateXml = (UpdateXML)serializer.Deserialize(reader);
}
else
{
throw new Exception("Update file is in the wrong format.");
}
}
}
catch (Exception ex)
{
Debug.WriteLine("The following error occurred trying to check for updates: {0}", new object[] { ex.Message });
return;
}
UpdateXML Code
public class UpdateXML
{
public class Item
{
private string _versionString;
private string _title;
private string _changelog;
private string _url;
[XmlElement("version")]
public string VersionString
{
get { return this._versionString; }
set { this._versionString = value; }
}
public Version Version
{
get
{
if (string.IsNullOrEmpty(this._versionString))
return null;
return new Version(this._versionString);
}
}
[XmlElement("title")]
public string Title
{
get { return this._title; }
set { this._title = value; }
}
[XmlElement("changelog")]
public string ChangeLog
{
get { return this._changelog; }
set { this._changelog = value; }
}
[XmlElement("url")]
public string URL
{
get { return this._url; }
set { this._url = value; }
}
}
private List<Item> _items = new List<Item>();
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items
{
get { return this._items; }
set { this._items = value; }
}
public UpdateXML()
{
}
}
I think the problem is that your XML doesn't really have a "root" element-- the top level element is an array. This answer applied to your problem seems to fix things (also removing the rootAttribute argument passed to the XmlSerializer):
[XmlRootAttribute("items")]
public class UpdateXML
{
private List<Item> _items;
[XmlElement("item")]
public List<Item> Items
{
get { return this._items; }
set { this._items = value; }
}
}
Example: https://dotnetfiddle.net/MAet5y
If you're able to modify the XML, you could add a root element and that would fix the issue as well.
For example, if you wrapped your current XML in <root></root> and then modified your UpdateXML class as follows:
[XmlRootAttribute("root")]
public class UpdateXML
{
private List<Item> _items;
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items
{
get { return this._items; }
set { this._items = value; }
}
}
Example: https://dotnetfiddle.net/6KfxA4

Finding the root nodes of all the of a tree from a nodes in any generic list

This is a entity and i want to list all the children node for a given node in a generic function
public static List<T> BuildTree<T>(List<T> list, T selectNode string keyPropName, string parentPropName, string levelPropName, int level = 0)
{
List<T> entity = new List<T>();
foreach (T item in list)
{
}
return entity;
}
example of the entity structure
protected long _coakey;
protected long _parentkey;
protected string _coacode;
protected string _coacodeclient;
protected string _coaname;
protected int _coalevel;
[DataMember]
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChnaged(); }
}
[DataMember]
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChnaged(); }
}
[DataMember]
public string coacode
{
get { return _coacode; }
set { _coacode = value; this.OnChnaged(); }
}
[DataMember]
public string coacodeclient
{
get { return _coacodeclient; }
set { _coacodeclient = value; this.OnChnaged(); }
}
[DataMember]
public string coaname
{
get { return _coaname; }
set { _coaname = value; this.OnChnaged(); }
}
[DataMember]
public int coalevel
{
get { return _coalevel; }
set { _coalevel = value; this.OnChnaged(); }
}
Your BuildTree<T> method cannot determine the structure of the tree unless it knows something about its structure. At a very minimum, I would suggest making a base class or interface that defines a tree node, and then change the BuildTree method to work specifically with those types of objects. Then, it will be able to figure out the tree structure. Each of you entity classes would have to implement that tree node interface or inherit from the tree node base class. For instance:
public abstract class TreeNodeBase
{
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChanged(); }
}
protected long _parentkey;
}
public class MyEntityTreeNode : TreeNodeBase
{
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChanged(); }
}
protected long _coakey;
// etc...
}
// Note the generic type constraint at the end of the next line
public static List<T> BuildTree<T>(List<T> list, T selectNode, string keyPropName, string parentPropName, string levelPropName, int level) where T : TreeNodeBase
{
List<T> entity = new List<T>();
foreach (TreeNodeBase node in list)
{
long parentKey = node.parentkey;
// etc...
}
return entity;
}
Node class:
public class Node<TKey, TValue> where TKey : IEquatable<TKey>
{
public TKey Key { get; set; }
public TKey ParentKey { get; set; }
public TValue Data { get; set; }
public readonly List<Node<TKey, TValue>> Children = new List<Node<TKey, TValue>>();
}
TreeBuilder:
public static Node<TKey, TValue> BuildTree<TKey, TValue>(IEnumerable<Node<TKey, TValue>> list,
Node<TKey, TValue> selectNode)
where TKey : IEquatable<TKey>
{
if (ReferenceEquals(selectNode, null))
{
return null;
}
var selectNodeKey = selectNode.Key;
foreach (var childNode in list.Where(x => x.ParentKey.Equals(selectNodeKey)))
{
selectNode.Children.Add(BuildTree(list, childNode));
}
return selectNode;
}
Usage:
List<MyClass> list = ...
var nodes = list.Select(x => new Node<long, MyClass>
{
Key = x.MyKey,
ParentKey = x.MyParentKey,
Data = x
}).ToList();
var startNode = nodes.FirstOrDefault(x => x.Data.Stuff == "Pick me!");
var tree = BuildTree(nodes, startNode);
MyClass example:
public class MyClass
{
public long MyKey;
public long MyParentKey;
public string Name;
public string Text;
public string Stuff;
}
I have solved it my self hope it help you
public static List<T> BuildTree<T>(List<T> list, T selectedNode, string keyPropName, string parentPropName, int endLevel = 0, int level = 0)
{
List<T> entity = new List<T>();
Type type = typeof(T);
PropertyInfo keyProp = type.GetProperty(keyPropName);
string _selectedNodekey = keyProp.GetValue(selectedNode, null).ToString();
PropertyInfo parentProp = type.GetProperty(parentPropName);
foreach (T item in list)
{
string _key = keyProp.GetValue(item, null).ToString();
string _parent = parentProp.GetValue(item, null).ToString();
if (_selectedNodekey == _parent)
{
T obj = (T)Activator.CreateInstance(typeof(T));
obj = item;
entity.Add(obj);
if (level == endLevel && level!=0) break;
entity.AddRange(BuildTree<T>(list, obj, keyPropName, parentPropName, level + 1));
}
}
return entity;
}

Serialize two nodes with the same name but different child nodes

I need to be able to define two nodes with the same name but completely different subnode structures. I didn't design this XML schema but for the time being I'm forced to use it as is. I realize it's a terrible abuse of everything that is XML but there you have it.
What I need it to look like:
<order>
<ItemType type="Clubs">
<Club num="1">
<ClubName>Some Name</ClubName>
<ClubChoice>Something Else</ClubChoice>
</Club>
</ItemType>
<ItemType type="Gift" val="MailGreeting">
<GiftName>MailGreeting</GiftName>
<GiftDescription></GiftDescription>
<GiftQuanity>1</GiftQuanity>
</ItemType
</order>
Of course it's far more complicated than but you get the gist.
I'm using XmlSerializer and would really like to avoid using XDocument but if that's what I need to do then so be it.
If your order contains properties and not a list you can tell the serializer to name the elements like this:
[XmlRoot("order")]
public class Order
{
private Whatever whateverInstance;
[XmlElement("ItemType")]
public Whatever WhateverInstance
{
get { return whateverInstance; }
set { whateverInstance = value; }
}
private Something somethingInstance;
[XmlElement("ItemType")]
public Something SomethingInstance
{
get { return somethingInstance; }
set { somethingInstance = value; }
}
}
If it's a list of things you could get to have a identical element name as well but you will get a redundant xsi:Type attribute:
[XmlRoot("order")]
public class Order
{
private ItemType[] itemTypes;
[XmlElement("ItemType")]
public ItemType[] ItemTypes
{
get { return itemTypes; }
set { itemTypes = value; }
}
}
[XmlInclude(typeof(Clubs))]
[XmlInclude(typeof(Gift))]
public abstract class ItemType
{
private string type = "None";
[XmlAttribute]
public string Type
{
get { return type; }
set { type = value; }
}
}
public class Clubs : ItemType
{
public Clubs()
{
Type = "Clubs";
}
private Club[] clubsArray;
[XmlElement("Club")]
public Club[] ClubsArray
{
get { return clubsArray; }
set { clubsArray = value; }
}
}
public class Club
{
private int num = 0;
[XmlAttribute("num")]
public int Num
{
get { return num; }
set { num = value; }
}
private string clubName = "";
public string ClubName
{
get { return clubName; }
set { clubName = value; }
}
private string clubChoice = "";
public string ClubChoice
{
get { return clubChoice; }
set { clubChoice = value; }
}
}
public class Gift : ItemType
{
public Gift()
{
Type = "Gift";
}
private string val = "";
[XmlAttribute("val")]
public string Val
{
get { return val; }
set { val = value; }
}
private string giftName = "";
public string GiftName
{
get { return giftName; }
set { giftName = value; }
}
private string giftDescription = "";
public string GiftDescription
{
get { return giftDescription; }
set { giftDescription = value; }
}
private int giftQuanity = 0;
public int GiftQuanity
{
get { return giftQuanity; }
set { giftQuanity = value; }
}
}
Test:
List<ItemType> list = new List<ItemType>();
list.Add(new Clubs() { ClubsArray = new Club[] { new Club() { Num = 0, ClubName = "Some Name", ClubChoice = "Something Else" } } });
list.Add(new Gift() { Val = "MailGreeting", GiftName = "MailGreeting", GiftDescription = "GiftDescription", GiftQuanity = 1});
Order order = new Order();
rder.ItemTypes = list.ToArray();
XmlSerializer serializer = new XmlSerializer(typeof(Order));
StreamWriter sw = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Stuff.xml");
serializer.Serialize(sw, order);
sw.Close();
Output:
<order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ItemType xsi:type="Clubs" Type="Clubs">
<Club num="0">
<ClubName>Some Name</ClubName>
<ClubChoice>Something Else</ClubChoice>
</Club>
</ItemType>
<ItemType xsi:type="Gift" Type="Gift" val="MailGreeting">
<GiftName>MailGreeting</GiftName>
<GiftDescription>GiftDescription</GiftDescription>
<GiftQuanity>1</GiftQuanity>
</ItemType>
</order>

Categories

Resources