convert from xml to list c# in .net core - c#

C#:
XElement Xml = null;
var apiResponse = response.Content.ReadAsStringAsync().Result;
Xml = Newtonsoft.Json.JsonConvert.DeserializeObject<XElement>(apiResponse);
XML response from above code:
I'm having errors with Images xml part, while converting it to List,
I tried so many options, Please provide suggestion from below
<root>
<Column1>
<ID>2702</ID>
<Desc>Failed</Desc>
<Address>Florida</Address>
<Date>2019-04-30T23:10:36.79</Date>
<**Images**>
<Image>
<File>1-RRamos.PNG</File>
</Image>
<Image>
<File>RRamos.PNG</File>
</Image>
<Image>
<File>3-RRamos.PNG</File>
</Image>
</**Images**>
</Column1>
</root>
Trying to convert from xml to List from below
public class objClass
{
public string ID{ get; set; }
public string Desc{ get; set; }
public string Address { get; set; }
public DateTime? Date{ get; set; }
//public string[] ImageFileNames { get; set; }
public List<Images> FileName { get; set; }
}
public class FileName
{
public string File{ get; set; }
}
List<objClass> list = Xml.Elements("ID").Select(sv => new objClass()
{
ID= (string)sv.Element("ID"),
Desc= (string)sv.Element("Desc"),
Address = (string)sv.Element("Address"),
Date= (DateTime?)sv.Element("Date"),
//**,Images = (List)sv.Element("Images")**
}).ToList();
From XML response, trying to convert it to List.

You can't use the Newtonsoft.Json library to deserialize from an XML.
Solution 1: Convert XML to list via XPath
Parse XML string to XDocument.
With XPath: "//root/Column1", select the <Column1> element.
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
var apiResponse = await response.Content.ReadAsStringAsync();
XDocument #Xml = XDocument.Parse(apiResponse);
List<ObjClass> list = #Xml.XPathSelectElements("//root/Column1")
.Select(sv => new ObjClass()
{
ID = (string)sv.Element("ID"),
Desc = (string)sv.Element("Desc"),
Address = (string)sv.Element("Address"),
Date = (DateTime?)sv.Element("Date"),
Images = sv.Element("Images")
.Elements("Image")
.Select(x => new Image
{
File = (string)x.Element("File")
})
.ToList()
})
.ToList();
Solution 2: Deserialize XML
This answer will be a bit complex but work the same as Solution 1.
Write the apiResponse value into MemoryStream.
Deserialize the MemoryStream via XmlSerializer as Root.
Extract root.Column and add into list.
[XmlRoot(ElementName = "root")]
public class Root
{
[XmlElement("Column 1")]
public ObjClass Column { get; set; }
}
public class ObjClass
{
public string ID { get; set; }
public string Desc { get; set; }
public string Address { get; set; }
public DateTime? Date { get; set; }
[XmlArray]
[XmlArrayItem(typeof(Image), ElementName = "Image")]
public List<Image> Images { get; set; }
}
public class Image
{
public string File { get; set; }
}
using System.Xml;
using System.Xml.Serialization;
using System.IO;
var apiResponse = await response.Content.ReadAsStringAsync();
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
writer.Write(apiResponse);
writer.Flush();
stream.Position = 0;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Root));
Root root = (Root)xmlSerializer.Deserialize(stream);
List<ObjClass> list = new List<ObjClass>();
list.Add(root.Column);
Concern:
Use await instead of Task<T>.Result as Task<T>.Result will block the calling thread until it (the task) is completed. With await, the task is waited to be completed asynchronously. Reference: What is the difference between await Task and Task.Result?

public class objClass
{
public string ID { get; set; }
public string Desc { get; set; }
public string Address { get; set; }
public DateTime? Date { get; set; }
public string[] ImageFileNames { get; set; }
}
var list = Xml.Elements("root").Elements("Column1")
.Select(sv => new objClass()
{
ID = (string)sv.Element("ID"),
Desc = (string)sv.Element("Desc"),
Address = (string)sv.Element("Address"),
Date = (DateTime?)sv.Element("Date"),
ImageFileNames = sv.Element("Images")
.Elements("Image")
.Select(i => (string)i.Element("File"))
.ToArray(),
})
.ToList();

Related

How to create JSON array from SQL rows in C# (Azure Function)

I am building an API pulling data from Azure SQL would like to create a JSON array.
Currently I have an Azure Function written in C#.
Sample data looks like this:
I would like the output to look like this
My Azure Function is working fine, I just need to create an array. (I think)
await connection.OpenAsync();
SqlDataReader dataReader = await command.ExecuteReaderAsync();
var r = Serialize(dataReader);
json = JsonConvert.SerializeObject(r, Formatting.Indented);
I'm new to .NET and not sure quite where to begin. Thanks!
You could do it this way. Read the data into a Type that you can then use LINQ on to group into the desired shape, then serialize to JSON.
//Start with a list of the raw data by reading the rows into CardData list
List<CardData> cards = new List<CardData>();
while (dataReader.Read())
{
//You should check for DBNull, this example not doing that
cards.Add(new CardData
{
card_key = dataReader.GetString(0),
card_name = dataReader.GetString(1),
card_network = dataReader.GetString(2),
annual_fee = dataReader.GetDecimal(3),
speed_bonus_category = dataReader.GetString(4),
speed_bonus_amount = dataReader.GetInt32(5)
});
}
//Now transform the data into an object graph that will serialize
//to json the way you want. (flattens the redundant data)
var grp = cards.GroupBy(x => new { x.card_key, x.card_name, x.card_network, x.annual_fee });
var groupedData = new List<CardsModel>();
groupedData = grp.Select(g => new CardsModel
{
card_key = g.Key.card_key,
card_name = g.Key.card_name,
card_network = g.Key.card_network,
annual_fee = g.Key.annual_fee,
Bonuses = g.Select(b => new SpeedBonus
{
SpeedBonusCategory = b.speed_bonus_category,
SpeedBonusAmount = b.speed_bonus_amount
}).ToList()
}).ToList();
//Finally you can serialize
var json = JsonConvert.SerializeObject(groupedData, Formatting.Indented);
Here are the supporting classes you could use:
//represents the non-redundant object graph
public class CardsModel
{
public string card_key { get; set; }
public string card_name { get; set; }
public string card_network { get; set; }
public decimal annual_fee { get; set; }
public List<SpeedBonus> Bonuses { get; set; }
}
public class SpeedBonus
{
public string SpeedBonusCategory { get; set; }
public int SpeedBonusAmount { get; set; }
}
//represents raw data, has redundant cc info
public class CardData
{
public string card_key { get; set; }
public string card_name { get; set; }
public string card_network { get; set; }
public decimal annual_fee { get; set; }
public string speed_bonus_category { get; set; }
public int speed_bonus_amount { get; set; }
}

How to deserialize this xml to objects?

I'm fetching data in the format of this:
<ReplyUserAccount xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" requestid="" version="1.0" xmlns="url">
<Sender partnerid="xx">xx</Sender>
<Users>
<User method="GET" ResultCode="OK" Description="">
<Guid>xx</Guid>
<FirstName>xx</FirstName>
<LastName>xx</LastName>
<Phone>xx</Phone>
<Mobile>xx</Mobile>
<Email>xx</Email>
<EmplNo>xx</EmplNo>
<TacPermission />
<InvPermission>xx</InvPermission>
<CustomerId>xx</CustomerId>
</User>
</Users>
</ReplyUserAccount>
With the following C# objects:
[XmlRoot("ReplyUserAccount")]
public class ReplyUserAccount
{
[XmlElement("Users")]
public Users Users{ get; set; }
}
[XmlType("Users")]
public class Users
{
[XmlElement("User")]
public List<User> UserList{ get; set; }
}
[XmlType("User")]
public class User
{
[XmlElement("EmplNo")]
public string Id{ get; set; }
[XmlElement("Guid")]
public string Guid { get; set; } = null;
[XmlElement("Email")]
public string Email { get; set; }
[XmlElement("FirstName")]
public string FirstName { get; set; }
[XmlElement("LastName")]
public string LastName { get; set; }
public bool Active { get; set; } = true;
public string PhoneNumber { get; set; } = null;
}
And the following deserializing:
var result = await httpClient.GetAsync(url);
var xdoc = XDocument.Parse(await result.Content.ReadAsStringAsync());
XmlSerializer serializer = new XmlSerializer(typeof(ReplyUserAccount));
var content = xdoc.ToString();
TextReader reader = new StringReader(content);
var res = (ReplyUserAccount)serializer.Deserialize(reader);
But I get the following error:
InvalidOperationException: <ReplyUserAccount xmlns='xxx'> was not expected.
I'm a little bit lost as to how to properly deserialize this specific xml data. Any and all help with regards to this is greatly appreciated.
To fix the error, You have to remove xmlns and xsi in xml text before deserialize. You can remove xmlns and xsi like this:
var content = xdoc.ToString();
string strXMLPattern = #"xmlns(:\w+)?=""([^""]+)""|xsi(:\w+)?=""([^""]+)""";
content = Regex.Replace(content, strXMLPattern, "");
Therefore the method should be as follows
var result = await httpClient.GetAsync(url);
var xdoc = XDocument.Parse(await result.Content.ReadAsStringAsync());
XmlSerializer serializer = new XmlSerializer(typeof(ReplyUserAccount));
var content = xdoc.ToString();
string strXMLPattern = #"xmlns(:\w+)?=""([^""]+)""|xsi(:\w+)?=""([^""]+)""";
content = Regex.Replace(content, strXMLPattern, "");
TextReader reader = new StringReader(content);
var res = (ReplyUserAccount)serializer.Deserialize(reader);

Writing nested list values to CSV file

I have class with nested list properties, I am trying to write the value to CSV file, but I am getting output appended with [{ }] like shown below:
Client TDeals
ABC [{DealName:59045599,TShape:[{StartDate:"2014-01-
28T23:00:00",EndDate:"2014-01-28T23:30:00",Volume:0.00},
{StartDateTime:"2014-01-
28T23:30:00",EndDateTime:"2014-01-29T00:00:00",Volume:0.00}}]
I want my output in CSV file like shown below:
Client DealNo StartDate EndDate Volume
ABC 59045599 - - -
Class Properties
public class TRoot
{
public string Client { get; set; }
public List<TDeal> Deals { get; set; }
}
public class TDeal
{
public string DealName{get;set;}
public List<TInterval> TShape { get; set; }
}
public class TInterval
{
public string StartDate{ get; set; }
public string EndDate{ get; set; }
public string Volume {get;set;}
}
I am using ServiceStack.Text to create CSV file from object
ServiceStack.Text.CsvSerializer.SerializeToWriter<TRoot>(TRoot, writer);
Reference URL
https://github.com/ServiceStack/ServiceStack.Text
Define a new class for single csv line:
public class CsvLine
{
public string Client { get; set; }
public string DealName { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string Volume { get; set; }
}
Now you can transfrom your objects into collection of lines with Linq SelectMany method:
TRoot root = ...
var lines = root.Deals.SelectMany(d => d.TShape.Select(s => new CsvLine
{
Client = root.Client,
DealName = d.DealName,
StartDate = s.StartDate,
EndDate = s.EndDate,
Volume = s.Volume
})).ToArray();
Then call SerializeToWriter on that collection
I would recommend to "flatten" your output to CSV.
Create one more class that will be a mirror of what you would like to have in CSV file. Before writing to the file, convert your TRoot to that new class and write it to CSV.
Quite quick and elegant solution :)
You can try Cinchoo ETL to create the CSV file. First you will have to flatten out root object using Linq and pass them to CSV writer to create file.
Sample below show how to
private static void Test()
{
TRoot root = new TRoot() { Client = "ABC", Deals = new List<TDeal>() };
root.Deals.Add(new TDeal
{
DealName = "59045599",
TShape = new List<TInterval>()
{
new TInterval { StartDate = DateTime.Today.ToString(), EndDate = DateTime.Today.AddDays(2).ToString(), Volume = "100" },
new TInterval { StartDate = DateTime.Today.ToString(), EndDate = DateTime.Today.AddDays(2).ToString(), Volume = "200" }
}
});
using (var w = new ChoCSVWriter("nestedObjects.csv").WithFirstLineHeader())
{
w.Write(root.Deals.SelectMany(d => d.TShape.Select(s => new { ClientName = root.Client, DealNo = d.DealName, StartDate = s.StartDate, EndDate = s.EndDate, Volume = s.Volume })));
}
}
The output is:
ClientName,DealNo,StartDate,EndDate,Volume
ABC,59045599,1/17/2018 12:00:00 AM,1/19/2018 12:00:00 AM,100
ABC,59045599,1/17/2018 12:00:00 AM,1/19/2018 12:00:00 AM,200
For more information about it, visit the codeproject article at
https://www.codeproject.com/Articles/1155891/Cinchoo-ETL-CSVWriter
Disclaimer: I'm the author of this library.

cant figure out how to map this json into C# classes

So I have the json below that I want to Deseralize into Classes so I can work with it. But the issues is that the top two fields are a different type to all the rest
"items": {
"averageItemLevel": 718,
"averageItemLevelEquipped": 716,
"head": { ... },
"chest": { ... },
"feet": { ... },
"hands": { ... }
}
Where ... is a the Item class below, but the problem is that 2 of the fields are ints and the rest are Item, there are about 20 fields in total. So what I'd like to do is put them into a Dictionary<string, Item> but the 2 int fields are preventing me from Deseralizing it into that. I'm using JavaScriptSerializer.Deserialize<T>() to do this.
I could have each item as it's own class with the name of the item as the name of the class, but I find that to be very bad, repeating so much each time, also very hard to work with later since I cant iterate over the fields, where as I could a Dictionary. Any idea how I could overcome this?
public class Item
{
public ItemDetails itemDetails { get; set; }
public int id { get; set; }
public string name { get; set; }
public string icon { get; set; }
public int quality { get; set; }
public int itemLevel { get; set; }
public TooltipParams tooltipParams { get; set; }
public List<Stat> stats { get; set; }
public int armor { get; set; }
public string context { get; set; }
public List<int> bonusLists { get; set; }
}
Update: from the comments I came up with this solution
JObject jsonObject = JObject.Parse(json);
jsonObject["averageItemLevel"] = int.Parse(jsonObject["items"]["averageItemLevel"].ToString());
jsonObject["averageItemLevelEquipped"] = int.Parse(jsonObject["items"]["averageItemLevelEquipped"].ToString());
jsonObject["items"]["averageItemLevel"].Parent.Remove();
jsonObject["items"]["averageItemLevelEquipped"].Parent.Remove();
var finalJson = jsonObject.ToString(Newtonsoft.Json.Formatting.None);
var character = _serializer.Deserialize<Character>(finalJson);
character.progression.raids.RemoveAll(x => x.name != "My House");
return character
If I add these two classes to match your JSON I can serialize and deserialize the objects:
public class root
{
public Items items { get; set; }
}
public class Items
{
public int averageItemLevel { get; set; }
public int averageItemLevelEquipped { get; set; }
public Item head {get;set;}
public Item chest {get;set;}
public Item feet {get;set;}
public Item hands {get;set;}
}
Test rig with the WCF Serializer:
var obj = new root();
obj.items = new Items
{
averageItemLevel = 42,
feet = new Item { armor = 4242 },
chest = new Item { name = "super chest" }
};
var ser = new DataContractJsonSerializer(typeof(root));
using (var ms = new MemoryStream())
{
ser.WriteObject(ms, obj);
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
Console.WriteLine("and deserialize");
ms.Position = 0;
var deserializeObject = (root) ser.ReadObject(ms);
Console.WriteLine(deserializeObject.items.feet.armor);
}
And with the JavaScriptSerializer:
var jsser = new JavaScriptSerializer();
var json = jsser.Serialize(obj);
Console.WriteLine(json);
Console.WriteLine("and deserialize");
var djson = jsser.Deserialize<root>(json);
Console.WriteLine(djson.items.feet.armor);
Both serializers give the same result for your given JSON.

How to Create multi level Json using Jobject in C#?

I want to create multi level Json, Using http://json2csharp.com/. I created classes. But not sure how to use it.
public class MassPay
{
public string legal_name { get; set; }
public string account_number { get; set; }
public string routing_number { get; set; }
public string amount { get; set; }
public string trans_type { get; set; }
public string account_class { get; set; }
public string account_type { get; set; }
public string status_url { get; set; }
public string supp_id { get; set; }
public string user_info { get; set; }
}
public class MassPayList
{
public string oauth_consumer_key { get; set; }
public string bank_id { get; set; }
public string facilitator_fee { get; set; }
public IList<MassPay> mass_pays { get; set; }
}
These are my classes and this is Json Format i want to create...
there are extra elements...
{
"oauth_consumer_key":"some_oauth_token",
"mass_pays":[
{"legal_name":"SomePerson1",
"account_number":"888888888",
"routing_number":"222222222",
"amount":"10.33",
"trans_type":"0",
"account_class":"1",
"account_type":"2"
},
{"legal_name":"SomePerson2",
"account_number":"888888888",
"routing_number":"222222222",
"amount":"10.33",
"trans_type":"0",
"account_class":"1",
"account_type":"1"}
]
}
So far i have come up with below code..I am using JObject, and all others wer single level so it was pretty easy. but when it comes to two or three level its difficult.
public JObject AddMassPayRequest(MassPayList lMassPayList, MassPay lMassPay)
{
JObject pin = new JObject(
new JProperty("legal_name", lMassPay.legal_name),
new JProperty("account_number", lMassPay.account_number),
new JProperty("routing_number", lMassPay.routing_number),
new JProperty("amount", lMassPay.amount),
new JProperty("trans_type", lMassPay.trans_type),
new JProperty("account_class", lMassPay.account_class),
new JProperty("account_type", lMassPay.account_type),
new JProperty("status_url", lMassPay.status_url),
new JProperty("supp_id", lMassPay.supp_id),
new JProperty("status_url", lMassPay.status_url),
new JProperty("user_info", lMassPay.user_info)
);
return pin;
}
public JObject AddMassPayRequestList(MassPayList lMassPayList, MassPay lMassPay)
{
JObject pin = new JObject(
new JProperty("mass_pays", lMassPayList.mass_pays),
new JProperty("bank_id", lMassPayList.bank_id),
new JProperty("facilitator_fee", lMassPayList.facilitator_fee),
new JProperty("oauth_consumer_key", lMassPayList.oauth_consumer_key)
);
return pin;
}
Can some one help me how to do this..?
if you're using ASP.NET MVC you just need to use the Json response action using your existing classes.
You could simply do something like this in a controller:
return Json(new { PoId = newPoId, Success = true });
or an actual concrete model class:
var _AddMassPayRequestList = new AddMassPayRequestList();
...
returning a populated instance of your AddMassPayRequestList class:
return Json(_AddMassPayRequestList);
So finally I got this answer, Its simple structure. Using this u can create any type of Json... It doesnt have to follow same structure..
The logic behind this is add things you want at start, create class and inside that properties you want to add into json. SO while passign just add for loop and pass Object to the list.. It will loop through and create JSon for You..
If you have any doubts, let me know happy to help you
public String ToJSONRepresentation(List<MassPay> lMassPay)
{
StringBuilder sb = new StringBuilder();
JsonWriter jw = new JsonTextWriter(new StringWriter(sb));
jw.Formatting = Formatting.Indented;
jw.WriteStartObject();
jw.WritePropertyName("oauth_consumer_key");
jw.WriteValue("asdasdsadasdas");
jw.WritePropertyName("mass_pays");
jw.WriteStartArray();
int i;
i = 0;
for (i = 0; i < lMassPay.Count; i++)
{
jw.WriteStartObject();
jw.WritePropertyName("legal_name");
jw.WriteValue(lMassPay[i].legal_name);
jw.WritePropertyName("account_number");
jw.WriteValue(lMassPay[i].account_number);
jw.WritePropertyName("routing_number");
jw.WriteValue(lMassPay[i].routing_number);
jw.WritePropertyName("amount");
jw.WriteValue(lMassPay[i].amount);
jw.WritePropertyName("trans_type");
jw.WriteValue(lMassPay[i].trans_type);
jw.WritePropertyName("account_class");
jw.WriteValue(lMassPay[i].account_class);
jw.WritePropertyName("account_type");
jw.WriteValue(lMassPay[i].account_type);
jw.WritePropertyName("status_url");
jw.WriteValue(lMassPay[i].status_url);
jw.WritePropertyName("supp_id");
jw.WriteValue(lMassPay[i].supp_id);
jw.WriteEndObject();
}
jw.WriteEndArray();
jw.WriteEndObject();
return sb.ToString();
}

Categories

Resources