XDocument:保存XML文件时不包含BOM

55

我使用XDocument生成一个utf-8 XML文件。

XDocument xml_document = new XDocument(
                    new XDeclaration("1.0", "utf-8", null),
                    new XElement(ROOT_NAME,                    
                    new XAttribute("note", note)
                )
            );
...
xml_document.Save(@file_path);

文件已经正确生成并且已成功使用xsd文件进行验证。 当我尝试将XML文件上传到在线服务时,服务显示我的文件在第一行处出现问题;我发现该问题是由文件开头的BOM引起的。 你知道为什么BOM会附加到文件中以及如何在保存文件时去除它吗? 如字节顺序标记维基百科文章所述: 虽然Unicode标准允许在UTF-8中使用BOM,但它不需要或建议这样做。在UTF-8中,字节顺序没有意义,因此BOM仅用于识别文本流或文件是否为UTF-8格式,或者它是从具有BOM的另一种格式转换而来。 这是XDocument的问题还是我应该联系在线服务提供商的人以请求解析器升级?
4个回答

81

使用 XmlTextWriter,并将其传递给 XDocument 的 Save() 方法,这样您就可以更好地控制所使用的编码类型:

var doc = new XDocument(
    new XDeclaration("1.0", "utf-8", null),
    new XElement("root", new XAttribute("note", "boogers"))
);
using (var writer = new XmlTextWriter(".\\boogers.xml", new UTF8Encoding(false)))
{
    doc.Save(writer);
}

UTF8Encoding类的构造函数有一个重载,可以使用布尔值来指定是否使用BOM(字节序标记),在您的情况下为false

使用Notepad++检查文件的编码来验证此代码的结果。


当您使用Notepad++打开时,即使使用new UTF8Encoding(false),它仍然处于utf-8编码吗? - systempuntoout
我以为你想要UTF-8格式的,只是不带BOM标识。 - Quick Joe Smith
12
考虑添加 writer.Formatting = Formatting.Indented;。这行代码的作用是将输出的XML格式化为带缩进的形式,以便更容易阅读。 - Kevin Panko
Kevin,这完全取决于文件是否旨在供人查看,否则它只是浪费的字节。问题没有提供足够的细节来假设任何一种情况。 - Quick Joe Smith
5
“警告:Dercsár的解决方案更好。从.NET Framework 2.0开始,我们建议您使用XmlWriter.Create方法和XmlWriterSettings类创建XmlWriter实例,以利用新功能。”。来源:XmlTextWriter Constructor (String, Encoding) (System.Xml) - Stéphane Gourichon
显示剩余2条评论

46

首先:根据XML规范,服务提供者必须处理BOM(字节顺序标记),因为UTF-8表示形式可能包含BOM。

你可以通过以下方法强制将XML保存为不带BOM的格式:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding(false); // The false means, do not emit the BOM.
using (XmlWriter w = XmlWriter.Create("my.xml", settings))
{
    doc.Save(w);
}

(从这里搜索到的:http://social.msdn.microsoft.com/Forums/en/xmlandnetfx/thread/ccc08c65-01d7-43c6-adf3-1fc70fdb026a


“在UTF-8表示中可能存在BOM,请问您能指向具体的文档吗?” - systempuntoout
1
这里是链接:http://www.w3.org/TR/2006/REC-xml-20060816/#charencoding 第一段:“所有XML处理器必须能够读取UTF-8和UTF-16编码中的实体。” UTF-8编码使得BOM成为可能(但不是必需的,详见Joe的评论),因此XML处理器必须能够处理带有BOM的UTF-8文件。 - Dercsár
2
虽然Unicode标准允许在UTF-8中使用BOM,但并不要求或建议这样做。字节顺序在UTF-8中没有意义。 - Quick Joe Smith
5
警告:如果您使用的是doc.Save(filename)而不是下面代码中所示的方法,则会产生副作用:所有内容都将写在一行上。 如果您希望文件保持易读性,请考虑在代码中添加settings.Indent = true; - Stéphane Gourichon

0

使用 XDocument 去掉 BOM 字符最有效的方法是保存文档,然后将其作为文件进行直接读取,接着再将其写回。文件例程会自动为您去除该字符:

        XDocument xTasks = new XDocument();
        XElement xRoot = new XElement("tasklist",
            new XAttribute("timestamp",lastUpdated),
            new XElement("lasttask",lastTask)
        );
        ...
        xTasks.Add(xRoot);
        xTasks.Save("tasks.xml");

        // read it straight in, write it straight back out. Done.
        string[] lines = File.ReadAllLines("tasks.xml");
        File.WriteAllLines("tasks.xml",lines);

(虽然有点不专业,但为了方便起见它是有效的 - 至少你会有一个格式良好的文件可以上传到你的在线提供商);)


只需使用 XmlWriter.CreateXmlWriterSettings.Indent = true; 即可。在这里,您可以根据自己的喜好格式化输出。 - SvenL

-2

关于UTF-8文档

String XMLDec = xDoc.Declaration.ToString();
StringBuilder sb = new StringBuilder(XMLDec);
sb.Append(xDoc.ToString());
Encoding encoding = new UTF8Encoding(false); // false = without BOM
File.WriteAllText(outPath, sb.ToString(), encoding); 

已经有多次回答了,而且你在这里使用StringBuilder的原因非常模糊,因为文档可以像其他答案中所示自己保存。请解释一下。 - Gert Arnold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接