当xml:space = preserve时,XmlWriter插入空格

时间:2022-05-30 21:44:08

Given this code (C#, .NET 3.5 SP1):

鉴于此代码(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);

The assertion fails because the XmlWriter is inserting a newline and indent around the <item> elements, which would seem to contradict the xml:space="preserve" attribute.

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

I am trying to take input with no whitespace (or only significant whitespace, and already loaded into an XmlDocument) and pretty-print it without adding any whitespace inside elements marked to preserve whitespace (for obvious reasons).

我试图在没有空格的情况下输入(或者只有很大的空白,并且已经加载到XmlDocument中)并且在不添加任何标记的元素内部空格的情况下进行漂亮的打印以保留空白(出于显而易见的原因)。

Is this a bug or am I doing something wrong? Is there a better way to achieve what I'm trying to do?

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

Edit: I should probably add that I do have to use an XmlWriter with Indent=true on the output side. In the "real" code, this is being passed in from outside of my code.

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

1 个解决方案

#1


4  

Ok, I've found a workaround.

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

It turns out that XmlWriter does the correct thing if there actually is any whitespace within the xml:space="preserve" block -- it's only when there isn't any that it screws up and adds some. And conveniently, this also works if there are some whitespace nodes, even if they're empty. So the trick that I've come up with is to decorate the document with extra 0-length whitespace in the appropriate places before trying to write it out. The result is exactly what I want: pretty printing everywhere except where whitespace is significant.

事实证明,如果在xml:space =“preserve”块中实际存在任何空格,XmlWriter会做正确的事情 - 只有在没有任何空格的情况下才会搞错并添加一些空格。并且方便地,如果存在一些空白节点,即使它们是空的,这也可以工作。所以我提出的技巧是在尝试写出文档之前,在适当的位置用额外的0长度空格来装饰文档。结果正是我想要的:除了空白很重要之外,所有地方都可以打印。

The workaround is to change the inner block to:

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

PreserveWhitespace(doc.DocumentElement);
doc.DocumentElement.WriteTo(writer);

...

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);
        }
    }
}

I'm still thinking that this behaviour of XmlWriter is a bug, though.

我仍然认为XmlWriter的这种行为是一个错误。

#1


4  

Ok, I've found a workaround.

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

It turns out that XmlWriter does the correct thing if there actually is any whitespace within the xml:space="preserve" block -- it's only when there isn't any that it screws up and adds some. And conveniently, this also works if there are some whitespace nodes, even if they're empty. So the trick that I've come up with is to decorate the document with extra 0-length whitespace in the appropriate places before trying to write it out. The result is exactly what I want: pretty printing everywhere except where whitespace is significant.

事实证明,如果在xml:space =“preserve”块中实际存在任何空格,XmlWriter会做正确的事情 - 只有在没有任何空格的情况下才会搞错并添加一些空格。并且方便地,如果存在一些空白节点,即使它们是空的,这也可以工作。所以我提出的技巧是在尝试写出文档之前,在适当的位置用额外的0长度空格来装饰文档。结果正是我想要的:除了空白很重要之外,所有地方都可以打印。

The workaround is to change the inner block to:

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

PreserveWhitespace(doc.DocumentElement);
doc.DocumentElement.WriteTo(writer);

...

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);
        }
    }
}

I'm still thinking that this behaviour of XmlWriter is a bug, though.

我仍然认为XmlWriter的这种行为是一个错误。