XML serialization array in C# - c#

I'm having trouble figuring this out, I have an xml sheet that looks like this
<root>
<list id="1" title="One">
<word>TEST1</word>
<word>TEST2</word>
<word>TEST3</word>
<word>TEST4</word>
<word>TEST5</word>
<word>TEST6</word>
</list>
<list id="2" title="Two">
<word>TEST1</word>
<word>TEST2</word>
<word>TEST3</word>
<word>TEST4</word>
<word>TEST5</word>
<word>TEST6</word>
</list>
</root>
And I'm trying to serialize it into
public class Items
{
[XmlAttribute("id")]
public string ID { get; set; }
[XmlAttribute("title")]
public string Title { get; set; }
//I don't know what to do for this
[Xml... something]
public list<string> Words { get; set; }
}
//I don't this this is right either
[XmlRoot("root")]
public class Lists
{
[XmlArray("list")]
[XmlArrayItem("word")]
public List<Items> Get { get; set; }
}
//Deserialize XML to Lists Class
using (Stream s = File.OpenRead("myfile.xml"))
{
Lists myLists = (Lists) new XmlSerializer(typeof (Lists)).Deserialize(s);
}
I'm really new with XML and XML serializing, any help would be much appreciated

It should work if you declare your classes as
public class Items
{
[XmlAttribute("id")]
public string ID { get; set; }
[XmlAttribute("title")]
public string Title { get; set; }
[XmlElement("word")]
public List<string> Words { get; set; }
}
[XmlRoot("root")]
public class Lists
{
[XmlElement("list")]
public List<Items> Get { get; set; }
}

If you just need to read your XML into an object structure, it might be easier to use XLINQ.
Define your class like so:
public class WordList
{
public string ID { get; set; }
public string Title { get; set; }
public List<string> Words { get; set; }
}
And then read the XML:
XDocument xDocument = XDocument.Load("myfile.xml");
List<WordList> wordLists =
(
from listElement in xDocument.Root.Elements("list")
select new WordList
{
ID = listElement.Attribute("id").Value,
Title = listElement.Attribute("title").Value,
Words =
(
from wordElement in listElement.Elements("word")
select wordElement.Value
).ToList()
}
).ToList();

Related

XML deserialization returns list with one empty item

I have the following XML:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
<accounts>
<items>
<account>
<voornaam><FirstName</voornaam>
<naam>LastName</naam>
<gebruikersnaam>Username</gebruikersnaam>
<internnummer></internnummer>
<klasnummer></klasnummer>
</account>
</items>
</accounts>
With these classes:
public class Accounts
{
public Accounts()
{
items = new List<Account>();
}
[XmlElement]
public List<Account> items { get; set; }
}
public class Account
{
public string voornaam { get; set; }
public string naam { get; set; }
public string gebruikersnaam { get; set; }
public int? internnummer { get; set; }
public int? klasnummer { get; set; }
}
And this code:
var decoded = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><accounts><items><account><voornaam>FirstName</voornaam><naam>LastName</naam><gebruikersnaam></gebruikersnaam><internnummer></internnummer><klasnummer></klasnummer></account></items></accounts>";
XmlSerializer serializer = new XmlSerializer(typeof(Accounts), new XmlRootAttribute("accounts"));
StringReader reader = new StringReader(decoded);
var accounts = (Accounts)serializer.Deserialize(reader);
All I get from this is an Accounts instance with the property Items containing one Account instance with every property null.
You need to specify the items as XML array with XmlArrayAttribute and also with the XmlArrayItemAttribute with (element) item's name: "account" and as Account type. XmlArrayAttribute Example.
public class Accounts
{
[XmlArrayItem(ElementName= "account",
Type = typeof(Account))]
[XmlArray(ElementName="items")]
public List<Account> items { get; set; }
}
Meanwhile, suggest using XmlElementAttribute to specify the element name in XML instead of naming the properties as camelCase.
For the reason why need InternnummerText and KlasnummerText properties you can refer to the question: Deserializing empty xml attribute value into nullable int property using XmlSerializer (will not cover in this answer).
public class Accounts
{
public Accounts()
{
Items = new List<Account>();
}
[XmlArrayItem(ElementName= "account",
Type = typeof(Account))]
[XmlArray(ElementName="items")]
public List<Account> Items { get; set; }
}
[XmlRoot(ElementName="account")]
public class Account
{
[XmlIgnore]
public int? Klasnummer { get; set; }
[XmlIgnore]
public int? Internnummer { get; set; }
[XmlElement(ElementName="voornaam")]
public string Voornaam { get; set; }
[XmlElement(ElementName="naam")]
public string Naam { get; set; }
[XmlElement(ElementName="gebruikersnaam")]
public string Gebruikersnaam { get; set; }
[XmlElement(ElementName="internnummer")]
public string InternnummerText
{
get { return (Internnummer.HasValue) ? Internnummer.ToString() : null; }
set { Internnummer = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?); }
}
[XmlElement(ElementName="klasnummer")]
public string KlasnummerText
{
get { return (Klasnummer.HasValue) ? Klasnummer.ToString() : null; }
set { Klasnummer = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?); }
}
}
Sample program

