Different kind of deserializing XML in C# - c#

I am trying to deserialize XML from AdWords API to a list of models. This is the XML format:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<report>
<report-name name='GeoPerformance Report for 5/26/2014 12:00:00 AM'/>
<date-range date='May 26, 2014'/>
<table>
<columns>
<column name='clicks' display='Clicks'/>
<column name='countryTerritory' display='Country/Territory'/>
<column name='day' display='Day'/>
</columns>
<row clicks='24286' countryTerritory='United States' day='2014-05-26'/>
<row clicks='26' countryTerritory='Africa' day='2014-05-26'/>
<row clicks='286' countryTerritory='Europe' day='2014-05-26'/>
<row clicks='242' countryTerritory='Asia' day='2014-05-26'/>
</table>
</report>
My model class is this:
[XmlRoot("report")]
public class AdWordsGeoPerformance
{
public int Clicks { get; set; }
public string CountryTerritory { get; set; }
public DateTime Day { get; set; }
}
I would like each row's attributes (clicks, countryTerritory, day) to map to an instance of AdWordsGeoPerformance.
Any suggestions on how I can do this?

You can try to generate the classes with the xsd tool:
xsd your.xsd /classes
In a fast search, I found this:
https://adwords.google.com/api/adwords/reportdownload/v201109/reportDefinition.xsd
I'm not sure if that's the correct schema, if not find it (it should be stated in the documentation) and use it to generate your classes.

I tend to favor Linq to XML over deserialization. You would have to play some games with many objects to be able to serialize/deserialize that data. Just using XDocument is a lot easier for me.
This might be helpful in you are looking for an alternate way:
var adWords = new List<AdWordsGeoPerformance>();
var xDoc = XDocument.Parse(doc);
foreach(var r in xDoc.Descendants("row"))
{
var adWord = new AdWordsGeoPerformance()
{
Clicks = int.Parse((string)r.Attribute("clicks")),
CountryTerritory = (string)r.Attribute("countryTerritory"),
Day = DateTime.Parse((string)r.Attribute("day")),
};
adWords.Add(adWord);
}

Related

Linq to XML data structure

This is my XML:
<home>
<contents>
<row>
<content>
<idContent>1</idContent>
<title>title1</title>
</content>
<content>
<idContent>2</idContent>
<title>title2</title>
</content>
</row>
<row>
<content>
<idContent>3</idContent>
<title>title3</title>
</content>
<content>
<idContent>4</idContent>
<title>title4</title>
</content>
</row>
</contents>
I want to store this information in a list of objects
List myList = ...
Where a Content could be:
int idContent;
string title;
int row_number;
Each Content object has to store the row where it is located in the XML.
What's the best way for doing this?
Presuming row_number is simply a sequence relating to the order it appears in the XML, then you can do something like this:
var doc = XDocument.Parse(xml);
var contents = doc.Descendants("row")
.Select((e, index) => new {Row = e, RowIndex = index})
.SelectMany(x => x.Row.Elements("content").Select(e => new {Content = e, x.RowIndex}))
.Select(x => new Content
{
IdContent = (int)x.Content.Element("idContent"),
Title = (string)x.Content.Element("title"),
RowNumber = x.RowIndex + 1
}).ToList();
I use this method for similar scenarios:
public static Object CreateObject(string XMLString, Object YourClassObject)
{
System.Xml.Serialization.XmlSerializer oXmlSerializer = new System.Xml.Serialization.XmlSerializer(YourClassObject.GetType());
//The StringReader will be the stream holder for the existing XML file
YourClassObject = oXmlSerializer.Deserialize(new System.IO.StringReader(XMLString));
//initially deserialized, the data is represented by an object without a defined type
return YourClassObject;
}
With this method you can create a class object from a XML String. I haven't tested it on your scenario, but you can use it on object of following home class:
public class home
{
public List<row> contents;
}
public class row
{
public List<content> content;
}
public class content
{
public int idContent;
public string title;
}
USAGE:
home h = new home();
h = (home)CreateObject(xml, h);
Remember that the variable and class names must be exactly same as that of XML nodes.
EXTRA:
If you want to convert a class object into XML String, use this method:
string CreateXML(Object YourClassObject)
{
XmlDocument xmlDoc = new XmlDocument(); //Represents an XML document,
// Initializes a new instance of the XmlDocument class.
XmlSerializer xmlSerializer = new XmlSerializer(YourClassObject.GetType());
// Creates a stream whose backing store is memory.
using (MemoryStream xmlStream = new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, YourClassObject);
xmlStream.Position = 0;
//Loads the XML document from the specified string.
xmlDoc.Load(xmlStream);
return xmlDoc.InnerXml;
}
}
The best solution I could think of - although it is not using Linq to XML - is to feed your XML document into one of those various XML Schema generators like http://www.freeformatter.com/xsd-generator.html and pipe this generated Schema right into xsd.exe (see https://msdn.microsoft.com/en-us/library/x6c1kb0s.aspx). The generated code can be used to read (and write) the XML document such as the one you provided and you can of course apply Linq to Objects on this collection.
However, since you mentioned the row_number field which does not yet appear in your example XML, you would have to add this to the XML or manually edit the XML Schema afterwards.

Linq to XML query analyz

This query does work but I am not sure it is proper way to write this kind of query. I feel it is using too many Descendants and Parent.
Is there a better way to write this query?
There can be more than one catalog in XML.
static IEnumerable<Parts> GetAllParts(XDocument doc, string catalog, string groupId, string subGroupId)
{
var parts = (from p in doc.Descendants("ROOT").Descendants("CATALOG").Descendants("GROUP").Descendants("SUBGROUP").Descendants("BOM").Descendants("PARTS")
where (string)p.Parent.Parent.Parent.Parent.Element("IDENT").Value == catalog
&& p.Parent.Parent.Parent.Element("IDENT").Value == groupId
&& p.Parent.Parent.Element("IDENT").Value == subGroupId
select new Parts
{
ObjectId = int.Parse(p.Attribute("OBJECTID").Value),
Ident = p.Element("IDENT").Value,
List = p.Element("LIST").Value,
Descr = p.Element("DESC").Value
});
return parts;
}
}
public class Parts
{
public int ObjectId { get; set;}
public string Descr { get; set; }
public string Ident { get; set; }
public string List { get; set; }
}
Update: XML added.
<ROOT>
<CATALOG>
<OBJECT_ID>001</OBJECT_ID>
<OBJECT_IDENT>X001</OBJECT_IDENT>
<GROUP>
<OBJECT_ID>1001</OBJECT_ID>
<OBJECT_IDENT>01</OBJECT_IDENT>
<NAME>HOUSING</NAME>
<SUBGROUP>
<OBJECT_ID>5001</OBJECT_ID>
<OBJECT_IDENT>01.05</OBJECT_IDENT>
<NAME>DESIGN GROUP 1</NAME>
<BOM>
<OBJECT_ID>6001</OBJECT_ID>
<OBJECT_IDENT>010471</OBJECT_IDENT>
<PARTS>
<OBJECT_ID>2316673</OBJECT_ID>
<OBJECT_IDENT>A002010660</OBJECT_IDENT>
<DESC>SHORT BLOCK</DESC>
<NOTES>
<ROW>
<NOTES>Note 1</NOTES>
<BOM>010471</BOM>
<POS>1</POS>
</ROW>
<ROW>
<NOTES>Note 2</NOTES>
<BOM>010471</BOM>
<POS>2</POS>
</ROW>
</NOTES>
</PARTS>
<PARTS>
</PARTS>
<PARTS>
</PARTS>
</BOM>
</SUBGROUP>
<SUBGROUP>
</SUBGROUP>
<SUBGROUP>
</SUBGROUP>
</GROUP>
<GROUP>
</GROUP>
</CATALOG>
</ROOT>
Some suggestions regarding your question (I hope you'll improve your future posts) :
Your code and the XML posted doesn't work. For instance, the XML has <OBJECT_IDENT> element, but your LINQ has IDENT. Please craft it carefully and make sure it does work to avoid confusion.
Please put some effort in explaining the problem and giving clarification. "I am retrieving Parts data as function name says" is not clear enough as simply getting <Parts> elements doesn't need filtering but your LINQ has where .... clause.
This question seems to suits better in https://codereview.stackexchange.com/
And here is some suggestions regarding your code :
Use .Elements() to get direct child of current node as opposed to Descendants() which get all descendat nodes.
You can use Elements().Where() to filter the element so you can avoid traversing Parents
You can cast XElement to string/int to avoid exception in case such element not found
Example code snippet :
var parts = (from p in doc.Root
.Elements("CATALOG").Where(o => catalog == (string)o.Element("OBJECT_IDENT"))
.Elements("GROUP").Where(o => groupId == (string)o.Element("OBJECT_IDENT"))
.Elements("SUBGROUP").Where(o => subGroupId == (string)o.Element("OBJECT_IDENT"))
.Elements("BOM")
.Elements("PARTS")
select new Parts
{
ObjectId = (int)p.Element("OBJECT_ID"),
Ident = (string)p.Element("OBJECT_IDENT"),
List = (int)p.Element("LIST"),
Descr = (string)p.Element("DESC")
});

How to Search in XML and show results in GridView in C#?

I have an XML data of Employees, I want to parse this data and show it in Gridview using C# in ASP.NET.
Based on search parameters like Employee ID or Company ID or Department ID, I should be able to filter the data and update the GridView.
Checked few links in internet, but nothing matches this particular format.. Is it possible to achieve.. (Any links to) code will be helpful.
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<Id> TG18-2002</Id>
<Name> AAPM^Test^Patterns</Name>
<Sex> O </Sex>
<Company>
<Id> 2.16</Id>
<Department>
<Id> 2.16.124</Id>
<Project>
<Id> 2.16.124.113543</Id>
</Project>
</Department>
</Company>
</Employee>
<Employee>
<ID> TG18-2003</ID>
<Name> AAPM^Test^Patt</Name>
<Sex> O </Sex>
<Company>
<ID> 2.16</ID>
<Department>
<ID> 2.16.124</ID>
<Project>
<ID> 2.16.124.113543</ID>
</Project>
</Department>
</Company>
</Employee>
<Employee>
</Employees>
Note: I am trying to build something like, this
Looking at the link you referenced, I think you're best off creating an Employee class and filling this with the XML data.
This will allow you to de-couple your data (in this case XML, but could be anything) from your view (in this case ASP.NET Web Forms, but again could be anything), which I find handy and seems to be common these days (MVVM etc..).
Another benefit is that you can turn a nested data source like XML into something a little flatter to make your view binding simpler, for example in the example you provided you could make the Company fields available as properties of the outer Employee class.
Yet another benefit is that if/when your view becomes responsive, then you can make properties of your view model observable, and therefore allow updates to the model, immediately update your view.
All that said, here is a small snippet showing your Employee class, and filling it from the XML sample you provided. I am using Linq to XML, but there are so many ways you could do this (adapters, readers, navigators...).
I think the important thing here is that you de-couple your data from the view.
class Employee
{
public string Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public Company Company { get; set; }
}
class Company
{
public string Id { get; set; }
public Department Department { get; set; }
}
class Department
{
public string Id { get; set; }
public Project Project { get; set; }
}
class Project
{
public string Id { get; set; }
}
var xml = #"<?xml version='1.0' encoding='utf-8'?>
<Employees>
<Employee>
<Id> TG18-2002</Id>
<Name> AAPM^Test^Patterns</Name>
<Sex> O </Sex>
<Company>
<Id> 2.16</Id>
<Department>
<Id> 2.16.124</Id>
<Project>
<Id> 2.16.124.113543</Id>
</Project>
</Department>
</Company>
</Employee>
<Employee>
<Id> TG18-2003</Id>
<Name> AAPM^Test^Patt</Name>
<Sex> O </Sex>
<Company>
<Id> 2.16</Id>
<Department>
<Id> 2.16.124</Id>
<Project>
<Id> 2.16.124.113543</Id>
</Project>
</Department>
</Company>
</Employee>
</Employees>
";
// read the xml into the class
var doc = XDocument.Parse(xml);
var data = (from row in doc.Root.Elements("Employee")
let company = row.Element("Company")
let dept = company.Element("Department")
let project = dept.Element("Project")
select new Employee
{
Id = row.Element("Id").Value.Trim(),
Name = row.Element("Name").Value.Trim(),
Sex = row.Element("Sex").Value.Trim(),
Company = new Company
{
Id = company.Element("Id").Value.Trim(),
Department = new Department
{
Id = dept.Element("Id").Value.Trim(),
Project = new Project
{
Id = project.Element("Id").Value.Trim()
}
}
}
});
// now you have a collection of 'employees', bind them..
Once we're that far, you need to decide how you want to query your data. The answer to this is as usual, it depends, and in this case I think it depends mostly on the size of the XML data you have and if it makes sense to bring this into memory or not.
If you can bring it into memory, then a collection of Employees is nice and simple to query using Linq and I would recommend this approach.
If the XML is large, then you will probably need to use an XMLReader to build your class. A little more complex, but the result should still be that you bind your grid to your class and keep the XML separate from the view.
DataSet xmlData = new DataSet();
xmlData.ReadXml(YourXMLPath);
GridviewControl1.DataSource = xmlData.Tables[0];
as far my understanding you need to do maipulication in data before showing it in Grid Control.
for that i recommend you to use LINQ query. you can manipulicate the things at client side with queries.
below i trying to solve the prob.
DataSet xmlData = new DataSet();
xmlData.ReadXml(YourXMLPath);
DataTable dt =From x in xmlData.Tables[0].AsEnumerable().Where(x=>x.Field<string>("Name").StartWith("A")) Selct(x=>x).CopytodDataTable;
now you can use "dt" for your data grid
xmlData.Tables[0]= dt;
GridviewControl1.DataSource = xmlData.Tables[0];
GridviewControl1.DataBind();//this line required if it is for asp.net
Hope it will helps you. :)

