【问题标题】:Objective-C: Parsing XML with gdataObjective-C:使用 gdata 解析 XML
【发布时间】:2026-01-24 19:20:18
【问题描述】:

我正在尝试使用 GdataxmlNode 目标 c 库解析一个巨大的 xml 文档(描述 3d 模型)。

这是一个阻碍我的 XML 示例:

<library_effects>
    <effect name="Love_Love-fx" id="Love_Love-fx">
        <profile_COMMON>
            <newparam sid="sexy-surface">
                <surface type="2D">
                    <init_from>sexy</init_from>
                    <format>A8R8G8B8</format>
                </surface>
            </newparam>
            ....
        </profile_COMMON>
    </effect>
    ....
</library_effects>

我的目标

  1. 获取效果名称 (*Love_Love-fx*):完美运行

  2. 获取 init_from (sexy) 的内容:根本不起作用

我是这样解析的:

xmlGetData = [xmlDoc.rootElement elementsForName:@"library_effects"];   

//Effects infos
int eff_c;
NSMutableArray *eff_ids = [[NSMutableArray alloc] init];  //effect names
NSMutableArray *eff_src = [[NSMutableArray alloc] init];  //efects sources

for (GDataXMLElement *e in xmlGetData)
{
    eff_c = [[e elementsForName:@"effect"]count];        
    NSArray *eff_node  = [e elementsForName:@"effect"];
    for (int i = 0; i < eff_c; i++)
    {
        //get the effect name (id & name are the same)
        [eff_ids addObject:[[eff_node objectAtIndex:i]attributeForName:@"id"]];
        //get the content of init_from
        [eff_src addObject:[[eff_node objectAtIndex:i]elementForName:@"init_from"]];
    }
}

我的问题: 我在最后一行 ([eff_src addObject.........) 上有一个 SIGABRT,所以我无法获取“init_from”的内容

(因为[[eff_node objectAtIndex:i]elementForName:@"init_from"]] 返回 Nil。?)

有人可以帮帮我吗? (有没有清晰完整的文档?我只看到博客文章解释了其中的一部分)

恶心的解决方案: 使用[[[[[[eff_node objectAtIndex:i]childAtIndex:0]childAtIndex:0]childAtIndex:0]childAtIndex:0]stri‌​ngValue];

【问题讨论】:

    标签: objective-c xml-parsing gdata


    【解决方案1】:

    eff_node 是 XML 节点 effect。我的猜测是elementForName: 方法不能递归工作并且返回 nil,因为init_from 不是effect 的直接子代。

    要么是这样,要么您的 XML 中有 effects,但其中不包含 init_from 节点。

    基本上,您不能将 nil 添加到 NSMutableArray,因此您需要测试您的两个 addObject: 参数是否为 nil,例如

    id idAttr = [[eff_node objectAtIndex:i]attributeForName:@"id"];
    if (idAttr != nil)
    {
        [eff_ids addObject:idAttr];
    }
    GDataXMLElement* initFrom = [[eff_node objectAtIndex:i]elementForName:@"init_from"];
    if (initFrom != nil)
    {
        [eff_src addObject: initFrom];
    }
    

    还要注意这一行

    NSArray *eff_node  = [[NSArray alloc] init];
    

    不必要地实例化一个空数组,并且在手动引用计数世界中是内存泄漏。


    我刚刚查看了 GDataXML API,它 a) 没有文档(在某种意义上,他们无法编写文档,而不是私有 API)和 b) 有限。

    您使用的方法不执行递归搜索,因此您有两个选择,要么实现自己的递归搜索,要么使用 XPath API。填充应该得到你想要的节点:

     NSError* myError = nil;
     NSArray* initFromNodes = [[eff_node objectAtIndex: i] nodesForXPath: @"//init_from" error: &myError]; 
    

    XPath 的//part 表示“树下任意数量的层级”

    【讨论】:

    • 使用你的 GDataXMLElement* initFrom = [[eff_node objectAtIndex:i]elementForName:@"init_from"]; 给我 initFrom=nil 所以同样的问题 :x (我没有添加 if() 因为在任何情况下我都需要所有这些信息)
    • @IggY 您需要if,因为您不能将nil 放入NSArray。这就是导致您的 SIGABRT 的原因。你要么得到 nil,因为 elementForName: 方法没有递归搜索,要么因为你有没有 init_from 子节点的元素。
    • 好吧,我明白了为什么我需要 if,对不起,这很愚蠢 ^^ 但是,init_from 总是 =nil :x 那么我怎样才能绕过 elementForName 不是递归的事实呢?跨度>
    • 我现在发现的唯一方法是制作:GDataXMLElement* initFrom = [[[[[[eff_node objectAtIndex:i]childAtIndex:0]childAtIndex:0]childAtIndex:0]childAtIndex:0]stringValue];,但真的很恶心:s
    • @IggY 是的,我一直在查看 GDataXML 的代码,但它对我来说似乎很糟糕,因为功能有限并且 API 根本没有记录。不过有一种方法可以搜索 XPath。我将编辑答案以显示这一点。