1

I am using the YAMLDotNet library, and was trying to have a YamlVisitor class fire its events as it would when it reaches the beginning and end of each node type. This would work fine if the stream is a StreamReader that uses a file or a string, but if I use a serialPort Stream it would get stuck (waiting for the stream to end I presume??)

My stream is data flowing through a serial port, that does not have a defined end.

I would like to be able to call a function at the beginning and end of each YAML node as they come through the stream.

here's what I tried:

static void Main(string[] args)
{
    using (var sp = new SerialPort("COM1", 600, Parity.Odd, 8, StopBits.One))
    {
        sp.Open();

        TextReader tr = new StreamReader(sp.BaseStream);
        var yaml = new YamlStream();

        // try assigning an instance of TracingVisitor before loading the stream...
        yaml.Accept(new TracingVisitor());

        // execution hangs at the following line 
        // waiting for something to indicate end of stream???
        yaml.Load(tr);
    }
}

When I call the yaml.Load(tr); it just sits there and waits. I was able to gather that it processes the tokens as they come in, but nothing in the TracingVisitor Class gets called.

here's the program that feeds the Serial Data to the stream.

// 's' is a properly formatted YAML String
// This code sends the contents of 's' it over COM7
void Main()
{
    // open a slow serial connection 
    using(var sp = new SerialPort("COM7", 600, Parity.Odd, 8, StopBits.One))
    {
        sp.Open();
        sp.Write(s);
    }
}

here's a YAML string to run through

#starting 
--- 
debug: |
  ->28 
  TxMessages 100, 
  RxMessages 100 
  Loopback Test - US: PASS 
... 
--- 
results: >
  TxMessages 100, 
  RxMessages 100, 
  Final: PASS 
--- 
results: [1,55,233,546.99]
... 
--- 
- ignore
- results: 
    min: -22
    max: 125
--- 
list:
    - 
    TxMessages: 100 
    RxMessages: 100
    results: [1,55,233,546.99]
    Loopback Test - US: PASS
    - results: result String Here!
...
K. R.
  • 1,220
  • 17
  • 20

1 Answers1

1

That will not work, because YamlStream.Load loads an entire stream into memory. Also, Visitors can't be assigned; when you call the Accept method, the visitor visits the current state.

You can achieve what you want if you use the Deserializer class, because it operates on individual documents instead of entire streams:

var deserializer = new Deserializer();
var eventReader = new EventReader(new Parser(new PipeReader(pipe)));

// Consume the initial StreamStart
eventReader.Expect<StreamStart>();

// Read each document
do
{
    var data = deserializer.Deserialize<Dictionary<string, object>>(eventReader);
    Console.WriteLine("{0}\t{1}", DateTime.Now, data["debug"]);
}
while(!eventReader.Accept<StreamEnd>());

I have created a working example in this fiddle.

If the structure of each document is not known, you can deserialize as object. Unless you use tags, the default types will be as follow:

  • mappings will be deserialized as Dictionary<object, object>
  • sequences will be deserialized as List<object>
  • scalars will be deserialized as string

See the following fiddle for an example.

Antoine Aubry
  • 12,203
  • 10
  • 45
  • 74
  • 1
    @K.R. , I have updated my answer with a workaround. Ideally, I would like to be able to use the Serializer and Deserializer to read and write a YamlDocument, but that is still in my TODO list. – Antoine Aubry Oct 13 '14 at 22:53
  • deserializer.Deserialize(eventReader) without specifying a type worked better for me, because my data is a bit more 'randomly' structured, Thanks! – K. R. Oct 13 '14 at 23:51