在XDocument.ToString()

时间:2019-06-04 17:15:53

标签: c# linq-to-xml

我正在将XML消息发送到无法处理标记中的空格的系统。值中的空格可以。我一直在使用linq / XDocument / XElements来操纵/生成消息。

问题在于元素为空。例如:

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

即使打开DisableFormatting,它也会在元素标题后的标记中输出带有空格的字符串。

<root><value /></root>

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

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

有什么坏事我可以碰到那里吗?有明显/更标准的方法可以做到这一点吗?好像很烂。

2 个答案:

答案 0 :(得分:1)

如果目标系统对待空xml元素的方式与自动关闭xml元素的方式相同-通常,两者都被认为是相等的(但请考虑此post上的说明)-您可以实现自定义XmlWriter,该自定义<value></value>会将自关闭xml标签输出为空xml标签。
空的xml标签在其标签内将不包含任何空格,例如。 XmlTextWriter

下面的示例中的自定义<value></value>产生以下xml。
请注意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();
    } 
}

"reviewers": [
    {
        "uuid": "{504c3b62-8120-4f0c-a7bc-87800b9d6f70}"
    },
    {
        "uuid": "{bafabef7-b740-4ee0-9767-658b3253ecc0}"
    }
]

答案 1 :(得分:0)

如果您可以使用额外的缓冲(使用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部分之类的东西。使用完全结束标记的不同之处在于,它可能会更紧密地复制您已解析的内容。