从C#动态构建Yaml文档

9

是否可以使用Yaml.DotNet或其他库从c#动态构建一个Yaml文档?

我知道可以使用序列化来完成这个任务,但这需要从对象结构开始。

我希望找到一种像使用XElement.Add(object)方法一样,在运行时动态创建Yaml文档节点的方法。

2个回答

10
你可以使用YamlDotNet来实现。首先创建一个YamlStream,然后向其中添加一个或多个document,接着可以向其中添加sequencesmappingsscalars以下是一个示例
var address = new YamlMappingNode(
    new YamlScalarNode("street"),
    new YamlScalarNode("123 Tornado Alley\nSuite 16") { Style = YamlDotNet.Core.ScalarStyle.Literal },
    new YamlScalarNode("city"),
    new YamlScalarNode("East Westville"),
    new YamlScalarNode("state"),
    new YamlScalarNode("KS")
) { Anchor = "main-address" };

var stream = new YamlStream(
    new YamlDocument(
        new YamlMappingNode(
            new YamlScalarNode("repeipt"),
            new YamlScalarNode("Oz-Ware Purchase Invoice"),
            new YamlScalarNode("date"),
            new YamlScalarNode("2007-08-06"),
            new YamlScalarNode("customer"),
            new YamlMappingNode(
                new YamlScalarNode("given"),
                new YamlScalarNode("Dorothy"),
                new YamlScalarNode("family"),
                new YamlScalarNode("Gale")
            ),
            new YamlScalarNode("items"),
            new YamlSequenceNode(
                new YamlMappingNode(
                    new YamlScalarNode("part_no"),
                    new YamlScalarNode("A4786"),
                    new YamlScalarNode("descrip"),
                    new YamlScalarNode("Water Bucket (Filled)"),
                    new YamlScalarNode("price"),
                    new YamlScalarNode("1.47"),
                    new YamlScalarNode("quantity"),
                    new YamlScalarNode("4")
                ),
                new YamlMappingNode(
                    new YamlScalarNode("part_no"),
                    new YamlScalarNode("E1628"),
                    new YamlScalarNode("descrip"),
                    new YamlScalarNode("High Heeled \"Ruby\" Slippers"),
                    new YamlScalarNode("price"),
                    new YamlScalarNode("100.27"),
                    new YamlScalarNode("quantity"),
                    new YamlScalarNode("1")
                )
            ),
            new YamlScalarNode("bill-to"), address,
            new YamlScalarNode("ship-to"), address,
            new YamlScalarNode("specialDelivery"),
            new YamlScalarNode("Follow the Yellow Brick\n" +
                               "Road to the Emerald City.\n" +
                               "Pay no attention to the\n" +
                               "man behind the curtain.")
            {
                Style = YamlDotNet.Core.ScalarStyle.Literal
            }
        )
    )
);

2
你能提供一个例子吗?我看不到任何添加文档内容的方法。 - sparkplug
1
我知道,这个语法很糟糕。欢迎提交拉取请求! - Antoine Aubry
1
谢谢你的示例 - 我没有想到将节点传递给构造函数。拉取请求现在在我的待办事项列表上。 - sparkplug

7

我现在已经通过使用Yaml.Net找到了解决办法。需要使用Load()方法加载一些初始内容来填充YamlStream。

const string initialContent = "---\nversion: 1\n...";

var sr = new StringReader(initialContent);
var stream = new YamlStream();
stream.Load(sr);

您可以将YamlDocument的RootNode转换为具有Add方法的YamlMappingNode。
var rootMappingNode = (YamlMappingNode)stream.Documents[0].RootNode;   
rootMappingNode.Add("shout", "yay!");

在保存之前,您可以添加各种节点类型:

var props = new YamlMappingNode();
props.Add("prop1", "value1");
props.Add("prop2", "value2");
rootMappingNode.Add("itemWithProps", props);

var props2 = new YamlMappingNode();
props2.Add("prop1", "value1");
props2.Add("prop2", "value2");

var props3 = new YamlMappingNode();
props3.Add("prop1", "value1");
props3.Add("prop2", "value2");

var seq = new YamlSequenceNode();
seq.Add(props2);
seq.Add(props3);
rootMappingNode.Add("sequenceOfItems", seq);

var col = new YamlSequenceNode();
col.Style = SequenceStyle.Flow;
col.Add("a");
col.Add("b");
col.Add("c");

var seqMapping = new YamlMappingNode();
seqMapping.Add("collection", col);
seq.Add(seqMapping);

using (TextWriter writer = File.CreateText("C:\\temp\\test.yaml"))
    stream.Save(writer, false);

这个例子的输出结果是:
version: 1
shout: yay!
itemWithProps:
  prop1: value1
  prop2: value2
sequenceOfItems:
- prop1: value1
  prop2: value2
- prop1: value1
  prop2: value2
- collection: [a, b, c]
...

感谢 @Antoine Aubry 创建的 Yaml.Net 库,并模糊地指导我朝正确的方向前进。

如果您想从文本文件而不是字符串读取初始内容,可以使用以下代码:using(var reader = File.OpenText("<path-and-name-of-your-yaml-file")) { var stream = new YamlStream(); stream.Load(reader); } - Manfred
在将YamlDocument的RootNode转换为YamlMappingNode时出现异常。 - newbie
@IMLERNCSHARP 通常不会抛出异常 - 请参见 https://dotnetfiddle.net/D6K1D6。也许异常与文档内容有关 - 如果没有看到错误消息(和完整代码),我们无法确定。 - sparkplug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接