如何使用 YamlDotNet 将 JSON 转换为 YAML
Posted
技术标签:
【中文标题】如何使用 YamlDotNet 将 JSON 转换为 YAML【英文标题】:How to convert JSON to YAML using YamlDotNet 【发布时间】:2016-07-03 19:55:58 【问题描述】:我正在尝试使用 YamlDotNet 将 JSON 转换为 YAML。这是我的代码:
class Program
static void Main(string[] args)
var json = "\"swagger\":\"2.0\",\"info\":\"title\":\"UberAPI\",\"description\":\"MoveyourappforwardwiththeUberAPI\",\"version\":\"1.0.0\",\"host\":\"api.uber.com\",\"schemes\":[\"https\"],\"basePath\":\"/v1\",\"produces\":[\"application/json\"]";
var swaggerDocument = JsonConvert.DeserializeObject(json);
var serializer = new YamlDotNet.Serialization.Serializer();
using (var writer = new StringWriter())
serializer.Serialize(writer, swaggerDocument);
var yaml = writer.ToString();
Console.WriteLine(yaml);
这是我提供的 JSON:
"swagger":"2.0",
"info":
"title":"UberAPI",
"description":"MoveyourappforwardwiththeUberAPI",
"version":"1.0.0"
,
"host":"api.uber.com",
"schemes":[
"https"
],
"basePath":"/v1",
"produces":[
"application/json"
]
这是我期望的 YAML:
swagger: '2.0'
info:
title: UberAPI
description: MoveyourappforwardwiththeUberAPI
version: 1.0.0
host: api.uber.com
schemes:
- https
basePath: /v1
produces:
- application/json
但是,这是我得到的输出:
swagger: []
info:
title: []
description: []
version: []
host: []
schemes:
- []
basePath: []
produces:
- []
我不知道为什么所有属性都是空数组。
我也尝试过这样的类型化反序列化和序列化:
var specification = JsonConvert.DeserializeObject<SwaggerDocument>(json);
...
serializer.Serialize(writer, swaggerDocument, typeof(SwaggerDocument));
但这会产生
非常感谢任何帮助。
【问题讨论】:
【参考方案1】:您实际上不需要将 JSON 反序列化为强类型对象,您也可以使用动态 Expando 对象将 JSON 转换为 YAML。这是一个小例子:-
var json = @"
'Name':'Peter',
'Age':22,
'CourseDet':
'CourseName':'CS',
'CourseDescription':'Computer Science',
,
'Subjects':['Computer Languages','Operating Systems']
";
var expConverter = new ExpandoObjectConverter();
dynamic deserializedObject = JsonConvert.DeserializeObject<ExpandoObject>(json, expConverter);
var serializer = new YamlDotNet.Serialization.Serializer();
string yaml = serializer.Serialize(deserializedObject);
您可以看到这两种方法的详细说明,即使用强类型对象和动态对象here。
【讨论】:
【参考方案2】:您可以将JObject
转换为 YamlDotNet 可以序列化的更简单的对象:
class Program
static void Main(string[] args)
var json = "\"swagger\":\"2.0\",\"info\":\"title\":\"UberAPI\",\"description\":\"MoveyourappforwardwiththeUberAPI\",\"version\":\"1.0.0\",\"host\":\"api.uber.com\",\"schemes\":[\"https\"],\"basePath\":\"/v1\",\"produces\":[\"application/json\"]";
var swaggerDocument = ConvertJTokenToObject(JsonConvert.DeserializeObject<JToken>(json));
var serializer = new YamlDotNet.Serialization.Serializer();
using (var writer = new StringWriter())
serializer.Serialize(writer, swaggerDocument);
var yaml = writer.ToString();
Console.WriteLine(yaml);
static object ConvertJTokenToObject(JToken token)
if (token is JValue)
return ((JValue)token).Value;
if (token is JArray)
return token.AsEnumerable().Select(ConvertJTokenToObject).ToList();
if (token is JObject)
return token.AsEnumerable().Cast<JProperty>().ToDictionary(x => x.Name, x => ConvertJTokenToObject(x.Value));
throw new InvalidOperationException("Unexpected token: " + token);
【讨论】:
【参考方案3】:我认为当 json 反序列化返回 JObject
时有问题。看起来 yaml 序列化器不喜欢它。
正如你提到的JsonConvert.DeserializeObject<SwaggerDocument>(json)
,我使用了指定类型的反序列化,这就是我得到的
Swagger: 2.0
Info:
Title: UberAPI
Description: MoveyourappforwardwiththeUberAPI
Version: 1.0.0
Host: api.uber.com
Schemes:
- https
BasePath: /v1
Produces:
- application/json
这是我的全部代码:
class Program
static void Main(string[] args)
var json = "\"Swagger\":\"2.0\",\"Info\":\"Title\":\"UberAPI\",\"Description\":\"MoveyourappforwardwiththeUberAPI\",\"Version\":\"1.0.0\",\"Host\":\"api.uber.com\",\"Schemes\":[\"https\"],\"BasePath\":\"/v1\",\"Produces\":[\"application/json\"]";
var swaggerDocument = JsonConvert.DeserializeObject<SwaggerDocument>(json);
var serializer = new YamlDotNet.Serialization.Serializer();
using (var writer = new StringWriter())
serializer.Serialize(writer, swaggerDocument);
var yaml = writer.ToString();
Console.WriteLine(yaml);
public class Info
public string Title get; set;
public string Description get; set;
public string Version get; set;
public class SwaggerDocument
public string Swagger get; set;
public Info Info get; set;
public string Host get; set;
public List<string> Schemes get; set;
public string BasePath get; set;
public List<string> Produces get; set;
更新
这里有两个问题。
当反序列化带有字段的类时,默认情况下,json.net
在执行此工作时不会考虑它们。为此,我们必须通过创建自定义合约解析器来自定义反序列化过程。我们可以很容易地做到这一点
var swaggerDocument = JsonConvert.DeserializeObject<SwaggerDocument>(json, new JsonSerializerSettings
ContractResolver = new MyContractResolver()
);
public class MyContractResolver : DefaultContractResolver
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(p => base.CreateProperty(p, memberSerialization))
.Union(type.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Select(f => base.CreateProperty(f, memberSerialization)))
.ToList();
props.ForEach(p => p.Writable = true; p.Readable = true; );
return props;
当我们想用字段序列化类时,还有第二个问题:来自字段的值不会包含在 yaml 结果中。我还没想好怎么处理。
您是否必须使用Swashbuckle.Swagger
类型,或者您可以为此类型创建包装器/装饰器/DTO?
希望对你有帮助。
【讨论】:
【参考方案4】:FWIW 我编写了一个 nuget 库,以使 YamlDotNet 与 Json.Net 一起工作,尊重所有 JSON.net 序列化属性。
Github:https://github.com/tomlm/YamlConvert Nuget 库:https://www.nuget.org/packages/YamlConvert/ var yaml = YamlConvert.SerializeObject(obj);
var obj2 = YamlConvert.DeserializeObject<T>(yaml);
它通过为 JTokens (JObject/JArray/JValue) 添加一个 YamlDotNet 类型序列化类来工作
var serializer = new SerializerBuilder()
.WithTypeConverter(new JTokenYamlConverter())
.Build();
【讨论】:
【参考方案5】:使用Cinchoo ETL - 一个可以轻松进行此类转换的开源库。
using (var r = new ChoJSONReader("*** YOUR JSON FILEPATH ***"))
using (var w = new ChoYamlWriter("*** YAML FILE OUTPUT PATH ***").SingleDocument())
w.Write(r);
输出:
swagger: 2.0
info:
title: UberAPI
description: MoveyourappforwardwiththeUberAPI
version: 1.0.0
host: api.uber.com
schemes:
- https
basePath: /v1
produces:
- application/json
小提琴示例: https://dotnetfiddle.net/rbOD0o
免责声明:我是这个库的作者。
【讨论】:
【参考方案6】:我正在使用以下代码从 JSON 构建 Yaml 元素并将其写入文件。
代码如下:
public static void BuildParametrizedYAML(string element, string element1)
var jsonBreakers = @"
'watchers' :
'timer' : '10',
'watcherPool' : '5',
's3fileExtension' : '.avr.gz',
'maxRetriesTask' : '3',
'telemetryFolder' : '/data',
'telemetryProcessor' :
'url' : '"+ element1 + @"'
,
'breakers' :
[
'breakerId' : 'COMMANDER',
'firstRetryTimeout' : '1000',
'secondRetryTimeout' : '6000',
'retries' : '5'
,
'breakerId' : 'PROCESSOR',
'firstRetryTimeout' : '1000',
'secondRetryTimeout' : '6000',
'retries' : '30'
],
'servers' :
[
'serverId' : 'vmax',
'url' : '"+ element + @"'
]
";
var expConverter = new ExpandoObjectConverter();
dynamic deserializedObject = JsonConvert.DeserializeObject<ExpandoObject>(jsonBreakers, expConverter);
var serializer = new Serializer();
string JSONContent = serializer.Serialize(deserializedObject);
var streamLoad = new StringReader(JSONContent);
var stream = new YamlStream();
stream.Load(streamLoad);
using (TextWriter writer = File.CreateText("application.yml"))
stream.Save(writer, false);
这是输出:
watchers:
timer: 10
watcherPool: 5
s3fileExtension: .avr.gz
maxRetriesTask: 3
telemetryFolder: /data
telemetryProcessor:
url: TELEMETRYPROCESSORURL
breakers:
- breakerId: COMMANDER
firstRetryTimeout: 1000
secondRetryTimeout: 6000
retries: 5
- breakerId: PROCESSOR
firstRetryTimeout: 1000
secondRetryTimeout: 6000
retries: 30
servers:
- serverId: vmax
url: TELEMETRYWATCHERVMAXURL
...
请随时给我写信。
【讨论】:
以上是关于如何使用 YamlDotNet 将 JSON 转换为 YAML的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 json.net 将 c# 通用列表转换为 json?
如何使用 json.net 将 c# 通用列表转换为 json?