Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
docs:guide-developer:jshn [2020/01/13 12:05] – [jsonfilter] stokitodocs:guide-developer:jshn [2024/08/03 12:52] (current) – [See also] stokito
Line 13: Line 13:
 # generating json data # generating json data
 json_init json_init
 +json_add_int "code" "0"
 json_add_string "msg" "Hello, world!" json_add_string "msg" "Hello, world!"
 json_add_object "test" json_add_object "test"
 json_add_int "testdata" "1" json_add_int "testdata" "1"
 json_close_object json_close_object
-MSG=`json_dump` +MSG_JSON=`json_dump` 
-MSG now contains: { "msg": "Hello, world!", "test": { "testdata": 1 } }+the MSG_JSON var now contains: { "code": 0, "msg": "Hello, world!", "test": { "testdata": 1 } }
  
  
-# parsing json data +# parsing json data from the MSG_JSON variable 
-json_load "$MSG+local var1 code msg # declare local variables to load data into 
-json_select test +json_load "$MSG_JSON
-json_get_var var1 testdata +json_select test # go into the object inside of the "test" field 
-json_select .. +json_get_var var1 testdata # first is var name "var1" then the JSON field name "testdata" 
-json_get_var var2 msg +json_select .. # go back to the upper level 
-echo "msg: $var2 - testdata: $var1"+# load the "code" field into corresponding code var, and the "msg" field into the msg var  
 +json_get_vars code msg 
 +  
 +echo "code: $code, msg: $msg, testdata: $var1"
 </code> </code>
  
Line 71: Line 75:
  
 ==== More complicated examples ==== ==== More complicated examples ====
 +=== Parse file example ===
 Given the file: Given the file:
 <code - /data1.json> <code - /data1.json>
Line 100: Line 104:
 json_get_var last_seen last_seen json_get_var last_seen last_seen
 </code> </code>
 +
 +=== Parse arrays example ===
  
 Given the file: Given the file:
Line 105: Line 111:
 { {
   "ip_addrs": {   "ip_addrs": {
-    "lan": ["192.168.0.100","192.168.0.101","192.168.0.200"], +    "lan": ["192.168.0.100","192.168.0.101","192.168.0.200"]
-    "wan": ["10.11.12.22","10.11.12.23", "10.11.12.25"]+
   }   }
 } }
Line 120: Line 125:
 json_select "ip_addrs" json_select "ip_addrs"
  
-if json_get_type Type lan && [ "$Type" == array ]+if json_is_a lan array
 then then
- json_select lan +  json_select lan 
- local idx="1" +  idx=1 # note that array element position starts from 1 not, 0 
- while json_get_type Type "$idx" && [ "$Type" == string ] ## iterate over data inside "lan" object +  while json_is_a ${idxstring  ## iterate over data inside "lan" object 
- do +  do 
- json_get_var ip_addr $idx  +    json_get_var ip_addr $idx 
- echo "$ip_addr" +    echo "$ip_addr" 
- $((idx++)) 2> /dev/null +    idx=$(( idx + )) 
- done+  done
 fi fi
 +</code>
 +
 +
 +=== Parse list of objects ===
 +
 +The example will download electricity hourly prices for Finland in JSON and parse it.
 +The prices JSON looks like
 +<code - prices.json>
 +{
 +  "prices": [
 +    {
 +      "date": "2024-08-03T11:00:00.000Z",
 +      "value": 6.41
 +    },
 +    {
 +      "date": "2024-08-03T12:00:00.000Z",
 +      "value": 4.1
 +    },
 +  ]
 +}
 +</code>
 +
 +Script to parse it:
 +<code bash>
 +#!/bin/sh
 +set -e
 +. /usr/share/libubox/jshn.sh
 +date=$(date -u +%Y-%m-%dT%H:00:00.000Z)
 +
 +# download prices JSON via wget in quiet mode with output to stdout that will be saved to a variable PRICES_JSON
 +PRICES_JSON=$(wget -qO - "https://sahkotin.fi/prices?start=$date")
 +exit_status=$?
 +# check exit code: if any error then exit
 +if [ $exit_status -ne 0 ]; then
 +   >&2 echo "error $exit_status"
 +   exit $exit_status
 +fi
 +
 +json_load "$PRICES_JSON"
 +json_select "prices"
 +idx=1 # note that array element position starts from 1 not, 0
 +# iterate over data inside "price" array until elements are objects
 +while json_is_a $idx object
 +do
 +  json_select  $idx
 +  # now parse {"date": "2024-08-04T21:00:00.000Z", "value": 22.58}
 +  json_get_var price_date "date"
 +  echo "price_date: $price_date"
 +  json_get_var price_value "value"
 +  echo "price_value: $price_value"
 +  idx=$(( idx + 1 ))
 +  json_select .. # go back to the upper level to the prices array
 +done
 +
 +echo "Total parsed $idx"
 +</code>
 +
 +===== json_for_each_item =====
 +Function useful to iterate through the different elements of an
 +array or object; the provided callback function is called for each
 +element which is passed the value, key and user provided arguments.
 +For field types different from array or object the callback is called
 +with the retrieved value.
 +
 +<code bash>
 +#!/bin/sh
 +. /usr/share/libubox/jshn.sh
 +
 +json_load_file /data2.json
 +
 +dump_item() {
 + echo "item: $1 '$2'"
 +}
 +
 +json_for_each_item "dump_item" "ip_addrs"
 +</code>
 +
 +===== json_get_values =====
 +To get all values of an array use the ''json_get_values'':
 +
 +<code bash>
 +#!/bin/sh
 +. /usr/share/libubox/jshn.sh
 +
 +json_load '{"alist":[1,2]}'
 +json_get_values values "alist"
 +echo "${values}" #=> 1 2
 +# print comma separated
 +echo "${values// /, }" #=> 1, 2
 +</code>
 +
 +
 +===== Get all fields into variables =====
 +Get all fields and declare variables for them:
 +<code bash>
 +json_load '{"params":{"id": 1, "name": "Alice"}}'
 +json_select "params"
 +json_get_keys keys
 +for key in $keys
 +do
 +  json_get_var "$key" "$key"
 +done
 +echo "$id" #=> 1
 +echo "$name" #=> Alice
 </code> </code>
  
