0

Having this JSON structure :

[
  {
    "Id": 885758,
    "IssueId": 611932,
    "Pinpoint": {
      "Name": null,
      "Position": {
        "X": -32.452857971191406,
        "Y": -14.971426010131836,
        "Z": 9.111014366149902
      },
      "Element1": null,
      "Element2": null
    }
  },
  {
    "Id": 885764,
    "IssueId": 611932,
    "Pinpoint": {
      "Name": null,
      "Position": {
        "X": -21.042057037353516,
        "Y": -21.742080688476562,
        "Z": 7.72857141494751
      },
      "Element1": null,
      "Element2": null
    },
  },
  {
    "Id": 885765,
    "IssueId": 611932,
    "Pinpoint": null
  }
]

I want to be able to obtain a List of JToken containing all Pinpoints that are not null So basically something like this :

  {
    "Pinpoint": {
      "Name": null,
      "Position": {
        "X": -32.452857971191406,
        "Y": -14.971426010131836,
        "Z": 9.111014366149902
      },
      "Element1": null,
      "Element2": null
    }
  },
  {
    "Pinpoint": {
      "Name": null,
      "Position": {
        "X": -21.042057037353516,
        "Y": -21.742080688476562,
        "Z": 7.72857141494751
      },
      "Element1": null,
      "Element2": null
    }
  }

Image here of what a normal LINQ select without the where condition returns : enter image description here

This is what I tried so far with related errors / exceptions :

//Cannot access child value on Newtonsoft.Json.Linq.JValue
List<JToken> results = JArray.Parse(response.Content)
    .Select(x => x["Pinpoint"])
    .Where(x => x["Pinpoint"] != null)
    .ToList();

//Object reference not set to an instance of an object.
List<JToken> results = JArray.Parse(response.Content)
    .Select(x => x["Pinpoint"])
    .Where(x => x["Pinpoint"].HasValues)
    .ToList();

//Object reference not set to an instance of an object.
List<JToken> results = JArray.Parse(response.Content)
    .Select(x => x["Pinpoint"])
    .Where(x => x["Pinpoint"].Type != JTokenType.Null)
    .ToList();
uwponcel
  • 786
  • 6
  • 15
  • Does [Checking for empty or null JToken in a JObject](https://stackoverflow.com/q/24066400) answer your question? – dbc Jun 16 '22 at 15:45
  • Errors are shown in the last **C# code block** see the comments. And no unfortunately it doesn't answer my question I can't make it work. – uwponcel Jun 16 '22 at 15:47
  • Edited for clarity – uwponcel Jun 16 '22 at 15:51
  • 1
    You need to put your `Where` clauses before your `Select` clause. Once you've done `.Select(x => x["Pinpoint"])` your current item will be the value of `x["Pinpoint"]` so you can't do `x => x["Pinpoint"] != null` subsequently. Or keep the `Where` clause first and do `.Where(p => !p.IsNullOrEmpty())` next, where `IsNullOrEmpty()` is from the linked question [Checking for empty or null JToken in a JObject](https://stackoverflow.com/q/24066400). – dbc Jun 16 '22 at 15:52
  • 1
    Demo of using Brian Roger's `JsonExtensions.IsNullOrEmpty(this JToken token)` here: https://dotnetfiddle.net/INCWaq. Do you need a separate answer or is a duplicate OK? – dbc Jun 16 '22 at 16:01
  • You can mark it as duplicate ty for the answer! However, could you explain why `x["Pinpoint"].Type !=null` doesn't work but `x["Pinpoint"].Type != JTokenType.Null` does achieve what I want? Also if im selecting the value of `x["Pinpoint"]` why can't I check for null directly ? Im still quite confused. – uwponcel Jun 16 '22 at 16:07
  • 1
    A null `JToken` will be returned when the value isn't present at all in the JSON. A non-null `JToken` will be returned with type `JTokenType.Null` when the value was found in the JSON but the value itself was null. I.e. if you do `x["Pinpoint"]` then if your JSON object looks like `{}` you will get back null but if your JSON object looks like `{"Pinpoint":null}` you will get back a `JValue` with `JTokenType.Null`. So you must check for both. For details see [Strange behavior in json.net: why is a null JToken replaced with a non-null value?](https://stackoverflow.com/a/51777115/3744182). – dbc Jun 16 '22 at 16:12

1 Answers1

1

try this

List<JObject> pinPoints = JArray.Parse(json).Where(p => (p["Pinpoint"] as JObject) != null)
.Select(p => (JObject)p["Pinpoint"]).ToList();

UPDATE

thanks to @dbc, there is a shorthand

JArray.Parse(json).Select(p => p["Pinpoint"]).OfType<JObject>().ToList();
dbc
  • 104,963
  • 20
  • 228
  • 340
Serge
  • 40,935
  • 4
  • 18
  • 45
  • `JArray.Parse(json).Select(p => p["Pinpoint"]).OfType().ToList()` would work also and avoid doing `p["Pinpoint"]` twice. – dbc Jun 16 '22 at 18:46
  • @dbc Thank you! It is really interesting syntax. I will certainly use it in the future. – Serge Jun 16 '22 at 18:50
  • I removed the cast from inside the `Select(p => p["Pinpoint"])` because, if `p["Pinpoint"]` is a `JValue` with `JTokenType.Null`, it will throw an exception. `OfType()` will filter them (as well as the actual null values) out later. – dbc Jun 16 '22 at 19:23