0

I've got a file with JSON content like this:

{
  "Data": {
    "A": {
      "A1": "S",
      "A2": 0.0
    }
  },
  "NoData": "text"
}

What I want to achieve is to get the inner json of "Data" as a string. I do not want it to be deserialized as an object. I already tried to deserialize it with Json.NET JsonConvert.DeserializeObject<TestClass> where Test class is defined as

class Testclass
{
  public string Data {get; set;}
  public string NoData {get; set;}
}

But this results in Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: {. Path 'Data', line 2, position 11.

The data in "Data" is cryptographically signed by a remote server and the signature needs to be checked. But I do not necessarily have the same classes the data was serialized with at the clients side. That's why I want to do as few conversions as possible. So deserializing and serializing again may change the original string in "data". All spaces and linebreaks have to stay intact.

5
  • take a look here: stackoverflow.com/a/29988081/7968203 Commented Feb 18, 2020 at 11:39
  • 1
    Does this answer your question? Deserialize JSON object property to string Commented Feb 18, 2020 at 11:40
  • Maybe you can deserialize Data from JSON to internal object DataInternal { get; set; }, and then get it with public string Data { get => JsonConvert.SerializeObject(DataInternal); } Commented Feb 18, 2020 at 11:40
  • 1
    "I do not want it to be deserialized as an object" - can you explain why not? Commented Feb 18, 2020 at 11:42
  • The data in "Data" is cryptographically signed by a remote server and the signature needs to be checked. But I do not necessarily have the same classes the data was serialized with at the clients side. That's why I want to do as few conversions as possible. Commented Feb 18, 2020 at 11:55

3 Answers 3

2
 {
    "A": {
      "A1": "S",
      "A2": 0.0
    }
  }

is a JSON Object Use JToken datatype

class JsonConverterObjectToString : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(JTokenType));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken token = JToken.Load(reader);
            if (token.Type == JTokenType.Object)
            {
                return token.ToString();
            }
            return null;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            //serializer.Serialize(writer, value);

            //serialize as actual JSON and not string data
            var token = JToken.Parse(value.ToString());
            writer.WriteToken(token.CreateReader());

        }
    }

Otherwise use JsonConverter like this

  JsonConvert.DeserializeObject<Testclass>(json, 
                new JsonConverterObjectToString());
Sign up to request clarification or add additional context in comments.

1 Comment

ReadJson technically deserializes and serializes again. Correct?! This may modify the original json in the "data" property depending on how the data is serialized again?
0
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApp5
    {
        class Testclass
        {
            public string Data { get; set; }
            public string NoData { get; set; }
        }
        class JsonConverterObjectToString : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return (objectType == typeof(string));
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                JToken token = JToken.Load(reader);
                if (token.Type == JTokenType.Object)
                {
                    return token.ToString();
                }
                return null;
            }

            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                //serializer.Serialize(writer, value);

                //serialize as actual JSON and not string data
                var token = JToken.Parse(value.ToString());
                writer.WriteToken(token.CreateReader());

            }
        }
        class Program
        {

            static void Main(string[] args)
            {
                var json = "{\r\n  \"Data\": {\r\n    \"A\": {\r\n      \"A1\": \"S\",\r\n      \"A2\": 0.0\r\n    }\r\n  },\r\n  \"NoData\": \"text\"\r\n}";
                var jObj = JsonConvert.DeserializeObject<Testclass>(json, new JsonConverterObjectToString());
                var jObjStrin = JsonConvert.SerializeObject(jObj, new JsonConverterObjectToString());
 Console.WriteLine(jObjString);
            }
        }
    }

we can able to JToken to string with the same format Please check the image. the Data has serialized again the same format using the same Convertor

enter image description here

Comments

0

I had implemented a naive JSON parser just for solving this specific problem, here's the code:

Method:

