在 XDocument.ToString() 的空元素中删除额外的 space

Removing extra space in empty elements in XDocument.ToString()

我正在向无法处理标记中的 space 的系统发送 XML 消息。值中的空格是可以的。我一直在使用 linq/XDocument/XElements 到 manipulate/generate 条消息。

问题出在元素为空时。例如:

XDocument xdoc = XDocument.Parse("<root><value/></root>");
Console.WriteLine(xdoc.ToString(SaveOptions.DisableFormatting));

即使 DisableFormatting 处于打开状态,这也会在元素标题后的标记中输出带有 space 的字符串。

<root><value /></root>

所以我只是在上面贴了一个替换:

Console.WriteLine(xdoc.ToString(SaveOptions.DisableFormatting).Replace(" />","/>"));

有什么不好的东西我可以 运行 进去吗?是否有 obvious/more 标准方法来执行此操作?好像卡顿了。

如果您的目标系统以与 self-closing xml 元素相同的方式处理空 xml 元素 - 通常,两者被视为相等(但考虑 post) 中的评论 - 您可以实现自定义 XmlWriter 输出 self-closing xml 标签作为空 xml 标签。
空 xml 标签不会在其标签中包含任何空格,例如。 <value></value> .

下面示例中的自定义 XmlTextWriter 生成以下 xml.
请注意 <value></value> 标记,并且 valueWithWhitespace 的空白值已被保留。

<root><value></value><valueWithWhitespace>   </valueWithWhitespace></root>

var xml = XElement.Parse(
    "<root><value /><valueWithWhitespace>   </valueWithWhitespace></root>",
    LoadOptions.PreserveWhitespace
    );

var stringWriter = new StringWriter();
using (var xmlWriter = new CustomXmlTextWriter(stringWriter))
{
    xml.WriteTo(xmlWriter);
    xmlWriter.Flush();
    Console.WriteLine(stringWriter);
}

public class CustomXmlTextWriter : XmlTextWriter
{
    public CustomXmlTextWriter(TextWriter writer)
        : base(writer)
    {}

    public CustomXmlTextWriter(Stream stream, Encoding encoding)
        : base(stream, encoding)
    {}

    public CustomXmlTextWriter(string filename, Encoding encoding)
        : base(filename, encoding)
    {}

    public override void WriteEndElement()
    {
        this.WriteFullEndElement();
    } 
}

也可以用不同的方式完成,如果你可以接受额外的缓冲(使用 String.Replace,看来你是):

class CustomXmlTextWriter : XmlTextWriter {
    public CustomXmlTextWriter(MemoryStream stream) : base(stream, new UTF8Encoding(false)) { }

    public override void WriteEndElement() {
        base.WriteEndElement();
        base.Flush();
        var stream = (MemoryStream)BaseStream;
        var buffer = stream.GetBuffer();
        var pos = stream.Position;
        if (pos > 3 && buffer[pos - 1] == '>' && buffer[pos - 2] == '/' && buffer[pos - 3] == ' ') {
            stream.Seek(-3, SeekOrigin.Current);
            stream.WriteByte((byte)'/');
            stream.WriteByte((byte)'>');
        }
    }
}

然后就可以从内存流中取出来了。字符串替换的不同之处在于,这种方法不会破坏 CDATA 部分之类的内容。使用完整结束标记的不同之处在于它可能会更接近地重现您已解析的内容。