使用Xpath时命名空间和libxml的问题

时间:2009-08-30 14:44:27

标签: xpath libxml2

当我使用带有XPath的libxml时,我遇到了问题。我想解析一个youtube播放列表:

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
  xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
  xmlns:media='http://search.yahoo.com/mrss/'
  xmlns:batch='http://schemas.google.com/gdata/batch'
  xmlns:yt='http://gdata.youtube.com/schemas/2007'
  xmlns:gd='http://schemas.google.com/g/2005'
  gd:etag='W/&quot;Dk8DRn47eCp7ImA9WxRQGEk.&quot;'>
  <id>tag:youtube,2008:user:andyland74:playlists</id>
  <updated>2008-07-21T16:43:25.232Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
  <title>Playlists of andyland74</title>
  <logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
  <link rel='related' type='application/atom+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
  <link rel='alternate' type='text/html'
    href='http://www.youtube.com/profile_play_list?user=andyland74'/>
  <link rel='http://schemas.google.com/g/2005#feed'
    type='application/atom+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
  <link rel='http://schemas.google.com/g/2005#post'
    type='application/atom+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
  <link rel='http://schemas.google.com/g/2005#batch'
    type='application/atom+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/batch?v=2'/>
  <link rel='self' type='application/atom+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?...'/>
  <link rel='service' type='application/atomsvc+xml'
    href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?alt=...'/>
  <author>
    <name>andyland74</name>
    <uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
  </author>
  <generator version='2.0'
    uri='http://gdata.youtube.com/'>YouTube data API</generator>
  <openSearch:totalResults>3</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
  <entry gd:etag='W/&quot;Dk8DRn47eCp7ImA9WxRQGEk.&quot;'>
    <id>tag:youtube,2008:user:andyland74:playlist:8BCDD04DE8F771B2</id>
    <published>2007-11-04T17:30:27.000-08:00</published>
    <updated>2008-07-15T12:33:20.000-07:00</updated>
    <app:edited xmlns:app='http://www.w3.org/2007/app'>2008-07-15T12:33:20.000-07:00</app:edited>
    <category scheme='http://schemas.google.com/g/2005#kind'
      term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
    <title>My New Playlist Title</title>
    <summary>My new playlist Description</summary>
    <content type='application/atom+xml;type=feed'
      src='http://gdata.youtube.com/feeds/api/playlists/8BCDD04DE8F771B2?v=2'/>
    <link rel='related' type='application/atom+xml'
      href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
    <link rel='alternate' type='text/html'
      href='http://www.youtube.com/view_play_list?p=8BCDD04DE8F771B2'/>
    <link rel='self' type='application/atom+xml'
      href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
    <link rel='edit' type='application/atom+xml'
      href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
    <author>
      <name>andyland74</name>
      <uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
    </author>
    <yt:countHint>9</yt:countHint>
  </entry>
</feed>

当我使用以下xpath表达式“/ feed”时,xmlXPathEvalExpression说我找不到。

如果我删除它的所有xmlns属性,它的工作原理。即使使用xmlns属性,我怎么能让它工作?

我使用带有objective-C的libxml

5 个答案:

答案 0 :(得分:2)

我在XPathQuery周围使用xmlXPathEvalExpression包装,这使得xmlXpathRegisterNS路径变得更加困难。

如果您直接查询字段,您可能不关心命名空间 - 这对我的应用程序无关紧要。所以,我只是在处理它之前修改了XML。

NSString *xmlString = [[NSString alloc] initWithData:originalXMLData encoding:NSUTF8StringEncoding];
NSString *modifiedXMLString = [xmlString stringByReplacingOccurrencesOfString:@"xmlns=" withString:@"foobar="];
NSData *modifiedXMLData = [modifiedXMLString dataUsingEncoding:NSUTF8StringEncoding];

现在,如果您使用modifiedXMLData,则可以在xmlXPathEvalExpressionPerformXMLXPathQuery中使用XPathQuery

答案 1 :(得分:2)

我在尝试使用libxml-ruby来解析xml时遇到了类似的问题。来自http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/XPath.html

  

要查找节点,您必须定义原子   libxml的命名空间。一种方法   这是:

     

node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')

     

或者,您可以注册   像这样的默认命名空间:

     

doc.root.namespaces.default_prefix = 'atom' node = doc.find('atom:title')

无论哪种方式都有效,但如果您要使用这些方法,注册是有意义的。然后你可以引用像'atom:title'这样的项目。

答案 2 :(得分:1)

您没有发布您的查询代码,但听起来您没有使用XpathContext注册名称空间。这是xmlXPathRegisterNS的API文档,我相信它会做你想要的。它不会让您注册默认命名空间,因此您需要将XPath表达式更改为/ feed:feed等。

答案 3 :(得分:1)

要使用默认命名空间,只需注册命名空间xlmns =然后在查询中使用/ xmlns:feed。

答案 4 :(得分:0)

经过一些研究,我发现以下解决方案就像NSXMLDocument路径查询一样:

当xml文档声明没有前缀的默认命名空间时,如 xmlns="..."

简单的xpaths查询失败,就像 xpath: /node

那是因为xmlXPathEvalExpression期望某种默认的名称空间前缀,但没有。

一种方法是修复丢失的前缀(就像GDataXML那样)但是需要所有xpath都使用这个前缀,比如         xpath: /__def_ns:node

但这不是xpath和NSXMLDocument的工作原理。

以下解决方案(基于DDXMLNode)转到根节点并扫描没有前缀的名称空间。 然后遍历下面的所有节点,如果它们属于该命名空间,则将其删除。 这就像首先没有命名空间一样。

- (void)fixNameSpace
{
    xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
    xmlNsPtr ns = nodePtr->nsDef;
    xmlNsPtr defaultNs = NULL;
    while(ns != NULL)
    {
        if (ns->prefix == NULL)
        {
            defaultNs = ns;
            break;
        }
        ns = ns->next;
    }
    if (defaultNs)
        [self resetDefaultNs:defaultNs];
}

- (void)resetDefaultNs:(xmlNsPtr)defaultNs
{
    xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
    xmlNsPtr ns = nodePtr->ns;
    if (ns && ns == defaultNs)
        xmlSetNs(nodePtr, NULL);

    for (NSXMLNode* child in self.children)
        [child resetDefaultNs:defaultNs];
}