Reputation: 1692
I have been up for hours trying to figure this out. There seem to be a lot of posts tip toe'ing around the issue I am having but none of the posts seem to work for me.
I very simply want to deserialize the $ref field in my json document using json.net
Example JSON:
{
"items": [
{ "$ref": "#/parameters/RequestId" },
{
"name": "user",
"in": "body",
"description": "User metadata object",
"required": true
}
],
"parameters": {
"RequestId": {
"name": "X-requestId",
"in": "header",
"description": "this is a request id",
"required": false
}
}
}
Example Classes:
public class Item
{
public string Name {get;set;}
public string In {get;set;}
public string Description {get;set;}
public bool Required {get;set;}
}
public class RootDoc
{
public List<Item> Items {get;set;}
public Dictionary<string, Item> Parameters {get;set;}
}
What I am expecting:
var doc = JsonConvert.DeserializeObject<RootDoc>(json, new JsonSerializerSettings()
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
Error = delegate (object sender, ErrorEventArgs args)
{
// Handle all errors
args.ErrorContext.Handled = true;
}
});
Assert.IsNotNull(doc);
Assert.IsNotNull(doc.Items);
Assert.IsTrue(doc.Items.Count == 2);
Assert.IsTrue(doc.Items[0].Name == "X-requestId");
Assert.IsTrue(doc.Items[1].Name == "user");
EDIT:
I answered the question below. I can't believe I had to do that but it works.
Upvotes: 2
Views: 1504
Reputation: 5764
You can use this code.
JObject o = JObject.Parse(json);
JToken tokenToReplace = o.SelectToken("$..$ref");
string[] s = tokenToReplace.Value<string>().Split('/');
string a = s[s.Length - 1];
JToken newToken = o.SelectToken("$.." + a);
JArray items = (JArray)o["items"];
items.Add(newToken);
tokenToReplace.Parent.Parent.Remove();
string newJson = o.ToString();
newJson
contains replaced $ref
.
Upvotes: 0
Reputation: 1692
Wow... So here is what I did to solve the problem. I'm not sure if there is an easier way and I can't believe json.net does not provide this out of the box.
var x = JObject.Parse(json);
var xx = x.Descendants().ToList().Where(d => d.Path.ToLower().EndsWith("$ref"));
foreach (var item in xx)
{
if (!item.HasValues)
continue;
string str = item.First.ToString().TrimStart(new char[] { '#' }).TrimStart(new char[] { '/' });
var split = str.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
JToken token = x;
for (int i = 0;i<split.Length; i++)
{
token = token[split[i]];
}
item.Parent.Replace(token);
}
var doc = JsonConvert.DeserializeObject<RootDoc>(x.ToString(), new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
// Handle all errors
args.ErrorContext.Handled = true;
}
});
Assert.IsNotNull(doc);
Assert.IsNotNull(doc.Items);
Assert.IsTrue(doc.Items.Count == 2);
Assert.IsTrue(doc.Items[0].Name == "X-requestId");
Assert.IsTrue(doc.Items[1].Name == "user");
Upvotes: 2