16

I have a JSON array returned from curl that looks like this:

[
 {
   "title": "Some Title",
   "tags":"tagA tag-B tagC"
 },
 {
   "title": "Some Title 2",
   "tags":"tagA tagC"
 },
 ...
]

I'd like to convert it to...

[
 {
   "title": "Some Title",
   "tags":["tagA",
           "tag-B",
           "tagC"]
 },
 {
   "title": "Some Title 2",
   "tags":["tagA", 
           "tagC"]
 },
 ...
]

So far I have:

(map(select(.tags!=null)) | map(.tags | split(" "))) as $tags | $tags

and that appears to give me something like:

     [
      [
       "tagA",
       "tag-B",
       "tagC"
      ],
      [
       "tagA", 
       "tagC"
      ]
     ]

But I don't seem to be able to weave that back into an output that would give me .tags as an array in the original objects with the original values...

2 Answers 2

29

You're making it a lot more complicated than it is. Just use map() and |=:

jq 'map(.tags |= split(" "))' file.json

Edit:

If you want to handle entries without tags:

jq 'map(try(.tags |= split(" ")))' file.json

Alternatively, if you want to keep unchanged all entries without tags:

jq 'map(try(.tags |= split(" ")) // .)' file.json

Result:

[
  {
    "tags": [
      "tagA",
      "tag-B",
      "tagC"
    ],
    "title": "Some Title"
  },
  {
    "tags": [
      "tagA",
      "tagC"
    ],
    "title": "Some Title 2"
  }
]
3
  • 1
    Okay I still needed to filter out the nulls first with 'map(select.tags!=null))' with my dataset, but you are correct that does work.
    – leeand00
    Commented Jun 10, 2017 at 9:34
  • @leeand00 Edited. Commented Jun 11, 2017 at 5:44
  • @SatōKatsura Thanks!
    – derflocki
    Commented Feb 21 at 14:23
1

You can attempt this is sed as follows:

The code below is using GNU version of sed (although it can be portably written in POSIX-compatible as well)

sed -e '
   /[{]/,/[}]/!b
   /"tags":/!b

   h;s/"tags":/&\n/;s/\n.*/ /;s/./ /g;x

   s/"tags":/&\n/
   :a
   s/\(\n.*\)\([^"]\) \([^"]\)/\1\2","\3/;ta

   y/\n/[/;s/$/]/;G

   :b
   s/","\(.*\)\(\n.*\)/",\2"\1\2/;tb
   s/\(.*\)\n.*/\1/

' yourjsonfile

Working

  1. We select the range as { to the next } lines.
  2. Zoom in on "tags" line in the range selected.
  3. Compute the nesting spaces for the given tag and store it in hold.
  4. Double quote the tag data in a loop :a
  5. Insert the nesting spaces after the , in a loop :b
  6. Remove everything after the last newline in the pattern space & print.

Results

[
 {
   "title": "Some Title",
   "tags":["tagA",
           "tag-B",
           "tagC"]
 },
 {
   "title": "Some Title 2",
   "tags":["tagA",
           "tagC"]
 },
 ...
]
3
  • 2
    OP specifically asks for jq.
    – JdeHaan
    Commented Aug 26, 2018 at 11:30
  • While this answer is not per OP's original request, and I really would avoid using sed for this job if at all possible, I don't think this deserves a down-vote. For those in a tight spot, POSIX options may be their only option and I see this answer as having value for that reason alone. That said, your sed skills are scary good.
    – James Harr
    Commented Jun 2, 2020 at 13:36
  • I agree. Also, jq isn't available everywhere, centos for example isn't providing it and you have to install epel to get it. In a CI deployment knowing how to do stuff with base tools without having to install stuff is a must have skill.
    – nnsense
    Commented Mar 19, 2021 at 17:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .