簡體   English   中英

Python“ yaml”模塊從JSON格式轉換意外的YAML

[英]Python “yaml” module converting unexpected YAML from JSON format

我正在嘗試將JSON數據轉換為YAML格式,但是得到了意外的YAML輸出

使用在線工具將JSON轉換為YAML,從而提供預期的YAML輸出。 但是,當以下Python代碼中使用相同的JSON時,會得到意外的不同結果。

import yaml                                                                     

job_template = [                                                                
  {                                                                             
    "job-template": {                                                           
      "name": "{name}_job",                                                     
      "description": "job description",                                         
      "project-type": "multibranch",                                            
      "number-to-keep": 30,                                                     
      "days-to-keep": 30,                                                       
      "scm": [                                                                  
        {                                                                       
          "git": {                                                              
            "url": "{git_url}"                                                  
          }                                                                     
        }                                                                       
      ]                                                                         
    }                                                                           
  }                                                                             
]                                                                               

yaml.dump(job_template, open("job_template.yaml", "w"))   

預期低於YAML數據:

- job-template:
    name: "{name}_job"
    description: job description
    project-type: multibranch
    number-to-keep: 30
    days-to-keep: 30
    scm:
    - git:
        url: "{git_url}"

取得以下YAML格式:

 - job-template:
     days-to-keep: 30
     description: job description
     name: '{name}_job'
     number-to-keep: 30
     project-type: multibranch
     scm:
     - git: {url: '{git_url}'}

使用default_flow_style=False

例如:

import yaml                                                                     

job_template = [                                                                
  {                                                                             
    "job-template": {                                                           
      "name": "{name}_job",                                                     
      "description": "job description",                                         
      "project-type": "multibranch",                                            
      "number-to-keep": 30,                                                     
      "days-to-keep": 30,                                                       
      "scm": [                                                                  
        {                                                                       
          "git": {                                                              
            "url": "{git_url}"                                                  
          }                                                                     
        }                                                                       
      ]                                                                         
    }                                                                           
  }                                                                             
]                                                                               

yaml.dump(job_template, open("job_template.yaml", "w"), default_flow_style=False)  

問題出在Python代碼中: dict是一個無序的容器。 pprint只是給出了yaml輸出的相同順序:

>>> pprint.pprint(job_template)
[{'job-template': {'days-to-keep': 30,
                   'description': 'job description',
                   'name': '{name}_job',
                   'number-to-keep': 30,
                   'project-type': 'multibranch',
                   'scm': [{'git': {'url': '{git_url}'}}]}}]

如果問題是關於最后一級字典{"url": "{git_url}"} ,則答案已由@Rakesh給出。

PyYAML中順序的更改阻礙了對YAML文件的雙向編輯,並且許多其他解析器都試圖解決該問題。

值得一看的是Ruamel.yaml ,它在其概述頁面顯示

block style and key ordering are kept, so you can diff the round-tripped source

作者提供的代碼示例演示了這一點:

import sys
import ruamel.yaml as yaml

yaml_str = """\
3: abc
conf:
    10: def
    3: gij     # h is missing
more:
- what
- else
"""

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
data['conf'][10] = 'klm'
data['conf'][3] = 'jig'
yaml.dump(data, sys.stdout, Dumper=yaml.RoundTripDumper)
will give you:

3: abc
conf:
  10: klm
  3: jig       # h is missing
more:
- what
- else

這是更充分的討論在這里 它被描述為是PyYAML的直接替代品,因此應該易於在您的環境中進行試驗。

首先,您只需要將作業模板保留在JSON文件中,例如input.json

[                                                                
  {                                                                             
    "job-template": {                                                           
      "name": "{name}_job",                                                     
      "description": "job description",                                         
      "project-type": "multibranch",                                            
      "number-to-keep": 30,                                                     
      "days-to-keep": 30,                                                       
      "scm": [                                                                  
        {                                                                       
          "git": {                                                              
            "url": "{git_url}"                                                  
          }                                                                     
        }                                                                       
      ]                                                                         
    }                                                                           
  }                                                                             
]

這樣,您可以更輕松地調整腳本來處理不同的文件。 這樣做還保證了JSON對象中的鍵是有序的,當您在代碼中包含JSON作為dicts和list時,這是不能保證的,至少對於所有當前版本的Python而言,這都不是保證的

然后,由於YAML 1.2(規范於2009年發布)是YAML的超集,因此您可以使用YAML 1.2庫,該庫在加載轉儲時保留鍵順序以將其轉換為所需的格式。 由於PyYAML仍然停留在2005年發布的YAML 1.1規范中,因此您不能使用它,但是可以使用ruamel.yaml (免責聲明,我是該軟件包的作者)。

唯一的“問題”是ruamel.yaml還將保留輸入中的(流)樣式。 那正是您不想要的。

因此,您必須遞歸遍歷數據結構並更改包含該信息的屬性:

import sys
import ruamel.yaml

def block_style(d):
    if isinstance(d, dict):
        d.fa.set_block_style()
        for key, value in d. items():
            try:
                if '{' in value:
                    d[key] = ruamel.yaml.scalarstring.DoubleQuotedScalarString(value)
            except TypeError:
                pass
            block_style(value)
    elif isinstance(d, list):
        d.fa.set_block_style()
        for elem in d:
            block_style(elem)

yaml = ruamel.yaml.YAML()

with open('input.json') as fp:
    data = yaml.load(fp)

block_style(data)

yaml.dump(data, sys.stdout)

這使:

- job-template:
    name: "{name}_job"
    description: job description
    project-type: multibranch
    number-to-keep: 30
    days-to-keep: 30
    scm:
    - git:
        url: "{git_url}"

上面對於Python2和Python3同樣有效

'{'的額外代碼測試是對不能用普通標量表示的字符串強制使用雙引號。 默認情況下,如果不需要使用YAML雙引號標量中可用的額外轉義序列來表示字符串, ruamel.yaml將使用單引號標量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM