Search for one key in multi-level JSON array - c#

I receive JSON output from several different web services. I need to obtain some token data from each service however it's in a different array each time. E.g.:
Service 1:
{
"service_name": "service1",
"service1_data": {
"token_data": "WSD123456789"
}
}
Service 2:
{
"service_name": "service2",
"service2_data": {
"token_data": "QSD76662345"
}
}
So I'm looking for a way to search for the value of "token_data" no matter where in the arrays it may be. At the moment I have to get it manually like so:
json1["service1_data"]["token_data"]
If theres a simple way to do this it would be much appreciated. Thanks!

You could convert the JSON to XML and then use an xpath like '//token_data' to find the token, assuming a simple string search or regex is not an option.
byte[] bytes = Encoding.ASCII.GetBytes(json);
using (var stream = new MemoryStream(bytes))
{
var quotas = new XmlDictionaryReaderQuotas();
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(stream, quotas);
var xml = XDocument.Load(jsonReader);
}
Xpath info can be found here

As suggested in the comments, you could use JSONPath.
In your scenario, $.service1_data.token_data.* should get you all the values you want.
This works only if the depth of token_data in the array is always the same.

The Newtonsoft.Json package - available on NuGet Install-Package Newtonsoft.Json allows you to walk Json objects using LINQ expressions.
var jsonText = #"{
""service_name"": ""service1"",
""service1_data"": {
""token_data"": ""WSD123456789""
}
}";
var jsonObject = JsonConvert.DeserializeObject<JToken>(jsonText);
System.Diagnostics.Debug.Assert(jsonObject["service1_data"].Value<string>("token_data") == "WSD123456789");
See the JToken reference to learn how to retrieve values from Json.

Related

How to delete and update based on a path in System.Text.Json (.NET 6)?

I have a JSON text:
{
"a":[
{
"a1":"string",
"a2":"string",
"a3":"string"
}
],
"b":"2021-12-29T14:20:21.948Z",
"c":{
"c1":[
{
"c11":"string",
"c12":"string",
"c13":"string",
"c14":true,
"c15":true,
"c16":"2021-12-29T14:20:21.948Z",
"c17":"string"
}
]
}
}
JsonNode class always has a unique path I want to use them to find a specific value (update/delete them).
So, I want to use System.Text.Json and .NET 6 to have the following methods:
public static JsonNode UpdateValue(string json /*JsonNode json*/, string path, object value)
{
// ?
}
public static JsonNode RemovePath(string json /*JsonNode json*/, string path)
{
// ?
}
Is it possible?
In short: Unfortunately you can't
Modification
JsonDocument is readonly by design. Before JsonNode has been introduced you had to
deserialize it as Dictionary<string, object>
perform the modification
serialize it back to json
Since JsonNode has been introduced in .NET 6 you can do the following
var node = JsonNode.Parse(json);
var rootObject = node as JsonObject;
var aArray = rootObject["a"] as JsonArray;
var firstA = aArray[0];
firstA["a3"] = "modified";
or in short
var node = JsonNode.Parse(json);
node["a"][0]["a3"] = "modified";
Locate element by Path
Even though the need has been expressed in 2019 it hasn't been address yet. But as layomia said
This feature is proposed for .NET 6, but not committed. To be clear, we acknowledge that this is an important feature for many users, however, work on features with higher priority may prevent this from coming in .NET 6.
Unfortunately this feature did not make it to the .NET 6.
There are 3rd party libraries which offers this capability for JsonDocument. One of the most mature one is called JsonDocumentPath. With its SelectElement method you can really easily retrieve the given field as JsonElement
var doc = JsonDocument.Parse(json);
JsonElement? a3 = doc.RootElement.SelectElement("$.a[0].a3");
Interoperability
Even though there is a way to convert JsonElement to JsonNode and in the other way around:
var a3Node = JsonSerializer.Deserialize<JsonNode>(a3.Value);
a3Node = "a";
it does not really help since the a3Node represents only the a3 field and according to my understanding you can't just merge two JsonNodes.
update json using Newtonsoft.Json
string json = File.ReadAllText("json");
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
jsonObj["a"][0]["test1"] = "new values";
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);

Convert Azure index Search result to json format data

I am fairly new to Azure search. While learning about it, I am wondering if it is possible to Convert the search result into a json formatted data(even if it is a complex one). So far, I have tried the following and was able to map it to a object.
parameters = new SearchParameters()
{
OrderBy = new[]{"companyName desc"},
Facets = new []{"companyName"}
};
using (var client = _azureSearchClientFactory.GetAzureIndexClientForAllAdverts())
{
client.Documents.Search<AdvertDetail>("Oslo", parameters);
}
If you want to covert the object to json string. As Yahnoosh mentioned that we could use the JsonConvert.SerializeObject(Object) to do that easily.
using Newtonsoft.Json
var json = JsonConvert.SerializeObject(object);

Parse the JSON string in the ASP.NET

