Jason.decode!() returning a string instead of Map

I’m doing some HTML scraping, and found the info I need as part of some tag in the HTML for the page.

window.__Y_DATA__ = JSON.parse("{ \"__PRELOADED_QUERIES__\": {\"yada yada \":67}}}]]} }");

Using some String.replace, I can clean up the JSON string and Jason.decode!() runs without raising.

y_data
|> String.replace("window.__Y_DATA__ = JSON.parse(", "")
|> String.replace(");", "")
|> Jason.decode!()

The problem is that Jason.decode!() is returning a string, and I can’t seem to access any of the properties of the JSON.

y_data_json["__PRELOADED_QUERIES__"]
|> IO.inspect()

The following arguments were given to Access.get/3:
    
        # 1
        "{ \"__PRELOADED_QUERIES__\": {\"queries\":[[[\"@web/domain-content/get-page-content\",{\"breadcrumbs\":true,\"children\":true,\"url\":\"/p/-/A-81117190\"}],{\"data\":{\"metadata\":{\"activation_date\":\"2020-12-01T07:00Z\",\"deactivation_date\":\"2030-12-04T08:00Z\",\"seo_data\":{\"ca

        # 2
        "__PRELOADED_QUERIES__"
    
        # 3
        nil
    
    Attempted function clauses (showing 5 out of 5):
    
        def get(%module{} = container, key, default)
        def get(map, key, default) when is_map(map)
        def get(list, key, default) when is_list(list) and is_atom(key)
        def get(list, key, _default) when is_list(list)
        def get(nil, _key, default)

Typically Jason.decode!() has always returned a Map for me, so I appreciate the help!

In your code there are 2 problems:

  1. First of all the json inside JSON.parse/1 call is invalid. There is extra }]]} }" before ); which you escaped already.

  2. You want to turn escaped json into map and not normal json into map. You just need to call Jason.decode!/1 twice! First one would parse it as an unescaped string and the second one would return a map.

Example code:

y_data = "window.__Y_DATA__ = JSON.parse(\"{ \\\"__PRELOADED_QUERIES__\\\": {\\\"yada yada \\\":67}}}]]} }\");"

y_data
|> String.replace("window.__Y_DATA__ = JSON.parse(", "")
|> String.replace("}]]} }\");", "\"")
|> Jason.decode!()
# returns:
"{ \"__PRELOADED_QUERIES__\": {\"yada yada \":67}}"

y_data
|> String.replace("window.__Y_DATA__ = JSON.parse(", "")
|> String.replace("}]]} }\");", "\"")
|> Jason.decode!()
|> Jason.decode!()
# returns:
%{"__PRELOADED_QUERIES__" => %{"yada yada " => 67}}
3 Likes

The string you are passing to Jason.decode! includes the surrounding double quotes, so Jason considers it a string literal.

Edit: @Eiji was faster than me with a better answer :slight_smile:

4 Likes

My man! Thank you!

1 Like