1

I have a long clojure String (java.lang.String) representing a JSON. It has "normal" looking syntax like so:

"{ a:1, b:"hello" }"

The keys do not have quotes around them.

All the libraries I have looked at such as clojure.data.json want this syntax in order to parse into an object:

"{\"a\":1,\"b\":"hello"}"

Is there a way to parse the top syntax into json or clj objects? Any help is appreciated. Thank you.

3
  • This isn't a solution for clojure, per se, so not a duplicate, but might give you some ideas: stackoverflow.com/questions/2060356/… Commented Feb 25, 2019 at 19:41
  • 4
    This is not valid JSON, but a JavaScript object. You'll notice when you try it in a validator like jsonlint.com. Commented Feb 25, 2019 at 19:53
  • The unfortunate answer is you'll have to parse it yourself. The only (better) answer is to get the source to feed you valid JSON instead. Commented Feb 25, 2019 at 20:35

2 Answers 2

4

Depending on your level of desperation, the Groovy JSON Slurper can read this "JSON" in the LAX setting (which allows those attributes, comments, ...)

Add the following dep:

[org.codehaus.groovy/groovy-json "2.5.6"]

Then you can run:

user=> (import [groovy.json JsonSlurper JsonParserType])
groovy.json.JsonParserType
user=> (def parser (doto (JsonSlurper.) (.setType JsonParserType/LAX)))
#'user/parser
user=> (def data (.parseText parser "{ a:1, b:\"hello\" }"))
#'user/data
user=> data
{"a" 1, "b" "hello"}
Sign up to request clarification or add additional context in comments.

2 Comments

Nice! I didn't know that was available from Clojure.
It's just .class files in a jar... :)
1

Update 2019-3-21

The link from @jas includes a comment that "it looks like YAML" (if the colons are followed by a space).

I have integrated the new snakeyaml-engine library into the Tupelo Library. API docs are here. The answer is now super-simple:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require [tupelo.parse.yaml :as yaml] ))

(dotest
  (let [data-1 "{ a: 1, b: 'Hello World' }"]
    (is= (yaml/parse data-1) {:a 1, :b "Hello World"})))

Old Answer

Given project.clj

 [io.forward/yaml "1.0.9"]

this works:

(ns tst.demo.core
  (:require [yaml.core :as yaml]) )

(def data-1 "{ a: 1, b: \"Hello World\" }" )

  (let [result-raw (yaml/parse-string data-1)
        result     (into {} result-raw)]

with result

----------------------------------
   Clojure 1.10.0    Java 10.0.1
----------------------------------

Testing tst.demo.core
result-raw   => #ordered/map ([:a 1] [:b "Hello World"])
result       => {:a 1, :b "Hello World"}

Unfortunately it (currently) fails under Java 11 because a dependent library needs a type hint. You can work around this by fixing up your project.clj:

  :dependencies [
     [io.forward/yaml "1.0.9" :exclusions [org.flatland/ordered
                                           org.yaml/snakeyaml] ]
     [org.yaml/snakeyaml "1.23"]
     [org.flatland/ordered "1.5.7"]
     [org.clojure/clojure "1.10.0"]

I filed an issue with the io.forward/yaml project to update their dependencies.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.