2016-11-19 4 views
1

私は事前に構造が分からない任意のYamlファイルを読み込むアプリケーションを持っています。私はYamlStreamと他のYamlNodeの実装が有用であることを発見しました。それらは私がYamlファイル全体をトラバースできるようにするためです。しかし、ある時点で私はYamlNode、通常はYamlScalarNodeであり、YamlDotNetがそのノードをオブジェクトに逆直列化する機能を使用したいと考えています。どうやってやるの?YamlDotNetでYamlNodeを逆シリアル化する方法は?

これは私が試みたものです。 (例えば!!bool "true"trueなるが、1"1"なり)それは醜いだし、それが唯一の明示的なタグを持つノードのために働く:

private T DeserializeNode<T>(YamlNode node) 
{ 
    if (node == null) 
     return default(T); 

    using (var stream = new MemoryStream()) 
    using (var writer = new StreamWriter(stream)) 
    using (var reader = new StreamReader(stream)) 
    { 
     new YamlStream(new YamlDocument[] { new YamlDocument(node) }).Save(writer); 
     writer.Flush(); 
     stream.Position = 0; 
     return new Deserializer().Deserialize<T>(reader); 
    } 
} 

私はまだ見つかっていない、より良い方法があるに違いありません。

答えて

2

現在のところ、YamlNodeから逆シリアル化する方法はありませんが、あなたのアプローチは考えられる回避策の1つです。ノードをバッファに書き込まないようにするには、this exampleのようにYamlNodeから読み取るIParserインターフェイスを実装できます。

私は上記の例ではそれをやった方法は、変換アダプタを作成することですYamlNodeIRnumerable<ParsingEvent>へ:あなたはこれをしたら、以来、IParserのためのアダプタを作成するのは簡単です

public static class YamlNodeToEventStreamConverter 
{ 
    public static IEnumerable<ParsingEvent> ConvertToEventStream(YamlStream stream) 
    { 
     yield return new StreamStart(); 
     foreach (var document in stream.Documents) 
     { 
      foreach (var evt in ConvertToEventStream(document)) 
      { 
       yield return evt; 
      } 
     } 
     yield return new StreamEnd(); 
    } 

    public static IEnumerable<ParsingEvent> ConvertToEventStream(YamlDocument document) 
    { 
     yield return new DocumentStart(); 
     foreach (var evt in ConvertToEventStream(document.RootNode)) 
     { 
      yield return evt; 
     } 
     yield return new DocumentEnd(false); 
    } 

    public static IEnumerable<ParsingEvent> ConvertToEventStream(YamlNode node) 
    { 
     var scalar = node as YamlScalarNode; 
     if (scalar != null) 
     { 
      return ConvertToEventStream(scalar); 
     } 

     var sequence = node as YamlSequenceNode; 
     if (sequence != null) 
     { 
      return ConvertToEventStream(sequence); 
     } 

     var mapping = node as YamlMappingNode; 
     if (mapping != null) 
     { 
      return ConvertToEventStream(mapping); 
     } 

     throw new NotSupportedException(string.Format("Unsupported node type: {0}", node.GetType().Name)); 
    } 

    private static IEnumerable<ParsingEvent> ConvertToEventStream(YamlScalarNode scalar) 
    { 
     yield return new Scalar(scalar.Anchor, scalar.Tag, scalar.Value, scalar.Style, false, false); 
    } 

    private static IEnumerable<ParsingEvent> ConvertToEventStream(YamlSequenceNode sequence) 
    { 
     yield return new SequenceStart(sequence.Anchor, sequence.Tag, false, sequence.Style); 
     foreach (var node in sequence.Children) 
     { 
      foreach (var evt in ConvertToEventStream(node)) 
      { 
       yield return evt; 
      } 
     } 
     yield return new SequenceEnd(); 
    } 

    private static IEnumerable<ParsingEvent> ConvertToEventStream(YamlMappingNode mapping) 
    { 
     yield return new MappingStart(mapping.Anchor, mapping.Tag, false, mapping.Style); 
     foreach (var pair in mapping.Children) 
     { 
      foreach (var evt in ConvertToEventStream(pair.Key)) 
      { 
       yield return evt; 
      } 
      foreach (var evt in ConvertToEventStream(pair.Value)) 
      { 
       yield return evt; 
      } 
     } 
     yield return new MappingEnd(); 
    } 
} 

2つのインターフェイスが基本的に同じです。

public class EventStreamParserAdapter : IParser 
{ 
    private readonly IEnumerator<ParsingEvent> enumerator; 

    public EventStreamParserAdapter(IEnumerable<ParsingEvent> events) 
    { 
     enumerator = events.GetEnumerator(); 
    } 

    public ParsingEvent Current 
    { 
     get 
     { 
      return enumerator.Current; 
     } 
    } 

    public bool MoveNext() 
    { 
     return enumerator.MoveNext(); 
    } 
} 

あなたはその後、任意のYamlStreamYamlDocumentまたはYamlNodeから逆シリアル化するために、アダプタを使用することができます:

var stream = new YamlStream(); 
stream.Load(new StringReader(input)); 

var deserializer = new DeserializerBuilder() 
    .WithNamingConvention(new CamelCaseNamingConvention()) 
    .Build(); 

var prefs = deserializer.Deserialize<YOUR_TYPE>(
    new EventStreamParserAdapter(
     YamlNodeToEventStreamConverter.ConvertToEventStream(stream) 
    ) 
); 
+0

これは素晴らしいものです。魅力的な作品!それを書き留める時間をとってくれてありがとう。 – Virtlink

関連する問題