XmlSerializer doesn't fill in values - c#

I created classes from a DTD (over XSD and xsd.exe) for my C# project, so I could easily deserialize them into a model class in my code.
This is roughly how I do it:
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.DtdProcessing = DtdProcessing.Parse;
XmlReader reader = XmlReader.Create(tipsfile.FullName, readerSettings);
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "Tips";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(Tips), xRoot);
Tips tips = (Tips)serializer.Deserialize(reader);
reader.Close();
But, upon inspection of tips, I see that it holds no values at all from the original XML file. Also, I tried setting a breakpoint on the set-Body of a property of Tips, and it is never reached, although I know for sure that it has a value in the original XML file.
Why is the file not correctly deserialized into the class? Is something missing in my code?
Edit: Here is the Tips.cs file, which was auto-generated from the XSD
using System.Xml.Serialization;
namespace MyNs.Model
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/caravan_1")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)]
public partial class Tips
{
private Chapter[] chapterField;
[System.Xml.Serialization.XmlElementAttribute("Chapter")]
public Chapter[] Chapter
{
get
{
return this.chapterField;
}
set
{
this.chapterField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/caravan_1")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)]
public partial class Chapter
{
private string headingField;
private CarType[] carTypesField;
private Section[] sectionField;
private string countryField;
private string languageField;
public string Heading
{
get
{
return this.headingField;
}
set
{
this.headingField = value;
}
}
[System.Xml.Serialization.XmlArrayItemAttribute("CarType", IsNullable = false)]
public CarType[] CarTypes
{
get
{
return this.carTypesField;
}
set
{
this.carTypesField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute("Section")]
public Section[] Section
{
get
{
return this.sectionField;
}
set
{
this.sectionField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public string Country
{
get
{
return this.countryField;
}
set
{
this.countryField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public string Language
{
get
{
return this.languageField;
}
set
{
this.languageField = value;
}
}
}
[... and so on ...]
And a sample XML file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Tips SYSTEM "caravan_1.dtd">
<Tips>
<Chapter Country="dafghagt" Language="de">
<Heading>fgagasgargaergarg</Heading>
<Section id="1">
<Heading>afdhwr6u5taehtaqh5</Heading>
<SubSection id="1">
<Heading>46k46kw6jhadfgadfha</Heading>
<Table>
<Row id="1">
<Heading>sgjsfgjsgfh443q572q356</Heading>
<Items>
<Item car="motor1" id="1">
<BodyText color="red">130*</BodyText>
<Subscript>3</Subscript>
</Item>
</Items>
</Row>
</Table>
</SubSection>
</Section>
</Chapter>
</Tips>

StreamReader sw = new StreamReader(fileName, false);
XmlTextReader xmlw = new XmlTextReader(sw);
XmlSerializer writer = new XmlSerializer(
type,
GetOverrides(),
extraTypes,
null,
null);
object o = writer.Deserialize(xmlw);
As per my comment, get overrides is just a method that contains something similar to your xml root attribute, I can show you this too if necessary
EDIT:
an example of extra types
public Type[] GetTypes()
{
return new Type[] { typeof(Class1), typeof(Class2)};
}
EDIT2: get overrides returns (Note this is untested)
XmlAttributes attribs = new XmlAttributes();
//attribs.XmlRoot - can edit root here (instead of xmlrootattribute)
attribs.XmlElements.Add(myAttribute);
XmlAttributeOverrides myOverride = new XmlAttributeOverrides();
myOverride.Add(typeof(Tips), "Tips", attribs);
return myOverride

Your object may not be identical to the xml model. In that case, you need map the properties of your class to the xml fields. I am giving you a quick example I had in one of my projects which may give you bit more information.
namespace DatabaseModel
{
[Description("Represents the selected nodes in the Coverage pane")]
[Serializable()]
[XmlRootAttribute("XmlCoverage", Namespace = "GISManager", IsNullable = false)]
public class TXmlCoverage : IXmlPolygon
{
[XmlArray(ElementName = "sbets"), XmlArrayItem(ElementName = "sbet")]
public List SbetsSelected { get; set; }
[XmlArray(ElementName = "sdcs"), XmlArrayItem(ElementName = "sdc")]
public List SdcsSelected { get; set; }
[XmlElementAttribute(ElementName = "area")]
public Boolean IsAreaSelected { get; set; }
[XmlElementAttribute(ElementName = "fpath")]
public Boolean IsFlightPathSelected { get; set; }
[XmlElementAttribute(ElementName = "fpoly")]
public Boolean IsFlightPolySelected { get; set; }
[XmlElementAttribute(ElementName = "mpoly")]
public Boolean IsMinePolySelected { get; set; }
[XmlElementAttribute(ElementName = "bldg")]
public Boolean IsBuildingsSelected { get; set; }
[XmlElementAttribute(ElementName = "hgt")]
public Boolean IsHeightSelected { get; set; }
[XmlIgnore()]
public Boolean ArePolygonsSelected { get { return IsMinePolySelected && IsBuildingsSelected && IsHeightSelected; } }
public TXmlCoverage()
{
SbetsSelected = new List<String>();
SdcsSelected = new List<String>();
IsAreaSelected = false;
IsFlightPathSelected = false;
IsFlightPolySelected = false;
}
}
}

So it turns out the problem is namespaces. Because my XML has no root namespace:
<Tips>
but the definition of my Model contained one:
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)]
the Serializer didn't match any elements together. When removing the namespace attribute, it worked fine.
So now, I reworked the complete model and excluded any attributes that were not absolutely necessary (as it turns out, all but one were), so now every Property has just one Attribute: XmlElement and consorts.
using System.Xml.Serialization;
namespace MyNs.Model
{
[XmlRoot("Tips")]
public partial class Tips
{
[XmlElement("Chapter")]
public Chapter[] Chapter { get; set; }
}
[XmlRoot("Chapter")]
public partial class Chapter
{
[XmlElement("Heading")]
public string Heading { get; set; }
[XmlElement("CarType")]
public CarType[] CarTypes { get; set; }
[XmlElement("Section")]
public Section[] Section { get; set; }
[XmlAttribute("Country")]
public string Country { get; set; }
[XmlAttribute("Language")]
public string Language { get; set; }
}
[... and so on ...]
With a simple deserialization it works just fine now:
XmlReaderSettings readerSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse };
XmlSerializer serializer = new XmlSerializer(typeof(Tips));
using (XmlReader reader = XmlReader.Create(fromXmlFile.FullName, readerSettings))
{
Tips tips = (Tips)serializer.Deserialize(reader);
return tips;
}

Related

During C# deserialization, getting System.InvalidOperationException: < xmlns=''> was not expected

I'm new to XMLdeserialization. I used xsd.exe to generate object classes for performing a deserialization on an existing XML file. When I run my solution below, I get the error
System.InvalidOperationException: < xmlns=''> was not expected
on the s = (NewDataSet)xs.Deserialize(sr) call. I looked this error up on Stack Overflow, and everyone says it's in the XMLRootAttribute line.
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
How can I correct this line? Or where can I find some documentation that explains how to correct it?
Also, why doesn't xsd.exe generate the correct XmlRootAttribute line in the first place? Am I invoking this utility wrong? Or are there some situations the xsd.exe utility can't handle?
public class Program
{
static void Main(string[] args)
{
SortedSet<string> symbolsEstablished = new SortedSet<string>();
GetXmlDataSet("Expt 2buy.xml", ref symbolsEstablished);
}
public static void GetXmlDataSet(string fileName, ref SortedSet<string> symbols)
{
XmlSerializer xs = new XmlSerializer(typeof(NewDataSet));
StreamReader sr = new StreamReader(#"C:\Users\mehl\AppData\Roaming\Fidelity Investments\WealthLabPro\1.0.0.0\Data\DataSets\" + fileName);
NewDataSet s = (NewDataSet)xs.Deserialize(sr);
Console.WriteLine(s.Items[0].DSString);
sr.Close();
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class DataSet
{
private string nameField;
private string scaleField;
private string barIntervalField;
private string dSStringField;
private string providerNameField;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Name
{
get { return this.nameField; }
set { this.nameField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Scale
{
get { return this.scaleField; }
set { this.scaleField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string BarInterval
{
get { return this.barIntervalField; }
set { this.barIntervalField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string DSString
{
get { return this.dSStringField; }
set { this.dSStringField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string ProviderName
{
get { return this.providerNameField; }
set { this.providerNameField = value; }
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class NewDataSet
{
private DataSet[] itemsField;
[System.Xml.Serialization.XmlElementAttribute("DataSet")]
public DataSet[] Items
{
get { return this.itemsField; }
set { this.itemsField = value; }
}
}
}
The entire above code segment is wrapped in a screener2wl namespace.
And here's the XML file I'm trying to deserialize:
<?xml version="1.0"?>
<DataSet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>Expt 2buy</Name>
<Scale>Daily</Scale>
<BarInterval>0</BarInterval>
<DSString>AAL,AFSI,BEN,BIG,BLKB,CDK,COHR,CRUS,EGP,EPE,ETH,FB,HUM,LSTR,MDP,MSI,NYT,TAST,TER,TSO,TXN,UTHR,VASC,VLO,WRI,</DSString>
<ProviderName>FidelityStaticProvider</ProviderName>
</DataSet>
Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
DataSet ds = doc.Descendants("DataSet").Select(x => new DataSet() {
nameField = (string)x.Element("Name"),
scaleField = (string)x.Element("Scale"),
barIntervalField = (string)x.Element("BarInterval"),
dSStringField = (string)x.Element("DSString"),
providerNameField = (string)x.Element("ProviderName")
}).FirstOrDefault();
}
}
public partial class DataSet
{
public string nameField { get; set; }
public string scaleField { get; set; }
public string barIntervalField { get; set; }
public string dSStringField { get; set; }
public string providerNameField { get; set; }
}
}
I got to thinking ... isn't it odd xsd.exe would provide a code generated solution that defines two independent XmlRootAttribute nodes? Can an XML file even have two Root Nodes? Maybe the solutions xsd.exe generates shouldn't be taken too literally. :-)
So after editing its solution, and removing one part with a second XmlRootAttribute defined, I got the solution below, which works.
namespace screener2wl
{
public class Program
{
static void Main(string[] args)
{
SortedSet<string> symbolsEstablished = new SortedSet<string>();
GetXmlDataSet("Expt 2buy.xml", ref symbolsEstablished);
}
public static void GetXmlDataSet(string fileName, ref SortedSet<string> symbols)
{
XmlSerializer xs = new XmlSerializer(typeof(DataSet));
StreamReader sr = new StreamReader(#"C:\Users\mehl\AppData\Roaming\Fidelity Investments\WealthLabPro\1.0.0.0\Data\DataSets\" + fileName);
DataSet s = (DataSet)xs.Deserialize(sr);
Console.WriteLine(s.DSString);
sr.Close();
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(IsNullable = false)]
public class DataSet
{
private string nameField;
private string scaleField;
private string barIntervalField;
private string dSStringField;
private string providerNameField;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Name
{
get { return this.nameField; }
set { this.nameField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Scale
{
get { return this.scaleField; }
set { this.scaleField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string BarInterval
{
get { return this.barIntervalField; }
set { this.barIntervalField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string DSString
{
get { return this.dSStringField; }
set { this.dSStringField = value; }
}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string ProviderName
{
get { return this.providerNameField; }
set { this.providerNameField = value; }
}
}
}
}
Bottom line, use the code solutions xsd.exe generates from your XML data file as a guide, not a truth. It's a great tool, but needs to be used with a grain of salt. ... welcome your comments on my XMLdeserialization problem.

C# - XML serialization: omitting a certain element in my XML output

I have a weird XML setup here: I need to interface with a third-party and their XML layout that they're using is beyond my control - no chance to changing anything...
In the scope of a larger XML, I find myself needing to serialize (and later also deserialize) a list of items (for a mobile device) which are defined as having a Type and a Number property (both strings). So this would be something like:
public class SerialNumber
{
public string Type { get; set; }
public string Number { get; set; }
}
And this would normally serialize a List<SerialNumber> SerialNumbers as
<SerialNumbers>
<SerialNumber>
<Type>SN</Type>
<Number>CBS583ABC123</Number>
</SerialNumber>
<SerialNumber>
<Type>IMEI</Type>
<Number>35-924106-659945-4</Number>
</SerialNumber>
</SerialNumbers>
However, in my case, I need to send this XML:
<SerialNumbers>
<Type>SN</Type>
<Number>CBS583ABC123</Number>
<Type>IMEI</Type>
<Number>35-924106-659945-4</Number>
</SerialNumbers>
So basically, the list elements need to be omitted - I just need a container <SerialNumbers> and then for each entry in the list, I only need to serialize out the Type and Number subelements.
How can I do this easily in .NET with the XmlSerializer ?
I tried to use
[XmlRoot(ElementName="")]
public class SerialNumber
or
[XmlArray]
[XmlArrayItem(ElementName = "")]
public List<SerialNumber> SerialNumbers { get; set; }
but neither of these worked - I still get my full serialization with the <SerialNumber> elements inside the <SerialNumbers> container...
Is there an easy trick to achieve what I'm looking for? I'd much rather not go low-level and start concetanating together my XML manually....
Thanks!
You could use custom serialization with IXmlSerializable.
public class SerialNumbers : List<SerialNumber>, IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
Clear();
reader.ReadStartElement();
while (reader.NodeType != XmlNodeType.EndElement)
{
var serialNumber = new SerialNumber
{
Type = reader.ReadElementContentAsString("Type", ""),
Number = reader.ReadElementContentAsString("Number", "")
};
Add(serialNumber);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
foreach (var serialNumber in this)
{
writer.WriteElementString("Type", serialNumber.Type);
writer.WriteElementString("Number", serialNumber.Number);
}
}
}
public class SerialNumber
{
public string Type { get; set; }
public string Number { get; set; }
}
Example:
var ser = new XmlSerializer(typeof(SerialNumbers));
var reader = new StringReader(#"
<SerialNumbers>
<Type>SN</Type>
<Number>CBS583ABC123</Number>
<Type>IMEI</Type>
<Number>35-924106-659945-4</Number>
</SerialNumbers>
".Trim());
var result = (SerialNumbers) ser.Deserialize(reader);
var writer = new StringWriter();
ser.Serialize(writer, result);
Result:
<?xml version="1.0" encoding="utf-16"?>
<SerialNumbers>
<Type>SN</Type>
<Number>CBS583ABC123</Number>
<Type>IMEI</Type>
<Number>35-924106-659945-4</Number>
</SerialNumbers>
This might do the trick for you
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class SerialNumbers
{
private string[] itemsField;
private ItemsChoiceType[] itemsElementNameField;
[System.Xml.Serialization.XmlElementAttribute("Number", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("Type", typeof(string))]
[System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
public string[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
[System.Xml.Serialization.XmlIgnoreAttribute()]
public ItemsChoiceType[] ItemsElementName
{
get
{
return this.itemsElementNameField;
}
set
{
this.itemsElementNameField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema = false)]
public enum ItemsChoiceType
{
Number,
Type,
}

Deserialising XML to nested object List returning count 0

I am having some issue with deserialising some XML to an object list, always getting count 0 and within that "raw data" when inspecting DateAndTimeSlot during debug.
Unfortunately I cannot change the names of these elements.
However when checking the XML I get back, there are DateAndTimeslot objects in the XML.
With other object lists I have all seems fine, without the inclusion of namespaces.
What have I missed?
C# Code:
[XmlRoot("AppointmentAvailabilityStatusResponse")]
public class CheckAppointmentAvailabilityContainer
{
[XmlElement("AppointmentAvailabilityStatusResult")]
public AppointmentAvailabilityStatus appointmentAvailabilityStatus { get; set; }
}
[XmlRoot("AppointmentAvailabilityStatusResult", Namespace = "Appointments")]
public class AppointmentAvailabilityStatus
{
[XmlArray("DateAndTimeSlot", Namespace = "Appointments")]
[XmlArrayItem(typeof(DateAndTimeslot))]
public DateAndTimeSlots DateAndTimeSlot { get; set; }
[XmlElement("RequestedStatus")]
public int RequestedStatus { get; set; }
}
[XmlRoot(ElementName = "DateAndTimeSlot")]
[XmlType("a")]
public class DateAndTimeSlots : List<DateAndTimeslot> { }
[XmlRoot(ElementName = "DateAndTimeslot", Namespace = "Appointments.TO")]
[XmlType("b")] // if included this renames the node to "b" for some reason
public class DateAndTimeslot
{
[XmlElement("Date")]
public string Date { get; set; }
[XmlElement("TimeSlot")]
public string TimeSlot { get; set; }
}
Shortened XML returned that I wish to fully deserialise.
<AppointmentAvailabilityStatusResponse>
<AppointmentAvailabilityStatusResult xmlns:a="Appointments" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:DateAndTimeSlot xmlns:b="Appointments.TO">
<b:DateAndTimeslot>
<b:Date>14/07/2016</b:Date>
<b:TimeSlot>AM</b:TimeSlot>
</b:DateAndTimeslot>
<b:DateAndTimeslot>
<b:Date>14/07/2016</b:Date>
<b:TimeSlot>PM</b:TimeSlot>
</b:DateAndTimeslot>
</a:DateAndTimeSlot>
<a:RequestStatus>0</a:RequestStatus>
</AppointmentAvailabilityStatusResult>
</AppointmentAvailabilityStatusResponse>
XML if I serialise a dummy object - some differences which I'm trying to rectify, not sure if the namespaces are necessary for deserialisation though
<AppointmentAvailabilityStatusResponse>
<AppointmentAvailabilityStatusResult>
<DateAndTimeSlot xmlns=\"Appointments\">
<DateAndTimeslot>
<Date xmlns=\"Appointments.TO\">today</Date>
<TimeSlot xmlns=\"Appointments.TO\">now</TimeSlot>
</DateAndTimeslot>
</DateAndTimeSlot>
<RequestedStatus xmlns=\"Appointments\">0</RequestedStatus>
</AppointmentAvailabilityStatusResult>
</AppointmentAvailabilityStatusResponse>
Deserialiser
public static T DeserializeThis<T>(string cleanXml)
{
//string cleanXml = RemoveBom(dirtyXml);
bool check = cleanXml.TrimStart().StartsWith("<");
if (!string.IsNullOrEmpty(cleanXml) && cleanXml.TrimStart().StartsWith("<"))
{
try
{
XmlSerializer xs = new XmlSerializer(typeof(T));
MatchCollection mc = Regex.Matches(cleanXml, #"</?(\d\w+)");
List<string> elements = new List<string>();
foreach (Match m in mc)
{
string cpval = m.Groups[1].Value;
if (!elements.Contains(cpval)) { elements.Add(cpval); }
}
foreach (string e in elements)
{
cleanXml = cleanXml.Replace(e, "d_" + e);
}
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(cleanXml)))
{
using (StringReader sr = new StringReader(cleanXml))
{
return (T)xs.Deserialize(sr);
}
}
}
catch(XmlException x)
{
var obj = (T)Activator.CreateInstance(typeof(T));
Type type = obj.GetType();
return (T)obj;
}
}
else
{
var obj = (T)Activator.CreateInstance(typeof(T));
Type type = obj.GetType();
// add in the generic derived class property search and assign
return (T)obj;
}
}
Thank you to those who commented above - I finally got it working. Removing the XmlArray and not including Anonymous and IsNullable attributes seemed to be the issue although I am unsure why as it works with all of the other functions I have, serializable possibly doesn't need to be present either.
Working class structure minus the container as that didn't change:
[Serializable()]
[XmlType(AnonymousType = true, Namespace = "")]
public class AppointmentAvailabilityStatusResult : WebserviceMessage
{
[XmlElement("DateAndTimeSlot", Namespace = "Appointments")]
public DateAndTimeSlot DateAndTimeSlot { get; set; }
[XmlElement("RequestedStatus")]
public int RequestedStatus { get; set; }
}
[Serializable()]
[XmlType(AnonymousType = true, Namespace = "Appointments")]
[XmlRoot(ElementName = "DateAndTimeSlot",Namespace = "Appointments", IsNullable = false)]
public class DateAndTimeSlot
{
[XmlElement(ElementName = "DateAndTimeslot", Namespace = "Appointments.TO")]
public List<DateAndTimeslot> DateAndTimeslot { get; set; }
}
[Serializable()]
[XmlType(AnonymousType = true, Namespace = "Appointments.TO")]
[XmlRoot(Namespace = "Appointments.TO", IsNullable = false)]
public class DateAndTimeslot
{
[XmlElement("Date")]
public string Date { get; set; }
[XmlElement("TimeSlot")]
public string TimeSlot { get; set; }
}

Deserializing XML into object returns null values

I am trying to deserialize an XML document but the code I using is returning Null Value each time.
I have a XML like this
<?xml version="1.0" encoding="utf-8"?>
<RegistrationOpenData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.gov">
<Description>Registration data is collected by ABC XYZ</Description>
<InformationURL>http://www.example.com/html/hpd/property-reg-unit.shtml</InformationURL>
<SourceAgency>ABC Department of Housing</SourceAgency>
<SourceSystem>PREMISYS</SourceSystem>
<StartDate>2016-02-29T00:03:06.642772-05:00</StartDate>
<EndDate i:nil="true" />
<Registrations>
<Registration xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<RegistrationID>108260</RegistrationID>
<BuildingID>4731</BuildingID>
</Registration>
</Registrations>
</RegistrationOpenData>
to deserialize it, I have created a class
using System.Xml.Serialization;
using System.Xml;
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.gov")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://example.gov", IsNullable=true)]
public partial class Registration : InfoClass {
private long registrationIDField;
private bool registrationIDFieldSpecified;
private System.Nullable<long> buildingIDField;
private bool buildingIDFieldSpecified;
public long RegistrationID
{
get
{
return this.registrationIDField;
}
set
{
this.registrationIDField = value;
}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool RegistrationIDSpecified {
get {
return this.registrationIDFieldSpecified;
}
set {
this.registrationIDFieldSpecified = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public System.Nullable<long> BuildingID {
get {
return this.buildingIDField;
}
set {
this.buildingIDField = value;
}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool BuildingIDSpecified {
get {
return this.buildingIDFieldSpecified;
}
set {
this.buildingIDFieldSpecified = value;
}
}
and the code I am using is
public void Test()
{
Registration RegistrationVal = null;
var xRoot = new XmlRootAttribute();
xRoot.ElementName = "RegistrationOpenData";
xRoot.Namespace = "http://services.hpd.gov";
xRoot.IsNullable = true;
var serializer = new XmlSerializer(typeof(Registration), xRoot);
using (TextReader reader = new StreamReader(#"D:\sample.xml"))
{
RegistrationVal = (Registration)serializer.Deserialize(reader);
}
}
Here it is always returning Null value.
Thanks in advance for your help.
Your problem is in the xml because it has a list of registrations. If you remove <Registration> and <Registrations> tag then it works. Do you need the Registration and Registrations because in this case you have to work with Lists.
You could do it like in this example (Deserializing nested xml into C# objects)
And create a own class Registrations which hold a List of Registration Elements.
With this code it works. Create a super class:
[XmlRoot("RegistrationOpenData")]
public class RegistrationOpenData
{
[XmlElement("Registrations")]
public Registrations Regs { get; set; }
}
and the Registrations:
[XmlRoot("Registrations")]
public class Registrations
{
[XmlElement("Registration")]
public List<Registration> Regs { get; set; }
}
and the Registration should be the same as before.
The main function should change to this:
static void Main(string[] args)
{
RegistrationOpenData RegistrationVal = null;
var xRoot = new XmlRootAttribute();
xRoot.ElementName = "RegistrationOpenData";
xRoot.Namespace = "http://services.hpd.gov";
xRoot.IsNullable = true;
var serializer = new XmlSerializer(typeof(RegistrationOpenData), xRoot);
using (TextReader reader = new StreamReader(#"D:\sample.xml"))
{
RegistrationVal = (RegistrationOpenData)serializer.Deserialize(reader);
}
}

how to remove namespace from XML root element?

is there a simple way to remove the namespace from the XML root element. I have tried with
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
on the serializable class. But no use. still getting the same result.
sample class
[Serializable]
[XmlRootAttribute("MCP", Namespace = "", IsNullable = false)]
public class BINDRequest
{
public BINDRequest()
{
}
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
public BINDRequestBody BIND { get; set; }
}
result xml
<?xml version="1.0" encoding="utf-8"?>
<MCP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CLIENT_REQUEST_ID="1">
<BIND CLIENT_ID="test" PASSWORD="test" />
</MCP>
i don't understand then whats the use of specifying namsespace in XmlRootAttribute??
Try this:
public class BINDRequest
{
[XmlAttribute]
public string CLIENT_REQUEST_ID { get; set; }
}
class Program
{
static void Main()
{
var request = new BINDRequest
{
CLIENT_REQUEST_ID = "123"
};
var serializer = new XmlSerializer(request.GetType());
var xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
using (var writer = XmlWriter.Create("result.xml"))
{
serializer.Serialize(writer, request, xmlnsEmpty);
}
}
}

Categories