How can I regroup in a same class XmlArrayAttributes that are named differently?

I have to deserialize an XML object that is made as follows :
<programs>
<item0></item0>
<item1></item1>
...
<item200></item200>
</programs>
The fact is that the structure of each <item></item> is the same so I want to regroup all these items in a same C# class that would look like this :
public class Item{
public object prop1{get; set; }
public object prop2{get; set; }
public object prop3{get; set; }
}
Instead of this, for now I've got this structure in C# :
[XmlRoot(ElementName="programs")]
public class Programs {
[XmlElement(ElementName="item0")]
public Item0 Item0 { get; set; }
[XmlElement(ElementName="item1")]
public Item1 Item1 { get; set; }
[XmlElement(ElementName="item2")]
public Item2 Item2 { get; set; }
...
[XmlElement(ElementName="item200")]
public Item200 Item200 { get; set; }
}
If anyone could help me, I would be very grateful !
Using LINQ you can convert the XML to desired output
Say the given xml is in this format
<programs>
<item0 attribute1="0">
<property1>test1</property1>
</item0>
<item1 attribute1="1">
<property1>test2</property1>
</item1>
<item200 attribute1="2">
<property1>test3</property1>
</item200>
</programs>
Have a Item class with defined elements
public class Items
{
public string id { get; set; }
public string property1 { get; set; }
public string attribute1 { get; set; }
}
Using LINQ you can filter all items and create desired object
var xdoc = XDocument.Parse(strFile);
var result = xdoc.Descendants().Where(x=>x.Name.LocalName.StartsWith("item")).Select(y=> new Items() {
id = y.Name.LocalName.Replace("item",""),
property1 = y.Element("property1").Value,
attribute1 = y.Attribute("attribute1").Value
});

Xml Serialization for list Property doesn't work when one item in the list

