4

我正在开发一个需要解析一些 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,尽管这感觉像是一种丑陋的 hack。处理这个问题的正确方法是什么?

4

2 回答 2

7

干净的方式:查询命名空间

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

namespace-uri(/*)

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

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

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

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

从 XPath 2.0 开始,您可以使用更短的命名空间通配符进行查询:

//*:book
于 2013-06-27T08:58:36.340 回答
5

根据这个评论, KissXML 实现了“正确”的行为,而 NSXML 没有。这并不完全有帮助。有一个等待合并的建议修复。[编辑] 11/2021 -仍在等待合并!

扩展已接受答案的第一个建议解决方案,我发现的解决方法是重命名默认命名空间,然后在我的 XPath 查询中使用该前缀。就像是:

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

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

于 2013-12-18T12:10:53.363 回答