Deserialize List Error - c#

I have an XML and the content is
<Contracts>
<Contract EntryType="U" ID="401" GroupCode="1">
</Contract>
</Contracts>
and I have a class with a list of contracts
[XmlArray("Contracts")]
[XmlArrayItem("Contract", typeof(Contract))]
public List<Contract> Contracts { get; set; }
so when I try to Deserialize this, I got this error:
"There was an error reflecting property 'Contracts'."
Deserialization code:
XmlSerializer reader = new XmlSerializer(typeof(ContractPosting));
xml.Position = 0;
eContractXML = (Contract)reader.Deserialize(xml);
Here are the classes:
public partial class ContractPosting
{
[XmlArray("Contracts")]
[XmlArrayItem("Contract", typeof(Contract))]
public List<Contract> Contracts { get; set; }
}
public class Contract
{
[XmlAttribute(AttributeName = "ContractID")]
public System.Nullable<int> ContractID { get; set; }
[XmlAttribute(AttributeName= "PostingID")]
public string PostingID { get; set; }
public EntryTypeOptions? EntryType { get; set; }
}

Nullable types cannot be serialised as attributes.
You must either change the Contract class to not use Nullable for the XML attributes or change the XML to write these properties as an XML element.
Try this:
public class Contract {
[XmlAttribute(AttributeName = "ContractID")]
public int ContractID { get; set; }
[XmlAttribute(AttributeName= "PostingID")]
public string PostingID { get; set; }
public System.Nullable<EntryTypeOptions> EntryType { get; set; }
}
OR:
public class Contract {
public int? ContractID { get; set; }
[XmlAttribute(AttributeName= "PostingID")]
public string PostingID { get; set; }
public System.Nullable<EntryTypeOptions> EntryType { get; set; }
}

Since the root node is <Contracts>, try re-arranging your class to this:
[XmlRoot("Contracts")]
public class ContractPosting {
[XmlElement("Contract", typeof(Contract))]
public List<Contract> Contracts { get; set; }
}
When you use XmlArray and XmlArrayItem, they have to both be nested inside of something. But your current XmlArray tag is actually the root node of the XML file, so it needs to be an XmlRoot.
Demo: http://ideone.com/jBSwGx

thanks, the problem was the Nullable type and I solved in this way
[XmlIgnore]
public System.Nullable<int> ContractID { get; set; }
[XmlAttribute("ContractID")]
public int ContractIDxml {
get { return ContractID ?? 00; }
set { ContractID = value; }
}

Related

Deserialize XML element returning null value

I have some data in an XML file. I am trying to deserialize the XML to some classes I have created.
I have been able to deserialize all the attributes of the PointCode and CodeAttributes elements. However, I can't seem to get the TextListValue attribute of the textList element.
The textList element returns a null value.
I am using c# and using System.Xml.Serialization
[XmlRoot("PointCode")]
public class PointCode
{
[XmlAttribute("codeLinework")]
public string codeLinework { get; set; }
[XmlElement("CodeAttributes")]
public List<CodeAttributes> codeAttributes { get; set; }
}
[XmlRoot("CodeAttributes")]
public class CodeAttributes
{
[XmlAttribute("attributeName")]
public string attributeName { get; set; }
[XmlAttribute("attributeType")]
public string attributeType { get; set; }
[XmlAttribute("valueType")]
public string valueType { get; set; }
[XmlAttribute("valueRegion")]
public string valueRegion { get; set; }
[XmlElement("text")]
public Text text { get; set; }
}
[XmlRoot("text")]
public class Text
{
[XmlElement("textChoiceList")]
public TextChoiceList textChoiceList { get; }
}
[XmlRoot("textChoiceList")]
public class TextChoiceList
{
[XmlElement("textList")]
public List<TextList> textList { get; set; }
}
[XmlRoot("textList")]
public class TextList
{
[XmlAttribute("textListValue")]
public string textListValue { get; set; }
}
Extract of the XML file I am deserializing.
<Code codeName="KERB" codeDesc="Kerbs" codeType="Point">
<PointCode codeLinework="open line">
<CodeAttributes attributeName="String" attributeType="Normal" valueType="Integer" valueRegion="None">
<integer />
</CodeAttributes>
<CodeAttributes attributeName="Type" attributeType="Normal" valueType="Text" valueRegion="ChoiceList">
<text>
<textChoiceList>
<textList textListValue="Square Kerb" />
<textList textListValue="Roll Kerb" />
</textChoiceList>
</text>
</CodeAttributes>
The missing setter for textChoiceList property in the Text class that leads to the text was null as the only property in the class is unable to set value.
So adding the missing setter to the property will solve the issue.
[XmlRoot("text")]
public class Text
{
[XmlElement("textChoiceList")]
public TextChoiceList textChoiceList { get; set; }
}
Sample .NET Fiddle

