YamlDotNet icon indicating copy to clipboard operation
YamlDotNet copied to clipboard

MergingParser Does not Merge Aliases

Open pensono opened this issue 4 years ago • 0 comments

Code example

https://dotnetfiddle.net/Es32Or

var yaml = @"
object: &anchorName anchorValue
another: *anchorName";

var parser = new MergingParser(new Parser(new StringReader(yaml)));

while (parser.MoveNext()) 
{
    Console.WriteLine(parser.Current);
}

Actual Output:

Stream start
Document start [isImplicit = True]
Mapping start [anchor = , tag = , isImplicit = True, style = Block]
Scalar [anchor = , tag = , value = object, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
Scalar [anchor = anchorName, tag = , value = anchorValue, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
Scalar [anchor = , tag = , value = another, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
Alias [value = anchorName]
Mapping end
Document end [isImplicit = True]
Stream end

Expected Output:

Stream start
Document start [isImplicit = True]
Mapping start [anchor = , tag = , isImplicit = True, style = Block]
Scalar [anchor = , tag = , value = object, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
Scalar [anchor = anchorName, tag = , value = anchorValue, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
Scalar [anchor = , tag = , value = another, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]
**Scalar [anchor = anchorName, tag = , value = anchorValue, style = Plain, isPlainImplicit = True, isQuotedImplicit = False]**
Mapping end
Document end [isImplicit = True]
Stream end

Motivation

Sometimes it is useful to deserialize part of a document. This may be the case when the document is very large, when type information is not known until the document is being parsed. Currently, substituting Aliases is handled by AliasValueDeserializer however this will not be able to resolve anchors which occur outside of the part of the document being parsed.

For example, consider the document:

products:
- &apple
  name: Apple
  cost: 1.25

sales:
- customer: pensono
  items:
  - *apple

Lets say this document is very large, so we would only like to deserilize the sales section. If only the sales section is deserialized, then *apple won't be resolved.

Code example: https://dotnetfiddle.net/rpsPia

var yaml = @"
products:
- &apple
  name: Apple
  cost: 1.25

sales:
- customer: pensono
  items:
  - *apple
";
		
var deserializer = new DeserializerBuilder().Build();

var parser = new MergingParser(new Parser(new StringReader(yaml)));
parser.Consume<StreamStart>();
parser.Consume<DocumentStart>();
parser.Consume<MappingStart>();

while (parser.TryConsume<Scalar>(out var section)) 
{
    // Only deserialize the sales section
    if (!section.Value.Equals("sales"))
    {
        parser.SkipThisAndNestedEvents();
        continue;
    }

    var sales = deserializer.Deserialize<List<object>>(parser); // This line throws "AnchorNotFoundException: Anchor 'apple' not found"
    Console.WriteLine(sales.Count);
}

pensono avatar Jun 23 '20 23:06 pensono