Как избежать специальных символов в JSON [дубликат]

arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
0
задан Anthony Mastrean 29 January 2018 в 16:03
поделиться

4 ответа

Вот выполнимое решение, которое я использовал, основываясь на ответе Сэма Я :

dynamic obj = JsonConvert.DeserializeObject(json);
foreach (var response in (IEnumerable<dynamic>)obj.responses)
{
    response.body = JsonConvert.DeserializeObject((string)response.body);
}
string result = JsonConvert.SerializeObject(obj);
0
ответ дан Community 15 August 2018 в 14:51
поделиться

Ваш JSON содержит литеральную строку для объектов "body", которые фактически встроены, с двойным сериализованным JSON. Чтобы десериализовать это в иерархию POCO без необходимости вводить промежуточное свойство суррогата string Json внутри любого из ваших типов, у вас есть несколько вариантов:

  1. Вы можете предварительно обработать ваш JSON, используя LINQ к JSON и заменить строки литерала "body" на их проанализированные эквиваленты:
        var rootToken = JToken.Parse(json);
        foreach (var token in rootToken.SelectTokens("responses[*].body").ToList().Where(t => t.Type == JTokenType.String))
        {
            token.Replace(JToken.Parse((string)token));
        }
    
        var root = rootToken.ToObject<RootObject>();
    
  2. Вы можете ввести общий JsonConverter для POCO, соответствующий каждому объекту Body, который анализирует входящий встроенный строковый литерал JSON в иерархию LINQ to JSON, затем десериализует следующее:
    public class EmbeddedLiteralConverter<T> : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(T).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var contract = serializer.ContractResolver.ResolveContract(objectType);
            if (contract is JsonPrimitiveContract)
                throw new JsonSerializationException("Invalid type: " + objectType);
            if (existingValue == null)
                existingValue = contract.DefaultCreator();
            if (reader.TokenType == JsonToken.String)
            {
                var json = (string)JToken.Load(reader);
                using (var subReader = new JsonTextReader(new StringReader(json)))
                {
                    // By populating a pre-allocated instance we avoid an infinite recursion in EmbeddedLiteralConverter<T>.ReadJson()
                    // Re-use the existing serializer to preserve settings.
                    serializer.Populate(subReader, existingValue);
                }
            }
            else
            {
                serializer.Populate(reader, existingValue);
            }
            return existingValue;
        }
    
        public override bool CanWrite { get { return false; } }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    
    Затем используйте его как:
        var root = JsonConvert.DeserializeObject<RootObject>(json, new EmbeddedLiteralConverter<Body>());
    
    Обратите внимание, что конвертер проверяет, является ли входящий токен JSON строкой, а если нет, десериализуется напрямую. Таким образом, преобразователь должен использоваться, когда "body" JSON является и не имеет двойного сериализации.

В целях тестирования я создал следующие целевые классы, используя http: // json2csharp. com / :

public class Error
{
    public string message { get; set; }
    public string type { get; set; }
    public int code { get; set; }
}

public class Body
{
    public Error error { get; set; }
}

public class Respons
{
    public string info { get; set; }
    public Body body { get; set; }
}

public class RootObject
{
    public List<Respons> responses { get; set; }
}
1
ответ дан dbc 15 August 2018 в 14:51
поделиться
  1. вы можете десериализовать его в промежуточный класс, который обладает свойством: string Body {get; set;}
  2. десериализовать строку «body» в соответствующий тип
  3. создать новый экземпляр вашего класса, который представляет вашу целевую модель.
  4. сериализовать эту модель

Вот программа, которая делает это с динамическим типом и анонимными объектами.

static void Main(string[] args)
{
    var json = File.ReadAllText("JsonFile1.json");
    dynamic obj = JsonConvert.DeserializeObject(json);

    var dest = new
    {
        responses = ((IEnumerable<dynamic>)obj.responses).Select(x => new
        {
            info = x.info,
            body = JsonConvert.DeserializeObject((string)x.body)
        })
    };

    var destJson = JsonConvert.SerializeObject(dest);
    File.WriteAllText("JsonFile2.json", destJson);
}

В качестве альтернативы вы можете просто построить новую версию любого типа назначения вместо анонимного типа, если вы не хотите повторить инициализацию josn.

0
ответ дан Sam I am 15 August 2018 в 14:51
поделиться
  • 1
    @downvoter Неверный ответ? Кто-то вроде OP, который уже может использовать JSON.Net, так или иначе неспособный использовать мой ответ? – Sam I am 25 August 2016 в 20:23
  • 2
    Похоже, мы оба забились. Я надеялся, что найду способ очистить JSON без создания повторяющихся классов для всех ответов API (это упрощенный пример чего-то более сложного) с чем-то общим, который я могу использовать для анализа значений. – Kcoder 25 August 2016 в 20:27
  • 3
    @Kcoder Я сделал редактирование – Sam I am 25 August 2016 в 20:48
0
ответ дан Lakshmana Prabhu Venkatesan 5 September 2018 в 13:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: