-1

I'm deserializing json-ld based json to validate it against things like schema.org. Because of this I can't deserialize into known object types, so I do the generic deserialization into a JObject.

If I encounter an error, like an unsupported property, I want to reference back to the source code. e.g. have line numbers can column positions.

I thought I had the answer here:

Newtonsoft.Json - Getting corresponding line numbers of deserialized objects from JSON for better error handling

But it does not work when deserializing to JObject. ReadJson is not called.

Is there any way to get position info when deserializing to JObject?

var lineNumberConverter = new LineNumberConverter();

var json = JsonConvert.DeserializeObject(jsonLdScript.TextContent, new JsonSerializerSettings()
  {
    Converters = new[] { lineNumberConverter }
  });

    public class JsonPosition
    {
        public int StartLine { get; set; }
        public int StartColumn { get; set; }

        public int EndLine { get; set; }
        public int EndColumn { get; set; }
    }

    public class LineNumberConverter : JsonConverter
    {
        public Dictionary<object, JsonPosition> Positions = new Dictionary<object, JsonPosition>();
        public override bool CanWrite
        {
            get { return false; }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException("Converter is not writable. Method should not be invoked");
        }

        public override bool CanConvert(Type objectType)
        {
            return true;
        }
        public override object ReadJson(JsonReader reader,
                                        Type objectType,
                                        object existingValue,
                                        JsonSerializer serializer)
        {
            JsonPosition position = null;

            var jsonLineInfo = reader as IJsonLineInfo;

            if (reader.TokenType != JsonToken.Null)
            {
                if (jsonLineInfo != null && jsonLineInfo.HasLineInfo())
                {
                    position = new JsonPosition() { StartLine = jsonLineInfo.LineNumber, StartColumn = jsonLineInfo.LinePosition };
                }
            }

            var jObject = JObject.Load(reader);

            if (position != null)
            {
                if (jsonLineInfo != null && jsonLineInfo.HasLineInfo())
                {
                    position.EndLine = jsonLineInfo.LineNumber;
                    position.EndColumn = jsonLineInfo.LinePosition;
                    Positions.Add(jObject, position);
                }
            }

            return jObject;
        }
    }
1
  • 1
    JToken implements IJsonLineInfo explicitly. If you need line information to be loaded for a JToken hierarchy, call JToken.Load() (or JToken.Parse()). If you don't, you can continue to use JsonConvert.DeserializeObject<JToken>() as this is the default behavior for both. See dotnetfiddle.net/ecsLcg for a demo. Or do you need something else? Commented Aug 30, 2020 at 0:19

1 Answer 1

0

I'm now using the JsonTextReader which is more complex to set up, but more flexible for my needs. The reader object contains current position info which means I can get positions down to each token as it reads through the json. Checking before and after a read and I get the range of text to highlight.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.