.NET XML Deserialization for fields with different values - c#

I have the following XML:
<results>
<row>
<id>4990321</id>
<field name="First name">John</field>
<field name="Last name">Snow</field>
<field name="Country">USA</field>
<field name="City">San-Diego</field>
<field name="Postcode">123456</field>
<field name="Email">username#stackoverflow.com</field>
<field name="Message">Hello</field>
</row>
<row>
...
<row>
</results>
I need to deserialize it in array of objects:
public class Employee
{
public string Id { set; get; }
public string Firstname { set; get; }
public string Lastname { set; get; }
public string Country { set; get; }
public string City { set; get; }
public string Postcode { set; get; }
public string Email { set; get; }
public string Message { set; get; }
}
I've tried to implement it using XmlElementAttribute and XmlAttributeAttribute, but property named ElementName doesn't understand XPath, so I couldn't get value of specific field (as field[name='Email'])
Who has any ideas how can I do it? Desirable without XDocument parse.

One suggestion would be to pre-process your data into a form that is more friendly to serialize via an XSLT transform. This can be accomplished in C# via the XslCompiledTransform class.
A sample XSL file to use would be:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" omit-xml-declaration="no"/>
<xsl:template match="results">
<Employees>
<xsl:for-each select="row">
<Employee>
<Id><xsl:value-of select="id" /></Id>
<Firstname><xsl:value-of select="field[#name='First name']" /></Firstname>
<Lastname><xsl:value-of select="field[#name='Last name']" /></Lastname>
<Country><xsl:value-of select="field[#name='Country']" /></Country>
</Employee>
</xsl:for-each>
</Employees>
</xsl:template>
</xsl:stylesheet>
(Incomplete but enough for illustration purposes)
In your C# program the transformation is simple:
var xslReader = XmlReader.Create(new StringReader(GetXslString()));
var xmlReader = XmlReader.Create(new StringReader(GetXmlString()));
var transformedStream = new MemoryStream();
var xmlWriter = XmlWriter.Create(transformedStream);
var xslt = new XslCompiledTransform();
xslt.Load(xslReader);
xslt.Transform(xmlReader, xmlWriter);
transformedStream.Seek(0, SeekOrigin.Begin);
// Use your transformedStream to deserialize the object
.NET fiddle demonstrating this code here
When this is run against your sample data, it produces outputs similar to:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Employees>
<Employee>
<Id>4990321</Id>
<Firstname>Jhon</Firstname>
<Lastname>Snow</Lastname>
<Country>USA</Country>
</Employee>
<Employee>
<Id>4990322</Id>
<Firstname>Mike</Firstname>
<Lastname>Ross</Lastname>
<Country>UK</Country>
</Employee>
</Employees>
This should be fairly easy now for the any of the default deserialization tools to take over without advanced document selectors, etc.

You can deserialize it by explicitly declaring the order the elements are deserialized in using Order:
[XmlRoot("results")]
public class Results
{
[XmlElement("row")]
public List<Employee> Employees { get; set; }
}
public class Employee
{
[XmlElement(ElementName = "id", Order = 1)]
public string Id { set; get; }
[XmlElement(ElementName = "field", Order = 2)]
public string Firstname { set; get; }
[XmlElement(ElementName = "field", Order = 3)]
public string Lastname { set; get; }
[XmlElement(ElementName = "field", Order = 4)]
public string Country { set; get; }
[XmlElement(ElementName = "field", Order = 5)]
public string City { set; get; }
[XmlElement(ElementName = "field", Order = 6)]
public string Postcode { set; get; }
[XmlElement(ElementName = "field", Order = 7)]
public string Email { set; get; }
[XmlElement(ElementName = "field", Order = 8)]
public string Message { set; get; }
}
You can then deserialize this as such (where xml is your XML string):
var results = new XmlSerializer(typeof(Results)).Deserialize(new StringReader(xml));

Related

