I have the following XML returned when I make an API call. I need to create an array that holds the <status> and <description> values for each of <order_status>, <payment_status>, and <fulfillment_status>. Can anyone share some knowledge that would help me?
<orderwave>
<call_result>
<order>
<order_number>17377</order_number>
<orderwave_order_number>RWD-336475921</orderwave_order_number>
<order_status>
<status>active</status>
<description>This order is free to be charged and shipped. It is open in the orderwave workflow.</description>
</order_status>
<payment_status>
<status>declined</status>
<description>This order has been declined by the payment network.</description>
</payment_status>
<fulfillment_status>
<status>not shipped</status>
<description>This order has not been allocated for shipment.</description>
</fulfillment_status>
</order>
</call_result>
<warning_count>0</warning_count>
<warnings/>
<error_count>0</error_count>
<errors/>
</orderwave>
LinqToXML is what you want I believe.
I haven't done this in a while so my syntax might not be perfect.
Something like this:
var xmlSource = contacts.Load(#"../../return.xml");
var q = xmlSource.Descendants("order").SelectMany(x => x.Elements("order_status")
To expand upon my earlier comment, an easy and quick way to do this is with List<T> Class and LINQ to XML.
Use a class to hold the data for each order - for example:
public class Order
{
public int OrderNumber { get; set; }
public string OrderStatus { get; set; }
public string OrderDescription { get; set; }
public string PaymentStatus { get; set; }
public string PaymentDescription { get; set; }
public string FulfillmentStatus { get; set; }
public string FulfillmentDescription { get; set; }
}
Next, you can load the XML into an XDocument, parse it with LINQ to XML and create a List of Order objects:
// Parse the XML string; you can also load the XML from a file.
XDocument xDoc = XDocument.Parse("<orderwave>....</orderwave>");
// Get a collection of elements under each order node
var orders = (from x in xDoc.Descendants("order")
// Use the data for each order node to create a new instance of the order class
select new Order
{
OrderNumber = ConvertTo.Int32(x.Element("order_number").Value),
OrderStatus = x.Element("order_status").Element("status").Value,
OrderDescription = x.Element("order_status").Element("description").Value,
PaymentStatus = x.Element("payment_status").Element("status").Value,
PaymentDescription = x.Element("payment_status").Element("description").Value,
FulfillmentStatus = x.Element("fulfillment_status").Element("status").Value,
FulfillmentDescription = x.Element("fulfillment_status").Element("description").Value
}).ToList();
// Convert the result to a list of Order objects
This is off the top of my head without testing it, but it should point you in the right direction if you want to use Lists instead of arrays.
Related
string json string = {\"GetMyClassListResult\":{\"MyClassList\":[{\"Id\":1,\"Amount\":\"5,00\"},{\"Id\":2,\"Amount\":\"10,00\"},{\"Id\":3,\"Amount\":\"20,00\"},{\"Id\":4,\"Amount\":\"25,00\"}],\"ReturnValues\":{\"ErrorCode\":1,\"ErrorDescription\":\"Successful\"}}}
How do get "Id":1" and "Amount":"5,00" ?
First, you would need to declare a class as following.
class MyClass
{
[JsonProperty(PropertyName = "Id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "Amount")]
public string Amount { get; set; }
}
and then, you can do the following in your method
var Jsonobj = JObject.Parse(json);
var list = JsonConvert.DeserializeObject<MyClass[]>(Jsonobj["GetMyClassListResult"]["MyClassList"].ToString()).ToList<MyClass>();
Hope that helps.
Combining the excellent Json.NET package with LINQ you could use:
var result = JObject.Parse(json)["GetMyClassListResult"]["MyClassList"]
.Select(item => new { Id = item["Id"], Amount = item["Amount"] })
.First();
result has the properties Id and Amount corresponding to the first item in the JSON array with values 1 and "5,00".
If instead you wanted an array of all items, just replace First() with ToArray().
So you have straight json and you're trying to convert it into an object to get some meaningful values?
I personally prefer working with classes where I can. I will throw my raw json into a json to C# converter. I like JsonUtils personally. (I have no affiliation, just a great free service.) There are some others out there, but it seems to be the most robust.
If you throw your raw json into there, you get the following classes:
public class MyClassList
{
public int Id { get; set; }
public string Amount { get; set; }
}
public class ReturnValues
{
public int ErrorCode { get; set; }
public string ErrorDescription { get; set; }
}
public class GetMyClassListResult
{
public IList<MyClassList> MyClassList { get; set; }
public ReturnValues ReturnValues { get; set; }
}
public class Example
{
public GetMyClassListResult GetMyClassListResult { get; set; }
}
Alright. Now that we have our models, we can deserialize the json. The most popular library for manipulating json is Newtonsoft.Json, which is available on NuGet or direct download.
You'll need to add a reference to that dll if you choose to download it; Nuget will auto-reference it when you install it.
At the top of your class file, you'll need to add
using Newtonsoft.Json;
along with your other using statements.
In your method you'll call JsonConvert.Deserialize<List<Example>>(json), which will give you your collection in POCOs.
Since there is only one object in the collection you can call .First() on the collection and then access the two values via the Id and Amount properties. You will need to make sure that System.Linq is in your using statements as well.
Full code:
var json = #"{\"GetMyClassListResult\":{\"MyClassList\":[{\"Id\":1,\"Amount\":\"5,00\"},{\"Id\":2,\"Amount\":\"10,00\"},{\"Id\":3,\"Amount\":\"20,00\"},{\"Id\":4,\"Amount\":\"25,00\"}],\"ReturnValues\":{\"ErrorCode\":1,\"ErrorDescription\":\"Successful\"}}}";
var collection = JsonConvert.Deserialize<List<Example>>(json);
var x = collection.First();
var amount = x.Amount;
var id = x.Amount;
You're then free to manipulate or work with those variables as you see fit. :)
first of all you need a class where you will de-serialize this string to your class object.
you need a class which will contain Id and Amount variable.
after that you can de-serialize this string to the object then you can access any data you want.
An existing JSON-based web-service returns a fairly messy JSON object, where all the useful data is contained in the elements of an array which is itself the content of a 1-element array. Something like this (I'm anonymising it, hopefully no typos):
{"rows":[[
{"name":"John","time":"2016-03-20 01:00:00","id":"2","code":"1234"},
{"name":"Sam","time":"2016-03-20 01:00:00","id":"24","code":"999"},
{"name":"Paul","time":"2016-03-20 01:00:00","id":"12","code":"6512"}
]]}
Using JSON.net I need to access each of those row sub-elements but I'm not sure how to iterate over this and if I should be deserializing to a concrete type or just reading the raw data from my json object.
The data will be aggregated inside a method so the 'type' of each row is not something that needs to be known outside the method.
rows will always be a 1-element array containing an array of elements as shown.
#Fals's solution should work well, but if you want to do away with the RootObject, you can use Json.Net's LINQ-to-JSON API to parse the JSON and get the data into a simple list of items that is easy to work with.
Assuming you have a class defined for the item data like this:
public class Item
{
public string name { get; set; }
public DateTime time { get; set; }
public string id { get; set; }
public string code { get; set; }
}
Then you can do this to get your list of items:
List<Item> items = JObject.Parse(json)["rows"][0]
.Select(jt => jt.ToObject<Item>())
.ToList();
Fiddle: https://dotnetfiddle.net/FtB3Cu
If you want to avoid declaring any classes at all and instead use an anonymous type, you can change the code to this:
var items = JObject.Parse(json)["rows"][0]
.Select(jt => new
{
name = (string)jt["name"],
time = (DateTime)jt["time"],
id = (string)jt["id"],
code = (string)jt["code"]
})
.ToList();
Fiddle: https://dotnetfiddle.net/0QXUzZ
It's simple, your root object contains a List<List<>>:
Your object should look like:
public class InnerObject
{
public string name { get; set; }
public DateTime time { get; set; }
public string id { get; set; }
public string code { get; set; }
}
public class RootObject
{
public List<List<InnerObject>> rows { get; set; }
}
Then use JSON.NET:
string json = #"{'rows':[[
{'name':'John','time':'2016-03-20 01:00:00','id':'2','code':'1234'},
{'name':'Sam','time':'2016-03-20 01:00:00','id':'24','code':'999'},
{'name':'Paul','time':'2016-03-20 01:00:00','id':'12','code':'6512'}
]]}";
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
By the way, this site json2csharp can generate the C# class from JSON, makes the life ease :)
EDIT:
You can also use dynamic, and then avoid the parser from the `RootObject:
var rootObject = JsonConvert.DeserializeObject<dynamic>(json);
rootObject.rows[0] <--- should have what you need
I'm trying to parse the following XML string that is being returned from a service.
DataReference.USZipSoapClient blah = new DataReference.USZipSoapClient("USZipSoap");
var results = blah.GetInfoByCity(tbCityName.Text).OuterXml;
returns the following
<NewDataSet xmlns=""><Table><CITY>Marana</CITY><STATE>AZ</STATE><ZIP>85653</ZIP><AREA_CODE>520</AREA_CODE><TIME_ZONE>M</TIME_ZONE></Table></NewDataSet>
I'm having no luck parsing the data:
I just want to display the results like City = Marana, State = AZ etc.
Why not just use XPath?
XmlDocument doc = new XmlDocument()
doc.LoadXml(results); // probably some try-catch here
var city = doc.SelectSingleNode("//CITY").InnerXml; //Handle null as well
You can create a serializing object and then serialize the data you get against that object, i used http://xmltocsharp.azurewebsites.net/ to generate the following xml object:
[XmlRoot(ElementName="Table")]
public class Table {
[XmlElement(ElementName="CITY")]
public string CITY { get; set; }
[XmlElement(ElementName="STATE")]
public string STATE { get; set; }
[XmlElement(ElementName="ZIP")]
public string ZIP { get; set; }
[XmlElement(ElementName="AREA_CODE")]
public string AREA_CODE { get; set; }
[XmlElement(ElementName="TIME_ZONE")]
public string TIME_ZONE { get; set; }
}
[XmlRoot(ElementName="NewDataSet")]
public class NewDataSet {
[XmlElement(ElementName="Table")]
public Table Table { get; set; }
[XmlAttribute(AttributeName="xmlns")]
public string Xmlns { get; set; }
}
Then just use the .net XML serializer to cast it to that object and use it in your code.
If you just need a string for visual inspection, a first step could be to convert the XMl to JSON with this code:
http://techhasnoboundary.blogspot.no/2011/08/convert-xml-to-json-using-c.html
Then you could go on by removing braces, replace comma with line break and colon with an equal sign.
Hi I Have the following XML
<Feed>
<Control>
<Username>Fnol13</Username>
<Password>12345</Password>
</Control>
<Repairer>
<RepairerName>Test</RepairerName>
<RepairerAddress>Test</RepairerAddress>
<RepairerTelephone>Test</RepairerTelephone>
</Repairer>
</Feed>
And a Model Class Containing following Properties
[Serializable]
public class Job {
public string Username { get; set; }
public string Password { get; set; }
public string Reference { get; set; }
public string RepairerAddress { get; set; }
public string RepairerTelephone { get; set; }
}
I am using following Linq Query to Extract Data from XML
var results = from job in xmlDoc.Descendants("Control")
select new Job {
Username = (string)job.Element("Username").Value,
Password = (string)job.Element("Password").Value
};
// Here I want to add as well Descendants("Repairer") using same query
return results.ToList();
Problem is that can return Descendants("Control") However I would like to get also Descendants("Repairer") and return in a same list as my model is showing. Could you please help me to write Linq Query and I am confirming you I am very new in Linq.
Your Model Job looks confusing to me because you may have multiple Control &
Repairer nodes in which case it should map to a collection. Anyways for current XML I assume you need the elements of first Repairer node, you can achieve it like this:-
var results = from job in xmlDoc.Root.Elements("Control")
let Repairer = job.Parent.Elements("Repairer").FirstOrDefault()
select new Job
{
Username = (string)job.Element("Username"),
Password = (string)job.Element("Password"),
RepairerName = (string)Repairer.Element("RepairerName"),
RepairerAddress = (string)Repairer.Element("RepairerAddress"),
RepairerTelephone = (string)Repairer.Element("RepairerTelephone")
};
Also, note (string)job.Element("Username") will give you the node value. There is no need to call the Value property.
Update:
You can use XDocument when working with LINQ-to-XML:-
XDocument xmlDoc = XDocument.Load(XMLpath);
You could do something like -
Reference = (string)job.Parent.Descendants("Repairer").FirstOrDefault().Element("RepairerAddress").Value;
I have a class called PurchaseOrderItem
public class PurchaseOrderItem
{
public Int64 PONumber { get; set; }
public string Description { get; set; }
public string UM { get; set; }
public int QTY { get; set; }
public double Cost { get; set; }
}
I'm trying to to read data from XML file by iterating sections from XML and populate data into PurchaseOrderItems which is List. But when i try the code below i'm getting an error message of "Object reference not set to an instance of an object."
I'm pretty sure i'm missing something because my poor OOP knowledge. Would someone kindly explain to me what causes this problem?
PurchaseOrderItems =
(from purchaseOrderItem in PO.Descendants("PurchaseOrder").Elements("ProductLineItem")
select new PurchaseOrderItem
{
PONumber = PONumber,
Description = purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("comments").Value.Trim(),
QTY = Convert.ToInt16(purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("OrderQuantity").Element("requestedQuantity").Element("ProductQuantity").Value.Trim()),
UM = purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("GlobalProductUnitOfMeasureCode").Value.Trim(),
Cost = Convert.ToDouble(purchaseOrderItem.Element("PurchaseOrder").Element("ProductLineItem").Element("requestedUnitPrice").Element("FinancialAmount").Element("MonetaryAmount").Value.Trim()),
}).ToList<PurchaseOrderItem>();
purchaseOrderItem is already a ProductLineItem element by the time you reach your select clause - so currently you're trying to find a PurchaseOrder element within ProductLineItem, which will return null if it isn't found. I suspect you just want:
PurchaseOrderItems =
(from purchaseOrderItem in PO.Descendants("PurchaseOrder").Elements("ProductLineItem")
select new PurchaseOrderItem
{
PONumber = PONumber,
Description = purchaseOrderItem.Element("comments").Value.Trim(),
QTY = (short) purchaseOrderItem.Element("OrderQuantity")
.Element("requestedQuantity")
.Element("ProductQuantity"),
UM = purchaseOrderItem.Element("GlobalProductUnitOfMeasureCode")
.Value.Trim(),
Cost = (double) purchaseOrderItem.Element("requestedUnitPrice")
.Element("FinancialAmount")
.Element("MonetaryAmount")
}).ToList();
Notes:
Using the explicit conversions from XElement to short, double etc is a more appropriate way of performing conversions for XML data
It looks like you're using double for currency values: don't do that - use decimal instead
Also, you may want to consider creating a static method in PurchaseOrderItem which knows how to deserialize one from an XElement; I often find that a pattern of:
class Foo
{
static Foo FromXElement(XElement element) { ... }
XElement ToXElement() { ... }
}
works well.