【问题标题】:How to convert JSON to YAML using YamlDotNet如何使用 YamlDotNet 将 JSON 转换为 YAML
【发布时间】: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));

但这会产生

{}

非常感谢任何帮助。

【问题讨论】:

    标签: c# json yaml yamldotnet


    【解决方案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&lt;SwaggerDocument&gt;(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 序列化属性。

              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
              ...
              

              请随时给我写信。

              【讨论】:

                猜你喜欢
                • 2022-01-02
                • 1970-01-01
                • 2015-08-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-02-16
                相关资源
                最近更新 更多