C # DataContractJsonSerializer не удается, когда значение может быть массивом или отдельным элементом - PullRequest
5 голосов
/ 04 октября 2011

Я использую DataContractJsonSerializer для анализа строки json в иерархии объектов.Строка json выглядит следующим образом:

{
    "groups": [
        {
            "attributes": [
                {
                    "sortOrder": "1",
                    "value": "A"
                },
                {
                    "sortOrder": "2",
                    "value": "B"
                }
            ]
        },
        {
            "attributes": {
                "sortOrder": "1",
                "value": "C"
            }
        }
    ]
}

Как видите, вспомогательное значение «атрибутов» может быть массивом или отдельным элементом.Я нашел часть кода, где возникает проблема:

[DataContract]
public class ItemGroup
{
    [DataMember(Name="attributes")]
    public List<DetailItem> Items  { get; set; }
}

Это работает для первого, но не работает для второго.

Кто-нибудь ответил на это?

Thx

Ответы [ 3 ]

3 голосов
/ 04 октября 2011

Как сказал Даниэль, если вы можете контролировать создание Джсона, лучше продолжать в том же духе.Но если вы не можете, то вы можете использовать библиотеку Json.Net и класс JsonObject из этой ссылки, чтобы написать такой код, как:

JObject o = (JObject)JsonConvert.DeserializeObject(input);
dynamic json = new JsonObject(o);
foreach (var x in json.groups)
{
      var attrs = x.attributes;
      if (attrs is JArray)
      {
           foreach (var y in attrs)
           {
               Console.WriteLine(y.value);
           }
      }
      else
      {
          Console.WriteLine(attrs.value);
      }
 }
3 голосов
/ 04 октября 2011

Если вы контролируете, как создается JSON, убедитесь, что атрибуты являются массивом, даже если он содержит только один элемент.Тогда второй элемент будет выглядеть так и будет нормально разбираться.

    {
        "attributes": [{
            "sortOrder": "1",
            "value": "C"
        }]
    }
1 голос
/ 17 февраля 2012

Я пытался заставить это работать с DataContractJsonSerializer, JavaScriptSerializer и JSON.Net, и ни один из них не мог десериализовать напрямую к объекту успешно во всех случаях.Я использовал такой же подход, как и LB, используя JSON.Net, но без использования динамического элемента и дополнительного класса JsonObject.Адаптация моего кода к вашему сценарию будет выглядеть примерно так:

private List<ItemGroup> ParseItemGroupList(string input)
    {
        JObject json = JObject.Parse(input);

        List<ItemGroup> groups = new List<ItemGroup>();
        JArray gArray = json["groups"] as JArray;
        foreach (var gToken in gArray)
        {
            ItemGroup newGroup = new ItemGroup();
            JToken attrToken = gToken["attributes"] as JToken;
            if (attrToken is JArray)
            {
                newGroup.Items = attrToken.Children().Select(MapDetailItem()).ToList();
            }
            else
            {
                newGroup.Items = new List<DetailItem>() { MapDetailItem().Invoke(attrToken) };
            }

            groups.Add(newGroup);
        }

        return groups;
    }

    private static Func<JToken, DetailItem> MapDetailItem()
    {
        return json => new DetailItem
        {
            SortOrder = (string)json["sortOrder"],
            Value = (string)json["value"]
        };
    }

Надеемся, что кто-то добавит параметр для JSON.Net, чтобы разрешить десериализацию в коллекцию с одним элементом, а не бросатьисключение.Жаль, что вам придется выполнять весь анализ вручную, когда есть только одна небольшая часть JSON, которая не анализируется автоматически автоматически.

...