accessing items in an json.net jarray in c# - c#

My API returns
{
"result": [
{
"id": "51473",
"name": "serv-vc",
"modifydate": "2014-10-09 18:29:48.033",
"expirationoff": "false",
"createdate": "",
"scheduleoff": "false",
}
],
"status": 0
}
which I've stored as a JObject reponseobj
I'm having trouble figuring out how to access responseobj["result"][0]["id"].
Every time I try that, it gives an array about being out of bounds.
What am I missing?
I also tried
JArray resultarr = (JArray)responseobj.SelectToken("result");
resultarr[0]["id"]
but have the same results.

Assuming the response is in a string variable called response, this would do it:
JObject responseobj = JObject.Parse(response);
JObject result = (JObject)(responseobj.SelectToken("result") as JArray).First();
int id = result.Value<int>("id");

Try using:
JObject jObject = JObject.Parse( "{\"result\": [{\"id\": \"51473\", \"name\": \"serv-vc\", \"modifydate\": \"2014-10-09 18:29:48.033\", \"expirationoff\": \"false\", \"createdate\": \"\", \"scheduleoff\": \"false\", } ], \"status\": 0 }" );
And to access to the different nodes, you can use:
string name = jObject["result"]["name"].ToString();
string expirationoff = jObject["result"]["expirationoff"].ToString();
Or you can convert result in a new json a work on it
And to access to result you can do:
var result = jObject["result"][0];
Remember that you can have 0, 1, 2... x numbers of results in your json, then you need do reference to the first position.

Not sure what's your issue, but this seems to work for me :
static void Main(string[] args)
{
JObject j = JObject.Parse(
"{\"result\": [{\"id\": \"51473\", \"name\": \"serv-vc\", \"modifydate\": \"2014-10-09 18:29:48.033\", \"expirationoff\": \"false\", \"createdate\": \"\", \"scheduleoff\": \"false\", } ], \"status\": 0 }" );
var res = j["result"];
Console.Out.WriteLine(res);
// show an arrays
var maybe = j["result"][0];
Console.Out.WriteLine(maybe);
// shows the first object in the array
var fail = j["result"][0]["id"];
Console.Out.WriteLine(fail);
// shows 51473
}

var Jobj = ((JObject)RequestObject)["data"];
foreach (JObject content in Jobj.Children<JObject>()) {
foreach (JProperty prop in content.Properties()) {
Console.WriteLine(prop.Name);//the column name
Console.WriteLine(prop.Value.ToString());// column value
}
}

Related

Add a JSON string to an existing one in C#

I'm trying to add a JSON string to an existing one but still haven't been able to do it successfully.
This is the original string: originalJSONString
{
"properties": [
"property1",
"property2"
]
}
And I want to add this to the original string: JSONStringIwantToAdd
{
"filter": {
"Name": "some filter name",
"Parameters": {
"LookupKey": "somekey",
"LookupValue": "somevalue"
}
}
}
To make a resulting string like this: finalJSONString
{
"properties": [
"property1",
"property2"
],
"filter": {
"Name": "some filter name",
"Parameters": {
"LookupKey": "somekey",
"LookupValue": "somevalue"
}
}
}
This is my direction so far but I'm getting null in propertiesJObject and can't figure out afterwards.
Is this even the right direction I'm going?
var originalJObj = JObject.Parse(originalJSONString);
var tobeaddedJObj = JObject.Parse(JSONStringIwantToAdd);
var propertiesJObject = originalJObj["properties"] as JObject;
propertiesJObject.Add(tobeaddedJObj);
var serializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var finalJSONString = JObject.FromObject(originalJObj, serializer).ToString();
Can someone please help me with this?
Thank You for your time!
JSON.NET includes functionality to do exactly what you need: JContainer.Merge
Note that Merge modifies the original object, rather than returning a new one:
var original = JObject.Parse(#"{
""properties"": [
""property1"",
""property2""
]
}");
var toAdd = JObject.Parse(#"{
""filter"": {
""Name"": ""some filter name"",
""Parameters"": {
""LookupKey"": ""somekey"",
""LookupValue"": ""somevalue""
}
}
}");
original.Merge(toAdd, new JsonMergeSettings
{
// union array values together to avoid duplicates
MergeArrayHandling = MergeArrayHandling.Union
});
Fiddle link: https://dotnetfiddle.net/o51GuA
You can do this without explicitly using a serializer.
This code adds the first property from JSONStringIwantToAdd to originalJSONString:
var originalJson = "{\r\n \"properties\": [\r\n \"property1\",\r\n \"property2\"\r\n ]\r\n}";
var extraJson = "{\r\n \"filter\": {\r\n \"Name\": \"some filter name\",\r\n \"Parameters\": {\r\n \"LookupKey\": \"somekey\",\r\n \"LookupValue\": \"somevalue\"\r\n }\r\n }\r\n}";
var original = JObject.Parse(originalJson);
var extra = JObject.Parse(extraJson);
var newProperty = extra.Children().First() as JProperty;
original.Add(newProperty.Name, newProperty.Value);
var newJson = original.ToString();
Output:
{
"properties": [
"property1",
"property2"
],
"filter": {
"Name": "some filter name",
"Parameters": {
"LookupKey": "somekey",
"LookupValue": "somevalue"
}
}
}
This should work, the main issue was not accessing the filter property when adding it to the jobject. I would recommend adding some safeguards like checking for existing properties, this may not be as performant as possible. If speed is important you may have to write your own serializer/deserializer for json.net.
[Test]
public void AugmentJsonObjectTest()
{
// Given
var originalString = "{ \"properties\": [ \"property1\", \"property2\" ]}";
var stringToBeAdded = "{ \"filter\": { \"Name\": \"some filter name\", \"Parameters\": { \"LookupKey\": \"somekey\", \"LookupValue\": \"somevalue\" } }}";
// When
var originalObject = JObject.Parse(originalString);
var objectToBeAdded = JObject.Parse(stringToBeAdded);
originalObject.Add("filter", objectToBeAdded["filter"]);
var mergedObjectAsString = originalObject.ToString();
// Then
var expectedResult =
"{ \"properties\": [ \"property1\", \"property2\" ], \"filter\": { \"Name\": \"some filter name\", \"Parameters\": { \"LookupKey\": \"somekey\", \"LookupValue\": \"somevalue\" } }}";
// Parsing and toString to avoid any formatting issues
Assert.AreEqual(JObject.Parse(expectedResult).ToString(), mergedObjectAsString);
}
using Expando
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using Newtonsoft.Json;
namespace jsonConcat {
class Program {
static void Main (string[] args) {
ExpandoObject inputData;
ExpandoObject appendData;
using (TextReader inputReader = new StreamReader ("originalData.json"))
using (TextReader appendReader = new StreamReader ("appendData.json")) {
inputData = JsonConvert.DeserializeObject<ExpandoObject> (inputReader.ReadToEnd ());
appendData = JsonConvert.DeserializeObject<ExpandoObject> (appendReader.ReadToEnd ());
}
foreach (var item in appendData) {
inputData.TryAdd (item.Key.ToString (), item.Value);
}
using (TextWriter outputWriter = new StreamWriter ("outputData.json")) {
outputWriter.Write (JsonConvert.SerializeObject (inputData));
}
}
}
}

Casting JArray to Dynamic[] so NEST's IndexMany works

