如何使用ruamel.yaml输出行分隔/格式化的json块?

eagi6jfj  于 2023-10-21  发布在  其他
关注(0)|答案(1)|浏览(80)

我目前正在pyyaml中使用这个代码块,但是我想用ruamel.yaml完成同样的事情

import yaml
import json
envList=envList={"env":"development", "region":"us", "tag":"latest", "kubesvcname":"service", "containername":"testcontainer", "namespace":"kubens", "buildid":"1000"}
jsonFile = json.dumps(envList, indent=4)
configMapHeader={ \
    "apiVersion": "v1", \
    "kind":"ConfigMap", \
    "metadata": { \
        "name": f'{envList["kubesvcname"]}_{envList["containername"]}-{envList["tag"]}-{envList["buildid"]}', \
        "namespace": f'{envList["namespace"]}'\
    },
    "data":{"appsettings.json": \
             jsonFile }
}

def str_presenter(dumper, data):
    """configures yaml for dumping multiline strings
    Ref: https://stackoverflow.com/questions/8640959/how-can-i-control-what-scalar-form-pyyaml-uses-for-my-data"""
    if len(data.splitlines()) > 1:  # check for multiline string
        return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
    return dumper.represent_scalar('tag:yaml.org,2002:str', data)

yaml.representer.SafeRepresenter.add_representer(str, str_presenter) 
print(yaml.safe_dump(configMapHeader, sort_keys=False, line_break=True))

它的输出看起来像这样:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service_testcontainer-latest-1000
  namespace: kubens
data:
  appsettings.json: |-
    {
        "env": "development",
        "region": "us",
        "tag": "latest",
        "kubesvcname": "service",
        "containername": "testcontainer",
        "namespace": "kubens",
        "buildid": "1000"
    }

当我尝试对ruamel.yaml执行类似的操作时,我会在输出文件中得到\n换行符。
这是代码:

def initYamlParser():
    import ruamel.yaml as yaml
    yaml = yaml.YAML()
    yaml.preserve_quotes = True
    yaml.explicit_start = True
    return yaml

import sys
import json
yaml=initYamlParser()
envList=envList={"env":"development", "region":"us", "tag":"latest", "kubesvcname":"service", "containerver": "latest", "containername":"testcontainer", "namespace":"kubens", "buildid":"1000"}
jsonFile = json.dumps(envList, indent=4)
configMapHeader={ \
    "apiVersion": "v1", \
    "kind":"ConfigMap", \
    "metadata": { \
        "name": f'{envList["kubesvcname"]}_{envList["containername"]}-{envList["containerver"]}-{envList["buildid"]}', \
        "namespace": f'{envList["namespace"]}'\
    },
    "data":{"appsettings.json": \
            jsonFile }
}
print(configMapHeader)
with open("file.yaml", 'w+') as file:
    yaml.dump(configMapHeader, file)

这是输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service_testcontainer-latest-1000
  namespace: kubens
data:
  appsettings.json: "{\n    \"env\": \"development\",\n    \"region\": \"us\",\n \
    \   \"tag\": \"latest\",\n    \"kubesvcname\": \"service\",\n    \"containerver\"\
    : \"latest\",\n    \"containername\": \"testcontainer\",\n    \"namespace\": \"\
    kubens\",\n    \"buildid\": \"1000\"\n}"

yaml不支持str_presenter,所以我希望该函数有一个与ruamel.yaml兼容的版本,或者有一种在内部用ruamel.yaml表示它的方法

qyuhtwio

qyuhtwio1#

首先,在转储YAML文档时,通常不应该追加到文件中。由于ruamel.yaml将UTF-8写入文件,因此将其作为"wb"打开。
您设置了yaml.preserve_quotes = True,但这仅在往返时有效(加载YAML,然后转储)。
然后在ruamel.yaml中,你也可以有一个不同的表示器,只需将它附加到representer属性(它是Representer属性的示例,默认为RoundTripRepresenter)。唯一的区别是,它是作为第一个参数提交的代表:

import sys
import json
import ruamel.yaml
   
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True

def str_presenter(cls, data):
    if len(data.splitlines()) > 1:  # check for multiline string
        return cls.represent_scalar('tag:yaml.org,2002:str', data, style='|')
    return cls.represent_scalar('tag:yaml.org,2002:str', data)

yaml.representer.add_representer(str, str_presenter)

envList={"env":"development", "region":"us", "tag":"latest", "kubesvcname":"service", "containerver": "latest", "containername":"testcontainer", "namespace":"kubens", "buildid":"1000"}
jsonFile = json.dumps(envList, indent=4)
configMapHeader={ \
    "apiVersion": "v1", \
    "kind":"ConfigMap", \
    "metadata": { \
        "name": f'{envList["kubesvcname"]}_{envList["containername"]}-{envList["containerver"]}-{envList["buildid"]}', \
        "namespace": f'{envList["namespace"]}'\
    },
    "data":{"appsettings.json": \
            jsonFile }
}
 

# print(data)
yaml.dump(configMapHeader, sys.stdout)

其给出:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: service_testcontainer-latest-1000
  namespace: kubens
data:
  appsettings.json: |-
    {
        "env": "development",
        "region": "us",
        "tag": "latest",
        "kubesvcname": "service",
        "containerver": "latest",
        "containername": "testcontainer",
        "namespace": "kubens",
        "buildid": "1000"
    }

如果加载预期的输出,然后转储它,可以看到ruamel.yaml可以保留块样式的文本标量。通过检查键appsetting.json的值,您将看到这是类LiteralScalarString的一个示例。这些知识可以用来使只有一个标量以这种方式转储(而不是所有嵌入了换行符的标量):

import sys
import json
import ruamel.yaml
   
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True

envList={"env":"development", "region":"us", "tag":"latest", "kubesvcname":"service", "containerver": "latest", "containername":"testcontainer", "namespace":"kubens", "buildid":"1000"}
jsonFile = json.dumps(envList, indent=4)
configMapHeader={ \
    "apiVersion": "v1", \
    "kind":"ConfigMap", \
    "metadata": { \
        "name": f'{envList["kubesvcname"]}_{envList["containername"]}-{envList["containerver"]}-{envList["buildid"]}', \
        "namespace": f'{envList["namespace"]}'\
    },
    "data":{"appsettings.json": \
            ruamel.yaml.scalarstring.LiteralScalarString(jsonFile) }
}

yaml.dump(configMapHeader, sys.stdout)

其给出:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: service_testcontainer-latest-1000
  namespace: kubens
data:
  appsettings.json: |-
    {
        "env": "development",
        "region": "us",
        "tag": "latest",
        "kubesvcname": "service",
        "containerver": "latest",
        "containername": "testcontainer",
        "namespace": "kubens",
        "buildid": "1000"
    }
  • 你可能想看看envList=envList=....,不知道为什么你给同一个变量赋值两次
  • 如果你想知道:因为JSON转储程序输出不包括最后的换行符,所以在文本标量指示符|-之后会有一个破折号

相关问题