static string ExtractInnerJsonObject(ReadOnlySpan<byte> jsonPayload, ReadOnlySpan<char> targetField, bool preserveWhiteSpaces = false)
{
    const int TYPE_OTHER = 0;
    const int TYPE_OBJECT = 1;
    const int TYPE_STRING = 2;
    const int TYPE_ARRAY = 3;

    ReadOnlySpan<char> jsonPayloadString = Encoding.UTF8.GetString(jsonPayload).AsSpan();

    int objectDepth = 0;
    int lastWhiteSpacePosition = 0;
    int fieldNameStartPosition = 0;
    int fieldNameEndPosition = 0;
    int valueStartPosition = 0;
    int valueEndPosition = 0;
    int detectedValueType = TYPE_OTHER;

    bool isValueTypeDetected = false;

    bool isValueScanStarted = false;
    bool isValueScanCompleted = false;

    bool isTargetField = false;
    bool isFieldNameScanStarted = false;
    bool isFieldNameScanCompleted = false;


    for (int i = 0; i < jsonPayloadString.Length; i++)
    {
        char c = jsonPayloadString[i];

        if (c == '{')
        {
            objectDepth++;

            if (isValueScanStarted && !isValueScanCompleted && !isValueTypeDetected)
            {
                detectedValueType = TYPE_OBJECT;
                isValueTypeDetected = true;
            }
        }
        else if (c == '}')
        {
            objectDepth--;

            if (isValueScanStarted && !isValueScanCompleted && detectedValueType == TYPE_OBJECT && objectDepth == 1)
            {
                valueEndPosition = i;
                isValueScanCompleted = true;
            }

            if (isValueScanStarted && !isValueScanCompleted && detectedValueType == TYPE_OTHER)
            {
                valueEndPosition = i - 1;
                isValueScanCompleted = true;
            }
        }
        else if (c == '"')
        {
            if (!isValueScanStarted)
            {
                if (!isFieldNameScanStarted)
                {
                    fieldNameStartPosition = i + 1;
                    isFieldNameScanStarted = true;
                }
                else
                {
                    fieldNameEndPosition = i - 1;
                    isFieldNameScanCompleted = true;
                }
            }
            else
            {
                if (!isValueTypeDetected)
                {
                    detectedValueType = TYPE_STRING;
                    isValueTypeDetected = true;
                }
                else
                {
                    if (!isValueScanCompleted && detectedValueType == TYPE_STRING)
                    {
                        valueEndPosition = i;
                        isValueScanCompleted = true;
                    }
                }
            }
        }
        else if (c == ':')
        {
            if (!isValueScanStarted)
            {
                valueStartPosition = i + 1;
                isValueScanStarted = true;
            }
        }
        else if (c == ',')
        {
            if (isValueScanStarted && !isValueScanCompleted && detectedValueType == TYPE_OTHER)
            {
                valueEndPosition = i - 1;
                isValueScanCompleted = true;
            }
        }
        else if (c == '[')
        {
            if (isValueScanStarted && !isValueScanCompleted && !isValueTypeDetected)
            {
                detectedValueType = TYPE_ARRAY;
                isValueTypeDetected = true;
            }
        }
        else if (c == ']')
        {
            if (isValueScanStarted && !isValueScanCompleted && detectedValueType == TYPE_ARRAY)
            {
                valueEndPosition = i;
                isValueScanCompleted = true;
            }
        }
        else if (char.IsWhiteSpace(c))
        {
            lastWhiteSpacePosition = i;
        }

        if (isFieldNameScanStarted && isFieldNameScanCompleted)
        {
            ReadOnlySpan<char> fieldName = jsonPayloadString[fieldNameStartPosition..(fieldNameEndPosition + 1)];

            if (fieldName.Equals(targetField, StringComparison.Ordinal))
            {
                isTargetField = true;
            }

            isFieldNameScanStarted = false;
            isFieldNameScanCompleted = false;
        }

        if (isValueScanStarted && isValueScanCompleted)
        {
            if (isTargetField)
            {
                ReadOnlySpan<char> value = jsonPayloadString[valueStartPosition..(valueEndPosition + 1)];

                if (preserveWhiteSpaces)
                {
                    return value.ToString();
                }
                else
                {
                    return value.ToString().Trim();
                }
            }

            isValueScanStarted = false;
            isValueScanCompleted = false;
            isValueTypeDetected = false;
            detectedValueType = TYPE_OTHER;
        }

    }

    return null;
}

Usage:

byte[] jsonPayloadReceivedFromSomewhere = Encoding.UTF8.GetBytes(
@"{
  ""Data"": {
    ""A"": {
      ""A1"": ""S"",
      ""A2"": 0.0
    }
  },
  ""NoData"":             ""hello
world!!@#$%^&*()_+-=[]{}|\/?><,.`01234     56789
""
, ""TestArray"":            [1, 2, 3 , 4, 5], ""TestBoolean"" :       true   
,        ""TestDouble""       :  123.45678
, ""TestInteger"" :-9999



}");

string a = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "Data");
string b = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "NoData");
string c = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "InvalidField");
string d = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "TestArray");
string e = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "TestBoolean");
string f = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "TestDouble");
string g = ExtractInnerJsonObject(jsonPayloadReceivedFromSomewhere, "TestInteger");

Result:

enter image description here

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.