【问题标题】:NSXMLParser and BOM bytesNSXMLParser 和 BOM 字节
【发布时间】:2010-01-14 18:23:31
【问题描述】:

由于来自某个服务器的 php 查询,我正在获取我的 xml 文件。当我将结果数据打印到控制台时,我得到了结构良好的 xml 文件。当我尝试使用 NSXMLParser 解析它时,它返回带有代码 4 的 NSXMLParserErrorDomain - 空文档。 我看到它无法解析的 xml 在关闭 xml 标头的“>”标记后立即具有 BOM(字节顺序标记)序列。问题是如何摆脱 BOM 序列。我试图用这样的 BOM 字节创建一个字符串:

    const   UInt8 bom[3] = {0xEF, 0xBB, 0xBF};
NSString    *bomString = [[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bom length:3] encoding:NSUTF8StringEncoding];
NSString    *noBOMString = [theResult stringByReplacingOccurrencesOfString:bomString withString:@" "];

但由于某种原因它不起作用。有 xml,在根元素之后有这个序列。在这种情况下,NSXMLParser 成功解析了 xml。 Safari 会忽略这些字符。所以 Xcode 调试器。请帮忙!

谢谢,

纳瓦

【问题讨论】:

    标签: iphone cocoa nsxmlparser byte-order-mark nsxmlparsererrordomain


    【解决方案1】:

    我试图用这样的 BOM 字节创建一个字符串:

    const   UInt8 bom[3] = {0xEF, 0xBB, 0xBF};
    NSString    *bomString = [[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bom length:3] encoding:NSUTF8StringEncoding];
    NSString    *noBOMString = [theResult stringByReplacingOccurrencesOfString:bomString withString:@" "];
    

    但由于某种原因它不起作用。

    确保在实例化 noBOMString 时提供了正确的编码。如果文档数据是 UTF-8,请确保将字符串实例化为 UTF-8。同样,如果数据是 UTF-16,请确保将字符串实例化为 UTF-16。

    如果你传递了错误的编码,要么字符串根本不会实例化(我假设这不是你的问题),要么某些字符会出错。 BOM 将是其中之一:如果输入是 UTF-8 并且您将其解释为 MacRoman 或 ISOLatin1,它将在字符串中显示为三个单独的字符。这三个单独的字符不会与作为 BOM 的单个字符进行比较。

    【讨论】:

    • 是的,结果字符串是用 NSUTF8StringEncoding 实例化的,所以我认为将 BOM 检查为 3 字符字符串的方法是正确的。事实是 c 代码有效。 AFAIK 对于不同的编码有不同的 BOM 序列。那么你建议如何检查呢?是否可以使用可可字符串?
    • 只有一个 BOM:U+FEFF。它表现为不同编码中的不同字节序列,因为不同的编码将相同的字符编码为不同的字节。从 UTF-8 创建 BOMString 是一种方法,但是从哪个 UTF 创建它并不重要,因为(只要您提供正确的代码单元)它在结果字符串中始终是 U+FEFF。您的代码应该可以正常工作;您可以尝试将theResult 转储到stringByReplacing… 之前和之后的文件中,并使用Hex Fiend 等十六进制编辑器查看它。
    • 我这样做清楚地看到了 2 个字符序列 0xEF、0xBB、0xBF。所以我不明白为什么 stringByReplacingOccurrencesOfString 对我不起作用。我试图记录 bomString,但可能这些字符是不可见的。你能举一个工作可可代码的例子吗? TIA
    • *forehead-smack* 我刚刚意识到为什么它不起作用——因为您传递的 UTF-8 数据以 UTF-8 BOM 开头!显然,Cocoa 将剥离(并在适当的情况下使用)出现在输入数据开头的 BOM。 BOM 之后没有任何其他字符;因此,您将字符串替换为空格,并且在文档字符串中的任何位置都找不到任何字符。因此,您需要以不同的方式创建 BOM 字符串。 [NSString stringWithFormat:@"%C", 0xFEFF] 有效。
    • 非常感谢,确实有效!我怎么一开始就知道这个?有没有可以了解的文档?
    【解决方案2】:

    我不确定这是否是问题所在。我有一个非常相似的经验,文件被编码为 UTF-8,但 xml 标头声称它是 UTF-16。

    由于不匹配,我无法解析它并出现与您相同的错误。但是,将 xml 标头从 UTF-16 更改为 UTF-8 解决了我的问题。

    您可能会遇到类似的问题。

    【讨论】:

    • 标题说:。如果我将此 xml 保存在一个文件中并使用 BBEdit 打开它,我会看到它有 utf-8 编码,没有 BOM。但是,当我打开此文件时,我在 Resourcerer 中看到的是关闭标题的“>”后的 BOM 序列。我的问题是我该如何摆脱这个?我在 BBEdit 中看到,
    【解决方案3】:

    好吧,这可能不是摆脱 BOM 字节的最佳方法,但它确实有效。对于那些像我一样花了几个小时试图让 NSXMLParser 吞下 BOM 的人: 假设您通过 NSURLConnection 获取数据并将其存储在 NSMutableData *webData 中。

        const char bom[3] = {0xEF, 0xBB, 0xBF};
    
    char *data = [webData mutableBytes];
    char *cp = data, *pp;
    long lessBom = 0;
    do {
        cp = strstr((const char *)cp, (const char *)bom);
        if (cp) {
            pp = cp;
            cp += 3;
            memcpy(pp, cp, strlen(cp));
            lessBom += 3;
        }
    } while (cp != NULL);
    
    NSMutableData   *newData = [[NSMutableData alloc] initWithBytes:data length:webData.length - lessBom];
    

    然后你用 newData 创建你的解析器,它就可以工作了!我很高兴得到此代码的任何 cmets/改进

    【讨论】:

    • 绝对不要在这里使用strstr。这是针对以空值结尾的 C 字符串(最后一个字节为 0)。 NSMutableData 的内容不是空终止的,除非您自己这样做,并且可以包含空字节,其中第一个 strstr 和其他 C 字符串函数将视为终止符。 NSData 和 NSMutableData 具有可以更安全地完成相同工作的方法;有关详细信息,请参阅他们的文档。
    • 谢谢,我想过这个,虽然我可以在最后添加一个 '\0'。无论如何都会重新考虑它。
    猜你喜欢
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 2023-03-12
    • 2021-10-25
    • 1970-01-01
    相关资源
    最近更新 更多