1

我正在尝试在 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。

4

5 回答 5

3

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

每个属性的五个项目是:

  1. localname(属性的名称)
  2. 前缀(属性的命名空间)
  3. URI
  4. [start of] value(指向值的 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

于 2009-04-14T01:51:08.317 回答
1

接受的答案解释是正确的,但查看一些示例代码也很有帮助。这只是从属性中提取值的一种方法,至少在我测试它时它是有效的。不过,我离成为 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 它可以一次读取块。它允许更大的灵活性,但更高的学习曲线。

于 2009-06-21T18:21:07.997 回答
1

该示例很棒,除了两件事:

  • 您需要在每个循环之后将“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);
}
于 2009-08-08T06:43:46.500 回答
0

'**'符号的意思是“指向指针的指针”。在 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。

于 2009-04-14T00:30:33.363 回答
0

const xmlChar **namespaces是一个 CStrings 数组(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方法是 expecting xmlChar *,它是一个指向 xmlChar(CString 中的第一个字符)的指针。

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

于 2009-04-14T02:04:06.400 回答