<TotalRecords ItineraryCount='1' >
<Recs ItineraryNumber="1" >
<Amount>516.6</Amount>
<TravelTime>940</TravelTime>
<FSegment>
<OutProperty>
<Segment No="1">
<Name>Ronald</Name>
<City>London</City>
<Country>United Kingdom</Country>
</Segment>
<Segment No="2">
<Name>Richard</Name>
<City>
London
</City>
<Country>United Kingdom</Country>
</Segment>
</OutProperty>
</FSegment>
</Recs>
</TotalRecords >
I am serializing xml to object of TotalRecords Class. It works fine when there are more than one segment in the OutProperty but in case of one segment it doesn't serialize into list property.
I have also tried with [XmlArray("")] and [XMlArrayItem("")] but it doesn't work. Anyone have idea?
public class TotalRecords
{
public Recs recs { get; set; }
public string ItineraryCount { get; set; }
}
public partial class Recs
{
public string amountField { get; set; }
public string travelTimeField { get; set; }
public FSegment fSegmentField { get; set; }
public string itineraryNumberField { get; set; }
}
public class FSegment
{
public List<Segment> OutProperty {get;set;}
}
public class Segment
{
public string nameField { get; set; }
public string cityField { get; set; }
public string countryField { get; set; }
}
Try to use the following for your Classes and their Properties:
[DataContract]
public class Contact
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
Hacking like this helps in many cases, perhaps in your too (converting List to array):
public class FSegment
{
[XmlIgnore]
public List<Segment> OutProperty {get;set;}
[XmlArray("OutProperty");
public Segment[] _OutProperty
{
get { return OutProperty.ToArray(); }
set { OutProperty = new List<Segment>(value); }
}
}
I am not exactly sure how your provided class definition worked previously without any XML attribute/element definitions since your variable names are not the same as the XML identifiers, meaning that the serialization wouldn't populate the properties that it couldn't find a name for.
Nether the less, the main issue here is that you are trying to put a list into a normal property.
From the XML provided, OutProperty is a single sub element of FSegment and Segment is an array of sub elements of OutProperty, but in your provided code, you tried to make Segment an array sub element of FSegment.
The correct structure of the class definition should be as follows (also including the XML definitions)
[System.Xml.Serialization.XmlRoot(ElementName="TotalRecords")]
public class TotalRecords
{
[System.Xml.Serialization.XmlElement(ElementName="Recs")]
public Recs recs { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "ItineraryCount")]
public string ItineraryCount { get; set; }
}
public partial class Recs
{
[System.Xml.Serialization.XmlElement(ElementName = "Amount")]
public string amountField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "TravelTime")]
public string travelTimeField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "FSegment")]
public FSegment fSegmentField { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "ItineraryNumber")]
public string itineraryNumberField { get; set; }
}
public class FSegment
{
[System.Xml.Serialization.XmlElement(ElementName = "OutProperty")]
public SegmentList OutProperty { get; set; }
}
public class SegmentList
{
[System.Xml.Serialization.XmlElement(ElementName = "Segment")]
public List<Segment> segmentField { get; set; }
}
public class Segment
{
[System.Xml.Serialization.XmlElement(ElementName = "Name")]
public string nameField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "City")]
public string cityField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "Country")]
public string countryField { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "No")]
public int segmentNoField { get; set; }
}
Please note that in the above structure, Segment is a list object under the OutProperty object, which resides under the FSegment object.
Using this class structure to load your XML produces the (assumed) correct data in the created objects.
Using the XML definitions allows you to decouple the actual names of class properties from what they are called in the XML data. This allows you to changes the one or the other without affecting the other one, which is useful when you don't control the creation of the XML data.
If you don't want all the XML definitions in your code, change the names of the classes so that you can name your properties the same as what they are called in the XML file. That will allow you couple everything directly

Deserialize XML with multiple namespaces to objects