Problem description
I need to receive JSON array of objects (with almost any shape) and store them to ES database using function IndexMany (or some similar bulk indexing function). I found some clumsy solution with one drawback - it doesn't set _id property in ES correctly (according to the id property in JSON object).
And also I would like to know if there is any more elegant way how to achieve my goal without casting every JArray item to string and back to ExpandoObject.
Additional info
Elasticsearch DB 7.5.1
NEST (7.6.1)
Newtonsoft.Json (12.0.3)
TLDR
Is there any elegant solution of following code:
var settings = new ConnectionSettings(new Uri("http://localhost:9200")).DefaultIndex("people");
var client = new ElasticClient(settings);
// this string represents incoming JSON message
string json = #"[
{
""id"": ""1"",
""name"": ""Andrej"",
""surname"": ""Burak"",
""dob"": ""1921-11-10T00:00:00+00:00""
},
{
""id"": ""2"",
""name"": ""Franta"",
""surname"": ""Dobrota"",
""dob"": ""1933-10-05T00:00:00+00:00""
},
{
""id"": ""3"",
""name"": ""Milos"",
""surname"": ""Ovcacek"",
""dob"": ""1988-05-05T00:00:00+00:00""
}
]";
JArray jArray = JArray.Parse(json);
foreach (var jtoken in jArray)
{
var jobj = (JObject)jtoken;
jobj.Add("DbCreated", JToken.FromObject(DateTime.UtcNow));
jobj.Add("DbCreatedBy", JToken.FromObject("authors name"));
}
//working, but seems to me a bit too clumsy to convert every item to string and then back to dynamic object
var converter = new ExpandoObjectConverter();
dynamic[] dlst = jArray.Select(t => (dynamic)JsonConvert.DeserializeObject<ExpandoObject>(t.ToString(), converter)).ToArray();
//not working cast
dynamic[] dlstNW = jArray.ToObject<dynamic[]>();
var indexManyResponse = client.IndexMany(dlst); //working partially (but not using ID as index)
var indexManyResponseNotWorking = client.IndexMany(jArray); //not working
var indexManyResponseNotWorking2 = client.IndexMany(dlstNW); //not working
// expected behavior
dynamic[] jsondyn = new dynamic[]
{
new { Id = "1", Name = "foo" },
new { Id = "2", Name = "bar" },
new { Id = "3", Name = "baz" },
};
var indexManyResponseWithIndex = client.IndexMany(jsondyn); //working perfectly, but don't know how to acieve this
After #gnud pointed me to low-level client I think I have found my answer. Important thing is to build request manually like it was explained here.
var settings = new ConnectionSettings(new Uri("http://localhost:9200")).DefaultIndex("people").DisableDirectStreaming();
var client = new ElasticClient(settings);
// this string represents incoming JSON message
string json = #"[
{
""id"": ""1"",
""name"": ""Andrej"",
""surname"": ""Burak"",
""dob"": ""1921-11-10T00:00:00+00:00""
},
{
""Id"": ""2"",
""name"": ""Franta"",
""surname"": ""Dobrota"",
""dob"": ""1933-10-05T00:00:00+00:00""
},
{
""Id"": ""3"",
""name"": ""Milos"",
""surname"": ""Ovcacek"",
""dob"": ""1988-05-05T00:00:00+00:00""
}
]";
JArray jArray = JArray.Parse(json);
// I have to build my request manually
List<string> esRequest = new List<string>();
foreach (var jtoken in jArray)
{
var jobj = (JObject)jtoken;
jobj.Add("DbCreated", JToken.FromObject(DateTime.UtcNow));
jobj.Add("DbCreatedBy", JToken.FromObject("authors name"));
string id;
// Ensure that Id is set even if we receive it in lowercase
if( jobj["Id"] == null)
{
if( jobj["id"] == null)
{
throw new Exception("missing Id");
}
id = jobj["id"].Value<string>();
}
else
{
id = jobj["Id"].Value<string>();
}
string indexName = "people";
esRequest.Add($"{{\"index\":{{\"_index\":\"{indexName}\",\"_id\":\"{id}\"}}}}");
esRequest.Add(jobj.ToString(Formatting.None));
}
PostData pd = PostData.MultiJson(esRequest);
var llres = client.LowLevel.Bulk<BulkResponse>(pd);
Hope it helps someone.

JObject in C# for independent data fetching of JSON

