Jq: Correct way to test for the type of a JSON value

Created on 22 Jan 2013  路  4Comments  路  Source: stedolan/jq

Hi,

what is the correct way to test for the type of a value?

Example: I only want to get arrays or objects and unwrap the contained values. If I don't filter out scalars jq gives an error:

% echo '[1, 2] 1' | jq '.[]'
1
2
jq: error: Cannot iterate over number

Now I test for arrays and objects "hijacking" the >= operator:

% echo '[1, 2] 1' | jq 'select(. >= []) | .[]'
1
2

Is there a better way of doing this?

And the general question is: How to test for

  • number
  • string
  • array
  • ...

Regards,
Tilo

docs support

Most helpful comment

While not as ingenious as @13ren's solution, you can also use the type function :)

$ echo '[true, null, 42, "hello", []]' | ./jq 'map(type)'
["boolean","null","number","string","array"]

All 4 comments

Thanks, i was looking for that! One hack to test for strings is:

echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.==tostring)'
"z"

Based on your test for "object or array", just discovered a test for objects only:

echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.>={})'
{
  "x": "y"
}
{}

Can combine to test for arrays:

echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.>=[] and .<{})'
[
  1111
]
[]

Finally, can test for number by combining "not an object or array", string test and exhaustive explicit tests for not true/false/null:

echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' |
jq 'select(.<[] and .!=tostring and .!=true and .!=false and .!=null)'
2222

Is there a shorter way?

While not as ingenious as @13ren's solution, you can also use the type function :)

$ echo '[true, null, 42, "hello", []]' | ./jq 'map(type)'
["boolean","null","number","string","array"]

On Wed, 23 Jan 2013 12:29:04 +0100, Stephen Dolan
[email protected] wrote:

While not as ingenious as @13ren's solution, you can also use the type
function :)

$ echo '[true, null, 42, "hello", []]' | ./jq 'map(type)'
["boolean","null","number","string","array"]

Great! Exactly what I was looking for.

I did search http://stedolan.github.com/jq/manual for such a function but
didn't find anything.

This function is probably useful for others too.

Regards,


This is great! It enables recurse(filter) to traverse arbitrary json (i.e. without an explicit field holding child values, unlike the reddit json in #37 which inspired it).

echo '[true, null, 42, "hello", []]' | jq 'recurse(.[])'
[
  true,
  null,
  42,
  "hello",
  []
]
true
jq: error: Cannot iterate over boolean
42
jq: error: Cannot iterate over number
"hello"
jq: error: Cannot iterate over string
[]
echo '[true, null, 42, "hello", []]' | jq 'recurse(select(type|.=="array"or.=="object") | .[])'
[
  true,
  null,
  42,
  "hello",
  []
]
true
42
"hello"
[]

NB: recurse omits nulls (due to its definition), and Tilo's sweet hack recurse( select(.>=[]) | .[] ) is shorter.

Would it make sense to include something like the above, as a builtin traverse(filter)? It seems an important special-case of recursion for JSON.

Aside: recurse can (of course) do general recursion e.g.

jq -n '0 | recurse( .+1|select(.<3) )'
0
1
2

Sorry, getting carried away here, but we can define a for-loop function, with optional step:

def for(args): args as $a| ($a[2] // 1) as $step|   $a[0] | recurse( .+$step| select(.<$a[1]) );
for([0,4,2])
0
2
for([0,4])
0
1
2
3
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rubensayshi picture rubensayshi  路  3Comments

tbelaire picture tbelaire  路  4Comments

ghost picture ghost  路  4Comments

lbrader picture lbrader  路  3Comments

thelonious picture thelonious  路  4Comments