Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I parse only part of YAML into an object? #599

Closed
rcdailey opened this issue Mar 30, 2021 · 6 comments
Closed

How do I parse only part of YAML into an object? #599

rcdailey opened this issue Mar 30, 2021 · 6 comments

Comments

@rcdailey
Copy link

Suppose I have the following YAML:

config_one:
  name: foo
  stuff: value

config_two:
  name: bar
  random: value

I want to selectively parse config_one into an object and I want config_two to be ignored:

class ConfigOne
{
  public string Name {get;set;}
  public string Stuff {get;set;}
}

How can I do this? The documentation is pretty lacking, or at least, it uses a lot of terminology that doesn't make much sense to me, and thus I was not able to search for this functionality.

@pensono
Copy link
Contributor

pensono commented Apr 4, 2021

This code should help you. The trick is to use the parser to scan to the point where you would like to deserialize.

https://dotnetfiddle.net/EitE4O

using System;
using System.IO;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

var yaml = @"
config_one:
  name: foo
  stuff: value

config_two:
  name: bar
  random: value";

var parser = new Parser(new StringReader(yaml));
var deserializer = new DeserializerBuilder()
	.WithNamingConvention(new CamelCaseNamingConvention())
	.Build();

parser.Consume<StreamStart>();
parser.Consume<DocumentStart>();
parser.Consume<MappingStart>();

while (parser.TryConsume<Scalar>(out var key))
{
	if (key.Value == "config_two")
	{
		var config = deserializer.Deserialize<ConfigTwo>(parser);
		Console.WriteLine(config.Random);
	} 
	else
	{
		parser.SkipThisAndNestedEvents();
		Console.WriteLine($"Skipped {key.Value}");
	}
}

class ConfigTwo
{
  public string Name { get; set; }
  public string Random { get; set ;}
}

@rcdailey
Copy link
Author

rcdailey commented Apr 4, 2021

Minor detail, but I found that because I'm deserializing, I have to use UnderscoredNamingConvention.Instance to get my code to recognize the YAML to C# property mappings. I don't know why this is contrary to many examples I'm seeing. My assumption was that direction (serialize/deserialize) affects the behavior. Deserializing means we have to tell the code to map underscored names config_one to whatever is there in the C# property, which is camel case: ConfigOne. I probably have this wrong but I'm basing this off of what works and what doesn't. If I use camel case enumerator as you have in your example, the YAML does not parse.

@rcdailey
Copy link
Author

rcdailey commented Apr 8, 2021

Thanks again for the solution. I changed my YAML slightly, but I still need to accomplish the same task (only parse config_two). How do you adapt your solution to work with List<ConfigTwo>?

config_one:
  name: foo
  stuff: value

config_two:
  - name: bar1
    random: value1
  - name: bar2
    random: value2

Doing this does not work:

var config = deserializer.Deserialize<List<ConfigTwo>>(parser);

@rcdailey
Copy link
Author

rcdailey commented Apr 8, 2021

Sorry for the false positive. This actually does work, but it breaks when ConfigTwo has a nullable enum member:

enum PossibleNames { Bar1, Bar2 }
class ConfigTwo
{
  public PossibleNames? Name { get; set; }
};

I made it nullable to express that this property in YAML is optional. You don't have to provide name: at all. I'm not sure if this is the appropriate representation of optional YAML properties mapped to enums.

@rcdailey
Copy link
Author

rcdailey commented Apr 8, 2021

Found the solution in #544. Hopefully that gets proper support by the library in the future. I'm closing now since my question is answered. Thanks again!

@rcdailey rcdailey closed this as completed Apr 8, 2021
@pensono
Copy link
Contributor

pensono commented Apr 8, 2021

The problem with nullable enums should be fixed once #600 is merged :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants