(Kiss)XML xpath和默认命名空间

时间:2013-06-26 09:05:40

标签: ios objective-c xml xpath kissxml

我正在开发一个需要解析一些xml的iPhone项目。 xml可能包含也可能不包含默认命名空间。我需要知道如何解析xml以防它使用默认命名空间。因为我需要阅读一个写xml,我倾向于使用KissXML,但我愿意接受建议。

这是我的代码:

NSString *content = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]
    pathForResource:@"bookstore" ofType:@"xml"] encoding:NSUTF8StringEncoding error:nil];

DDXMLDocument *theDocument = [[DDXMLDocument alloc] initWithXMLString:content options:0 error:nil];

NSArray *results = [theDocument nodesForXPath:@"//book" error:nil];
NSLog(@"%d", [results count]);

它在xml:

上按预期工作
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING">
  <title lang="en">Everyday Italian</title>
</book>
<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
</book>
</bookstore>

但是当xml有一个命名空间时,它会停止工作:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore xmlns="[INSERT RANDOM NAMESPACE]">
<book category="COOKING">
  <title lang="en">Everyday Italian</title>
</book>
<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
</book>
</bookstore>

当然,我可以预处理字符串并删除xmlns,虽然这感觉就像是一种丑陋的黑客。处理这个问题的正确方法是什么?

2 个答案:

答案 0 :(得分:6)

清洁方式:查询命名空间

您可以使用两个XPath查询,一个用于获取命名空间,然后注册它;作为第二个查询使用您已经拥有的名称空间。我只能帮助您查询,但似乎您对命名空间以及如何在KissXML框架中注册它们非常熟悉:

namespace-uri(/*)

此表达式从文档根开始提取所有子节点,每个XML定义是一个根元素,并返回它的命名空间uri。

丑陋的方式:仅测试本地名称

似乎KissXML仅支持XPath 1.0。使用这种功能较弱的语言版本,您需要在每个轴步骤中使用通配符选择器,并在谓词中比较本地名称(不带名称空间前缀):

//*[local-name(.) = 'book']

从XPath 2.0开始,您可以使用名称空间通配符进行查询,该通配符要短得多:

//*:book

答案 1 :(得分:4)

根据this comment,KissXML实现“正确”行为,而NSXML则不行。哪个不完全有帮助。有proposed fix for this等待合并。

扩展已接受答案的第一个提议的解决方案,解决方法I found是重命名默认命名空间,然后在我的XPath查询中使用该前缀。类似的东西:

    DDXMLNode *defaultNamespace = [document.rootElement namespaceForPrefix:@""];
    defaultNamespace.name = @"default";
    NSArray *xmlNodes = [[document rootElement] nodesForXPath:@"//default:foo/default:bar" error:nil];

这对我来说比文件的文本处理更清晰。您当然可以检查和处理命名空间冲突,但上述情况应该适用于大多数简单的情况。