Есть ли способ десериализовать конкретное свойство документа YAML?

В JSON.Net я могу прочитать файл JSON в структуру данных, а затем преобразовать в объекты только интересующие меня свойства. Например, если у меня есть файл JSON, например

{
    "Bob": {
               "Steve": 5
           }
}

Я могу получить объект так:

class SteveObject {
    public int Steve;
}

var jsonSerializer = JsonSerializer.Create()
var jsonFile = JObject.Parse(text);
vat steveObject = jsonFile["Bob"].ToObject<SteveObject>(jsonSerializer)

Как сделать то же самое с YAMLDotNet или SharpYaml? т.е. если у меня есть файл YAML, например

Bob:
  Steve: 5

Как мне восстановить SteveObject из этого, не создавая внешний объект?


person reveazure    schedule 28.08.2017    source источник


Ответы (1)


Хорошо, я написал код с использованием SharpYaml, который принимает упрощенный запрос JPath и возвращает запрошенный объект.

    public static T ReadPath<T>(Serializer serializer, string yaml, string path) {
        var eventReader = new EventReader(new Parser(new StringReader(yaml)));

        var streamReader = new MemoryStream(Encoding.UTF8.GetBytes(path ?? ""));
        if ((char)streamReader.ReadByte() != '$')
            throw new Exception();

        if (streamReader.Position == streamReader.Length)
            return serializer.Deserialize<T>(eventReader);

        eventReader.Expect<StreamStart>();
        eventReader.Expect<DocumentStart>();

        while (streamReader.Position < streamReader.Length) {
            if ((char)streamReader.ReadByte() != '.')
                throw new Exception();

            eventReader.Expect<MappingStart>();

            var currentDepth = eventReader.CurrentDepth;

            var nextKey = ReadPropertyName(streamReader);
            if (string.IsNullOrEmpty(nextKey))
                throw new Exception();

            while (eventReader.Peek<Scalar>() == null || eventReader.Peek<Scalar>().Value != nextKey) {
                eventReader.Skip();

                // We've left the current mapping without finding the key.
                if (eventReader.CurrentDepth < currentDepth)
                    throw new Exception();
            }

            eventReader.Expect<Scalar>();
        }

        return serializer.Deserialize<T>(eventReader);
    }

    public static string ReadPropertyName(MemoryStream stream) {
        var sb = new StringBuilder();

        while (stream.Position < stream.Length) {
            var nextChar = (char) stream.ReadByte();
            if (nextChar == '.') {
                stream.Position--;
                return sb.ToString();
            }

            sb.Append(nextChar);
        }

        return sb.ToString();
    }

Учитывая приведенный выше YAML, следующие работы:

var t = "Bob:\r\n  Point: [1.0, 2.0, 3.0]\r\n  Steve: 5\r\n";
var serializer = new Serializer(settings);
var s = ReadPath<SteveObject>(serializer, t, "$.Bob"); // { "Steve": 5 }
var s2 = ReadPath<int>(serializer, t, "$.Bob.Steve"); // 5

Конечно, хотелось бы, чтобы для этого была библиотека.

person reveazure    schedule 29.08.2017