使用C#,可以在不定义大量类型的情况下查询YAML吗?

Joh*_*lla 9 c# yaml

我需要使用Kubernetes生成的YAML,我希望能够jq在C#中使用类似XPath或类似DSL的符号读取特定属性.

Kubernetes生成的YAML的结构和性质在大多数地方都是明确定义的,但在某些情况下是任意的并且来自用户输入,因此不可能预先定义可以捕获YAML的整个结构的静态类型.

在C#中反序列化和读取YAML的最流行的解决方案似乎是YamlDotNet,但它主要用于反序列化为完全类型的对象.

我宁愿不必定义一堆静态类型或做很多繁琐的转换只是为了得到一个或两个字段或聚合它们.我的理想方法是:

var reader = new FileReader("my-file.yaml");
List<string> listOfPodNames = Yaml.Deserialize(reader)
                                  .Query(".pods[*].name")
                                  .AsList;
// expected result: list of all pod names as strings
Run Code Online (Sandbox Code Playgroud)

这可能与YamlDotNet或其他类似且受到良好支持的C#工具有关吗?

更新:我尝试了很多方法,但最后,效果最好的方法是重新编译为JSON,然后查询Json.NET,它有更好的支持.

cod*_*teq 6

在不指定目标类型的情况下使用 YamlDotNet 反序列化机制时,我们总是得到一个字典(映射)、一个KeyValuePair列表(列表)或单个 KeyValuePair/字符串(标量)。KeyValuePairs 将包含另一个字典、另一个列表或实际值。

我们现在可以实现查询功能:

var data = new YamlQuery(yamlObject)
                        .On("pods")  // parent
                      // this functionality could be implemented as well wihtout much effort
                      //.Where("ignore").Equals(true)
                        .Get("name") // propery
                        .ToList<string>();
Run Code Online (Sandbox Code Playgroud)

编辑:多个嵌套值

var data = new YamlQuery(yamlObject)
                .On("ressources")
                .On("pods")
                .Get("name")
                .ToList<string>();
Run Code Online (Sandbox Code Playgroud)

工作示例:https : //dotnetfiddle.net/uNQPyl

using System.IO;
using System;
using System.Linq;
using YamlDotNet.Serialization;
using System.Collections.Generic;
using YamlDotNet.RepresentationModel;

namespace ConsoleApp1
{
    public class Program
    {
        public static void Main()
        {
            object yamlObject;
            using (var r = new StringReader(Program.Document))
                yamlObject = new Deserializer().Deserialize(r);

            var data = new YamlQuery(yamlObject)
                                .On("pods")
                                .Get("name")
                                .ToList<string>();
            Console.WriteLine("all names of pods");
            Console.WriteLine(string.Join(",", data));


            data = new YamlQuery(yamlObject)
                    .On("ressources")
                    .On("pods")
                    .Get("name")
                    .ToList<string>();
            Console.WriteLine("all names of pods in ressources");
            Console.WriteLine(string.Join(",", data));

        }

        public class YamlQuery
        {
            private object yamlDic;
            private string key;
            private object current;

            public YamlQuery(object yamlDic)
            {
                this.yamlDic = yamlDic;
            }

            public YamlQuery On(string key)
            {
                this.key = key;
                this.current = query<object>(this.current ?? this.yamlDic, this.key, null);
                return this;
            }
            public YamlQuery Get(string prop)
            {
                if (this.current == null)
                    throw new InvalidOperationException();

                this.current = query<object>(this.current, null, prop, this.key);
                return this;
            }

            public List<T> ToList<T>()
            {
                if (this.current == null)
                    throw new InvalidOperationException();

                return (this.current as List<object>).Cast<T>().ToList();
            }

            private IEnumerable<T> query<T>(object _dic, string key, string prop, string fromKey = null)
            {
                var result = new List<T>();
                if (_dic == null)
                    return result;
                if (typeof(IDictionary<object, object>).IsAssignableFrom(_dic.GetType()))
                {
                    var dic = (IDictionary<object, object>)_dic;
                    var d = dic.Cast<KeyValuePair<object, object>>();

                    foreach (var dd in d)
                    {
                        if (dd.Key as string == key)
                        {
                            if (prop == null)
                            { 
                                result.Add((T)dd.Value);
                            } else
                            { 
                                result.AddRange(query<T>(dd.Value, key, prop, dd.Key as string));
                            }
                        }
                        else if (fromKey == key && dd.Key as string == prop)
                        { 
                            result.Add((T)dd.Value);
                        }
                        else
                        { 
                            result.AddRange(query<T>(dd.Value, key, prop, dd.Key as string));
                        }
                    }
                }
                else if (typeof(IEnumerable<object>).IsAssignableFrom(_dic.GetType()))
                {
                    var t = (IEnumerable<object>)_dic;
                    foreach (var tt in t)
                    {
                        result.AddRange(query<T>(tt, key, prop, key));
                    }

                }
                return result;
            }
        }




        private const string Document = @"---
            receipt:    Oz-Ware Purchase Invoice
            date:        2007-08-06
            customer:
                given:   Dorothy
                family:  Gale

            pods:
                - name:   pod1
                  descrip:   Water Bucket (Filled)
                  price:     1.47
                  quantity:  4


                - name:   pod2
                  descrip:   High Heeled ""Ruby"" Slippers
                  price:     100.27
                  quantity:  1
                - name:   pod3
                  descrip:   High Heeled ""Ruby"" Slippers
                  ignore:    true
                  quantity:  1

            bill-to:  &id001
                street: |-
                        123 Tornado Alley
                        Suite 16
                city:   East Westville
                state:  KS
                pods:
                    - name: pod4
                      descrip:   High Heeled ""Ruby"" Slippers
                      price:     100.27
                      quantity:  
            ressources:
                      - pids:
                            - id: 1
                            - name: pid
                      - pods: 
                            - name: pod5
                              descrip:   High Heeled ""Ruby"" Slippers
                              price:     100.27
                              quantity:  
                            - name: pod6
                              descrip:   High Heeled ""Ruby"" Slippers
                              price:     100.27
                              quantity:  
            specialDelivery: >
                Follow the Yellow Brick
                Road to the Emerald City.
                Pay no attention to the
                man behind the curtain.

...";
    }

}
Run Code Online (Sandbox Code Playgroud)