XmlDocument in an array like object

I googled for hours and didn't find anything.
I'm trying to make a Metro App which is reading from an online XML Service. Getting the XML is not the problem, i'm simply doing it like this ->
var xmlDoc = await XmlDocument.LoadFromUriAsync(new Uri(url));
but now the problem is, how to convert it into a list or something readable like this.
The XML I want to read is really huge and i don't want to go through all nodes with foreach.
A simple Array/List with all nodes and innerText as Value would be awesome.
Is this possible? If yes.. how ?
The structure of my XML is like this ->
<?xml version="1.0" encoding="UTF-8"?>
<city>
...
<credit>
...
</credit>
<forecast>
<date value="2013-11-08">
...
<time value="06:00">
...
</time>
<time value="11:00">
...
</time>
<time value="17:00">
...
</time>
<time value="23:00">
...
</time>
...
</date>
<date value="2013-11-09">
<same content here>
</date>
<date value="2013-11-09">
<same content here>
</date>
</forecast>
</city>
as you can see... there's a lot of information in the XML and I need nearly everything. In Actionscript I would realize it with a XMLList and make 3 Lists of the date Tags with content, so i can use
xmllist1.time[0] - xmllist1.time[3]
xmllist2.time[0] - xmllist2.time[3]
xmllist3.time[0] - xmllist3.time[3]
to get my data.
And now i want this XMLList in C#... I hope it's possible...Thx 4 help
If I understand you correctly, you want to parse the list of "city" items from the xml.
I do something similar using XDocument and Linq like this and it should work for you:
XDocument xdoc = <add your code to get xml from url>;
var ns = xdoc.Root.GetDefaultNamespace();
var cityList = from query in xdoc.Descendants(ns + "city")
select new CityItem
{
Date = (string)query.Element(ns + "date").Attribute("value").Value,
Time = (string)query.Element(ns + "time").Attribute("value").Value
};
public class CityItem
{
public string Date {get;set;}
public string Time {get;set;}
}

