NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义
Posted
技术标签:
【中文标题】NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义【英文标题】:NSJSONSerialization serialization of a string containing forward slashes / and HTML is escaped incorrectly 【发布时间】:2013-04-03 17:55:42 【问题描述】:我正在尝试将一些简单的 html 转换为 JSON 对象中的字符串值,但我无法让字符串编码不转义 NSJSONSerialization 中的字符串。
示例...我有一个包含一些基本 HTML 文本的字符串:
NSString *str = @"<html><body><p>Samples / Text</p></body></html>";
期望的结果是带有 HTML 作为值的 JSON:
"Title":"My Title",
"Instructions":"<html><body><p>Samples / Text</p></body></html>"
我正在使用标准技术将 NSDictionary 转换为包含 JSON 的 NSString:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:str forKey:@"Instructions"];
[dict setObject:@"My Title" forKey:@"Title"];
NSError *err;
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&err];
NSString *resultingString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", resultingString);
此方法生成的 JSON 是有效的,但是 HTML 中的所有正斜杠都被转义了:
"Title":"My Title",
"Instructions":"<html><body><p>Samples \/ Text<\/p><\/body><\/html>"
这会在说明 JSON 字符串中创建无效的 HTML。
我想坚持使用 NSJSONSerialization,因为我们在框架中的其他任何地方都使用它,并且在切换到非 Apple 库之前我已经被烧毁了,因为它们被取消支持。我已经尝试了许多不同的字符串编码,它们都避开了尖括号。
显然 \/ 是 javascript 中 / 字符的有效表示,这就是转义正斜杠的原因(甚至 *** 文本编辑器也转义了它)。看: escaping json string with a forward slash? 还有JSON: why are forward slashes escaped?。我只是不希望它这样做,而且似乎没有办法阻止 ios 在序列化时转义字符串值中的正斜杠。
【问题讨论】:
另一个不使用 NSJSONSerialization 的好理由,我想。人们总是可以扫描数据并将相邻的“\/”字符替换为“/”,但有点乱。 这就是我现在正在做的事情,感觉就像是 hack。不幸的是,我目前使用的所有第三方 iOS 框架都在原作者感到无聊或忙碌后被取消支持。 我们仍在使用 SBJSON。最坏的情况是你可以自己写——实际上只有大约 2K 行代码,只要你不要太花哨。 序列化完全有效。任何体面的反序列化器都可以毫无问题地取回原始字符串。 【参考方案1】:我相信NSJSONSerialization
在编码 HTML 方面的行为符合设计。
如果您查看一些关于在 JSON 中编码 HTML 的问题(1、2),您会看到答案总是提到转义正斜杠。
JSON 不需要转义正斜杠,但 HTML 不允许 javascript 字符串包含 </
,因为它可能与 <SCRIPT>
标记的结尾混淆。
查看答案here、here 和最直接的w3.org HTML4 Appendix,其中在B.3.2 Specifying non-HTML data 中声明
ILLEGAL EXAMPLE:
The following script data incorrectly contains a "</" sequence (as part of "</EM>") before the SCRIPT end tag:
<SCRIPT type="text/javascript">
document.write ("<EM>This won't work</EM>")
</SCRIPT>
虽然这种行为可能会给您带来问题,但 NSJSONSerialisation
只是在按照古老的编码 HTML 数据以用于<SCRIPT>
标记的规则进行游戏。
【讨论】:
【参考方案2】:这是我的 AFJSONRequestSerializer
子类,用于在生成的 JSON 中删除 /
符号之前的 \
;如果你使用 AFNetworking 会很方便
class SanitizedAFJSONRequestSerializer: AFJSONRequestSerializer
override func requestBySerializingRequest(request: NSURLRequest!, withParameters parameters: AnyObject!, error: NSErrorPointer) -> NSURLRequest!
var request = super.requestBySerializingRequest(request, withParameters: parameters, error: error)
if let jsonData = request.HTTPBody
if let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as? String
let sanitizedString = jsonString.stringByReplacingOccurrencesOfString("\\/", withString: "/", options: NSStringCompareOptions.CaseInsensitiveSearch, range:nil) as NSString
println("sanitized json string: \(sanitizedString)")
var mutableRequest = request.mutableCopy() as! NSMutableURLRequest
mutableRequest.HTTPBody = sanitizedString.dataUsingEncoding(NSUTF8StringEncoding)
request = mutableRequest
return request
【讨论】:
【参考方案3】:仅限 iOS 13:
如果您不担心产生无效的 HTML 序列(如 this answer 中所述),您可以通过将选项 NSJSONWritingWithoutEscapingSlashes
传递给序列化程序来禁用正斜杠转义。
例子:
jsonData = [NSJSONSerialization dataWithJSONObject:batchUpdates
options:NSJSONWritingWithoutEscapingSlashes
error:nil];
【讨论】:
以上是关于NSJSONSerialization 包含正斜杠的字符串序列化 / 和 HTML 被错误地转义的主要内容,如果未能解决你的问题,请参考以下文章