问题
I am trying to convert JSON to YAML using YamlDotNet. This is the code I have:
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);
}
}
}
This is the JSON I provide:
{
"swagger":"2.0",
"info":{
"title":"UberAPI",
"description":"MoveyourappforwardwiththeUberAPI",
"version":"1.0.0"
},
"host":"api.uber.com",
"schemes":[
"https"
],
"basePath":"/v1",
"produces":[
"application/json"
]
}
This is the YAML I expect:
swagger: '2.0'
info:
title: UberAPI
description: MoveyourappforwardwiththeUberAPI
version: 1.0.0
host: api.uber.com
schemes:
- https
basePath: /v1
produces:
- application/json
However, this is the output I get:
swagger: []
info:
title: []
description: []
version: []
host: []
schemes:
- []
basePath: []
produces:
- []
I don't have a clue why all properties are empty arrays.
I also tried typed deserialization and serialization like this:
var specification = JsonConvert.DeserializeObject<SwaggerDocument>(json);
...
serializer.Serialize(writer, swaggerDocument, typeof(SwaggerDocument));
But that produces
{}
Any help is much appreciated.
回答1:
I think there is problem when json deserialization returns JObject
. Looks like yaml serializer doesn't like it.
I used deserialization with specified type as you mentioned JsonConvert.DeserializeObject<SwaggerDocument>(json)
and this is what I get
Swagger: 2.0
Info:
Title: UberAPI
Description: MoveyourappforwardwiththeUberAPI
Version: 1.0.0
Host: api.uber.com
Schemes:
- https
BasePath: /v1
Produces:
- application/json
This is my whole code:
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; }
}
update
Two issues here.
When deserializing class with fields, by default json.net
won't take them into consideration when doing his job. For this purpose we have to customize deserialization procces by creating custom contract resolver. We can easily do this by
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;
}
}
There is second issue when we want to serialize class with fields. Values from fields won't be included into yaml result. I didn't figure how to deal with this yet.
Do you have to use Swashbuckle.Swagger
type or you can just create wrapper/decorator/DTO for this type?
I hope it helps you.
回答2:
You don't actually need to deserialize JSON into strongly typed object you can convert JSON to YAML using dynamic Expando object as well. Here is a small example:-
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);
You can see a detailed explanation of both methods i.e. using strongly typed object and dynamic object here.
回答3:
You can convert the JObject
to a simpler object that YamlDotNet can serialize:
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);
}
}
回答4:
I'm using the following piece of code to build a Yaml element from a JSON and writing it to a file.
Here is the code:
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);
}
}
And here is the output:
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
...
Feel free to write me about this.
来源:https://stackoverflow.com/questions/36061049/how-to-convert-json-to-yaml-using-yamldotnet