由于REST API响应中的前导unicode字符导致的Xml异常

时间:2011-06-03 18:39:27

标签: c# xml unicode

当我尝试解析来自某个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;
}

4 个答案:

答案 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签名的文件,以便可以直接作为响应发送。