Error when trying to create an object from XML (C#)

I have an issue when trying to convert an xml string as an object, I keep getting "There is an error in XML document (1, 40)."
Here is my code :
httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
httpResponseBody = await httpResponse.Content.ReadAsStringAsync();
XmlSerializer serializer = new XmlSerializer(typeof(Feed));
StringReader rdr = new StringReader(httpResponseBody);
Feed resultingMessage = (Feed)serializer.Deserialize(rdr);
The class :
[XmlRoot("feed"), Serializable]
public class Feed
{
[XmlElement("title")]
public string title { get; set; }
[XmlElement("entry")]
public List<Entry> Entry { get; set; }
}
public class Entry
{
[XmlElement("content")]
public Content content { get; set; }
}
public class Content
{
[XmlElement("properties")]
public Properties properties { get; set; }
}
public class Properties
{
[XmlElement("EntityID")]
public int properties { get; set; }
[XmlElement("Latitude")]
public Double latitude { get; set; }
[XmlElement("Longitude")]
public Double longitude { get; set; }
[XmlElement("DisplayName")]
public Properties name { get; set; }
[XmlElement("__Distance")]
public Double distance { get; set; }
}
And an sample of the XML received :
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title type="text"></title>
<id>uuid:ce35d2a9-1966-4bd7-8730-80cff2a0ce58;id=13760</id>
<rights type="text">© 2017 Microsoft and its suppliers. This API and any results cannot be used or accessed without Microsoft's express written permission.</rights>
<updated>2017-06-28T19:27:04Z</updated>
<entry>
<id>https://spatial.virtualearth.net/REST/v1/data/c2ae584bbccc4916a0acf75d1e6947b4/NavteqEU/NavteqPOIs('800791175')</id>
<title type="text"></title>
<updated>2017-06-28T19:27:04Z</updated>
<content type="application/xml">
<m:properties>
<d:EntityID>800791175</d:EntityID>
<d:Latitude m:type="Edm.Double">47.386450</d:Latitude>
<d:Longitude m:type="Edm.Double">0.690600</d:Longitude>
<d:DisplayName>Au Chantecler</d:DisplayName>
<d:LanguageCode>FRE</d:LanguageCode>
<d:__Distance m:type="Edm.Double">0.0730920601952144</d:__Distance>
</m:properties>
</content>
</entry>
</feed>
When I remove the the error is not on 1,40 but 1,2.
Thanks in advance !
I resolved the issue, I forgot to specify the namespace for the elements, for instance in Feed:
[XmlElement(ElementName = "entry", Namespace = "http://www.w3.org/2005/Atom")]
public List<Entry> Entries { get; set; }

Error Deserializing an Xml to Object [duplicate]

I need some help with XmlSerializer. I have to following xml fragment:
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'>
<id>tag:blogger.com,1999:blog-4233645339430781865.archive</id>
<updated>2012-10-22T07:00:02.139+03:00</updated>
<title type='text'>Code !t</title>
<link rel='alternate' type='text/html' href='http://www.etabakov.com/'/>
<author>
<name>Емил Табаков</name>
<email>noreply#blogger.com</email>
<gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-TbRwL19G85U/AAAAAAAAAAI/AAAAAAAAFxg/NRV6ZYqd9Wg/s512-c/photo.jpg'/>
</author>
<generator version='7.00' uri='http://www.blogger.com'>Blogger</generator>
<entry>
<id>tag:blogger.com,1999:blog-4233645339430781865.post-513753811167440871</id>
<published>2012-10-12T11:22:35.759+03:00</published>
<updated>2012-10-12T11:22:35.759+03:00</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/blogger/2008/kind#comment'/>
<title type='text'>Great post indeed. I really like that you are prov...</title>
<content type='html'>Great post indeed. I really like that you are providing information on .NET for freshers , Being enrolled at http://www.wiziq.com/course/57-fresher-training-projects i found your information very helpful indeed. Thanks for it.</content>
<link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4233645339430781865/8317071019326278340/comments/default/513753811167440871'/>
<author>
<name>sarabjeet</name>
<uri>http://www.blogger.com/profile/11223974173581186160</uri>
<email>noreply#blogger.com</email>
<gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/>
</author>
<thr:in-reply-to href='http://www.etabakov.com/2012/06/net-guy-velocityconf-2012-day-1.html' ref='tag:blogger.com,1999:blog-4233645339430781865.post-8317071019326278340' source='http://www.blogger.com/feeds/4233645339430781865/posts/default/8317071019326278340' type='text/html'/>
<gd:extendedProperty name='blogger.itemClass' value='pid-899300522'/>
</entry>
</feed>
And I also have the following c# objects:
Feed.cs
[XmlRoot(ElementName = "feed", Namespace = "http://www.w3.org/2005/Atom"), XmlType("feed")]
public class Feed
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("author")]
public Author Author { get; set; }
[XmlElement("entry")]
public List<Entry> Entry;
}
public class Entry
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("content")]
public string Content { get; set; }
[XmlElement("published")]
public DateTime Published { get; set; }
[XmlElement("updated")]
public DateTime Updated { get; set; }
[XmlElement("category")]
public List<Category> Categories;
[XmlElement("author")]
public Author Author { get; set; }
[XmlElement(ElementName = "in-reply-to", Namespace = "thr", Type = typeof(ReplyTo), IsNullable = true)]
public ReplyTo ReplyTo { get; set; }
}
public class ReplyTo
{
[XmlAttribute("ref")]
public string Id { get; set; }
}
Everything works perfectly so far, except that ReplyTo property always stays null. I need to get the src attribute from the
I will be really happy if someone show me what I'm missing. Thanks!
The namespace you need is "http://purl.org/syndication/thread/1.0"
"thr" is just the alias - as declared by the xmlns:thr at the top.
So:
[XmlElement(ElementName = "in-reply-to", Namespace = "http://purl.org/syndication/thread/1.0", Type = typeof(ReplyTo), IsNullable = true)]
public ReplyTo ReplyTo { get; set; }

Deserialize with RestSharp

I've been looking on similar StackOverFlow posts but nothing seems to work.
I'm trying to deserialize an XML string that is being sent to me from a restful service using RestSharper. Basically, my problem is that some of the properties of my model class are being left null, and I have no clue why.
The model class I'm using is this:
class Photo
{
[SerializeAs(Name = "id")]
public long? id { get; set; }
[SerializeAs(Name = "title")]
public string title { get; set; }
[SerializeAs(Name = "description")]
public string description { get; set; }
[SerializeAs(Name = "size")]
public long? size { get; set; }
[SerializeAs(Name = "user")]
public User user { get; set; }
[SerializeAs(Name = "tags")]
public List<Tag> listTags { get; set; }
[SerializeAs(Name = "comments")]
public List<Comment> listComments { get; set; }
}
class Photos
{
[SerializeAs(Name = "photos")]
public List<Photo> listPhotos { get; set; }
}
The XML I'm trying to deserialize follows this structure :
<photos>
<photo>
<id>1</id>
<title>some title...</title>
<description>some description...</description>
<size>162798</size>
<user>
<id>4</id>
<name>John</name>
</user>
<tags>
<tag>
<id>1</id>
<value>some value...</value>
</tag>
</tags>
<comments>
<comment>
<id>1</id>
<value>some comment</value>
<author>admin</author>
</comment>
</comments>
</photo>
</photos>
Back to the C# code. The thing is that the list of comments, the list of tags, and the user object of the Photo class are being left null . Does anyone knows why is this happening?

Deserialize XML string not working

