2013-11-12 4 views
1

Я пытаюсь разобрать следующий json: http://libris.kb.se/xsearch?query=%22design%22+language:%28%22ENG%22%29&format=json&format_level=full&database=swepub Как вы можете видеть в первом элементе элемента списка, описание представляет собой обычную строку. Это справедливо и для другого 8 результата, но по 9-му результату он по какой-то причине превращается в массив строк.Parsing json string, который иногда является массивом

Я использую C# и DataContract, пытаясь разобрать это, но он, очевидно, не будет работать, поскольку тип отличается от результата. Как я могу обойти это? Я предполагаю, что можно просто вручную разобрать все, но я не хочу этого делать.

Это мой DataContract-х

[DataContract] 
public class SwepubHeader 
{ 
    [DataMember(Name = "xsearch")] 
    public SwepubBody Body { get; set; } 
} 

[DataContract] 
public class SwepubBody 
{ 
    [DataMember(Name = "from")] 
    public int From { get; set; } 

    [DataMember(Name = "to")] 
    public int To { get; set; } 

    [DataMember(Name = "records")] 
    public int Records { get; set; } 

    [DataMember(Name = "list")] 
    public SwepubSearchItem[] SearchItems { get; set; } 
} 

[DataContract] 
public class SwepubSearchItem 
{ 
    [DataMember(Name = "isbn")] 
    public string ISBN { get; set; } 

    [DataMember(Name = "title")] 
    public string Title { get; set; } 

    [DataMember(Name = "description")] 
    public string Description { get; set; } 

    [DataMember(Name = "identifier")] 
    public string Identifier { get; set; } 

    [DataMember(Name = "type")] 
    public string Type { get; set; } 

    [DataMember(Name = "publisher")] 
    public string Publisher { get; set; } 

    [DataMember(Name = "date")] 
    public string Date { get; set; } 

    [DataMember(Name = "language")] 
    public string Language { get; set; } 

    [DataMember(Name = "relation")] 
    public string Relation { get; set; } 

    [DataMember(Name = "subject")] 
    public string[] Subjects { get; set; } 

    [DataMember(Name = "creator")] 
    public string[] Creators { get; set; } 
} 

и это, как я разобрать его

    using (var response = request.GetResponse() as HttpWebResponse) 
       { 
        if (response != null) 
        { 
         if (response.StatusCode != HttpStatusCode.OK) 
          throw new Exception(String.Format(
           "Server error (HTTP {0}: {1}).", 
           response.StatusCode, 
           response.StatusDescription)); 
         var jsonSerializer = new DataContractJsonSerializer(typeof(SwepubHeader)); 
         object objResponse = jsonSerializer.ReadObject(response.GetResponseStream()); 
         var jsonResponse = objResponse as SwepubHeader; 
         return jsonResponse; 
        } 
       } 
+0

Если они дают вам различные типы данных, то, что они делают что-то неправильно и вы должны сказать им. Они должны обеспечивать согласованный тип своих записей. Чтобы обойти это без ручного анализа вещей, вы можете просто определить два похожих типа (оба из которых основаны на одной базе) - один со строкой и один с строковым массивом - вы можете попробовать/уловить сериализацию в одну, а затем другую , Оба класса могли реализовать что-то вроде 'GetDescription()', который читает строку или объединяет строковый массив. –

+0

, вероятно, поможет: http://stackoverflow.com/questions/7501846/xml-serialize-dynamic-object –

+1

Я бы использовал Json.Net вместо DataContractJsonSerializer. Он может десериализоваться почти в два раза быстрее и имеет больше возможностей. Например, вы можете создать JsonConverter, который примет это значение и позволит вам определить, как он десериализован. –

ответ

2

Это действительно не большой дизайн для их формата JSON, но вы можете справиться с этим, имея описание, являющееся объектом. Тогда, как вы справляетесь с этим объектом до вас, но вы можете создать еще одно свойство, которое преобразует его в то, что вам нужно:

[DataMember(Name = "description"] 
private object _description; 

public string Description 
{ 
    get 
    { 
     if (_description != null) 
     { 
      if (_description is string) 
      { 
       // Do Nothing 
       // You can remove this, just putting this here to 
       // show conditional is implicit 
      } 
      else if (_description is string[]) 
      { 
       // Join string[] using '\n\n' as the connector 
       _description = string.Join("\n\n", (string[])_description); 
      } 
     } 

     return _description as string; 
    } 
} 
+0

Я согласен, это ужасный дизайн, но это не мое, и я не могу заставить их изменить его. Спасибо за ваш ответ, даже не думали о том, чтобы сделать его объектом! –

2

URL-адрес возвращает два объекта JSON. Это не очень хороший дизайн с их стороны, но если у вас нет контроля над этим, тогда стоит попробовать десериализовать его со строковыми данными, и если это не приведет к десериализации его с помощью массива строк.

EDIT: Для облегчения этой работы у вас должно быть описание десериализации объекта. Однако это не массив строк ... это либо строка, либо массив объектов ... так что следующий код будет обрабатывать это ... замените свойство Description следующим образом:

[DataMember(Name = "description")] 
public object description { get; set; } 

public string Description { 
    get 
    { 
     var seperator = string.Empty; // replace with what you want 
     var s = description as string; 
     if (s != null) 
      return s; 
     var sArray = description as object[]; 
     if (sArray != null) 
      return String.Join(seperator, sArray); 
     return null; 
    } 
    set 
    { 
     description = value; 
    } 
} 
+0

Спасибо, даже не подумал о создании типа объекта! –

+0

@ AndreasLjungström upvote/mark как ответ? – Kevin

Смежные вопросы