One way of achieving this is to use the RepresentationModel
API. It allows to get a representation of the YAML document that closely matches the underlying structure:
var stream = new YamlStream();
stream.Load(new StringReader(yaml));
var document = stream.Documents.First();
var rootMapping = (YamlMappingNode)document.RootNode;
var valuesMapping = (YamlMappingNode)rootMapping.Children[new YamlScalarNode("values")];
foreach(var tuple in valuesMapping.Children)
{
Console.WriteLine("{0} => {1}", tuple.Key, tuple.Value);
}
The downside of this approach is that you need to parse the document "manually". Another approach is to use serialization, and use a type that preserves ordering. I am not aware of any ready-to-use implementation of IDictionary<TKey, TValue>
that has this characteristic, but if you are not concerned about high performance, it is fairly simple to implement:
// NB: This is a minimal implementation that is intended for demonstration purposes.
// Most of the methods are not implemented, and the ones that are are not efficient.
public class OrderPreservingDictionary<TKey, TValue>
: List<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
public bool ContainsKey(TKey key)
{
throw new NotImplementedException();
}
public ICollection<TKey> Keys
{
get { throw new NotImplementedException(); }
}
public bool Remove(TKey key)
{
throw new NotImplementedException();
}
public bool TryGetValue(TKey key, out TValue value)
{
throw new NotImplementedException();
}
public ICollection<TValue> Values
{
get { throw new NotImplementedException(); }
}
public TValue this[TKey key]
{
get
{
return this.First(e => e.Key.Equals(key)).Value;
}
set
{
Add(key, value);
}
}
}
Once you have such container, you can take advantage of the Serialization
API to parse the document:
var deserializer = new Deserializer();
var result = deserializer.Deserialize<Dictionary<string, OrderPreservingDictionary<string, string>>>(new StringReader(yaml));
foreach(var tuple in result["values"])
{
Console.WriteLine("{0} => {1}", tuple.Key, tuple.Value);
}
You can see a fully working example in this fiddle