i have the following xml structure im trying to deserialize into a c# object:
<leagueTable>
<competition>Calor League Division One Central</competition>
<description>League Table</description>
<team>
<position>1</position>
<name>Barton Rovers</name>
<played>13</played>
<won>8</won>
<drawn>3</drawn>
<lost>2</lost>
<for>25</for>
<against>16</against>
<goalDifference>+9</goalDifference>
<points>27</points>
</team>
<team>
......
</team>
<team>
.....
</team>
</leagueTable>
and have created two classes for them to be deserialized into which are as follows
public class leagueTable
{
public string competition { get; set; }
public string description { get; set; }
[XmlElement("team")]
public List<team> TeamsList { get; set; }
}
and
[Serializable()]
public class team
{
public int position { get; set; }
public String name { get; set; }
public int played { get; set; }
public int won { get; set; }
public int drawn { get; set; }
public int lost { get; set; }
[XmlElement("for")]
public int goalsfor { get; set; }
[XmlElement("against")]
public int goalsagainst { get; set; }
[XmlElement("goalDifference")]
public int goaldifference { get; set; }
public int points { get; set; }
}
What i cant seem to figure out is how to get the teams deserialized into a list object. When the deserialization happens the competition and description properties are populated, however the teamslist list object is null. i have tried a number of different ways to create the property but each either fail or just stay as null. I have followed a number of different posts on here and on the web but no matter what i try it still fails to be populated.
For completeness this is the deserialisation code, edited to show xml setting
XmlSerializer serializer = new XmlSerializer(typeof(leagueTable));
leagueTable league = null;
Stream xmldoc = response.GetResponseStream();
XmlReaderSettings xmlsettings = new XmlReaderSettings();
xmlsettings.DtdProcessing = DtdProcessing.Parse;
using (XmlReader reader = XmlReader.Create(xmldoc, xmlsettings))
{
league = (leagueTable)serializer.Deserialize(reader);
}
Related
I am having some difficulties figuring out how to correctly structure my classes to mirror the XML that I am attempting to deserialize. Most elements are coming through, but for example, in the XML below the UOMs object is not being deserialized.
Example XML:
<Items xmlns="http://www.manh.com/ILSNET/Interface" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Item>
<Desc>Desc Field Example Value</Desc>
<Item>PE0000009790</Item>
<ItemCategories>
<Action>SAVE</Action>
<Category1>COMPONENT</Category1>
<Category2>Category2ExampleValue</Category2>
</ItemCategories>
<ItemClass>
<Action>SAVE</Action>
<ItemClass>Example ItemClass</ItemClass>
</ItemClass>
<UOMS>
<UOM>
<Action>SAVE</Action>
<ConvQty>1</ConvQty>
<DimensionUm>IN</DimensionUm>
<Height>0.0</Height>
<Length>0.0</Length>
<QtyUm>EA</QtyUm>
<Sequence>1</Sequence>
<Weight>0</Weight>
<WeightUm>LB</WeightUm>
<Width>0.0</Width>
</UOM>
</UOMS>
</Item>
</Items>
I am using basic XML deserialization code, which works well but just providing for background:
using (FileStream fileStream = new FileStream(Filename, FileMode.Open))
{
this.CreatedObjects = (ItemList)serializer.Deserialize(fileStream);
}
The first class is below:
[XmlRoot(ElementName = "Items", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemList
{
[XmlElement("Item")]
public Item[] Items { get; set; }
}
public class Item
{
[XmlElement("ItemCategories")]
public ItemCategory[] Categories { get; set; }
[XmlElement("ItemClass")]
public ItemClass[] Classes { get; set; }
[XmlElement("UOMS")]
public ItemUOMS UOMs { get; set; }
[XmlElement("Desc")]
public string Description { get; set; }
[XmlElement("Item")]
public string Id { get; set; }
}
The second class, which I am struggling to populate, is below (this class is a member of the Item class shown above:
[XmlRoot(ElementName = "UOMS", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemUOMS
{
[XmlElement("UOM")]
public ItemUOM[] UOM { get; set; }
}
[XmlRoot(ElementName = "UOM", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemUOM
{
[XmlElement("Action")]
public string Action { get; }
[XmlElement("DimensionUm")]
public string DimensionUnit { get; }
[XmlElement]
public decimal Height { get; }
[XmlElement]
public decimal Length { get; }
[XmlElement("QtyUm")]
public string QtyUnit { get; }
[XmlElement("ConvQty")]
public decimal Quantity { get; }
[XmlElement]
public int Sequence { get; }
[XmlElement]
public decimal Weight { get; }
[XmlElement("WeightUm")]
public string WeightUnit { get; }
[XmlElement]
public decimal Width { get; }
}
Unfortunately, I don't get an error, but instead the UOMs objects are just default objects without any values being set. I tried to reference some XML to C# Class tools online that are supposed to output C# classes for you based on XML provided to the tool, but their classes didn't seem to solve the issue for me either. I attempted to use [XmlArray] / [XmlArrayItem], but neither had any effect either.
If you need any more information from me, please let me know. Thanks for any assistance/guidance you are able to provide in advance.
I have the XML below:
<y:input xmlns:y='http://www.blahblah.com/engine/42'>
<y:datas>
<y:instance yclass='ReportPeriod' yid="report">
<language yid='en'/>
<threshold>0.6</threshold>
<typePeriod>predefinedPeriod</typePeriod>
<interval>month</interval>
<valuePeriod>April</valuePeriod>
<fund yclass="Fund">
<name>K</name>
<indexName>CAC40</indexName>
</fund>
</y:instance>
</y:datas>
</y:input>
That I am trying to deserialize to
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
public string Y { get; set; }
}
However, when deserializing the XML above:
public static class Program
{
public static void Main(params string[] args)
{
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StringReader(File.ReadAllText("file.xml")))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
var instance = (Input)serializer.Deserialize(stringReader);
}
}
}
}
I get an error due to the y prefix...
There is an error in XML document (1, 1). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
Reading some posts like that one: https://stackoverflow.com/a/36163079/4636721 it seems that there is maybe a bug with the XmlSerializer.
The cause of the exception is that you are passing stringReader rather than xmlReader to serializer.Deserialize(). You should be passing the XML reader instead:
Input instance = null;
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StreamReader("file.xml"))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
instance = (Input)serializer.Deserialize(xmlReader);
}
}
(Apparently XmlReader.Create(stringReader) advances the text reader a bit, so if you later attempt to read from the stringReader directly, it has been moved past the root element.)
You also have some errors in your data model. It should look like:
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance")]
[XmlType(Namespace = "")] // Add this
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
//Remove This
//[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
//public string Y { get; set; }
}
// Add this
[XmlRoot(ElementName="language")]
public class Language
{
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
Notes:
xmlns:y='http://www.blahblah.com/engine/42' is an XML namespace declaration and thus should not be mapped to a member in the data model.
The child elements of <y:instance ...> are not in any namespace. Unless the namespace of the child elements is specified by attributes somehow, XmlSerializer will assume that they should be in the same namespace as the containing element, here http://www.blahblah.com/engine/42".
Thus it is necessary to add [XmlType(Namespace = "")] to Instance to indicate the correct namespace for all child elements created from Instance. (Another option would be to add [XmlElement(Form = XmlSchemaForm.Unqualified)] to each member, but I think it is easier to set a single attribute on the type.)
A definition for Language is not included in your question, so I included one.
It will be more efficient to deserialize directly from your file using a StreamReader than to read first into a string, then deserialize from the string using a StringReader.
Working sample fiddle here.
First, i tried on the internet different ways, but i didn't got what i want. i have viewmodel class with the following properties;
public class UserEntitySubmissionsReportViewModel
{
public UserEntitySubmissionsReportViewModel()
{
Submissions = new FinalUserEntitiesAssignmentViewModel();
}
public int Id { get; set; }
public int Status { get; set; }
public DateTime SubmissionDate { get; set; }
public int UserEntityAssignmentId { get; set; }
public FinalUserEntitiesAssignmentViewModel Submissions { get; set; }
}
and the nested class FinalUserEntitiesAssignmentViewModel whcih is;
[Serializable]
public class FinalUserEntitiesAssignmentViewModel
{
public FinalUserEntitiesAssignmentViewModel()
{
ProjectInformation = new ProjectInformationViewModel();
MilestoneInformation = new MilestoneInformationViewModel();
ActivityListInformation = new ActivityListInformationViewModel();
ActivityInformation = new ActivityInformationViewModel();
SubActivityInformation = new List<SubActivityInformationViewModel>();
}
[XmlElement(ElementName = "ProjectInformation")]
public ProjectInformationViewModel ProjectInformation { get; set; }
[XmlElement(ElementName = "MilestoneInformation")]
public MilestoneInformationViewModel MilestoneInformation { get; set; }
[XmlElement(ElementName = "ActivityListInformation")]
public ActivityListInformationViewModel ActivityListInformation { get; set; }
[XmlElement(ElementName = "ActivityInformation")]
public ActivityInformationViewModel ActivityInformation { get; set; }
[XmlElement(ElementName = "SubActivityInformation")]
public List<SubActivityInformationViewModel> SubActivityInformation { get; set; }
}
[Serializable]
public class ProjectInformationViewModel
{
[XmlElement(ElementName = "Id")]
public int Id { get; set; }
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
public string Description { get; set; }
}
When i serialize this, i only get the 1 property i.e Id for nested class.
var obj = new UserEntitySubmissionsReportViewModel();
var writer = new System.Xml.Serialization.XmlSerializer(typeof(UserEntitySubmissionsReportViewModel));
System.IO.StreamWriter file = new System.IO.StreamWriter(Server.MapPath("~/App_Data/UserEntitySubmissionsReportViewModel.xml"));
writer.Serialize(file, obj);
file.Close();
The result i get is;
<?xml version="1.0" encoding="utf-8"?>
<UserEntitySubmissionsReportViewModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>0</Id>
<Status>0</Status>
<SubmissionDate>0001-01-01T00:00:00</SubmissionDate>
<UserEntityAssignmentId>0</UserEntityAssignmentId>
<Submissions>
<ProjectInformation>
<Id>0</Id>
</ProjectInformation>
<MilestoneInformation>
<Id>0</Id>
</MilestoneInformation>
<ActivityListInformation>
<Id>0</Id>
</ActivityListInformation>
<ActivityInformation>
<Id>0</Id>
<Attributes />
<Tools />
</ActivityInformation>
</Submissions>
</UserEntitySubmissionsReportViewModel>
As you can see, i am not able to serialize other properties. Similarly i have nest collection too. How can i serialize nested properties using C# ?
I think that when serializing XML that you need to define a default constructor for your classes. Try adding a construction for your ProjectInformationViewModel class.
public class ProjectInformationViewModel
{
// Default Constructor
public ProjectInformationViewModel()
{
}
}
I have searched alot to find a solution, but couldn't come up with one after all.
So I hope that someone here can help me out.
I have an xml structure:
<?xml version="1.0" encoding="utf-8" ?>
<ReleaseNoteConfig>
<ReleaseNoteProperties>
<TemplateLocation>Path to the template location</TemplateLocation>
<TemplateFileName>wordfile.docx</TemplateFileName>
<OutLocation>Path to the outlocation</OutLocation>
<ReleaseName>Stackoverflow</ReleaseName>
<ChangeOrder>1234</ChangeOrder>
<ChangesHeader>Change ID</ChangesHeader>
<ProblemsHeader>Problem ID</ProblemsHeader>
<Environment>Test</Environment>
</ReleaseNoteProperties>
<DocProperties>
<AuthorReleaseNote>Vincent Verweij</AuthorReleaseNote>
<CustomerResponsible>Customer name</CustomerResponsible>
<PlannedTestInstallDate>-</PlannedTestInstallDate>
<PlannedAccInstallDate>30/04/2014</PlannedAccInstallDate>
<PlannedProdInstallDate>07/05/2014</PlannedProdInstallDate>
<TestInstallDate>-</TestInstallDate>
<AccInstallDate>-</AccInstallDate>
<ProdInstallDate>-</ProdInstallDate>
<TestInstaller>-</TestInstaller>
<AccInstaller>-</AccInstaller>
<ProdInstaller>-</ProdInstaller>
<UrlProjectPortal>Url to project site</UrlProjectPortal>
</DocProperties>
<SpecialProperties>
<Customer_x0020_Name>Customer company name</Customer_x0020_Name>
<Customer_x0020_Reference>No reference</Customer_x0020_Reference>
<Approval_x0020_Date>15/04/2014</Approval_x0020_Date>
<MyFerranti_x0020_Reference>1234</MyFerranti_x0020_Reference>
<Project_x0020_ID>Proj000001</Project_x0020_ID>
</SpecialProperties>
</ReleaseNoteConfig>
I have used an online generator to create a json from my XML and then json2csharp to obtain the classes that I need. So eventually it came up with this c# code:
public class ReleaseNoteProperties
{
public string TemplateLocation { get; set; }
public string TemplateFileName { get; set; }
public string OutLocation { get; set; }
public string ReleaseName { get; set; }
public string ChangeOrder { get; set; }
public string ChangesHeader { get; set; }
public string ProblemsHeader { get; set; }
public string Environment { get; set; }
}
public class DocProperties
{
public string AuthorReleaseNote { get; set; }
public string CustomerResponsible { get; set; }
public string PlannedTestInstallDate { get; set; }
public string PlannedAccInstallDate { get; set; }
public string PlannedProdInstallDate { get; set; }
public string TestInstallDate { get; set; }
public string AccInstallDate { get; set; }
public string ProdInstallDate { get; set; }
public string TestInstaller { get; set; }
public string AccInstaller { get; set; }
public string ProdInstaller { get; set; }
public string UrlProjectPortal { get; set; }
}
public class SpecialProperties
{
public string Customer_x0020_Name { get; set; }
public string Customer_x0020_Reference { get; set; }
public string Approval_x0020_Date { get; set; }
public string MyFerranti_x0020_Reference { get; set; }
public string Project_x0020_ID { get; set; }
}
public class ReleaseNoteConfig
{
public ReleaseNoteProperties ReleaseNoteProperties { get; set; }
public DocProperties DocProperties { get; set; }
public SpecialProperties SpecialProperties { get; set; }
}
This code will read my XML file and deserializes the XML to the objects.
public ReleaseNoteConfig ReadXmlToObject(string xmlPath)
{
StringReader stream = null;
XmlTextReader reader = null;
var xDocument = XDocument.Load(xmlPath);
string xml = xDocument.ToString();
try
{
// Serialise the object
XmlSerializer serializer = new XmlSerializer(typeof(ReleaseNoteConfig));
// Read the XML data
stream = new StringReader(xml);
// Create a reader
reader = new XmlTextReader(stream);
// Convert reader to an object
return (ReleaseNoteConfig)serializer.Deserialize(reader);
}
catch
{
return null;
}
finally
{
if (stream != null) stream.Close();
if (reader != null) reader.Close();
}
}
Now the problem; when I debug in Visual Studio, I see that two of the three objects are filled. Here is a screenshot that I took from the debugger:
http://www.smartus.be/xmlProblem/debugger.png
As you can see, DocProperties and ReleaseNoteProperties are filled correctly but SpecialProperties has all null values. First I thought it had something to do with the underscores, but when I added an underscore to a property in DocProperties it was also filled correctly.
I also tried adding the attributes above the properties like XmlElement, XmlRoot etc. but that didn't help either.
I also double checked for typos but it seems that there are none...
Hopefully you guys can help me out on this one.
Thanks in advance.
Vincent
Change your SpecialProperties class to this:
public class SpecialProperties
{
[XmlElement("Customer Name")]
public string CustomerName { get; set; }
[XmlElement("Customer Reference")]
public string CustomerReference { get; set; }
[XmlElement("Approval Date")]
public string ApprovalDate { get; set; }
[XmlElement("MyFerranti Reference")]
public string MyFerrantiReference { get; set; }
[XmlElement("Project ID")]
public string ProjectID { get; set; }
}
You can change the property names if you want, the important parts are the XmlElement attributes.
I have checked your code.
Can you Remove the underscores in the "Customer_x0020_Name" ? at the same time you need to change the property names in the class.
Its going to work.
Will this suggestions helps you?
i have checked it .. its working.
I am not sure , whether the tag name with underscore is legal or not.
Mark the answer , if it has solved you question
I have the following code but unable to deserialize, can you see where I'm going wrong? It only catch the first record on the first array item.
[XmlRootAttribute("Booking")]
public class Reservation
{
[XmlArray("Included")]
[XmlArrayItem("Meals")]
public Meals[] Food { get; set; }
[XmlArrayItem("Drinks")]
public Drinks[] Drink { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Here's the associated XML
<?xml version="1.0" standalone="yes"?>
<Booking>
<Included>
<Meals
Breakfast="True"
Lunch="True"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="False"
Wine="False">
</Drinks>
</Included>
<Included>
<Meals
Breakfast="True"
Lunch="False"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="True"
Wine="True">
</Drinks>
</Included>
</Booking>
I'm a bit of a newbie so any help would be great, unfortunately after trawling through the many exmaples you already have online I still haven't been able to figure this out.
Use the following example and apply this syntax in ListItem array,
[XmlType("device_list")]
[Serializable]
public class DeviceList {
[XmlAttribute]
public string type { get; set; }
[XmlElement( "item" )]
public ListItem[] items { get; set; }
}
following link contains all the syntax & attributes
http://msdn.microsoft.com/en-us/library/2baksw0z.aspx
I see no obvious way your class structure could be matched to the XML document. The underlying organizations seem to be quite different.
The following class hierarchy could be easily deserialized from the XML document you provide (assuming your document covers the general case) :
[Serializable]
[XmlRoot("Booking")]
public class Booking : List<Included>
{
}
[Serializable]
public class Included
{
public Meals Meals { get; set; }
public Drinks Drinks { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Then, deserialization code would be : (serializedObject is the string containing your serialized object)
XmlSerializer ser = new XmlSerializer(typeof (string));
XmlReader reader = XmlTextReader.Create(new StringReader(serializedObject));
var myBooking = ser.Deserialize(reader) as Booking;