当我尝试解析来自某个REST API的响应时,我得到一个XmlException
说“根级别的数据无效。第1行,位置1”。看看XML 看起来很好,但是然后检查第一个字符,我看到它实际上是zero-width no-break space(字符代码65279或0xFEFF)。
这个角色有什么好的理由吗?也许我应该在提出要求时设置不同的编码?目前我正在使用Encoding.UTF8
。
我考虑过只是从字符串中删除字符,或者要求REST API的开发人员修复它,但在我执行其中任何一项操作之前,我想检查该字符是否有正当理由在那里。我不是unicode专家。我应该做些什么不同吗?
编辑:我怀疑它可能是那样的(BOM)。那么,问题就变成了,我是否应该特别处理这个角色?我尝试过两种方式加载XML,并且都抛出相同的异常:
public static User GetUser()
{
WebClient req = new WebClient();
req.Encoding = Encoding.UTF8;
string response = req.DownloadString(url);
XmlSerializer ser = new XmlSerializer(typeof(User));
User user = ser.Deserialize(new StringReader(response)) as User;
XElement xUser = XElement.Parse(response);
...
return user;
}
答案 0 :(得分:3)
U + FFEF是byte order mark。它位于文档的开头,用于指示字符编码(或者更确切地说,编码的字节顺序,可以是任何一种方式;最具体地说是UTF-16)。它在XML文档的开头就在那里是完全合理的。它被用作零宽度不间断空间而不赞成使用U + 2060。
如果字节顺序标记采用不同的编码,那将是不合理的,例如如果它是声称为UTF-8的文件中的UTF-8 BOM。
你是如何加载文件的?也许你在某处指定了不合适的编码?如果可能的话,最好让XML API检测编码。
编辑:在您将其作为字符串下载后,我可以想象这可能会导致问题...因为它已用于检测您已经获得的编码。不要将其作为字符串下载 - 将其下载为二进制数据(WebClient.DownloadData
)然后你应该能够解析它,我相信。但是,您可能仍然不应该使用XElement.Parse
,因为可能存在文档声明 - 使用XDocument.Parse
。如果调用的结果可以直接输入XmlSerializer
,我会感到有些惊讶,但是如果需要的话,你可以把它包裹在MemoryStream
中。
答案 1 :(得分:2)
这称为Byte Order Mark。但是在UTF-8中不需要它。
答案 2 :(得分:1)
使用构造函数重载创建您自己的UTF-8编码器,而不是使用Encoding.UTF8,您可以指定是否要发出BOM:
req.Encoding = new UTF8Encoding( false ) ; // omit the BOM
我相信这会为你做到这一点。
修改为注意:以下将工作:
public static User GetUser()
{
WebClient req = new WebClient();
req.Encoding = Encoding.UTF8;
byte[] response = req.DownloadData(url);
User instance ;
using ( MemoryStream stream = new MemoryStream(buffer) )
using ( XmlReader reader = XmlReader.Create( stream ) )
{
XmlSerializer serializer = new XmlSerializer(typeof(User)) ;
instance = (User) serializer.Deserialize( reader ) ;
}
return instance ;
}
答案 3 :(得分:0)
开头的那个字符是BOM(字节顺序标记)。它被放置为unicode文本文件中的第一个字符,用于指定用于创建文件的编码。
BOM不应该是响应的一部分,因为HTTP内容的编码指定方式不同。
通常,响应中的BOM来自发送文本文件作为响应,其中文本文件与BOM签名一起保存。例如,Visual Studio可以选择保存没有BOM签名的文件,以便可以直接作为响应发送。