Use jq to Format Certain Fields as Compact?

*爱你&永不变心* 提交于 2020-01-11 12:38:05

问题


Is jq the best choice for pretty-printing arbitrary JSON?

cat my.json | jq . pretty-prints the given JSON, but expands every field on a separate line.

But what if some of the fields are repetitive, such as a list of points? How can fields that match a pattern be formatted on a single line with --compact-output?

For example, format "coords" and "list" fields below on a single line:

 [
   { 
      "field1": {
        "a": "",
        "b": ""
        "list": [{ "name": "x", "score": 1, "rect": { "x": 156, "y": 245, "w": 35, "h": 45 }, ... ]
      },
      "field2": 2,
      "coords": [{ "x": 100, "y": 400 },{ "x": 100, "y": 0 }]
    },
    ....
 ]

The fields formatted with --compact-output can wrap (no need to break these long lines).


回答1:


A constrained-width JSON pretty-printer could be written in jq itself. Here is a pretty-printer which illustrates how this could be done, though in its present incarnation, it is of limited usefulness.

ppArray(indent; incr; width) will emit a stream of JSON strings that together are equivalent to the tostring value of the input. For robustness, it will always act as a pretty-printer, even if the width restriction is violated.

If the input is an array, and if none of its elements (or recursively their elements) contains any large objects or long strings, then assuming the values of the parameters are reasonably chosen and that nesting is not too deep relative to these parameters, each emitted string should be no longer than "width".

# indent is the initial indentation level;
# incr is the number of spaces to add for one additional indentation level;
# width is the target maximum width.
#
def ppArray(indent; incr; width):
  # The inner function produces an array of unindented strings.
  def ppArray_(incr_; width_):
    tostring as $tostring
    | if $tostring|length <= (width_ - incr_) then [$tostring]
      else reduce .[] as $i
        ([];  
         ($i|tostring) as $is
          | if length == 0 then [ $is ]
            else .[-1] as $s
            | ($s|length) as $n
            | ($is|length) as $isl
            | if $n + $isl <= (width_ - incr_)
             then .[-1] = ($s + ", " + $is)
              elif ($i|type) == "array"
             then (.[-1]+=",") + [ $i | ppArray(0; incr_; width_ - incr_) ]
              else  (.[-1]+=",") + [ $is ]
              end 
            end )
      end;

    (" " * indent) as $indentation
    | if type == "array" 
      then ppArray_(incr; width - indent)
           | $indentation + "[",
           (.[] | ($indentation + "  " + . )),
           $indentation + "]"
    else $indentation + tostring
    end
;

Example:

[range(0;16)]
|
(ppArray(0; 2; 10)),
"::",
([{a:1}, {b:2}, {c:3}]  | ppArray(0; 2; 10)),
"::",
(.[2]=[range(0;10)]) | ppArray(0; 2; 10)

Invocation:

jq -nrf pp.jq

Output:

[
  0, 1, 2, 3,
  4, 5, 6, 7,
  8, 9, 10,
  11, 12, 13,
  14, 15
]
::
[
  {"a":1},
  {"b":2},
  {"c":3}
]
::
[
  0, 1,
  [
    0, 1, 2,
    3, 4, 5,
    6, 7, 8,
    9
  ], 3, 4, 5,
  6, 7, 8, 9,
  10, 11, 12,
  13, 14, 15
]


来源:https://stackoverflow.com/questions/42729731/use-jq-to-format-certain-fields-as-compact

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!