FsJson – a Reasonably Complete JSON Parser in F#

A while ago I created a JSON parser in F# just to understand F# Active Patterns. Over the course of a year, I have updated the parser as needed and now it seems fairly complete.

I will take this blog entry to document the major features of “FsJson” in case anyone wants to use it for any purpose.

You can download the F# source from here: https://fsjson.codeplex.com

Let’s step through a few usages…

Parsing

#load “FsJson.fs”

#load “FsJsonDescription.fs”

open System.Net

 

let download (url:string) =

    use wc = new WebClient()

    wc.DownloadString(url)

 

let fbRoot =

    download “https://graph.facebook.com/19292868552”

    |> FsJson.parse

 

The above will download the Facebook company entity from the Facebook Graph API and parse it into “fbRoot”.

Description

To see what is contained in the JSON you could optionally use FsDescription.describe or FsDescription.describeTo <depth>:

fbRoot |> FsJsonDescription.describe

 

>

val it : FsJsonDescription.JTree =

  JObj

    [|(“about”, Js); (“category”, Js); (“company_overview”, Js);

      (“cover”, JObj [|(“cover_id”, Js); (“offset_y”, Ji); (“source”, Js)|]);

      (“founded”, Js); (“id”, Js); (“is_published”, Jb); (“likes”, Ji);

      (“link”, Js); (“mission”, Js); (“name”, Js); (“picture”, Js);

      (“talking_about_count”, Ji); (“username”, Js); (“website”, Js)|]

This gives the tree structure of the JSON with just the keys (and the types of the associated values).

Accessing Content

The dynamic operator (“?”) can be used to traverse the object tree. For example the above JSON has a nested object “cover”; to access the properties of “cover” you could use:

fbRoot?cover?cover_id.Val

 

>

val it : System.String = “10150835335278553”

The “.Val” property returns a string value and it always succeeds. Other members can be used for other property types (but can fail if the object is not convertible to the return type). These members are listed below:

·         Val – returns a string and always succeeds

·         ValI – returns an int

·         ValF – returns a float

·         ValD – returns a DateTime

·         ValDF – accepts a date format string and parses the underlying string value according to this format to return a DateTime

·         Array – returns an Array of JSON values

·         Map – returns a dictionary of key-value pairs

You can combine traversal and description as in:

·         Json?prop1?nestedprop2 |> FsDescription.describe

Tree Traversal

You can use FsJson.choose to traverse the JSON document and pull out values using pattern matching:

open FsJson

 

fbRoot |> FsJson.choose (fun (n,v) ->

    match (n,v) with

    | “likes”,JsonInt _ -> Some v

    | _-> None)

The above query will extract all “likes” that have integer values in the document. You can use the “?” traversal and FsJson.choose to start the query at the desired location.

Construction

Finally, to construct JSON using a combinator style approach, use the “jval” constructor:

#load “FsJson.fs”

open FsJson

open System

 

let j = jval [|”a”; “b”; “c” |]

j.Array.[1]

 

let jobj =

    jval

        [

            “a”, jval DateTime.Now

            “b”, jval “abcd”

            “c”, jval [1; 2; 3; 4]

            “n1”, jval

                [

                    “n2”, jval

                        [

                            “n3″,”nested value”

                        ]

                ]

        ]

 

jobj?n1?n2?n3.Val

jobj |> FsJson.serialize

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s