Unable to deserialize XML to List<> - c#

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

Related

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.

XmlSerializer empty properties in class with interface

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>?

Using XmlReader to deserialize custom object

I have a huge XML file like this:
<Tests>
<Test>
<Code>a</Code>
<Destination>test a</Destination>
<Coordinate>
<Latitude>0.0</Latitude>
<Longitude>0.0</Longitude>
</Coordinate>
<Images>
<ImageURL>1. url 1</ImageURL>
<ImageURL>1. url 2</ImageURL>
<ImageURL>1. url 3</ImageURL>
</Images>
</Test>
<Test>
<Code>b</Code>
<Destination>test b</Destination>
<Coordinate>
<Latitude>0.0</Latitude>
<Longitude>0.0</Longitude>
</Coordinate>
<Images>
<ImageURL>2. url 1</ImageURL>
<ImageURL>2. url 2</ImageURL>
<ImageURL>2. url 3</ImageURL>
<ImageURL>2. url 4</ImageURL>
<ImageURL>2. url 5</ImageURL>
</Images>
</Test>
...
</Tests>
and I try this
reader = XmlReader.Create("file");
while (reader.Read())
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "Test":
{
.....
Test elem = (Test)DeSerializerDestination.Deserialize(reader);
.....
} break;
default: reader.Skip(); break;
}
}
private static readonly XmlSerializer DeSerializerTest = new XmlSerializer(typeof(Test));
public class Test
{
private string _Code = string.Empty;
public string Code
{
get { return _Code; }
set { _Code = value; }
}
private string _Destination = string.Empty;
public string Destination
{
get { return _Destination; }
set { _Destination = value; }
}
private Coordinate _Coordinates = new Coordinate();
public Coordinate Coordinates
{
get { return _Coordinates; }
set { _Coordinates = value; }
}
private ImageUrl[] _ImageUrl;
public ImageUrl[] Images
{
get { return _ImageUrl; }
set { _ImageUrl = value; }
}
}
public class Coordinate
{
private string _Latitude = string.Empty;
public string Latitude
{
get { return _Latitude; }
set { _Latitude = value; }
}
private string _Longitude = string.Empty;
public string Longitude
{
get { return _Longitude; }
set { _Longitude = value; }
}
}
public class ImageUrl
{
private string _ImageURL = string.Empty;
public string ImageURL
{
get { return _ImageURL; }
set { _ImageURL = value; }
}
}
The object elem contains information but not all; property "Images" is always empty.
I think it's because I don't initialize this private ImageUrl[] _ImageUrl;, but would I initialize it, considering I don't know the number of images? I need to mention, I must use .net 2.0.
Update: If I use this in "Images" always I get the first image url.
public class ImageUrl
....
System.Xml.Serialization.XmlElementAttribute("ImageURL")]
public string ImageURL
...
public class Test
...
System.Xml.Serialization.XmlElementAttribute("Images")]
public ImageUrl[] Images
...
Update: I use this
[System.Xml.Serialization.XmlArray("Images")]
[System.Xml.Serialization.XmlArrayItem("ImageURL")]
public List<ImageUrl> Images
{
get { return _ImageUrl; }
set { _ImageUrl = value; }
}
now I get list but "ImageUrl" is empty, do not contain "1. url 1" ....
This is the resolve
[System.Xml.Serialization.XmlIgnore]
private List<string> images = new List<string>();
[System.Xml.Serialization.XmlArray("Images")]
[System.Xml.Serialization.XmlArrayItem("ImageURL")]
public List<string> Images
{
get { return images; }
set { images = value; }
}
Try the following, which will serialize your Xml into your object, providing you object matches your Xml structure.
YourObject oObject = new YourObject ();
try
{
XmlSerializer oSerializer = new XmlSerializer(typeof(YourObject));
using (StringReader oReader = new StringReader(XmlString))
{
oObject = (YourObject)oSerializer.Deserialize(oReader);
}
}
catch
{
...
}

XML Deserialization inner exception

I am trying to deserialize an XML file to a class. The XML file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<locations>
<location id="0">
<name>park</name>
<temperature>5</temperature>
<wind>26</wind>
<weather_text_SI>sunny</weather_text_SI>
<visibility></visibility>
<latitude>46.4527</latitude>
<longitude>15.334</longitude>
<elevation>1517</elevation>
</location>
</locations>
The class that I want to deserialize it to is:
[XmlRootAttribute("locations")]
public class SnowPark
{
public SnowPark()
{
}
private int id;
[XmlAttribute("id")]
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
[XmlElement("name")]
public string Name
{
get { return name; }
set { name = value; }
}
private int temperature;
[XmlElement("temperature")]
public int Temperature
{
get { return temperature; }
set { temperature = value; }
}
private int wind;
[XmlElement("wind")]
public int Wind
{
get { return wind; }
set { wind = value; }
}
private string weatherText;
[XmlElement("weather_text_SI")]
public string WeatherText
{
get { return weatherText; }
set { weatherText = value; }
}
private double latitude;
[XmlElement("latitude")]
public double Latitude
{
get { return latitude; }
set { latitude = value; }
}
private double longitude;
[XmlElement("longitude")]
public double Longitude
{
get { return longitude; }
set { longitude = value; }
}
private int elevation;
[XmlElement("elevation")]
public int Elevation
{
get { return elevation; }
set { elevation = value; }
}
}
I try to deserialize the XML file
XmlSerializer deserializer = new XmlSerializer(typeof(List<SnowPark>));
TextReader textReader = new StreamReader(#"file.xml");
List<SnowPark> parks;
parkss = (List<SnowPark>)deserializer.Deserialize(textReader);
textReader.Close();
However I get an exception:
There is an error in XML document (2, 2).
and an inner exception:
<locations xmlns=''> was not expected.
No luck finding the solution so far. Help appreciated.
The XmlRootAttribute doesn't apply since you are serialising a list of then, not an individual item; this also means your XML is one layer further-out than needed.
IMO, your easiest option here is:
[XmlRoot("locations")]
public class Locations
{
[XmlElement("location")]
public List<SnowPark> Parks {get;set;}
}
and deserialize a Locations object, using typeof(Locations) to initialisers the XmlSerializer

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