How to Get the Next value from a string in c#? - c#

I have this API Response as a string.
/subscriptions/5e5c4cca-75b4-412d-96a1-45a9446ef08c/resourcegroups/ft-us-point-dev/providers/microsoft.datafactory/factories/ftadfqpb/providers/Microsoft.ResourceHealth/availabilityStatuses/current
Response object look like this :
{
"id": "/subscriptions/5e5c4cca-75b4-412d-96a1-45a9446ef08c/resourcegroups/ft-us-point-dev/providers/microsoft.purview/accounts/ft-ue-pdc-dev-purview/providers/Microsoft.ResourceHealth/availabilityStatuses/current",
"name": "current",
"type": "Microsoft.ResourceHealth/AvailabilityStatuses",
"location": "eastus",
"properties": {
"availabilityState": "Unknown",
"title": "Unknown",
"summary": "We are currently unable to determine the health of this Azure Purview.",
"reasonType": "",
"occuredTime": "2022-05-24T08:10:58.4372995Z",
"reasonChronicity": "Transient",
"reportedTime": "2022-05-24T08:10:58.4372995Z"
}
Now, I need each and every value from this response.
For Example,
subscriptions value as 5e5c4cca-75b4-412d-96a1-45a9446ef08c,
resourcegroups value as ft-us-point-dev,
providers value as microsoft.datafactory,
factories value as ftadfqpb
How can I store these value so if in future if the api response has one or more values , my code is not affected by that.

Building on #Jeroen Mostert's idea:
var pairs =
#"/subscriptions/5e5c4cca-75b4-412d-96a1-45a9446ef08c/resourcegroups/ft-us-point-dev/providers/microsoft.purview/accounts/ft-ue-pdc-dev-purview/providers/Microsoft.ResourceHealth/availabilityStatuses/current"
.Split('/', StringSplitOptions.RemoveEmptyEntries)
.Chunk(2)
.Select(s => (key: s[0], value: s[1]))
.ToList();
Gets you a list of pairs. It can't be a dictionary as there are two providers. You should be able to do some more with that list though to get what you need.

Consider parsing to an XElement object which offers the advantage of providing the means to act on the values received:
XElement xel = new XElement("id");
var id = deserialized.id;
var parse = id.TrimStart(new char[]{'/'}).Split('/');
for (int key = 0; key < parse.Length; key+=2)
{
var value = key + 1;
if (key < parse.Length)
{
xel.Add(new XElement(parse[key], parse[value]));
}
else System.Diagnostics.Debug.Assert(false, "Mismatched pair.");
}
Test runner:
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Newtonsoft.Json;
namespace json_model
{
class Program
{
static void Main(string[] args)
{
Model deserialized = JsonConvert.DeserializeObject<Model>(json);
// [Prelim] Requires further testing
XElement xel = new XElement("id");
var id = deserialized.id;
var parse = id.TrimStart(new char[]{'/'}).Split('/');
for (int key = 0; key < parse.Length; key+=2)
{
var value = key + 1;
if (key < parse.Length)
{
xel.Add(new XElement(parse[key], parse[value]));
}
else System.Diagnostics.Debug.Assert(false, "Mismatched pair.");
}
Console.WriteLine(xel.ToString());
Console.WriteLine();
// An XElement is simple to search on and iterate.
Console.WriteLine("Processing:");
foreach (var element in xel.Elements("providers"))
{
Console.WriteLine($"'{(string)element}' is a Provider");
}
}
class Model
{
public string id { get; set; }
public string name { get; set; }
public Dictionary<string, string> properties { get; set; }
}
const string json = #"{
""id"": ""/subscriptions/5e5c4cca-75b4-412d-96a1-45a9446ef08c/resourcegroups/ft-us-point-dev/providers/microsoft.purview/accounts/ft-ue-pdc-dev-purview/providers/Microsoft.ResourceHealth/availabilityStatuses/current"",
""name"": ""current"",
""type"": ""Microsoft.ResourceHealth/AvailabilityStatuses"",
""location"": ""eastus"",
""properties"": {
""availabilityState"": ""Unknown"",
""title"": ""Unknown"",
""summary"": ""We are currently unable to determine the health of this Azure Purview."",
""reasonType"": """",
""occuredTime"": ""2022-05-24T08:10:58.4372995Z"",
""reasonChronicity"": ""Transient"",
""reportedTime"": ""2022-05-24T08:10:58.4372995Z""
}
}";
}
}

var responseId = "/subscriptions/5e5c4cca-75b4-412d-96a1-45a9446ef08c/resourcegroups/ft-us-point-dev/providers/microsoft.purview/accounts/ft-ue-pdc-dev-purview/providers/Microsoft.ResourceHealth/availabilityStatuses/current";
var parts = responseId.Substring(1).Split("/");
var results = new Dictionary<string, string>();
for(int keyIdx = 0; keyIdx < parts.Length; keyIdx += 2)
{
if(!results.ContainsKey(parts[keyIdx]))
results.Add(parts[keyIdx], parts[keyIdx + 1]);
}
Either call .Split('/').Skip(1) or .Substring(1).Split('/') to get rid of the leading /
Iterate through the parts by incrementing the loop variable with 2
If the key is already present ignore that key-value pair
Otherwise put the key value into the results collection

Related

Convert CSV to JSON, How to address columns containing comma(,) using c#

I tried to convert CSV data to JSON. It quiet worked fine but few columns have comma, while converting to json, comma contained data is getting split.
This is the code I tried,
var path = #"C:xyz\\abc.csv";
var csv = new List<string[]>();
var lines = File.ReadAllLines(path);
foreach (string line in lines)
csv.Add(line.Split(','));
var properties = lines[0].Split(',');
var listObjResult = new List<Dictionary<string, string>>();
for (int i = 1; i < lines.Length; i++)
{
var objResult = new Dictionary<string, string>();
for (int j = 0; j < properties.Length; j++)
objResult.Add(properties[j], csv[i][j]);
listObjResult.Add(objResult);
}
var json = JsonConvert.SerializeObject(listObjResult, Formatting.Indented);
List<ABCModel> desrilize = JsonConvert.DeserializeObject<List<ABCModel>>(json);
return desrilize;
CSV data
employee,emp city,state,emp address
"abc","efg","lkj","building name"
"wer","sdf","qwe","afj Building, near cross"
In above third line contains comma, which should not get split while converting to json. Where as using above code, its getting split. Kindly help.
Also there is a space in "emp city", how to define jsonProperty for the same while creating model.
Expected json
[
{
"employee": "abc",
"emp city": "efg",
"state": "lkj",
"emp address": "building name"
},
{
"employee": "wer",
"emp city": "sdf",
"state": "qwe",
"emp address": "afj Building, near cross"
}
]
You can try with csvHelper or csv converter.
using csv:
var options = new CsvOptions // Defaults
{
RowsToSkip = 0, // Allows skipping of initial rows without csv data
SkipRow = (row, idx) => string.IsNullOrEmpty(row) || row[0] == '#',
Separator = '\0', // Autodetects based on first row
TrimData = false, // Can be used to trim each cell
Comparer = null, // Can be used for case-insensitive comparison for names
HeaderMode = HeaderMode.HeaderPresent, // Assumes first row is a header row
ValidateColumnCount = true, // Checks each row immediately for column count
ReturnEmptyForMissingColumn = false, // Allows for accessing invalid column names
Aliases = null, // A collection of alternative column names
AllowNewLineInEnclosedFieldValues = false, // Respects new line (either \r\n or \n) characters inside field values enclosed in double quotes.
AllowBackSlashToEscapeQuote = false, // Allows the sequence "\"" to be a valid quoted value (in addition to the standard """")
AllowSingleQuoteToEncloseFieldValues = false, // Allows the single-quote character to be used to enclose field values
NewLine = Environment.NewLine // The new line string to use when multiline field values are read (Requires "AllowNewLineInEnclosedFieldValues" to be set to "true" for this to have any effect.)
};
var csv = File.ReadAllText(fileName or filePath);
foreach (var line in CsvReader.ReadFromText(csv, options))
{
yourModel.Add(new yourModel()
{
StoneCode = line["Field1"],
StoneTypeName = line["Field2"],
});
}
To read your desired CSV input by using CsvHelper, this example should help you:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using CsvHelper;
using CsvHelper.Configuration;
public class Program
{
public static void Main()
{
var csvContent = #"employee,emp city,state,emp address
""abc"",""efg"",""lkj"",""building name""
""wer"",""sdf"",""qwe"",""afj Building, near cross""";
List<Employee> employees;
using (var reader = new StringReader(csvContent))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<EmployeeMap>();
var records = csv.GetRecords<Employee>();
employees = records.ToList();
}
foreach (var employee in employees)
{
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(employee));
}
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Map(e => e.Name).Name("employee");
Map(e => e.City).Name("emp city");
Map(e => e.State).Name("state");
Map(e => e.Address).Name("emp address");
}
}
public class Employee
{
public string Name { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Address { get; set; }
}
Here is another one to the list, Cinchoo ETL - an open source library does the job of converting CSV to JSON quickly as below
string csv = #"employee,emp city,state,emp address
""abc"",""efg"",""lkj"",""building name""
""wer"",""sdf"",""qwe"",""afj Building, near cross""";
using (var r = ChoCSVReader.LoadText(csv)
.WithFirstLineHeader()
.MayHaveQuotedFields()
)
{
using (var w = new ChoJSONWriter(Console.Out))
{
w.Write(r);
}
}
Output:
[
{
"employee": "abc",
"emp city": "efg",
"state": "lkj",
"emp address": "building name"
},
{
"employee": "wer",
"emp city": "sdf",
"state": "qwe",
"emp address": "afj Building, near cross"
}
]
Sample fiddle: https://dotnetfiddle.net/Dk4vtO

how do I extract a specific substring from a string in c# using a loop?

I am trying to extract just the route number from a response I get from a web server. The response looks like this;
[{"Description":"METRO Blue Line","ProviderID":"8","Route":"901"},{"Description":"METRO Green Line","ProviderID":"8","Route":"902"},
All I need is to get the route numbers so I can populate a combobox with them. I am trying to use a loop as there are quite a few. My current solution gets the first route number, but then for some reason I only get the provider number after that.This is what I have so far.
//get bus routes and popluate the busRoutecmb
restClient.endPoint = routeUrl + formatLine;
string response = restClient.request();
//show me what was returned for debug puposes
System.Diagnostics.Debug.Write(response);
//sort through data and put relevent item in a list
List<string> responseItems = new List<string>();
//splitting into routes
string[] splitByRoute = response.Split('}');
//extracting route number from elements in splitByRoute
List<string> extractedRouteNums = new List<string>();
foreach (string thing in splitByRoute)
{
//splitting each bus route up by piece of information
string[] splitByWord = thing.Split(',');
//getting rid of everything but the route number
int length = splitByWord.Length;
int count = 2;
while (count <= length)
{
string[] word = splitByWord[count].Split(':');
string routeNum = word[1].Trim('"');
count += 3;
extractedRouteNums.Add(routeNum);
System.Diagnostics.Debug.WriteLine(count);
System.Diagnostics.Debug.WriteLine(routeNum);
}
}
//add repsonse to busRoutecmb
busRoutecmb.DataSource = extractedRouteNums;
}
Gratzy is right about this being JSON, but I would propose you use JSON.NET to deserialize it.
var items = JsonConvert.DeserializeObject<JArray>(response);
var routeNumbers = items.Select(i => i.Value<string>("Route")).ToList();
You could also use http://json2csharp.com/ to produce a strongly-typed model, and deserialize to that model type if you prefer.
public class RootObject
{
public string Description { get; set; }
public string ProviderID { get; set; }
public string Route { get; set; }
}
var items = JsonConvert.DeserializeObject<RootObject[]>(response);
var routeNumbers = items.Select(i => i.Route).ToList();
What your getting back is basically a JSON string which is just an array of name value pairs or a Dictionary List.
[{
"Description": "METRO Blue Line",
"ProviderID": "8",
"Route": "901"
},
{
"Description": "METRO Green Line",
"ProviderID": "8",
"Route": "902"
}]
You can deserialize that string into a List in several ways one is to use System.Web.Script.Serialization.JavaScriptSerializer or JSON.NET. Once in a List you can query that list and return just the route key,Value pair.
var data = "[{ Description:\"METROBlueLine\",ProviderID:\"8\",Route:\"901\"},{Description:\"METRO Green Line\",ProviderID:\"8\",Route:\"902\"}]";
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
var mylist = ser.Deserialize<List<Dictionary<string,string>>>(data);
//or JSON.net
var mylist = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
var routes = mylist.SelectMany(a => a).Where(c => c.Key == "Route").ToList();
foreach (var route in routes)
Console.Write(route);
output
[Route, 901][Route, 902]
If you really only want the values then
var routesonly = routes.Select(r => r.Value).ToList();

Creating JSON from a CSV file in C#

First of all my apologies because this is going to be a "How to" question rather than a technical question. I have a CSV file as follows-
London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4
Now my plan is to create a JSON object from that CSV in the following format-
[
{
"From": "London",
"To": "Dubai",
"Duration": 4
},
{
"From": "Dubai",
"To": "Mumbai",
"Duration": 8
},
{
"From": "Dubai",
"To": "Dhaka",
"Duration": 4
},
]
How do I go about and do that? Currently I can load the CSV using OpenFileDialog but no idea what else I should do to get it done? Use Model Classes? JSON.Net? Please advice me and some code samples would be appreciated!
You can add csv records to a List<T> and then serialize it with Newtonsoft.Json to get your required JSON object. See the example below:
class Program
{
static void Main(string[] args)
{
string[] csv = new[] { "London,Dubai,4", "Dubai,Mumbai,8", "Dubai,Dhaka,4" };
List<model> list = new List<model>();
foreach (var item in csv)
{
string[] fields = item.Split(',');
list.Add(new model
{
From = fields[0],
To = fields[1],
Duration = fields[2]
});
}
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadLine();
}
}
public class model
{
public string From { get; set; }
public string To { get; set; }
public string Duration { get; set; }
}
You can use TextFieldParser from the Microsoft.VisualBasic.FileIO namespace and Microsoft.VisualBasic.dll assembly to parse CSV files. Despite the VisualBasic name the class is perfectly usable in c#.
First, add the following extension method:
public static class TextFieldParserExtensions
{
public static IEnumerable<string []> ReadAllFields(this TextFieldParser parser)
{
if (parser == null)
throw new ArgumentNullException();
while (!parser.EndOfData)
yield return parser.ReadFields();
}
}
Now you can use LINQ to transform each CSV line into an anonymous or named type for serialization, like so:
var csv = #"London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4";
string json;
using (var stream = new StringReader(csv))
using (TextFieldParser parser = new TextFieldParser(stream))
{
parser.SetDelimiters(new string[] { "," });
var query = parser.ReadAllFields()
.Select(a => new { From = a[0], To = a[1], Duration = int.Parse(a[2]) });
json = new JavaScriptSerializer().Serialize(query);
}
Here I am using JavaScriptSerializer but the same code can be used with json.net
json = JsonConvert.SerializeObject(query, Formatting.Indented);
Be sure to evaluate the query before closing the TextFieldParser.
I Believe this should work for all different kinds of .csv files
Comments are in the code
public class Program
{
public static void Main(string[] args)
{
var list = new List<Dictionary<string, string>>();
Console.WriteLine("Put in the path to your .csv file");
var response1 = Console.ReadLine();
Console.WriteLine("Initializing...");
// Read All of the lines in the .csv file
var csvFile = File.ReadAllLines(response1);
// Get The First Row and Make Those You Field Names
var fieldNamesArray = csvFile.First().Split(',');
// Get The Amount Of Columns In The .csv
// Do the -1 so you can use it for the indexer below
var fieldNamesIndex = fieldNamesArray.Count() - 1;
// Skip The First Row And Create An IEnumerable Without The Field Names
var csvValues = csvFile.Skip(1);
// Iterate Through All Of The Records
foreach (var item in csvValues)
{
var newDiction = new Dictionary<string, string>();
for (int i = 0; i < fieldNamesIndex;)
{
foreach (var field in item.Split(','))
{
// Think Of It Like This
// Each Record Is Technically A List Of Dictionary<string, string>
// Because When You Split(',') you have a string[]
// Then you iterate through that string[]
// So there is your value but now you need the field name to show up
// That is where the Index will come into play demonstrated below
// The Index starting at 0 is why I did the -1 on the fieldNamesIndex variable above
// Because technically if you count the fields below its actually 6 elements
//
// 0,1,2,3,4,5 These Are The Field Names
// 0,1,2,3,4,5 These Are The Values
// 0,1,2,3,4,5
//
// So what this is doing is int i is starting at 0 for each record
// As long as i is less than fieldNamesIndex
// Then split the record so you have all of the values
// i is used to find the fieldName in the fieldNamesArray
// Add that to the Dictionary
// Then i is incremented by 1
// Add that Dictionary to the list once all of the values have been added to the dictionary
//
// Add the field name at the specified index and the field value
newDiction.Add(fieldNamesArray.ElementAt(i++), field);
}
list.Add(newDiction);
}
}
Console.WriteLine("Would You Like To Convert To Json Now?");
Console.WriteLine("[y] or [n]");
var response = Console.ReadLine();
if (response == "y")
{
Console.WriteLine("Where Do You Want The New File?");
var response2 = Console.ReadLine();
// Serialize the list into your Json
var json = JsonConvert.SerializeObject(list);
File.Create(response2).Dispose();
File.AppendAllText(response2, json);
Console.WriteLine(json);
Console.ReadLine();
}
else
{
Console.WriteLine("Ok See You Later");
Console.ReadLine();
}
}
}

Get values and keys in json object using Json.Net C#

Hi there I have json that looks like this:
{
"Id": " 357342524563456678",
"title": "Person",
"language": "eng",
"questionAnswer": [
{
"4534538254745646.1": {
"firstName": "Janet",
"questionNumber": "1.1"
}
}
]
}
Now I have written some code that loops over the objects in the questionAnswer array and then gets the name of the object which is 4534538254745646.1. Now Im trying to save the key of each Item and the value aswell but I am only managing to get the value.
How would I do this, here is my code:
JToken entireJson = JToken.Parse(json);
JArray inner = entireJson["questionAnswer"].Value<JArray>();
foreach(var item in inner)
{
JProperty questionAnswerDetails = item.First.Value<JProperty>();
//This line gets the name, which is fine
var questionAnswerSchemaReference = questionAnswerDetails.Name;
var properties = questionAnswerDetails.Value.First;
//This only gets Janet
var key = properties.First;
var value = properties.Last;
}
So at the moment Im only able to get Janet, But I also want the firstname field. I want to then take this and add to a dictionary i.e.
Dictionary<string, string> details = new Dictionary<string, string>();
//suedo
foreach(var item in questionAnswerObjects)
details.Add(firstName, Janet);
//And then any other things found below this
So Here is he complete code that gets the keys and values for each item in the object in the array:
string key = null;
string value = null;
foreach(var item in inner)
{
JProperty questionAnswerDetails = item.First.Value<JProperty>();
var questionAnswerSchemaReference = questionAnswerDetails.Name;
var propertyList = (JObject)item[questionAnswerSchemaReference];
questionDetails = new Dictionary<string, object>();
foreach (var property in propertyList)
{
key = property.Key;
value = property.Value.ToString();
}
questionDetails.Add(key, value);
}
I can now add key and value to the dictionary

Convert Newtonsoft.Json.Linq.JArray to a list of specific object type

I have the following variable of type {Newtonsoft.Json.Linq.JArray}.
properties["Value"] {[
{
"Name": "Username",
"Selected": true
},
{
"Name": "Password",
"Selected": true
}
]}
What I want to accomplish is to convert this to List<SelectableEnumItem> where SelectableEnumItem is the following type:
public class SelectableEnumItem
{
public string Name { get; set; }
public bool Selected { get; set; }
}
I am rather new to programming and I am not sure whether this is possible. Any help with working example will be greatly appreciated.
Just call array.ToObject<List<SelectableEnumItem>>() method. It will return what you need.
Documentation: Convert JSON to a Type
The example in the question is a simpler case where the property names matched exactly in json and in code. If the property names do not exactly match, e.g. property in json is "first_name": "Mark" and the property in code is FirstName then use the Select method as follows
List<SelectableEnumItem> items = ((JArray)array).Select(x => new SelectableEnumItem
{
FirstName = (string)x["first_name"],
Selected = (bool)x["selected"]
}).ToList();
The API return value in my case as shown here:
{
"pageIndex": 1,
"pageSize": 10,
"totalCount": 1,
"totalPageCount": 1,
"items": [
{
"firstName": "Stephen",
"otherNames": "Ebichondo",
"phoneNumber": "+254721250736",
"gender": 0,
"clientStatus": 0,
"dateOfBirth": "1979-08-16T00:00:00",
"nationalID": "21734397",
"emailAddress": "sebichondo#gmail.com",
"id": 1,
"addedDate": "2018-02-02T00:00:00",
"modifiedDate": "2018-02-02T00:00:00"
}
],
"hasPreviousPage": false,
"hasNextPage": false
}
The conversion of the items array to list of clients was handled as shown here:
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
JObject result = JObject.Parse(responseData);
var clientarray = result["items"].Value<JArray>();
List<Client> clients = clientarray.ToObject<List<Client>>();
return View(clients);
}
I can think of different method to achieve the same
IList<SelectableEnumItem> result= array;
or (i had some situation that this one didn't work well)
var result = (List<SelectableEnumItem>) array;
or use linq extension
var result = array.CastTo<List<SelectableEnumItem>>();
or
var result= array.Select(x=> x).ToArray<SelectableEnumItem>();
or more explictly
var result= array.Select(x=> new SelectableEnumItem{FirstName= x.Name, Selected = bool.Parse(x.selected) });
please pay attention in above solution I used dynamic Object
I can think of some more solutions that are combinations of above solutions. but I think it covers almost all available methods out there.
Myself I use the first one
using Newtonsoft.Json.Linq;
using System.Linq;
using System.IO;
using System.Collections.Generic;
public List<string> GetJsonValues(string filePath, string propertyName)
{
List<string> values = new List<string>();
string read = string.Empty;
using (StreamReader r = new StreamReader(filePath))
{
var json = r.ReadToEnd();
var jObj = JObject.Parse(json);
foreach (var j in jObj.Properties())
{
if (j.Name.Equals(propertyName))
{
var value = jObj[j.Name] as JArray;
return values = value.ToObject<List<string>>();
}
}
return values;
}
}
Use IList to get the JArray Count and Use Loop to Convert into List
var array = result["items"].Value<JArray>();
IList collection = (IList)array;
var list = new List<string>();
for (int i = 0; i < collection.Count; j++)
{
list.Add(collection[i].ToString());
}

Categories

Resources