JSON

From Rosetta Code
Revision as of 18:49, 27 August 2010 by rosettacode>Paddy3118 (→‎{{header|Python}}: Add some output)
Task
JSON
You are encouraged to solve this task according to the task description, using any language you may know.

Load a JSON string into a data structure. Also create a new data structure and serialize it into JSON. Use objects and arrays (as appropriate for your language) and make sure your JSON is valid (http://www.jsonlint.com/).

Go

<lang go>package main import "json" import "fmt"

func main() {

   var data map[string]interface{}
   json.Unmarshal([]byte("{ \"foo\": 1, \"bar\": [10, \"apples\"] }"), &data)
   fmt.Println(data)
   sample := map[string]interface{}{ "blue": []interface{}{1,2}, "ocean": "water" }
   json_string, err := json.Marshal(sample)
   if err == nil {
       fmt.Println(string(json_string))
   } else {
       fmt.Println(err)
   }

}</lang>

J

Here is a minimal implementation based on an old email message.

<lang j>NB. character classes: NB. 0: whitespace NB. 1: " NB. 2: \ NB. 3: [ ] , { } : NB. 4: ordinary classes=.3<. '"\[],{}:' (#@[ |&>: i.) a. classes=.0 (I.a.e.' ',CRLF,TAB)} (]+4*0=])classes

words=:(0;(0 10#:10*".;._2]0 :0);classes)&;: NB. states:

 0.0  1.1  2.1  3.1  4.1  NB. 0 whitespace
 1.0  5.0  6.0  1.0  1.0  NB. 1 "
 4.0  4.0  4.0  4.0  4.0  NB. 2 \
 0.3  1.2  2.2  3.2  4.2  NB. 3 { : , } [ ]
 0.3  1.2  2.0  3.2  4.0  NB. 4 ordinary
 0.3  1.2  2.2  3.2  4.2  NB. 5 ""
 1.0  1.0  1.0  1.0  1.0  NB. 6 "\

)

tokens=. ;:'[ ] , { } :' actions=: lBra`rBracket`comma`lBra`rBracket`colon`value

NB. action verbs argument conventions: NB. x -- boxed json word NB. y -- boxed json state stack NB. result -- new boxed json state stack NB. NB. json state stack is an list of boxes of incomplete lists NB. (a single box for complete, syntactically valid json) jsonParse=: 0 {:: (,a:) ,&.> [: actions@.(tokens&i.@[)/ [:|.a:,words

lBra=: a: ,~ ] rBracket=: _2&}.@], [:< _2&{::@], _1&{@] comma=: ] rBrace=: _2&}.@], [:< _2&{::@], [:|: (2,~ [: -:@$ _1&{@]) $ _1&{@] colon=: ] value=: _1&}.@], [:< _1&{::@], jsonValue&.>@[

NB. hypothetically, jsonValue should strip double quotes NB. interpret back slashes NB. and recognize numbers jsonValue=:]


require'strings' jsonSer1=: ']' ,~ '[' }:@;@; (',' ,~ jsonSerialize)&.> jsonSer0=: '"', jsonEsc@:":, '"'"_ jsonEsc=: rplc&(<;._1' \ \\ " \"') jsonSerialize=:jsonSer0`jsonSer1@.(*@L.)</lang>

Example use:

<lang> jsonParse'{ "blue": [1,2], "ocean": "water" }' ┌──────────────────────────────┐ │┌──────┬─────┬───────┬───────┐│ ││"blue"│┌─┬─┐│"ocean"│"water"││ ││ ││1│2││ │ ││ ││ │└─┴─┘│ │ ││ │└──────┴─────┴───────┴───────┘│ └──────────────────────────────┘

  jsonSerialize jsonParse'{ "blue": [1,2], "ocean": "water" }'

[["\"blue\"",["1","2"],"\"ocean\"","\"water\""]]</lang>

Note that these are not strict inverses of each other. These routines allow data to be extracted from json and packed into json format, but only in a minimalistic sense. No attempts are made to preserve the subtleties of type and structure which json can carry. This should be good enough for most applications which are required to deal with json but will not be adequate for ill behaved applications which exploit the typing mechanism to carry significant information.

Also, a different serializer will probably be necessary, if you are delivering json to legacy javascript. Nevertheless, these simplifications are probably appropriate for practical cases.

JavaScript

Requires JSON library, now present in some browsers. <lang JavaScript>var data = JSON.parse('{ "foo": 1, "bar": [10, "apples"] }');

var sample = { "blue": [1,2], "ocean": "water" }; var json_string = JSON.stringify(sample);</lang>

Of course, it IS called JavaScript Object Notation, so it is a JavaScript object literal, and you can, alternately, parse it by just eval'ing it. This should work in any browser without a library. (Eval may be dangerous, depending on the source of the data.) However, there is an ambiguity with parsing JavaScript object literals by themselves, where it might be mistakenly interpreted as a block, and the key followed by a colon as a label. To avoid this, remember to surround it in parentheses to force it to be interpreted as an expression: <lang javascript>var data = eval('(' + '{ "foo": 1, "bar": [10, "apples"] }' + ')');</lang>

Oz

With the JSON library from here: <lang oz>declare

 [JSON] = {Module.link ['JSON.ozf']}
 {System.show {JSON.decode "{ \"foo\": 1, \"bar\": [10, \"apples\"] }"}}
 Sample = object(blue:array(1 2) ocean:"water")
 {System.showInfo {JSON.encode Sample}}</lang>

Output:

object(bar:array(10 [97 112 112 108 101 115]) foo:1)
{"blue":[1,2],"ocean":"water"}

PHP

<lang php><?php $data = json_decode('{ "foo": 1, "bar": [10, "apples"] }'); // dictionaries will be returned as objects $data2 = json_decode('{ "foo": 1, "bar": [10, "apples"] }', true); // dictionaries will be returned as arrays

$sample = array( "blue" => array(1,2), "ocean" => "water" ); $json_string = json_encode($sample); ?></lang>

PicoLisp

PicoLisp has no JSON library, but it is easy enough to write one: <lang PicoLisp>(de checkJson (X Item)

  (unless (= X Item)
     (quit "Bad JSON" Item) ) )

(de readJson ()

  (case (read "_")
     ("{"
        (make
           (for (X (readJson)  T  (readJson))
              (checkJson ":" (readJson))
              (link (cons X (readJson)))
              (T (= "}" (setq X (readJson))))
              (checkJson "," X) ) ) )
     ("["
        (make
           (link T)  # Array marker
           (for (X (readJson)  T  (readJson))
              (link X)
              (T (= "]" (setq X (readJson))))
              (checkJson "," X) ) ) )
     (T @) ) )

(de printJson (Item) # For simplicity, without indentation

  (cond
     ((atom Item) (print Item))
     ((=T (car Item))
        (prin "[")
        (map
           '((X)
              (printJson (car X))
              (and (cdr X) (prin ", ")) )
           (cdr Item) )
        (prin "]") )
     (T
        (prin "{")
        (map
           '((X)
              (print (caar X))
              (prin ": ")
              (printJson (cdar X))
              (and (cdr X) (prin ", ")) )
           Item )
        (prin "}") ) ) )</lang>