I´m trying to deserialize this XML to objects in C# .NET 4.5:
<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
<item id="28" parentID="19" restricted="1">
<dc:creator>Alicia Keys</dc:creator>
<dc:date>2003-01-01</dc:date>
<dc:title>Gangsta Lovin&apos; (feat. Alicia Keys)</dc:title>
</item>
</DIDL-Lite>
Code:
I´m not getting any "item" Lists. The object isn't deserialized.
MemoryStream reader = new MemmoryStream(System.Text.Encoding.Unicode.GetBytes(Result));
var ser = new XmlSerializer(typeof(DIDLLite));
DIDLLite device = (DIDLLite)ser.Deserialize(reader);
Class DIDLLite:
[XmlRoot("DIDL-Lite", Namespace = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/")]
public class DIDLLite {
DIDLLite() {
this.serviceItem = new List<ContainerItem>();
}
[System.Xml.Serialization.XmlArrayItem("item", typeof(ServiceListTypeService), IsNullable = false)]
List<ContainerItem> serviceItem = new List<ContainerItem>();
}
Class ContainerItem:
public class ContainerItem
{
[System.Xml.Serialization.XmlAttribute("id")]
public string id { get; set; }
[System.Xml.Serialization.XmlAttribute("parentID")]
public string parentID { get; set; }
[System.Xml.Serialization.XmlAttribute("restricted")]
public string restricted { get; set; }
[System.Xml.Serialization.XmlAttribute("searchable")]
public string searchable { get; set; }
public string title { get; set; }
}
You have several issues:
you define an XmlArrayItem attribute - but really, in your XML, you don't have any list of items. If you want to use an Xml array construct, you'd need to have something like this for your XML:
<DIDL-Lite .....>
<Items>
<item id="28" parentID="19" restricted="1">
......
</item>
<item id="29" parentID="19" restricted="1">
......
</item>
</Items>
</DIDL-Lite>
So you would need to have an <Items>...</Items> wrapper around your <item> elements.
You have this declaration:
[XmlArrayItem("item", typeof(ServiceListTypeService), IsNullable = false)]
but where is the ServiceListtypeService defined? I don't see any trace of it....
I simplified your code a bit - and this works just fine:
[XmlRoot("DIDL-Lite", Namespace = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/")]
public class DIDLLite
{
[XmlElement("item")]
public ContainerItem Item { get; set; }
}
public class ContainerItem
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("parentID")]
public string parentID { get; set; }
[XmlAttribute("restricted")]
public string restricted { get; set; }
[XmlAttribute("searchable")]
public string searchable { get; set; }
// you were missing these elements and their namespace
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string creator { get; set; }
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string date { get; set; }
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string title { get; set; }
}
And now, when I run your code to deserialize your XML, I do get the objects filled nicely.

Problem creating XML using c#

I am searching a batter solution for creating xml through xml serialization. What i need, i have a given format like this
<product Id="1">
<name>2 1/2 X 6 PVC NIPPLE TOE SCH 80</name>
<notes>
<note>!--note 1---</note>
<note>!--note 2--</note>
......
</notes>
</product>
what i am doing here, i created a 2 classes like this
public class product
{
[XmlElement("name")]
public string Name { get; set; }
[XmlArray("notes")]
public List<notes> ListNotes { get; set; }
}
public class notes
{
[XmlIgnore]
public string Note { get; set; }
}
when i am serializing this then i am getting xml in this formate
<product Id="1">
<name>2 1/2 X 6 PVC NIPPLE TOE SCH 80</name>
<notes>
<notes>
<note>!--note 1---</note>
<note>!--note 2--</note>
</notes>
</notes>
</product>
i don't want extra <notes>. Any batter solution to solve this problem?
Thanks
Solution
public class product
{
[XmlElement("name")]
public string Name { get; set; }
[XmlArray("notes")]
public List<notes> ListNotes { get; set; }
}
public class notes
{
[XmlText]
public string Note { get; set; }
}
product ObjProduct = new product
{
Name ="Pankaj",
notes=new List<note>()
}
foreach (var note in item.ListNote)
{
ObjProduct.notes.Add(new Highmark.BLL.Common.note { Note = EncodeTo64(note.Note) });
}
Now use this ObjProduct for serialization.
Try like this:
[XmlRoot("product")]
public class Product
{
[XmlAttribute]
public int Id { get; set; }
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("note")]
public List<Note> ListNotes { get; set; }
}
public class Note
{
[XmlText]
public string Text { get; set; }
}
class Program
{
public static void Main()
{
var p = new Product
{
Id = 1,
Name = "2 1/2 X 6 PVC NIPPLE TOE SCH 80",
ListNotes = new List<Note>
{
new Note { Text = "!--note 1---" },
new Note { Text = "!--note 2---" },
}
};
var serializer = new XmlSerializer(p.GetType());
serializer.Serialize(Console.Out, p);
}
}
And if you want to remove the namespace from the root node:
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(Console.Out, p, ns);
Try like this:
class Program
{
static void Main(string[] args)
{
var product = new Product() { Name = "PVC SCHOOL" };
product.Notes = new List<note>();
product.Notes.Add(new note() { Note = "A" });
product.Notes.Add(new note() { Note = "B" });
var serialer = new XmlSerializer(typeof(Product));
using (var stream = new StreamWriter("test.txt"))
{
serialer.Serialize(stream, product);
}
}
}
public class Product
{
[XmlElement("name")]
public string Name { get; set; }
[XmlArray("notes")]
public List<note> Notes { get; set; }
}
public class note
{
[XmlIgnore]
public string Note { get; set; }
}
This doesn't directly answer your question, but if you can't figure out this problem, you can create a Schema.xsd file, and use .NET's XSD tool to generate the proper serialization classes for you.
I've had pretty good success with that.
The obvious benefit of using a schema is the validation on XML, prior to serialization.

Categories