I have this XML string
<Root>
<Row>
<ITEMNO>1</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>2</QTY>
<CUSTPARTNO>469</CUSTPARTNO>
<DESCRIPT>35W 1/4W 5%</DESCRIPT>
</Row>
<Row>
<ITEMNO>3</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>5</QTY>
<CUSTPARTNO>116</CUSTPARTNO>
<DESCRIPT>1.74K 1/8W 1% Film</DESCRIPT>
</Row>
<Row>
<ITEMNO>2</ITEMNO>
<PARTSOURCE>MAKE</PARTSOURCE>
<QTY>5</QTY>
<CUSTPARTNO>651321</CUSTPARTNO>
<DESCRIPT>Make Part</DESCRIPT>
</Row>
</Root>
I am trying to Deserialize it into this Root class
public class Root
{
public BOMItems Row { get; set; }
}
public class BOMItems
{
public string ITEMNO { get; set; }
public string USED { get; set; }
public string PARTSOURCE { get; set; }
public string QTY { get; set; }
public string CUSTPARTNO { get; set; }
public string CREV { get; set; }
public string DESCRIPT{ get; set; }
}
Using this method:
public Root TransformXMLToClass(string pXml)
{
var serializer = new XmlSerializer(typeof(Root));
XmlReader reader = XmlReader.Create(new StringReader(pXml));
return (Root)serializer.Deserialize(reader);
}
This works only on the first node.
I have tried changing the Root class like this:
public List<BOMItems> Row{get;set;}
It didn't work for any of the nodes
How do I get it to deserialize all nodes?
In your case it's quite simple. You just need to tell the serializer how to handle the collection of elements.
You do need to have the property as a collection or array like this:
public class Root
{
[XmlElement("Row")]
public BOMItems[] Row { get; set; }
}
The "[XmlElement]" is what will tell it how to deserialize correctly. Adding the XmlElementAttribute tells the serializer to treat it as a "flat" sequence.
<!-- Row Elements Flattened -->
<Root>
<Row>
<ITEMNO>1</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>2</QTY>
<CUSTPARTNO>469</CUSTPARTNO>
<DESCRIPT>35W 1/4W 5%</DESCRIPT>
</Row>
<Row>
<ITEMNO>3</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>5</QTY>
<CUSTPARTNO>116</CUSTPARTNO>
<DESCRIPT>1.74K 1/8W 1% Film</DESCRIPT>
</Row>
</Root>
<!-- Versus Row Elements Unflattened -->
<Root>
<Row>
<BOMItems>
<ITEMNO>1</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>2</QTY>
<CUSTPARTNO>469</CUSTPARTNO>
<DESCRIPT>35W 1/4W 5%</DESCRIPT>
</BOMItems>
<BOMItems>
<ITEMNO>3</ITEMNO>
<PARTSOURCE>Buy</PARTSOURCE>
<QTY>5</QTY>
<CUSTPARTNO>116</CUSTPARTNO>
<DESCRIPT>1.74K 1/8W 1% Film</DESCRIPT>
</BOMItems>
</Row>
</Root>
Your BOM class should be something like below,
[XmlElement("ITEMNO")]
public string ITEMNO { get; set; }
so as to inform the serializer that you read ITEMNO and save it in the ITEMNO
EDIT:
It has to be done for every property of BOM class.
Answer: (with the list )
public class Root
{
[XmlElement("Row")]
public List<BOMItems> Row { get; set; }
}
public class BOMItems
{
[XmlElement("ITEMNO")]
public string ITEMNO { get; set; }
[XmlElement("USED")]
public string USED { get; set; }
[XmlElement("PARTSOURCE")]
public string PARTSOURCE { get; set; }
[XmlElement("QTY")]
public string QTY { get; set; }
[XmlElement("CUSTPARTNO")]
public string CUSTPARTNO { get; set; }
[XmlElement("CREV")]
public string CREV { get; set; }
[XmlElement("DESCRIPT")]
public string DESCRIPT { get; set; }
}
class Program
{
static void Main(string[] args)
{
var serializer = new XmlSerializer(typeof(Root));
var reader = XmlReader.Create(new StringReader(File.ReadAllText("c:\\tet.xml")));
var serializedOutput = (Root)serializer.Deserialize(reader);
Console.ReadKey();
}

c#: Deserializing xml with namespaces to clr object

I need some help with XmlSerializer. I have to following xml fragment:
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'>
<id>tag:blogger.com,1999:blog-4233645339430781865.archive</id>
<updated>2012-10-22T07:00:02.139+03:00</updated>
<title type='text'>Code !t</title>
<link rel='alternate' type='text/html' href='http://www.etabakov.com/'/>
<author>
<name>Емил Табаков</name>
<email>noreply#blogger.com</email>
<gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-TbRwL19G85U/AAAAAAAAAAI/AAAAAAAAFxg/NRV6ZYqd9Wg/s512-c/photo.jpg'/>
</author>
<generator version='7.00' uri='http://www.blogger.com'>Blogger</generator>
<entry>
<id>tag:blogger.com,1999:blog-4233645339430781865.post-513753811167440871</id>
<published>2012-10-12T11:22:35.759+03:00</published>
<updated>2012-10-12T11:22:35.759+03:00</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/blogger/2008/kind#comment'/>
<title type='text'>Great post indeed. I really like that you are prov...</title>
<content type='html'>Great post indeed. I really like that you are providing information on .NET for freshers , Being enrolled at http://www.wiziq.com/course/57-fresher-training-projects i found your information very helpful indeed. Thanks for it.</content>
<link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4233645339430781865/8317071019326278340/comments/default/513753811167440871'/>
<author>
<name>sarabjeet</name>
<uri>http://www.blogger.com/profile/11223974173581186160</uri>
<email>noreply#blogger.com</email>
<gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/>
</author>
<thr:in-reply-to href='http://www.etabakov.com/2012/06/net-guy-velocityconf-2012-day-1.html' ref='tag:blogger.com,1999:blog-4233645339430781865.post-8317071019326278340' source='http://www.blogger.com/feeds/4233645339430781865/posts/default/8317071019326278340' type='text/html'/>
<gd:extendedProperty name='blogger.itemClass' value='pid-899300522'/>
</entry>
</feed>
And I also have the following c# objects:
Feed.cs
[XmlRoot(ElementName = "feed", Namespace = "http://www.w3.org/2005/Atom"), XmlType("feed")]
public class Feed
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("author")]
public Author Author { get; set; }
[XmlElement("entry")]
public List<Entry> Entry;
}
public class Entry
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("content")]
public string Content { get; set; }
[XmlElement("published")]
public DateTime Published { get; set; }
[XmlElement("updated")]
public DateTime Updated { get; set; }
[XmlElement("category")]
public List<Category> Categories;
[XmlElement("author")]
public Author Author { get; set; }
[XmlElement(ElementName = "in-reply-to", Namespace = "thr", Type = typeof(ReplyTo), IsNullable = true)]
public ReplyTo ReplyTo { get; set; }
}
public class ReplyTo
{
[XmlAttribute("ref")]
public string Id { get; set; }
}
Everything works perfectly so far, except that ReplyTo property always stays null. I need to get the src attribute from the
I will be really happy if someone show me what I'm missing. Thanks!
The namespace you need is "http://purl.org/syndication/thread/1.0"
"thr" is just the alias - as declared by the xmlns:thr at the top.
So:
[XmlElement(ElementName = "in-reply-to", Namespace = "http://purl.org/syndication/thread/1.0", Type = typeof(ReplyTo), IsNullable = true)]
public ReplyTo ReplyTo { get; set; }

Categories