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

发布于 2024-11-28 16:53:08 字数 1208 浏览 4 评论 0原文

给定此代码(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);

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

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

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

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

Given this code (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.

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).

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

灯下孤影 2024-12-05 16:53:08

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

事实证明,如果 xml:space="preserve" 块中实际上存在任何空格,则 XmlWriter 会执行正确的操作 - 这只是当没有任何东西时,它会搞砸并添加一些。方便的是,如果存在一些空白节点,即使它们是空的,这也适用。因此,我想出的技巧是在尝试将文档写出来之前,在适当的位置用额外的 0 长度空白来装饰文档。结果正是我想要的:除了空白很重要的地方之外,到处都打印得很漂亮。

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

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

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文