I am using Json.Net to parse my JSON
This is my JSON:
"OptionType": {
"C": [
"C",
"Call"
],
"P": [
"P",
"Put"
]
}
Before this step, when processed, as a result, I would get a value from any of this.
For example Option Type: Call
Whatever value I get, I need it to be transcodified according to the above JSON.
Example: Option Type: C
First of all your sample data is not a valid JSON. You need to wrap it to the curvy braces.
If your sample is a part of the JSON object, you can map OptionType to the Dictionary<string, List<string>>.
To find valid option you will need to iterate this dictionary like in the sample below:
var valueToCheck = "Call";
string type = null;
foreach (var kvp in optionTypes)
{
if (kvp.Value.Contains(valueToCheck))
{
type = kvp.Key;
break;
}
}
Same using JObject with fixed JSON data:
var json = #"{
""OptionType"":{
""C"": [
""C"",
""Call""
],
""P"": [
""P"",
""Put""
]
}
}";
var valueToCheck = "Call";
string type = null;
var ot = JObject.Parse(json);
var objectType = ot["OptionType"];
foreach (var token in objectType)
{
var prop = token.ToObject<JProperty>();
var key = prop.Name;
var values = prop.Value.ToObject<List<string>>();
if (values.Contains(valueToCheck))
{
type = key;
break;
}
}
Code is not perfect but it is just an idea what to do.
You need to iterate over properties of JObject and then search your option type and then replace your search option with its parent key.
This is custom function can do above task.
public static JObject GetJObject(JObject jObject, List<string> optionType)
{
foreach (var type in jObject["OptionType"])
{
var key = type.ToObject<JProperty>().Name;
var values = type.ToObject<JProperty>().Value.ToObject<List<string>>();
foreach (var option in optionType)
{
if (values.Contains(option))
{
int index = values.IndexOf(option);
values.RemoveAt(index);
values.Insert(index, key);
}
}
JToken jToken = JToken.FromObject(values);
jObject.SelectToken("OptionType." + key).Replace(jToken);
}
return jObject;
}
And you can use above custom function this like
string json = File.ReadAllText(#"Path to your json file");
JObject jObject = JObject.Parse(json);
List<string> optionType = new List<string> { "Call", "Put" };
JObject result = GetJObject(jObject, optionType);
Output:

How to access children values of a JObject

I have a JObject item that looks like this:
{
"part":
{
"values": ["engine","body","door"]
"isDelivered": "true"
},
{
"manufacturer":
{
"values": ["Mercedes"]
"isDelivered": "false"
}
}
How can I get the values as a single string in C#?
First create JObject from your string
String json = "{\"part\":{ \"values\": [\"engine\",\"body\",\"door\"], \"isDelivered\": \"true\"},\"manufacturer\":{\"values\": [\"Mercedes\"],\"isDelivered\": \"false\"}}";
JObject jObject = JObject.Parse(json);
Then get values array (from part for example as)
JArray jArray= (JArray)jObject["part"]["values"];
Convert JArray of String to string array
string[] valuesArray = jArray.ToObject<string[]>();
Join your string array & create a singe string
String values = string.Join(",",valuesArray);
Full code here ..
String json = "{\"part\":{ \"values\": [\"engine\",\"body\",\"door\"], \"isDelivered\": \"true\"},\"manufacturer\":{\"values\": [\"Mercedes\"],\"isDelivered\": \"false\"}}";
JObject jObject = JObject.Parse(json);
JArray jArray= (JArray)jObject["part"]["values"];
string[] valuesArray = jArray.ToObject<string[]>();
String values = string.Join(",",valuesArray);
Console.WriteLine(values);
First things first, that json is not properly formatted, it should be:
{
"part":
{
"values": ["engine","body","door"],
"isDelivered": "true"
},
"manufacturer":
{
"values": ["Mercedes"],
"isDelivered": "false"
}
}
Now, getting to the answer, I believe this is what you want
var jObject = JObject.Parse(testJson);
var children = jObject.Children().Children();
var valuesList = new List<string>();
foreach (var child in children)
{
valuesList.AddRange(child["values"].ToObject<List<string>>());
}
var valuesJsonArray = JsonConvert.SerializeObject(valuesList); // not sure if you want an array of strings or a json array of strings

How to write "params" in JSON-RPC 2.0 in C#?

I want to use JSON-RPC to control an application called aria2. I can control it when it doesn't need params. But I tried many ways, I never successful in controlling it with params.
Some of the code I've tried is like this:
if (secret != null && secret != "")
json = JsonConvert.SerializeObject(new JObject { ["jsonrpc"] = "2.0", ["id"] = "m", ["method"] = "aria2.addUri", ["params"] = { "token:" + secret, "[http://csharp.org/file.zip]" } });
else
json = JsonConvert.SerializeObject(new JObject { ["jsonrpc"] = "2.0", ["id"] = "m", ["method"] = "aria2.addUri", ["params"] = #"[http://csharp.org/file.zip]" });
I also tried:
if (secret != null && secret != "")
string json = "{\"jsonrpc\": \"2.0\",\"method\": \"aria2.addUri\",\"params\": {\"token:\"" + secret + "\",\"http://csharp.org/file.zip\"},\"id\": \"m\"}";
else
string json = "{\"jsonrpc\": \"2.0\",\"method\": \"aria2.addUri\",\"params\": {\"http://csharp.org/file.zip\"},\"id\": \"m\"}";
And I have tried many combinations and permutations with [{'" but nothing works.
Here is the RPC guide about aria2 for Python:
https://aria2.github.io/manual/en/html/aria2c.html#rpc-authorization-secret-token
Here is the solution may some beginners want to know.
First, know what you want to output, in this case is:
{"jsonrpc":"2.0","id":"m","method":"aria2.addUri","params":["token:secret",["http://csharp.org/file.zip"]]}
Result is here: http://jsoneditoronline.org/?id=4ee8fb1e0314e124bd3ab7d4b2ed19f1
And then, the little tip, [] is outside from the params's value, so they're arrays, not string. It can't use ["params"] = {}, it also won't cover string to array, for example, following wrong code:
JsonConvert.SerializeObject(new JObject { ["params"] = "[\"token:secret\", [\"http://csharp.org/file.zip\"]]" });
only get:
{"params":"[\"token:secret\", [\"http://csharp.org/file.zip\"]]"}
The most important is the format of token, it's not a
JProperty() in JObject(), it's just a string in params's
JArray(). And uri is also in params's JArray()'s JArray(). So
the right version is:
JArray param = new JArray { "token:secret", new JArray { "http://csharp.org/file.zip" } };
string json = JsonConvert.SerializeObject(new JObject { ["jsonrpc"] = "2.0", ["id"] = "m", ["method"] = "aria2.addUri", ["params"] = param });
JArray() is [], JObject() is {}; JArray() ≠ JObject().
If we don't need JsonConvert(), the right version is easy:
string json = "{ \"jsonrpc\": \"2.0\", \"id\": \"m\", \"method\": \"aria2.addUri\", \"params\": [\"token:secret\", [\"http://csharp.org/file.zip\"]] }";
We can't change " to ' in this case.

Categories