如何使用 ansible/jmespath/jq 解析转义的 json 字符串?

如何使用 ansible/jmespath/jq 解析转义的 json 字符串?

我正在使用 Bluecat 的 Ansible 模块进行授权 API 调用以获取有关子网的一些信息。响应看起来像这样:

"result": {
        "changed": false,
        "failed": false,
        "json": "b'{\"id\":12345,\"name\":\"SUBNET NAME\",\"properties\":\"CIDR=10.2.2.0/24|allowDuplicateHost=enable|pingBeforeAssign=disable|inheritAllowDuplicateHost=true|inheritPingBeforeAssign=true|gateway=10.2.2.1|inheritDNSRestrictions=true|inheritDefaultDomains=true|inheritDefaultView=true|\",\"type\":\"IP4Network\"}\\n'",
        "msg": "",
        "status": 200
}

正如您所看到的,所有有用的数据都在该json字段中,但它是一些带有转义引号和换行符的令人厌恶的字符串文字。如果我跑

- debug:
      msg: "{{ result | json_query('json.name') }}"

在 Ansible 中,它msg反而给了我这个领域!我可以获得整个json字段,但无法获取其中的任何内容。如果我稍微修改一下并修剪b开头、内部单引号以及末尾换行符的额外反斜杠,然后jq .json | fromjson正确解析它。但我相当确定b''只是意味着字节编码并且不应该破坏解析,但它确实如此。最后的双反斜杠是怎么回事?

sed除了使用一些黑魔法来消灭所有转义字符之外,我还有其他选择吗?为什么 Web API 会返回这样的字符串?

答案1

去掉大括号外面的内容{},Ansible 将解析字典

  subnet: "{{ result.json[2:-3] }}"

给出

  subnet:
    id: 12345
    name: SUBNET NAME
    properties: CIDR=10.2.2.0/24|allowDuplicateHost=enable|pingBeforeAssign=disable|inheritAllowDuplicateHost=true|inheritPingBeforeAssign=true|gateway=10.2.2.1|inheritDNSRestrictions=true|inheritDefaultDomains=true|inheritDefaultView=true|
    type: IP4Network

可选地,使用更强大的条带化。例如,下面的表达式给出相同的结果

  subnet: "{{ result.json|regex_replace(_regex, _replace) }}"
  _regex: '^.*?\{(.*)\}.*$'
  _replace: '{\1}'

如果你想解析属性特性同样,下面的表达式

  subnet_prop: "{{ subnet|combine({'properties': dict(_prop)}) }}"
  _prop: "{{ subnet.properties.split('|')|select|map('split', '=')|list }}"

给出

  subnet_prop:
    id: 12345
    name: SUBNET NAME
    properties:
      CIDR: 10.2.2.0/24
      allowDuplicateHost: enable
      gateway: 10.2.2.1
      inheritAllowDuplicateHost: 'true'
      inheritDNSRestrictions: 'true'
      inheritDefaultDomains: 'true'
      inheritDefaultView: 'true'
      inheritPingBeforeAssign: 'true'
      pingBeforeAssign: disable
    type: IP4Network

布尔值由上面字典中的字符串表示。如果这是一个问题,请更换分裂过滤器正则表达式_替换来自_yaml。如果过滤器也这样做分裂不可用

  _prop: "{{ subnet.properties.split('|')|
             select|
             map('regex_replace', '^(.*)=(.*)$', '[\\1, \\2]')|
             map('from_yaml')|list }}"

给出

  subnet_prop:
    id: 12345
    name: SUBNET NAME
    properties:
      CIDR: 10.2.2.0/24
      allowDuplicateHost: enable
      gateway: 10.2.2.1
      inheritAllowDuplicateHost: true
      inheritDNSRestrictions: true
      inheritDefaultDomains: true
      inheritDefaultView: true
      inheritPingBeforeAssign: true
      pingBeforeAssign: disable
    type: IP4Network

相关内容