I mostly work on the PHP , recently have switched to ASP.NET,
When parse the JSON, I can simply use -> to get the field, e.g.
foreach(json_decode($_POST['mandrill_events']) as $event) {
$event = $event->event;
$email_type = $event->msg->metadata->email_type;
}
However, in ASP.NET , there is no action, this is my attempt code
var post_data = Request.Form["mandrill_events"];
JavaScriptSerializer ser = new JavaScriptSerializer();
var post_data_json = ser.Deserialize<Dictionary<string, string>>(post_data);
foreach (var event_obj in post_data_json) {
//how to parse the event_obj?
}
Thanks a lot for helping.
use Newtonsoft Json.NET
JsonConvert.DeserializeObject<DataModel>(json);
Unless you want to write a C# class that represents the JSON you are POSTing (the safest solution), you can use the dynamic type to create an object which will look like your JSON. You can then do something like this answer to access the properties.
This solution doesn't give you type safety and the DLR will resolve the properties of the dynamic object at runtime.
As other answers have mentioned, your life will be made much easier by using Newtonsoft JSON which will allow you to write:
dynamic events = JsonConvert.DeserializeObject<dynamic>(post_data);
foreach(dynamic evt in events)
{
string emailType = evt.msg.metadata.email_type;
}

How to create a json string where a property contains a dot (period)?

I'm trying to send an HttpRequest that takes a JSON object like this:
{
"some.setting.withperiods":"myvalue"
}
I've been creating anonymous objects for my other requests, but I can't do that with this one since the name contains a dot.
I know I can create a class and specify the [DataMember(Name="some.setting.withperiods")] attribute, but there must be a more lightweight solution.
There is no "easy" way to achieve this because the . in C# is reserved.
However, you could achieve something pretty close by using a dictionary and collection initializer. It's still somewhat isolated, and doesn't require you to create a custom class.
var obj = new Dictionary<string, object>
{
{ "some.setting.withperiods", "myvalue" }
};
var json = JsonConvert.SerializeObject(obj);
//{"some.setting.withperiods":"myvalue"}
You can use "JsonProperty" attribute for the same For example
[JsonProperty(".Name")]
public string Name { get; set; }
On top of this I want to add how to retrieve the data from the json where it has name property starting with special character as in Web API 2.0 token has ".issued".
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var jsonRespons="json response from the web api";
var issue= JObject.Parse(jsonResponse).GetValue(".issued");
if you do it from in javascript, you can easily go back and forth, as shown with:
var obj = {
"some.setting.withdots":"myvalue"
};
var json = JSON.stringify(obj);
console.log(json);
var str = JSON.parse(json);
console.log(str);
have you tried putting it into a serialized string and sending that, then deserializing on the client-side?
you could do something like
var myAnnon = new
{
WithPeriod = "value"
};
var j = JsonConvert.SerializeObject(myAnnon);
j = j.Replace("WithPeriod", "some.setting.withdots");
You can use a JObject (part of Json.Net's LINQ-to-JSON API) to create the JSON in question:
string json = new JObject(new JProperty("some.setting.withperiods", "myvalue")).ToString();
Fiddle: https://dotnetfiddle.net/bhgTta
You could try prefixing your member names with a # to allow use of literals, but the way to do it is using [DataMember] as you have already mentioned in your question.

How do i convert a JSON string to a native C# array using a namespace compatible with Windows Store Apps?

I am trying to make a windows 8 Store app that gets results from a MySQL database from a PHP page as a REST service.
I'm looking for the PHP to return a JSON representation of an array of strings and have done that happily when dong the same between Javascript and PHP.
I need to take that same JSON string and use it in my C# Windows 8 store App, is there a way to take the return of that PHP page and convert it into a normal C# array, not a dictionary or more complex collection.
The database does have four fields so if i have to use a special object made for this i will, but I'd rather I didn't as this function doesn't require that amount of data.
The PHP page is like so - $search_text is passed in via a GET:
$databaseConnection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($databaseConnection->connect_error)
{
echo "Database connection failed: $databaseConnection->connect_error";
}
else
{
$search_text = $search_text."%";
$query = "SELECT DISTINCT street FROM gritroutes WHERE street LIKE ? LIMIT 5";
$statement = $databaseConnection->prepare($query);
$statement->bind_param('s', $search_text);
$statement->execute();
$statement->store_result();
$statement->bind_result($street);
$autonumber = 1;
while ($statement->fetch())
{
$resultarr[] = $street;
}
$statement->close();
echo json_encode($resultarr);
}
Just to be clear. I am writing a Windows Store App, the System.Web Namespace is unavailable so i can't use JavaScriptSerializer.
Just to add to Matthew's answer, you can deserialize using Json.NET (you can get it from NuGet), you'd do something like:
List<string> myStrings = JsonConvert.DeserializeObject<List<string>>(myJson);
This is in:
using Newtonsoft.Json;
Check out this article for practical example.
EDIT
- I'd also like to throw in this link, since it's just awesome.
I hope this helps.
Take a look at the JavaScriptSerializer class.
string myJson = "{blablabla I'm json}";
var serializer = new JavaScriptSerializer();
var myStrings = serializer.Deserialize<List<string>>(myJson);
foreach (var str in myString)
{
Console.WriteLine(str);
}
You could also use native Windows.Data.Json classes to do the parsing:
string json = #"[""item1"", ""item2"", ""item3""]";
var array = JsonArray.Parse(json).Select(i => i.GetString()).ToArray();

Categories