-1

Working with NewtonSoft's Json library and using JObject to access various elements in complex json records. Below is a modified extract of one for the purposes of this question.

Accessing PID.2.1 using a literal path is successful, but replacing the path with a variable that contains the same path returns null.

I've read the documentation and I'm not sure why the approach using the variable does not work. What am I missing? Any insight is appreciated.

Here is a simple example demonstrating the issue.

string json = @"{
  ""organizationId"": ""FFAE1D00-D7EF-E123-B00D-D12345D0000"",
  ""hl7"": {
    ""HL7Message"": {
      ""PID"": {
        ""PID.1"": {
          ""PID.1.1"": 1
        },
        ""PID.2"": {
          ""PID.2.1"": ""1111111"",
          ""PID.2.2"": null,
          ""PID.2.3"": null,
          ""PID.2.4"": ""SXA SYS ID""
        }
        }
      }
    }
}";

JObject MessageObject = JObject.Parse(json);
var test = MessageObject["hl7"]["HL7Message"]["PID"]["PID.2"]["PID.2.1"] // this finds the property
string val = test.Value<string>(); // this returns the string "1111111"

// this does not find the property
string path = "[\"hl7\"][\"HL7Message\"][\"PID\"][\"PID.2\"][\"PID.2.1\"]";
var otherTest = MessageObject[path]; // this returns null


Thank you.

  • You must use [`SelectToken()`](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JToken_SelectToken.htm) to select via JSONPath, see the documentation page [Querying JSON with JSON Path](https://www.newtonsoft.com/json/help/html/QueryJsonSelectToken.htm). See e.g. [Json.NET get nested jToken value](https://stackoverflow.com/q/42290485). Does that answer your question? – dbc Sep 01 '23 at 17:31
  • Notice how your first example doesn't put the square brackets as part of the string and your second example does? This is why the second example doesn't work. Your first example is specifying the key value for each nested item. The second example is specifying the key for the first item only, and this key is being defined as what's in the string, including the square brackets. – quaabaam Sep 01 '23 at 17:42
  • Thank you for the responses. Interesting. I was hoping to avoid using the SelectToken method. Using a Dynamic object provides access, but not using the path value stored in a variable. – Mike Williams Sep 01 '23 at 18:21
  • *I was hoping to avoid using the SelectToken method* -- why? – dbc Sep 01 '23 at 18:27
  • Because there is the need to replace the values as well as query them. The actual scope of replacements involves 130+ different properties on millions of records. So, was hoping to be able to use the JObject record since instantiating a JToken is only a copy and then after making the update to the JToken copy, then another operation is required to update the JObject. – Mike Williams Sep 01 '23 at 18:42
  • Isn't this code, `var test = MessageObject["hl7"]["HL7Message"]["PID"]["PID.2"]["PID.2.1"] ` returning a JToken? Replace your `var` to verify this. If so, you are getting a JToken and not a JObject in your working example, and may as well consider using @dbc 's suggestion. – quaabaam Sep 01 '23 at 19:05
  • @quaabaam MessageObject is the JObject I was referrring to. Yes, test is a JToken, but that is not what I ideally want to use as it requires additional operations to implement an update of the MessageObject. – Mike Williams Sep 01 '23 at 19:10
  • @MikeWilliams - `JToken` is the abstract base class of `JObject`, see [JSON.NET: Why Use JToken--ever?](https://stackoverflow.com/a/38212978/3744182). Anyway, `MessageObject["hl7"]["HL7Message"]["PID"]["PID.2"]["PID.2.1"]` and `MessageObject.SelectToken("['hl7']['HL7Message']['PID']['PID.2']['PID.2.1']")` return exactly the same thing -- `Object.ReferenceEquals(test, otherTest)` is `true`, see https://dotnetfiddle.net/XFZA6n. So it's not clear why using `SelectToken()` would require *additional operations to implement an update*. Please [edit] your question to clarify. – dbc Sep 01 '23 at 19:37
  • @dbc my reasoning is based on having to apply the replacement value to the token first and then replace the token on MessageObject with the updated token instead of being able to just updating the MessageObject with the replacement value directly like when using either a dynamic object `dynamicObj.hl7.HL7Message.PID["PID.2"]["PID.2.1"].Value = newValue` or the literal path `MessageObject["hl7"]["HL7Message"]["PID"]["PID.2"]["PID.2.1"].Value = newValue`. – Mike Williams Sep 01 '23 at 20:05

0 Answers0