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:
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;
}
}
JTokenimplementsIJsonLineInfoexplicitly. If you need line information to be loaded for aJTokenhierarchy, callJToken.Load()(orJToken.Parse()). If you don't, you can continue to useJsonConvert.DeserializeObject<JToken>()as this is the default behavior for both. See dotnetfiddle.net/ecsLcg for a demo. Or do you need something else?