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

Yaml2JsonNode fails json->yaml->json roundtrip #476

Closed
amis92 opened this issue Jun 15, 2023 · 9 comments · Fixed by #477
Closed

Yaml2JsonNode fails json->yaml->json roundtrip #476

amis92 opened this issue Jun 15, 2023 · 9 comments · Fixed by #477
Labels
bug Something isn't working

Comments

@amis92
Copy link
Contributor

amis92 commented Jun 15, 2023

Environment

  • Nuget Package: Yaml2JsonNode
  • Nuget Version: 1.2.0
  • OS: Linux
  • .Net Target: .NET 7

Describe the bug

When converting JSON string it's always converted to Any-style of Yaml Scalar.

Converting a JSON with a number within a string prevents roundtripping to yaml and again JSON, because a string (that looks like a number) in original JSON becomes an actual JSON number scalar when converting back from YAML.

Additionally, when creating repro, I've discovered that json.ToYamlNode doesn't handle null values within JSON.

To Reproduce

See fiddle: https://dotnetfiddle.net/FfxJlu

using System;
using System.Linq;
using System.Text.Json.Nodes;
using Yaml2JsonNode;
					
var jsonText = """
  {"foo":123,"foz":"123","bar":1.23,"baz": "1.23"}
  """;
var json = JsonNode.Parse(jsonText);
var yaml = json.ToYamlNode();
var yamlText = YamlSerializer.Serialize(yaml: yaml);

var jsonRoundtripped = YamlSerializer.Parse(yamlText).Single().ToJsonNode();
var jsonRoundText = jsonRoundtripped.ToJsonString();

Console.WriteLine("# jsonText:");
Console.WriteLine(jsonText);
Console.WriteLine();
Console.WriteLine("# yamlText:");
Console.WriteLine(yamlText);
Console.WriteLine("# jsonRoundText:");
Console.WriteLine(jsonRoundText);

Diff what is and what I'd want:

# jsonText:
{"foo":123,"foz":"123","bar":1.23,"baz": "1.23"}

# yamlText:
foo: 123
- foz: 123
+ foz: '123'
bar: 1.23
- baz: 1.23
+ baz: '1.23'

# jsonRoundText:
- {"foo":123,"foz":123,"bar":1.23,"baz":1.23}
+ {"foo":123,"foz":"123","bar":1.23,"baz":"1.23"}

Expected behavior

A json converted into YAML and back to JSON keeps the scalar types. That'd mean that the YAML scalar nodes are created as single- or double-quoted string-scalars for decimal- or bool- parsable strings.

Additional context

Generally, the conversion from YAML to JSON handles type differentiation quite well, but opposite direction isn't as thorough.

@amis92 amis92 added the bug Something isn't working label Jun 15, 2023
@amis92
Copy link
Contributor Author

amis92 commented Jun 15, 2023

And also thank you for that package in general. I've found it very useful!

@gregsdennis
Copy link
Owner

Thanks for the reproduction. That helps a lot. In the future, could you also add the output you get vs the output you expect, please?

I'll get to work on this.

@gregsdennis
Copy link
Owner

Didn't mean to close this.

@gregsdennis gregsdennis reopened this Jun 15, 2023
@amis92
Copy link
Contributor Author

amis92 commented Jun 15, 2023

Added output vs expected!

@gregsdennis
Copy link
Owner

I see what you mean. Numbers are interpreted as strings from the YAML back to JSON.

This is actually a consequence of YAML and hwo YamlDotNet handles parsing more than anything with this library. With YAML in general it's not always possible/efficient to tell if a value is intended to be a string or a number.

I'll see if I can do anything about it. Ultimately, I'm limited to how that project is parsing the YAML.

@gregsdennis
Copy link
Owner

You can actually see this is the case with this code:

var yamlValue = new YamlScalarNode("123");
var yamlKey = new YamlScalarNode("a");

var yamlObject = new YamlMappingNode(new Dictionary<YamlNode, YamlNode>
{
	[yamlKey] = yamlValue
});

var builder = new SerializerBuilder();
var serializer = builder.Build();
using var writer = new StringWriter();
serializer.Serialize(writer, yamlObject);
var text = writer.ToString();

Console.WriteLine(text);

This outputs

a: 123

I've tried all of the serializer configuration methods that are offered, and I don't see any that will serialize numeric strings (or even just all strings) as quoted strings.

When this is read back by the YAML parser, it interprets the value as a number.

@gregsdennis
Copy link
Owner

I think this is probably the best match to what you're wanting.

aaubry/YamlDotNet#315

You might try the workaround. You can configure the serializer as part of the .Serialize() method:

var text = YamlSerialize.Serialize(yaml,
    builder => builder.WithEventEmitter(nextEmitter => new QuoteSurroundingEventEmitter(nextEmitter)));

I'm not sure this is something that I'm ready to put in this lib, though.

@amis92
Copy link
Contributor Author

amis92 commented Jun 15, 2023

Couldn't setting YamlScalar.Style to Quoted work when mapping from JSON ode to YamlNode?

@gregsdennis
Copy link
Owner

Yep. That worked! I didn't even know that was a thing I could set. Nice call.

I'll have an update out soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants