【问题标题】:how to extract data from cocoa iPhone sax xml parsing routine如何从可可 iPhone sax xml 解析例程中提取数据
【发布时间】:2009-04-14 00:05:52
【问题描述】:

我正在尝试在 iPhone 应用程序中读取和解析 xml 文档。我开始解析,然后使用覆盖方法:

   static void startElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, 
                        int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)

然后我尝试将属性转换为字符串:

   NSString *str1 = [[NSString alloc] initWithCString:attributes encoding:NSUTF8StringEncoding];

为什么attributes参数前面有两个**。以及为什么在尝试使用上述代码提取数据并将其转换为字符串时会收到警告:

从不兼容的指针类型传递 'initWithCString:encoding:' 的参数 1。

【问题讨论】:

    标签: objective-c xml cocoa-touch parsing sax


    【解决方案1】:

    libxml 的start element callback 的文档指出,该指针指向一个数组,该数组为每个属性保存 5 个值(属性数在 nb_attributes 中返回)。这意味着数组中的每 5 个值都是一个新的属性项。

    每个属性的五个项目是:

    1. localname(属性的名称)
    2. 前缀(属性的命名空间)
    3. URI
    4. [start of] 值(指向开始的指针 xmlChar 字符串的值)
    5. end [of value](指向结束的指针 值的 xmlChar 字符串)

    所以你需要单步遍历数组,从第一个属性的项中取出每个值,然后使用起始值指针获取长度 = 结束 - 开始的 xmlChar 字符串。然后从下一个属性重新开始,直到你读入 nb_attributes 值。

    如果这让您头疼,那么我强烈建议您切换到 Apple 的 NSXMLParser(链接可能需要登录,或使用此链接 NSXMLParser)。在这种情况下,您将获得属性作为 NSDictionary。要从中获取所有属性,您可以执行以下操作:

    for (NSString *attributeName in [attributeDict allKeys]) {
        NSString *attributeValue = [attributeDict objectForKey:attributeName];
        // do something here with attributeName and attributeValue
    }
    

    如果您可以访问 iPhone 开发者网站,请查看示例 SeismicXML。

    【讨论】:

    • for (NSString *attributeName in [attributeDict allKeys]) 可以写成for (NSString *attributeName in attributeDict)
    • 由于内存问题,NSXMLParser 在 iOS 上对于任何大的东西都是无用的。 Libxml 是 Apple 提供的唯一一个允许以最少的内存使用解析大文件的库。
    【解决方案2】:

    这个样本很棒,除了两点:

    • 您需要在每次循环后将“i”增加 5,因为每个属性有 5 个项目。
    • 在开始和结束时都执行 strlen() 代价高昂;简单地从结尾减去开始更容易
    
    for (int i = 0; i < nb_attributes*5; i += 5) 
    {
        const char *attr = (const char *)attributes[i];
        const char *begin = (const char *)attributes[i + 3];
        const char *end = (const char *)attributes[i + 4];
        int vlen = end - begin;
        char val[vlen + 1];
        strncpy(val, begin, vlen);
        val[vlen] = '\0';
        NSLog(@"attribute %s = '%s'", attr, val);
    }
    

    【讨论】:

      【解决方案3】:

      接受的答案解释是正确的,但查看一些示例代码也很有帮助。这只是从属性中提取值的一种方法,至少在我测试它时它是有效的。不过,我离成为 C 大师还差得很远。

      for (int i = 0; i < nb_attributes; i += 5) {
          const char *attr = (const char *)attributes[i];
          const char *begin = (const char *)attributes[i + 3];
          const char *end = (const char *)attributes[i + 4];
          int vlen = strlen(begin) - strlen(end);
          char val[vlen + 1];
          strncpy(val, begin, vlen);
          val[vlen] = '\0';
          NSLog(@"attribute %s: %d = %s", attr, i, val);
      }
      

      NSXMLParser 很好,但据我所知,它会在处理之前下载整个 XML。使用 libxml 它可以一次读取块。它允许更大的灵活性,但更高的学习曲线。

      【讨论】:

        【解决方案4】:

        '**' 表示法的意思是“指向指针的指针”。在 C/C++ 中,“字符串”由字符数组表示。数组实际上只是一个指针,因此 C/C++ 中的字符串实际上可以声明为“char[]”或“char*”。 [] 符号编译为指向数组的指针。

        一个常见的例子是 C/C++ 中典型的“main”函数:

        int main(int argc, char **argv)
        

        相当于:

        int main(int argc, char *argv[])
        

        argv 是一个 char*“字符串”数组(程序的命令行参数)。

        目前我无法提供示例,但您似乎需要遍历属性才能访问各个字符串。例如,attributes[0] 将是第一个属性字符串(一个 xmlChar*)。您应该能够将每个单独的属性转换为 NSString。

        【讨论】:

          【解决方案5】:

          const xmlChar **namespaces 是一个 CString 数组(int nb_namespaces 告诉你有多少)。如果您希望每个命名空间都作为 NSString,您可以执行以下操作:

          NSMutableArray *namespaces = [[NSMutableArray alloc] init];
          
          int i;
          for (i = 0; i < nb_namespaces; i++) {
              NSString *namespace = [[NSString alloc] initWithCString:attributes[i] encoding:NSUTF8StringEncoding];
              [namespaces addObject:namespace];
          }
          

          initWithCString 方法需要 xmlChar *,它是一个 指向 xmlChar 的指针(CString 中的第一个字符)。

          xmlChar ** 表示指向指针的指针 指向 xmlChar(first CString 中的第一个字符)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-08
            • 1970-01-01
            • 1970-01-01
            • 2011-06-17
            • 1970-01-01
            • 2011-05-26
            相关资源
            最近更新 更多