I am wondering if we can take some parts inside a JSON string and print it out. I have a JSON string and I only want to take some specific things in it.
My JSON string:
{
"A": {
"a1":[
{
"a11": {
"a111": "something1",
"a112": "something2"
},
"a12": [
{
"a121": "something1",
"a122": "something2"
},
{
"a211": "something1",
"a212": "soemthing2"
}
]
]
},
"B": {
"b1":[
{
"b11": {
"b111": "something1",
"b112": "something2"
},
"b12": [
{
"b121": "something1",
"b122": "something2"
},
{
"b211": "something1",
"b212": "soemthing2"
}
]
}
]
}
}
I only want to print out: b121 is something1. How can I do it in C#?
Firstly, your JSON example has some problems so I'll give an example using this part as the JSON file.
{
"B": {
"b1":
{
"b11": {
"b111": "something1",
"b112": "something2"
},
"b12": [
{
"b121": "something1",
"b122": "something2"
},
{
"b211": "something1",
"b212": "soemthing2"
}
]
}
}
}
You can access to a specific part like this using Json.NET:
var jsonData = File.ReadAllText(#"\test.json");
dynamic jsonObject = JsonConvert.DeserializeObject(jsonData);
// print out a specific part
Console.WriteLine(jsonObject.B.b1.b11.b111);
Related
I am trying to update a value which is a parameter in an array of JToken type. But I am getting the error below:
Set JArray values with invalid key value: "tagCategoryId". Int32 array index expected.
Below is my method:
JObject _asset;
JToken _tagCategoryObject ;
public void Test1()
{
var invalidTagCategoryId = "invalidTagCategoryId";
while (invalidTagCategoryId.Length <= 255) invalidTagCategoryId += invalidTagCategoryId;
_asset.TryGetValue("enumeratedTagCategories", out _tagCategoryObject);
if (_tagCategoryObject != null)
{
_tagCategoryObject["tagCategoryId"] = invalidTagCategoryId;
}
.....
}
Below is the json:
"enumeratedTagCategories": [
{
"tagCategoryId": "TagCategoryId",
"tagCategoryDisplayName": "TagCategoryDisplayName",
"version": "Version",
"tagValueIdsList": [
{
"displayName": "DisplayName1"
},
{
"displayName": "DisplayName2"
}
]
}
]
How can I assign a value to tagCategoryId ?
_tagCategoryObject is array so try this
var _tagCategoryObject = JObject.Parse(json)["enumeratedTagCategories"];
if (_tagCategoryObject != null)
{
_tagCategoryObject[0]["tagCategoryId"] = invalidTagCategoryId;
}
and fix you json by wrapping in {}
{ "enumeratedTagCategories": [
{
"tagCategoryId": "TagCategoryId",
"tagCategoryDisplayName": "TagCategoryDisplayName",
"version": "Version",
"tagValueIdsList": [
{
"displayName": "DisplayName1"
},
{
"displayName": "DisplayName2"
}
]
}
]
}
I'm trying to understand why JSON.Net will modify the original JObject (formSchema) in two cases below where I'm adding JArray and JObject
to objects I've defined as vars.
I assume the two vars I created were standalone objects in their own right but it appears they are not.
In the first case, requiredItems is a JArray var, in which I want to add the token "certification" to formSchema, but I've placed the Add method
on requiredItems. Not formSchema.
In the second case, I add certifyProperty to formSchema using the Add method on consentProps. The property handily gets added to formSchema
without a direct reference to it.
Why is this? Are they linked in memory? Where in the JSON.Net docs is this explained? I cannot find it.
namespace JSONProps
{
class Program
{
static void Main(string[] args)
{
string jsonSchema = #"
{
""jsonSchema"": {
""type"": ""object"",
""title"": ""a title"",
""properties"": {
""consent"": {
""type"": ""object"",
""title"": ""Consent of Applicant"",
""required"": [
""applicantConsent""
],
""properties"": {
""applicantConsent"": {
""type"": ""boolean"",
""title"": ""I give my Consent"",
},
}
}
}
}
}
";
// First case
var formSchema = JObject.Parse(jsonSchema);
var requiredProps = formSchema["jsonSchema"]["properties"]["consent"]["required"] as JArray;
requiredProps.Add("certification");
// Second case
var consentProps = formSchema["jsonSchema"]["properties"]["consent"]["properties"] as JObject;
var certifyProperty = JObject.Parse(#" { ""type"" : ""boolean"", ""title"" : ""This is true."" } ");
consentProps.Add("certification", certifyProperty);
Console.WriteLine(formSchema.ToString());
}
}
}
$ dotnet run
{
"jsonSchema": {
"type": "object",
"title": "a title",
"properties": {
"consent": {
"type": "object",
"title": "Consent of Applicant",
"required": [
"applicantConsent",
"certification"
],
"properties": {
"applicantConsent": {
"type": "boolean",
"title": "I give my Consent"
},
"certification": {
"type": "boolean",
"title": "This is true."
}
}
}
}
}
}
As you can see below, in the json i have "data", "data2" and invoice.
My goal is to split a json file in more parts that have "data" and "data2" and a part of "invoice".
I've de-serialized the string, that contain the json code, in a dynamic object so i need to make a partial copy of this in a temp dynamic object, serialize it and than continue my job.
string strJsonOuput = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlInput);
dynamic objComune = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(strJsonOuput);
This an example of the json:
{
"data": {
"a": "1",
"b": "2"
},
"data2": {
"something1": {
"thing1": "xxx",
},
"Invoice": [
{
"head": "bbb",
"body": {
"argument1":"aaa"
}
}
{
"head": "xxxx",
"body": {
"argument2": "ccc"
}
}
{
"head": "xxxx",
"body": {
"argument2": "ccc"
}
}
{...}
]
}
}
Below is my JSON:
[
{
"name": "Node-1",
"flag": true,
"myObj": {
region: {
info: {
name: null,
infoFlag: false,
}
}
},
"nodes": [
{
"name": "Node-1-1",
"flag": true,
"myObj": {
region: {
info: {
name: "abc",
infoFlag: false,
}
}
},
"nodes": [
{
"name": "Node-1-1-1",
"flag": true,
"myObj": {
region: {
info: {
name: "xyz",
infoFlag: false,
}
}
},
"nodes": [
]
}
]
}
]
}
]
I want to update two properties of my above JSON string with following rule :
Flag : I want to blindly update this property to false.
infoFlag: If name property of info is null then I want to update infoFlag to true else false if it is not null.
So after updating my JSON with these rules I want to have that JSON as a string.
Note: I don't want to deserialize and then update property based on above two rules as because my JSON has lots of properties for which I don't want to create classes, so I am looking for something which will work without deserializing with class.
This is how I am trying to do it:
string json = "MyJson";
var temp = JArray.Parse(json);
temp.Descendants()
.OfType<JProperty>()
json = temp.ToString();
But here I am not getting as how to traverse my JSON recursively; as you can see I have recursive structure like below :
Node-1
Node-1-1
Node-1-1-1
Json.NET allows you to treat its internal objects representing the JSON content as dynamic, which makes the task in question no harder than using regular typed objects.
The only kind of tough problem is the recursive object structure (the nodes array), but that's not a JSON or dynamic specific problem, and can be solved in many ways - the obvious recursive method or with my preferable tree flattening enumeration (the Expand method from my answer to How to flatten tree via LINQ?).
With that being said, the solution could be like this:
var array = JArray.Parse(json);
var nodes = array.Cast<dynamic>().Expand(x => x.nodes);
foreach (var node in nodes)
{
node.flag = true;
var info = node.myObj.region.info;
info.infoFlag = (info.name == null);
}
var newJson = array.ToString();
If I have understood your needs this code is pretty verbose and not so elegant but works:
JArray temp = JArray.Parse(json);
foreach (JToken tk in temp.Descendants())
{
if (tk.Type == JTokenType.Property)
{
JProperty p = tk as JProperty;
if (p.Name == "flag")
{
if ((bool)p.Value.ToObject(typeof(bool)) == true)
p.Value = false;
}
if ((p.Name == "info") && p.HasValues)
{
bool flag = false;
foreach (JToken tkk in p.Descendants())
{
if (tkk.Type == JTokenType.Property)
{
JProperty pp = tkk as JProperty;
if ((pp.Name == "name") && (pp.Value.Type == JTokenType.Null))
{
flag = true;
}
if ((pp.Name == "infoFlag"))
{
pp.Value = (flag == true) ? true : false;
}
}
}
}
}
}
json = temp.ToString();
This is the resulting output:
[
{
"name": "Node-1",
"flag": false,
"myObj": {
"region": {
"info": {
"name": null,
"infoFlag": true
}
}
},
"nodes": [
{
"name": "Node-1-1",
"flag": false,
"myObj": {
"region": {
"info": {
"name": "abc",
"infoFlag": false
}
}
},
"nodes": [
{
"name": "Node-1-1-1",
"flag": false,
"myObj": {
"region": {
"info": {
"name": "xyz",
"infoFlag": false
}
}
},
"nodes": []
}
]
}
]
}
]
I have this Document:
{
"$id": "1",
"DocType": "Unidade",
"Nome": "TONY",
"RG_InscricaoEstadual": "4347924938742",
"Setores": [
{
"$id": "9",
"Nome": "Child0",
"Setores": [
{
"$id": "10",
"Nome": "Child1",
"Setores": [
/* <n depth nested level> */
"$id": "11",
"Nome": "Child2",
"Id": "90228c56-eff2-46d2-a324-b04e3c69e15c",
"DocType": "Setor"
],
"Id": "60228c56-dff2-46d2-a324-b04e3c69e15b",
"DocType": "Setor"
}
],
"Id": "8457e1b7-39dc-462c-8f46-871882faea2c",
"DocType": "Setor"
}
]
}
How to query this SubDocument if I want to retrieve a Setor, for example
"Id": "60228c56-dff2-46d2-a324-b04e3c69e15b"
I know that if I know now many levels it is Nested, I can write a query to look for something like
Unidade.Setor.Id=="8457e1b7-39dc-462c-8f46-871882faea2c"
But How can I search for it for a unknown number of nested Levels, for example 1, 2, 3 n levels?
How to find the Setor with Id '90228c56-eff2-46d2-a324-b04e3c69e15c', for example?
Comments about how to solve this question will also be appreciated.
In c# we can create a recursive method to achieve this scenario.
Here is a BsonDocument I created:
BsonDocument doc = new BsonDocument {
{ "id","1"},
{ "DocType", "Unidade"},
{ "Nome", "TONY"},
{ "RG_InscricaoEstadual", "4347924938742"},
{ "Setores",new BsonArray {
new BsonDocument {
{ "id","9" },
{ "Nome", "Child0"},
{ "Setores", new BsonArray { new BsonDocument {
{ "id","10" },
{ "Nome", "Child1"},
{ "Setores", new BsonArray { new BsonDocument {
{ "id","11" },
{ "Nome", "Child2"},
{ "Id","90228c56-eff2-46d2-a324-b04e3c69e15c" },
{ "DocType", "Setor"}
}
}
},
{ "Id","60228c56-dff2-46d2-a324-b04e3c69e15b" },
{ "DocType", "Setor"}
}
}
},
{ "Id","8457e1b7-39dc-462c-8f46-871882faea2c" },
{ "DocType", "Setor"}
}
}
}
};
You can use Mongo c# Query method to get this BsonDocument from MongoDB.
Here is a recursive method I used to query document via "Id":
BsonDocument result = GetID(doc, "90228c56-eff2-46d2-a324-b04e3c69e15c");
public static BsonDocument GetID(BsonDocument doc, string queryId)
{
BsonDocument result = new BsonDocument();
if (doc.Elements.Where(c => c.Name == "Setores").Count() != 0)
{
foreach (var item in doc.GetElement("Setores").Value.AsBsonArray)
{
var id = item.AsBsonDocument.GetElement("Id").Value;
if (id == queryId)
{
result = item.AsBsonDocument;
break;
}
result = GetID(item.AsBsonDocument, queryId);
}
}
return result;
}
I hope this could give you some tips.
The only thing you could do is have nested queries i.e.
find({"Unidade.Setor.Id": ObjectId("8457e1b7-39dc-462c-8f46-871882faea2c")
find({"Unidade.Setor.Setor.Id": ObjectId("8457e1b7-39dc-462c-8f46-871882faea2c")
find({"Unidade.Setor.Setor.Setor.Id": ObjectId("8457e1b7-39dc-462c-8f46-871882faea2c")
Run then one after the other if the previous one fails.
But DON'T!!!
You should be storing these Setor records as separate documents. You can store them with references to each other and then query for them using lookup (like a join in SQL)
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/