2016-03-17 102 views
2

我想使用YamlDotNet将JSON转换为YAML。这是我的代码:如何使用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: 
- [] 

我没有ac为什么所有的属性都是空的数组。

我也尝试过的类型化和反序列化系列化是这样的:

var specification = JsonConvert.DeserializeObject<SwaggerDocument>(json); 
... 
serializer.Serialize(writer, swaggerDocument, typeof(SwaggerDocument)); 

但产生

{} 

任何帮助深表感谢。

+0

这不一定有帮助:YAML似乎不受欢迎(在Ruby之外)。你能解释一下你为什么要这样做吗? – ashes999

+0

我的客户需要我的API在JSON和YAML中都公开其规范。 – venerik

回答

2

我认为当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?

我希望它能帮助你。

+0

非常感谢!它帮助我发现问题:显然,“YamlDotNet”不喜欢字段。我试过你的代码:像魅力一样工作。我将你的类的属性转换为字段([真SwaggerDocument](https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/Swagger/SwaggerDocument.cs)),输出变成' {}'。虽然没有找到解决这个新问题的方法。 – venerik

+0

我看到了问题。我马上更新我的答案。 – Rob

+0

感谢您的更新。我可以包装Swashbuckle类,但这很不理想。我对[This answer](http://stackoverflow.com/a/28456466/502395)的评论中描述的自定义'ITypeInspector'感到高兴,但我还没找到一种方法将其插入到串行器中。 – venerik

1

您可以将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); 
    } 
} 
4

你实际上并不需要反序列化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两种方法,即一个详细的解释。