C# 如何使用XDocument往返实体化车厢?

C# 如何使用XDocument往返实体化车厢?,c#,xml,linq-to-xml,C#,Xml,Linq To Xml,假设我有以下XML文档: <x xml:space='preserve'>&#xd; </x> 我对W3C规范的理解是序列13 10。为了让序列13 10显示在我的解析树中,我必须包含字符实体&xdas(我认识到它们来自XML-1.1而不是XML-1.0,但它们澄清了XML-1.0中令人困惑的事情,但没有描述不同的行为) 如中所述,在执行任何其他处理之前,XML文档中的所有#xD字符都会被删除或替换为#xA字符。获取与此结果匹配的#xD字符的唯一方法是在实体值文

假设我有以下XML文档:

<x xml:space='preserve'>&#xd;
</x>
我对W3C规范的理解是序列
13 10
。为了让序列
13 10
显示在我的解析树中,我必须包含字符实体
&xdas(我认识到它们来自XML-1.1而不是XML-1.0,但它们澄清了XML-1.0中令人困惑的事情,但没有描述不同的行为)

如中所述,在执行任何其他处理之前,XML文档中的所有#xD字符都会被删除或替换为#xA字符。获取与此结果匹配的#xD字符的唯一方法是在实体值文字中使用字符引用

有了它,这一切似乎都正常工作了。上述XML的文本内容是
13 10
(而不是
13 10
),这表明在解析之前,字符实体被保留,文本
13 10
被替换为
10

但是,我不知道如何让
XDocument.ToString()
在序列化时对换行符进行实体化。也就是说,我希望
(XDocument xd)=>XDocument.Parse($“{xd}”)
是一个无损函数。但如果我传入一个
XDocument
实例,其中
13 10
作为文本内容,则该函数将输出一个
XDocument
实例,其中
10
作为文本内容。请参见此演示:

var x = XDocument.Parse("<x xml:space='preserve'>&#xd;\r\n</x>");
present("content", x.Root.Value); // 13 10, expected
present("formatted", $"{x}"); // inside <x/>: 13 10, unexpected
x = XDocument.Parse($"{x}");
present("round tripped", x.Root.Value); // 10, unexpected

// Note that when formatting the version with just 10 in the value,
// we get Environment.NewLine in the formatted XML. So there is no
// way to differentiate between 10 and 13 10 with XDocument because
// it normalizes when serializing.
present("round tripped formatted", $"{x}"); // inside <x/>: 13 10, expected

void present(string label, string thing)
{
    Console.WriteLine(label);
    Console.WriteLine(thing);
    Console.WriteLine(string.Join(" ", Encoding.UTF8.GetBytes(thing)));
    Console.WriteLine();
}
var x=XDocument.Parse(
;\r\n”);
呈现(“内容”,x.Root.Value);//13月10日,预计
呈现(“格式化的“,$”{x}”);//内部:13-10,意外
x=XDocument.Parse($“{x}”);
当前(“往返”,x.Root.Value);//10,出乎意料
//请注意,在格式化值仅为10的版本时,
//我们在格式化的XML中获取Environment.NewLine。所以没有
//使用XDocument区分10和13 10的方法,因为
//它在序列化时正常化。
当前(“往返格式的“,$”{x}”);//内部:13-10,预计
存在无效(字符串标签、字符串对象)
{
控制台写入线(标签);
控制台。写线(东西);
WriteLine(string.Join(“,Encoding.UTF8.GetBytes(thing));
Console.WriteLine();
}

您可以看到,当序列化
XDocument
时,它无法将回车符实体化为


。结果是它丢失了信息。如何安全地编码
XDocument
,以免丢失我加载的原始文档中的任何内容,尤其是回车?

对于往返
XDocument
不要使用,因为这是有损的。还要注意,即使您执行类似于
xd.ToString(SaveOptions.DisableFormatting)
的操作,解析树中的任何回车符都将丢失

相反,请将正确配置的
XmlWriter
与一起使用。如果使用
XmlWriter
,则
XmlWriter
将能够看到包含文本框的文档返回并正确编码。要指示它这样做,请设置为。您可能希望编写一个扩展方法,使其更易于重用

更改为使用此方法的演示如下:

var x = XDocument.Parse("<x xml:space='preserve'>&#xd;\r\n</x>");
present("content", x.Root.Value); // 13 10, expected
present("formatted", toString(x)); // inside <x/>: 38 35 120 68 59 10 ("&#xD;\n"), acceptable
x = XDocument.Parse(toString(x));
present("round tripped", x.Root.Value); // 13 10, expected

string toString(XDocument xd)
{
    using var sw = new StringWriter();
    using (var writer = XmlWriter.Create(sw, new XmlWriterSettings
    {
        NewLineHandling = NewLineHandling.Entitize,
    }))
    {
        xd.WriteTo(writer);
    }
    return sw.ToString();
}

void present(string label, string thing)
{
    Console.WriteLine(label);
    Console.WriteLine(thing);
    Console.WriteLine(string.Join(" ", Encoding.UTF8.GetBytes(thing)));
    Console.WriteLine();
}
var x=XDocument.Parse(
;\r\n”);
呈现(“内容”,x.Root.Value);//13月10日,预计
呈现(“格式化”,toString(x));//内部:3835120685910(
;\n),可接受
x=XDocument.Parse(toString(x));
当前(“往返”,x.Root.Value);//13月10日,预计
字符串到字符串(XDocument xd)
{
使用var sw=new StringWriter();
使用(var writer=XmlWriter.Create(sw,新的XmlWriter设置
{
NewLineHandling=NewLineHandling.Entitize,
}))
{
xd.WriteTo(writer);
}
返回sw.ToString();
}
存在无效(字符串标签、字符串对象)
{
控制台写入线(标签);
控制台。写线(东西);
WriteLine(string.Join(“,Encoding.UTF8.GetBytes(thing));
Console.WriteLine();
}

根据网站礼仪,请您发表评论并说明理由?谢谢
var x = XDocument.Parse("<x xml:space='preserve'>&#xd;\r\n</x>");
present("content", x.Root.Value); // 13 10, expected
present("formatted", toString(x)); // inside <x/>: 38 35 120 68 59 10 ("&#xD;\n"), acceptable
x = XDocument.Parse(toString(x));
present("round tripped", x.Root.Value); // 13 10, expected

string toString(XDocument xd)
{
    using var sw = new StringWriter();
    using (var writer = XmlWriter.Create(sw, new XmlWriterSettings
    {
        NewLineHandling = NewLineHandling.Entitize,
    }))
    {
        xd.WriteTo(writer);
    }
    return sw.ToString();
}

void present(string label, string thing)
{
    Console.WriteLine(label);
    Console.WriteLine(thing);
    Console.WriteLine(string.Join(" ", Encoding.UTF8.GetBytes(thing)));
    Console.WriteLine();
}