【问题标题】:(Kiss)XML xpath and default namespace(Kiss)XML xpath 和默认命名空间
【发布时间】:2013-06-23 08:13:42
【问题描述】:

我正在开发一个需要解析一些 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。处理这个问题的正确方法是什么?

【问题讨论】:

    标签: ios objective-c xml xpath kissxml


    【解决方案1】:

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

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

    namespace-uri(/*)
    

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

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

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

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

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

    //*:book
    

    【讨论】:

    • 无数小时的谷歌搜索、研究、拉扯头发……我感激不尽。
    【解决方案2】:

    根据this comment KissXML 实现“正确”行为,而 NSXML 没有。这并不完全有帮助。有一个proposed fix for this 等待合并。 [编辑] 11/2021 - 仍在等待合并!

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

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

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

    【讨论】:

      猜你喜欢
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 2014-09-17
      • 1970-01-01
      • 2011-07-24
      • 2014-04-19
      相关资源
      最近更新 更多