Create a custom XML serializer in c# to help the xml doc get converted to object

I have a xml format in following format mentioned below:-
<JobRunnerPluginStaus PluginName="JobRun">
<JobstepStatus>
<JobStatus StepNumber="1" StepStatus="Done"/>
<JobStatus StepNumber="2" StepStatus="Started" />
</JobstepStatus>
</JobRunnerPluginStaus>
I want to get it converted to following class object using Generics and Reflection.
I want to convert the attributes to simple type(PluginName) and the nested property to a list object(JobstepStatus).
public class JobRunnerPluginStaus
{
public List<JobStatus> JobstepStatus { get; set; }
public string PluginName { get; set; }
}
public class JobStatus
{
public int StepNumber { get; set; }
public string StepStatus { get; set; }
}
I mostly use sites like: https://xmltocsharp.azurewebsites.net/
to do the dirty work for me.
Below is how your class hierarchy would look like:
[XmlRoot(ElementName="JobStatus")]
public class JobStatus {
[XmlAttribute(AttributeName="StepNumber")]
public string StepNumber { get; set; }
[XmlAttribute(AttributeName="StepStatus")]
public string StepStatus { get; set; }
}
[XmlRoot(ElementName="JobstepStatus")]
public class JobstepStatus {
[XmlElement(ElementName="JobStatus")]
public List<JobStatus> JobStatus { get; set; }
}
[XmlRoot(ElementName="JobRunnerPluginStaus")]
public class JobRunnerPluginStaus {
[XmlElement(ElementName="JobstepStatus")]
public JobstepStatus JobstepStatus { get; set; }
[XmlAttribute(AttributeName="PluginName")]
public string PluginName { get; set; }
}

Why an XML string cannot be deserialized due to prefixes in root elements?

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.

JSon.NET deserialising subitems

For deserialisation I usually use an object with the same property names as found in the JSon and JsonConvert.DeserializeObject<Des>(jsonstring).
But now I came across this:
{
"id": 0815,
"name": "whatever"
"addedInfo": {
"thisisinteresting": 4711,
"id_str": "2336"
}
}
How can I tell JSon.Net to pull the 'thisisinteresting' part of the sub category into a class like:
class Des
{
int id;
string name;
int thisisinteresting;
}
The trivial way would be to actually model your class to the JSON structure:
public class AddedInfo
{
public int thisisinteresting { get; set; }
public string id_str { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
}
Then add a property to the RootObject to emit the property:
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
[JsonIgnore]
public int thisisinteresting { get { return addedInfo.thisisinteresting; } }
}
There are alternatives like creating a custom serializer or using JObject and deserialize the structure yourself, but I won't go into that. If you need to parse the JSON anyway, the price to deserialize it entirely is small.

C# Xml deserialization Element in object property

I'm consuming a Web API, and i get an xml result:
<tarification cle="XXXX">
<gamme reference="refX">
<tarif formula="F100">44.84</tarif>
<tarif formula="F125">47.63</tarif>
<tarif formula="F150">57.34</tarif>
<tarif formula="F200">67.95</tarif>
<option name="indiv-acc">0.5</option>
<option name="rap-cor">6.06</option>
</gamme>
</tarification>
I use this model to deserialize :
[XmlRoot(ElementName = "tarification", Namespace="")]
public class TarifResponse
{
[XmlElement(ElementName = "gamme")]
public Gamme Gamme { get; set; }
}
public class Gamme
{
[XmlAttribute(AttributeName="reference")]
public string Name { get; set; }
[XmlElement(ElementName = "tarif")]
public Formula[] Formulas { get; set; }
[XmlElement(ElementName = "option")]
public Option[] Options { get; set; }
}
public class Formula
{
[XmlAttribute(AttributeName="formula")]
public string Name { get; set; }
// WRONG ATTRIBUTE.. but witch one ?
[XmlElement]
public Decimal Amount { get; set; }
}
public class Option
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
// WRONG ATTRIBUTE.. but witch one ?
[XmlElement]
public Decimal Amount { get; set; }
}
The TarifResponse object is created, all fields are filled, except the two amounts fields. I expect this is because the right xml should be:
<amount>5.5</amount>
inside tarif or option elements..
Is this format is deserializable ?
Is there a way to this with attribute ?
Is this even an acceptable xml format ?
thank you
The [XmlText] attribute will get the inner text of the node. You might need to use [XmlText(Type=typeof(decimal))] to get the number parsed.
public class Option
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlText]
public Decimal Amount { get; set; }
}

Categories

Resources