1

I'm trying to parse the following json: http://libris.kb.se/xsearch?query=%22design%22+language:%28%22ENG%22%29&format=json&format_level=full&database=swepub As you can see in the first item of the list element the description is a regular string. This is also true for the other 8 result but on the 9th result it, for some reason, turns into an array of strings instead.

I'm using C# and a DataContract trying to parse this but it will obviously not work as the type is different between the result. How can i work around this? I suppose to could just manually parse everything but I'd rather not do that.

This is my DataContract's

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

and this is how i parse it

                    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;
                    }
                }
  • If they're giving you different data types, then they're doing something wrong and you should tell them. They should provide a consistent type for their records. To get around it without manually parsing things, you may be able to just define two similar types (both deriving from the same base) - one with a string and one with a string array - you could try/catch serializing into one then the other. Both classes could implement something like `GetDescription()` which reads the string or concatenates the string array. – Joe Enos Nov 12 '13 at 15:37
  • probably would help: http://stackoverflow.com/questions/7501846/xml-serialize-dynamic-object – Artyom Neustroev Nov 12 '13 at 15:39
  • 1
    I would use Json.Net instead of DataContractJsonSerializer . It can deserialize almost twice as fast and has more features. For example you can create a JsonConverter that will take that value and let you determine how it is deserialized. – Rush Frisby Nov 12 '13 at 15:45

2 Answers2

2

The url returns two different JSON objects. This really isn't a great design on their part but if you have no control over that then an option is to try to deserialize it with string data and if that fails deserialize it with an array of strings.

EDIT: In order to make this work easily you should have description deserialize to an object. However it isn't an array of strings... it's either a string or an array of objects... so the following code will handle this... replace your Description property with the following...

[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;
    }
}
Kevin
  • 4,586
  • 23
  • 35
2

This really is not a great design for their JSON format, but you can handle it by having description being an object. Then, how you deal with that object is up to you, but you can create another property that converts it to what you need:

[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;
    }
}
Mike Richards
  • 5,557
  • 3
  • 28
  • 34
  • I agree, its a terrible design but it's not mine and I can't make them change it. Thank you for your answer, didnt even think about making it an object! – Andreas Ljungström Nov 13 '13 at 10:17