【问题标题】:Problem with namespace and libxml when i use Xpath使用 Xpath 时命名空间和 libxml 出现问题
【发布时间】:2010-11-24 03:39:26
【问题描述】:

我在使用带有 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 说我找不到。

如果我删除 feed 的所有 xmlns 属性,它就可以工作。即使使用 xmlns 属性,我怎样才能使它工作?

我在 Objective-C 中使用 libxml

【问题讨论】:

标签: xpath libxml2


【解决方案1】:

经过一番研究,我发现以下解决方案与 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];
}

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 很简单。谢谢!注意:如果您正在读取各种 XML 数据,请确保使用更独特的字符串。
    • 不适用于非默认命名空间,例如xmlns:potato
    【解决方案3】:

    我在尝试使用 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'这样的项目。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 可以用于 xmlXpathRegisterNS 函数。但是为什么我不能注册默认命名空间?如果我只想获取 ,为什么要使用 /feed:feed 表达式?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-07
        • 1970-01-01
        • 2014-10-14
        • 1970-01-01
        相关资源
        最近更新 更多