XML Serialization of member variable as xmlnode

I have some XML which I would like to serialize into a class.
<Group>
<Employees>
<Employee>
<Name>Hari</Name>
<Age>30</Age>
</Employee>
<Employee>
<Name>Yougov</Name>
<Age>31</Age>
</Employee>
<Employee>
<Name>Adrian</Name>
<Age>28</Age>
</Employee>
</Employees >
The above XML can be realized in C# pretty much easily.
But I'm stumbled upon my requirement, where the XML looks like,
<Group>
<Employees>
<Hari Age=30 />
<Yougov Age=31 />
<Adrian Age=28 />
</Employees >
</Group>
Where Employees is a List<Employee> with KeyValuePair<string, int>("Hari", 30)
How do I design the classes and member variables to get the above serialized XML?
(Provided, there wont be any duplicate names in the employee list)
Any help is much appreciated.
*Serializing KeyValuePair
I would go with Linq2Xml in your case.
XDocument xDoc = XDocument.Load(......);
var emps = xDoc.Descendants("Employees").Elements()
.Select(x => new Employee() {
Name = x.Name.ToString(),
Age = int.Parse(x.Attribute("Age").Value)
})
.ToList();
PS: Age=30 is not valid. It shoudl be Age="30"
It is not a good idea to use the data as the schema; in particular, an awful lot of names are not valid as xml element names, but also: it just isn't good practice (for example, it makes it virtually useless in terms of schema validation). If you want to be terse, maybe something like:
<Employees>
<Add Name="Hari" Age="30" />
</Employees>
or
<Employees>
<Employee Name="Hari" Age="30" />
</Employees>
which can be done simply with:
[XmlArray("Employees"), XmlArrayItem("Employee")]
public List<Employee> Employees {get;set;}
and:
public class Employee {
[XmlAttribute]
public string Name {get;set;}
[XmlAttribute]
public int Age {get;set;}
}
XmlSerializer does not support the "content as an element name" serializer, unless you do everything yourself with IXmlSerializable from the parent element (it would have to be from the parent, as XmlSerializer would have no way of identifying the child to handle there).

Categories

Resources