This reads/prints JSON from/to files, pipes, sockets etc. To read from a string, a pipe can be used:

: (pipe (prinl "{ \"foo\": 1, \"bar\": [10, \"apples\"] }")
   (readJson) )
-> (("foo" . 1) ("bar" T 10 "apples"))

: (printJson
   (quote
      ("name" . "Smith")
      ("age" . 25)
      ("address"
         ("street" . "21 2nd Street")
         ("city" . "New York")
         ("state" . "NY")
         ("zip" . "10021") )
      ("phone" T "212 555-1234" "646 555-4567") ) )
{"name": "Smith", "age": 25, ... {"street": ... "phone": ["212 555-1234", ...

Python

Works with: Python version 2.6+
Works with: Python version 3.0+

<lang Python>>>> import json >>> data = json.loads('{ "foo": 1, "bar": [10, "apples"] }') >>> sample = { "blue": [1,2], "ocean": "water" } >>> json_string = json.dumps(sample) >>> json_string '{"blue": [1, 2], "ocean": "water"}' >>> sample {'blue': [1, 2], 'ocean': 'water'} >>> data {'foo': 1, 'bar': [10, 'apples']}</lang>

Tcl

For parsing JSON, there is a package in

Library: Tcllib

which provides the capability (see the Tcler's Wiki page on it for more discussion):

<lang tcl>package require json set sample {{ "foo": 1, "bar": [10, "apples"] }}

set parsed [json::json2dict $sample] puts $parsed</lang> Output:

foo 1 bar {10 apples}

However, that package is very weak in its generation of JSON because Tcl's official type system is substantially different to that envisaged by JSON. It's possible to work around this though the use of Tcl 8.6, as this next example shows:

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6

proc tcl2json value {

   # Guess the type of the value; deep *UNSUPPORTED* magic!
   regexp {^value is a (.*?) with a refcount} \

[::tcl::unsupported::representation $value] -> type

   switch $type {

string { # Skip to the mapping code at the bottom } dict { set result "{" set pfx "" dict for {k v} $value { append result $pfx [tcl2json $k] ": " [tcl2json $v] set pfx ", " } return [append result "}"] } list { set result "\[" set pfx "" foreach v $value { append result $pfx [tcl2json $v] set pfx ", " } return [append result "\]"] } int - double { return [expr {$value}] } booleanString { return [expr {$value ? "true" : "false"}] } default { # Some other type; do some guessing... if {$value eq "null"} { # Tcl has *no* null value at all; empty strings are semantically # different and absent variables aren't values. So cheat! return $value } elseif {[string is integer -strict $value]} { return [expr {$value}] } elseif {[string is double -strict $value]} { return [expr {$value}] } elseif {[string is boolean -strict $value]} { return [expr {$value ? "true" : "false"}] } }

   }
   # For simplicity, all "bad" characters are mapped to \u... substitutions
   set mapped [subst -novariables [regsub -all {[][\u0000-\u001f\\""]} \

$value {[format "\\\\u%04x" [scan {& } %c]]}]]

   return "\"$mapped\""

}</lang> Sample code (note that the value is built with dict create and list so that there is some auxiliary type hints available, which the above procedure can read): <lang tcl>set d [dict create blue [list 1 2] ocean water] puts [tcl2json $d]</lang> Output:

{"blue": [1, 2], "ocean": "water"}

Note that this is capable of correctly handling the round-trip of values parsed from the json package described above.