关于javascript:在http响应xml中处理unicode

Handling unicode in the http response xml

我正在编写一个基于myanimelist.net rest API的Google Chrome扩展。有时xmlhttpRequest响应文本包含Unicode。

例如:

1
Onegai My Melody Sukkiriâ?ª

如果我从文本创建一个HTML节点,它看起来是这样的:

1
Onegai My Melody Sukkiria?a

然而,实际标题是:

1
Onegai My Melody Sukkiri?

为什么我的文本没有正确呈现,我如何修复它?

更新代码:background.html

我认为这些是关键部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function htmlDecode(input){
  var e = document.createElement('div');
  e.innerHTML = input;
  return e.childNodes.length === 0 ?"" : e.childNodes[0].nodeValue;
}

function xmlDecode(input){
  var result = input;
  result = result.replace(/</g, "&lt;");
  result = result.replace(/>/g, "&gt;");
  result = result.replace(/
/g,"&#10;");
  return htmlDecode(result);
}

进一步:

1
2
3
var parser = new DOMParser();
var xmlText = response.value;
var doc = parser.parseFromString(xmlDecode(xmlText),"text/xml");


1
Onegai My Melody Sukkiri&acirc;?&ordf;

哦,天哪!不仅是错误的文本,它甚至不是格式良好的XML。acircordf是未在XML中预先定义的HTML实体,它们之间有一个无效的utf-8序列(一个高字节,可能最初是0x99)。

问题是MyAnimalList正在使用PHP函数htmlentities()生成其输出"xml"(但"如果格式不正确,则不是xml")。这不仅试图对HTML字符<&"'中可能敏感的字符进行HTML转义,而且还试图对所有非ASCII字符进行HTML转义。

这会生成错误的字符,因为PHP默认将htmlentities()的输入视为iso-8859-1,而不是实际使用的编码utf-8。但是这是错误的,因为HTML实体集在XML中不存在。他们真正想要使用的是htmlspecialchars(),它只剩下非ASCII字符,只不过是逃避真正敏感的字符。因为它们在XML中是敏感的,所以htmlspecialchars()在XML和HTML中同样适用。

htmlentities()几乎总是错误的;通常应该使用htmlspecialchars()。您可能希望将非ASCII字节编码为实体引用的一个地方是,当您以纯ASCII输出为目标时。但即使这样,htmlentities()也失败了,因为它没有为没有预定义实体名的字符进行字符引用(&#...;)。很没用。

无论如何,您不能从中恢复损坏的数据。?表示一个字节序列,该序列是对xmlhttprequest不可编码的utf-8,因此信息将不可恢复地丢失。您必须说服MyAnimalList按照以上几段修复其损坏的XML输出,然后才能继续。

同时,他们应该把它作为Content-Type: text/xml而不是目前的text/html归还。然后,您可以直接从xmlhttpRequest对象中获取responseXML,而不是乱弄domparsers。


所以,我遇到了一些类似于这里工作的事情,我做了更多的研究来证实我的假设。

如果您查看上面发布的返回值,您会注意到tell-tell实体"â;"。99%的时间当你看到这个实体,如果意味着你有一个字符编码问题(通常UTF-8字符被编码为ISO-8859-1)。

我要测试的第一件事是在API返回中强制进行字符编码。(这是一个远射,但你可以看)

其次,我会尝试强制对返回的数据进行字符编码(我知道有一个.htaccess重写,但我不知道chrome扩展中允许什么,所以您必须研究一下)。

我认为正在发生的事情是,当您用数据包装节点时,文档上没有设置字符编码,浏览器(通常在我的经验中)默认为ISO-8859-1。所以,检查以确保问题不是您的文档。

最后,如果您找不到字符编码的源(或无法阻止它),则必须编写一个会话表,用您想要的JS'"replace"替换您得到的格式错误的值(http://www.w3schools.com/jsref/jsrefu replace.asp)。


不能只使用简单的搜索和替换来解决编码问题,因为它们是Unicode,而不是键盘上键入的字符。

如果计划通过Ajax检索数据,则必须将数据以UTF-8格式存储在服务器上。这个问题可能是因为有人从MS Word粘贴字符,而MS Word使用了完全不同的编码方案(ISO-8859)。

如果你不能修复数据,你就有点搞砸了。

有关详细信息,请参见:UTF-8与Unicode