【问题标题】:Get inner JSON content as string without deserializing获取内部 JSON 内容作为字符串而不反序列化
【发布时间】:2020-06-02 10:09:36
【问题描述】:

我有一个包含如下 JSON 内容的文件:

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

我想要实现的是将“Data”的内部json作为字符串。我不希望它被反序列化为一个对象。我已经尝试使用 Json.NET JsonConvert.DeserializeObject<TestClass> 对其进行反序列化,其中 Test 类定义为

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

但这会导致 Newtonsoft.Json.JsonReaderException:解析值时遇到意外字符:{。路径“数据”,第 2 行,位置 11。

“数据”中的数据由远程服务器加密签名,需要检查签名。但我不一定有在客户端序列化数据的相同类。这就是为什么我想做尽可能少的转换。所以反序列化和再次序列化可能会改变“数据”中的原始字符串。所有空格和换行符都必须保持不变。

【问题讨论】:

  • 这能回答你的问题吗? Deserialize JSON object property to string
  • 或许你可以将Data从JSON反序列化为internal object DataInternal { get; set; },然后用public string Data { get => JsonConvert.SerializeObject(DataInternal); }得到它
  • “我不希望它被反序列化为一个对象” - 你能解释一下为什么不吗?
  • “Data”中的数据由远程服务器加密签名,需要检查签名。但我不一定有在客户端序列化数据的相同类。这就是为什么我想尽可能少地进行转换。

标签: c# json json.net


【解决方案1】:
 {
    "A": {
      "A1": "S",
      "A2": 0.0
    }
  }

是一个 JSON 对象,使用 JToken 数据类型

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());

        }
    }

否则像这样使用JsonConverter

  JsonConvert.DeserializeObject<Testclass>(json, 
                new JsonConverterObjectToString());

【讨论】:

  • ReadJson 在技术上再次反序列化和序列化。正确的?!这可能会根据数据再次序列化的方式修改“data”属性中的原始json?
【解决方案2】:
    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);
            }
        }
    }

我们可以将 JToken 转换为相同格式的字符串 请检查图像。数据已使用相同的转换器再次序列化相同的格式

【讨论】:

    【解决方案3】:

    我已经实现了一个简单的 JSON 解析器来解决这个特定的问题,代码如下:

    方法:

    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;
    }
    

    用法:

    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");
    

    结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-19
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      相关资源
      最近更新 更多