FSA
FSA

Reputation: 21

using jq delete key value pair when value contains a specific string

Using jq I need to delete a specific key:value pair if value contains string "null". The string could be " null" or "null ". Hence need to use contains and not exact string match. If not a string it will be a number

My sample json is as below: (The null value is expected only in the 'th' and 'sf' keys)

'dets':{
   'S1':{
        'type':'class',
        'input': [12,7,6,19],
        'config':{
                'file':'sfile1',
                 'th': -10,
                 'sf': 'null'
                }
         },
    'S2':{
        'type':'class',
        'input': [12,7,6,19],
        'config':{
                'file':'sfile2',
                 'th': -5,
                 'sf': 3
                }
         },
    'S3':{
        'type':'bottom',
        'input': [12,7,16],
        'config':{
                'file':'sfile3',
                 'th': ' null',
                 'sf': 'null '
                }
         }
    }

The required output should be like:

    'dets':{
   'S1':{
        'type':'class',
        'input': [12,7,6,19],
        'config':{
                'file':'sfile1',
                 'th': -10
                }
         },
    'S2':{
        'type':'class',
        'input': [12,7,6,19],
        'config':{
                'file':'sfile2',
                 'th': -5,
                 'sf': 3
                }
         },
    'S3':{
        'type':'bottom',
        'input': [12,7,16],
        'config':{
                'file':'sfile3'
                }
         }
    }

I believe something on the lines of del(.[][].config.smoothing_span | select(contains("null"))) but i am running into a problem since type is different.

Upvotes: 1

Views: 2161

Answers (1)

peak
peak

Reputation: 116880

  1. The given data is not valid JSON but it is valid HJSON, so the first step in the following jq-oriented solution is to use hjson to convert the data to JSON:

    hjson -j input.hjson

  2. The concept of what values should be regarded as "null" might change over time, so in the following let's define a filter that can be used to capture whichever definition is appropriate, e.g. def isnull: . == null or (type=="string" and test("null"));

(Perhaps a better definition would use test("^ *null *$").)

  1. If you want to delete all keys whose value isnull, you could use walk/1:

walk(if type=="object" then with_entries(select(.value|isnull|not)) else . end)

(If your jq does not have walk, you could simply copy-and-paste its definition from https://github.com/stedolan/jq/blob/master/src/builtin.jq or elsewhere on the web.)

Assuming your jq has walk, we could therefore write:

hjson -j input.hjson |
  jq 'def isnull: . == null or (type=="string" and test("null")); 
      walk(if type=="object" 
           then with_entries(select(.value|isnull|not))
           else . end)'
  1. If you want to "walk" the input but restrict attention to specific keys, you can easily modify the selection criterion in (3).

delkey

If you want the scope of the changes to be as narrow as possible, you could use map_values, e.g. in conjunction with a helper function for checking and possibly deleting a specific key:

  # key is assumed to be a filter, e.g. .foo
  def delkey(key): if key | isnull then del(key) else . end;
  .dets |= map_values(.config |= (delkey(.th) | delkey(.sf)))

delkeys

If there are several specific keys to be checked, it might be more convenient to define a function for checking a list of keys:

# keys is assumed to be an array of strings
def delkeys(keys):
  with_entries(select(.key as $k
    | (keys|index($k)) and (.value|isnull) | not));

.dets |= map_values(.config |= delkeys(["th", "sf"]))

Upvotes: 3

Related Questions