Json

如何使用 ansible/jmespath/jq 解析轉義的 json 字元串?

  • May 16, 2022

我正在使用 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 會返回這樣的字元串文字?

去掉大括號外的內容{},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

布爾值由上面字典中的字元串表示。如果這是一個問題,請使用regex_replace和*_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

引用自:https://unix.stackexchange.com/questions/702328