Line 136: Line 245:
  
 Internally the ''/usr/share/libubox/jshn.sh'' is just a wrapper for [[https://git.openwrt.org/?p=project/libubox.git;a=blob;f=jshn.c;hb=HEAD|/usr/bin/jshn]] utility. Internally the ''/usr/share/libubox/jshn.sh'' is just a wrapper for [[https://git.openwrt.org/?p=project/libubox.git;a=blob;f=jshn.c;hb=HEAD|/usr/bin/jshn]] utility.
-You can use it directly: 
- 
 <code> <code>
 root@OpenWrt:/# jshn root@OpenWrt:/# jshn
 Usage: jshn [-n] [-i] -r <message>|-R <file>|-o <file>|-p <prefix>|-w Usage: jshn [-n] [-i] -r <message>|-R <file>|-o <file>|-p <prefix>|-w
-root@OpenWrt:/# jshn -i -R /etc/board.json +</code> 
 + 
 +Options: 
 +  * ''-r <message>'' parse from string ''<message>'': called from ''json_load()'' 
 +  * ''-R <file>'' parse from file ''<file>'': called from ''json_load_file()'' 
 +  * ''-w'' write the constructed object to stdout: called from ''json_dump()'' 
 +  * ''-o <file>'' write to file ''<file>'' 
 +  * ''-p <prefix>'' set prefix 
 +  * ''-n'' no newlines \n on formatting 
 +  * ''-i'' indent nested objects on formatting 
 + 
 + 
 +You can call it directly: 
 + 
 +<code> 
 +root@OpenWrt:/# jshn -R /etc/board.json 
 json_init; json_init;
 json_add_object 'model'; json_add_object 'model';
Line 158: Line 280:
 json_close_object; json_close_object;
 </code> </code>
 +The output is then evaluated inside of the shell script to create in memory structure as in file.
  
-Options+If you created an object like
-  * ''-r <message>'' parse from string ''<message>'' +<code
-  * ''-R <file>'' parse from file ''<file>'' +json_init; 
-  ''-w'' write to stdout +json_add_string 'username' 'root'; 
-  * ''-o <file>'' write to file ''<file>'' +json_dump; 
-  * ''-p <prefix>'' set prefix +</code
-  ''-n'' no newline +Then internally it will call ''jshn -w'' with the json obj passed via multiple env variables like
-  * ''-i'' indent +
- +
  
 +<code>
 +root@OpenWrt:/# JSON_CUR=J_V T_J_V_username=string K_J_V=username J_V_username=root jshn -w
 +{ "username": "root" }
 +</code>
 +Here ''J_V'' stands for "JSON value":
 +  * ''JSON_CUR'' means a name of var with root object to format
 +  * ''K_J_V'' is a key name i.e. ''username''
 +  * ''T_J_V_username'' is a type of the ''username'' field
 +  * ''J_V_username=root'' is a value of the  the ''username'' field i.e. ''root''
 ===== Other examples ===== ===== Other examples =====
  
Line 274: Line 403:
  
 ==== jsonfilter ==== ==== jsonfilter ====
-The ''jsonfilter'' tool in included into OpenWrt. The help output:+The [[commit>project/jsonpath.git|jsonfilter]] tool in included into OpenWrt. The help output:
 <code> <code>
 root@openwrt:~# jsonfilter --help root@openwrt:~# jsonfilter --help
-jsonfilter: unrecognized option: - 
 == Usage == == Usage ==
  
Line 326: Line 454:
  
 ==== jq ==== ==== jq ====
-[[https://stedolan.github.io/jq/|jq]] jq is a lightweight and flexible command-line JSON processor. +[[https://stedolan.github.io/jq/|jq]] jq is a flexible command-line JSON processor that is very popular for scripting
-You can install it with ''opkg install jq''+It's not installed by default in OpenWRT because is too big (more than 200Kb) so to install use ''opkg update; opkg install jq''
 By default it just colorize an output e.g. ''cat /etc/board.json | jq'' By default it just colorize an output e.g. ''cat /etc/board.json | jq''
 +
 +==== See also ====
 +  * [[https://github.com/burningtree/awesome-json|Awesome JSON]] A curated list of awesome JSON libraries and resources.
 +  * [[https://github.com/yurt-page/openwrt-script-samples|OpenWrt script samples]]
 +  * [[https://forum.openwrt.org/t/writing-shell-scripts-support-topic/206144|Writing shell scripts support forum topic]]
  
  
  
  
  • Last modified: 2020/01/13 12:05
  • by stokito