XmlWriter 在 xml:space=preserve 时插入空格

Mir*_*ral 5 .net c# xml whitespace xmlwriter

鉴于此代码(C#,.NET 3.5 SP1):

var doc = new XmlDocument();
doc.LoadXml("<?xml version=\"1.0\"?><root>"
    + "<value xml:space=\"preserve\">"
    + "<item>content</item>"
    + "<item>content</item>"
    + "</value></root>");

var text = new StringWriter();
var settings = new XmlWriterSettings() { Indent = true, CloseOutput = true };
using (var writer = XmlWriter.Create(text, settings))
{
    doc.DocumentElement.WriteTo(writer);
}

var xml = text.GetStringBuilder().ToString();
Assert.AreEqual("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<root>\r\n"
    + "  <value xml:space=\"preserve\"><item>content</item>"
    + "<item>content</item></value>\r\n</root>", xml);
Run Code Online (Sandbox Code Playgroud)

断言失败是因为在元素XmlWriter周围插入换行符和缩进<item>,这似乎与xml:space="preserve"属性相矛盾。

我试图接受没有空格的输入(或只有重要的空格,并且已经加载到XmlDocument)并漂亮地打印它而不在标记为保留空格的元素内添加任何空格(出于显而易见的原因)。

这是一个错误还是我做错了什么?有没有更好的方法来实现我想要做的事情?

编辑:我可能应该补充一点,我必须在输出端使用XmlWriterwith Indent=true。在“真实”代码中,这是从我的代码外部传入的。

Mir*_*ral 5

好的,我找到了解决方法。

事实证明,XmlWriter如果块内确实任何空白,那会做正确的事情xml:space="preserve"——只有当没有任何空白时,它才会搞砸并添加一些空白。方便的是,如果有一些空白节点,即使它们是空的,这也适用。所以我想出的技巧是在尝试写出之前,在适当的地方用额外的 0 长度空白装饰文档。结果正是我想要的:除了空白很重要的地方,到处都是漂亮的打印。

解决方法是将内部块更改为:

PreserveWhitespace(doc.DocumentElement);
doc.DocumentElement.WriteTo(writer);
Run Code Online (Sandbox Code Playgroud)

...

private static void PreserveWhitespace(XmlElement root)
{
    var nsmgr = new XmlNamespaceManager(root.OwnerDocument.NameTable);
    foreach (var element in root.SelectNodes("//*[@xml:space='preserve']", nsmgr)
        .OfType<XmlElement>())
    {
        if (element.HasChildNodes && !(element.FirstChild is XmlSignificantWhitespace))
        {
            var whitespace = element.OwnerDocument.CreateSignificantWhitespace("");
            element.InsertBefore(whitespace, element.FirstChild);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不过,我仍然认为这种行为XmlWriter是一个错误。