2016-03-17 27 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兩種方法,即一個詳細的解釋。