Проблема с пространством имен и libxml при использовании Xpath - PullRequest
4 голосов
/ 30 августа 2009

У меня проблема, когда я использую libxml с XPath. Я хочу проанализировать плейлист 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?

я использую libxml с целью-C

Ответы [ 5 ]

2 голосов
/ 23 апреля 2011

Я столкнулся с подобной проблемой при попытке использовать 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 голосов
/ 21 января 2011

Я использую обертку 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 в xmlXPathEvalExpression или PerformXMLXPathQuery, если вы используете XPathQuery.

1 голос
/ 28 октября 2010

Чтобы использовать пространство имен по умолчанию, просто зарегистрируйте пространство имен xlmns = и затем используйте / xmlns: feed в своем запросе.

1 голос
/ 30 августа 2009

Вы не опубликовали свой код запроса, но, похоже, вы не регистрируете пространства имен в своем XpathContext. Вот документы по API для xmlXPathRegisterNS , я думаю, что это сделает то, что вы ищете. Это не позволит вам зарегистрировать пространство имен по умолчанию, поэтому вам нужно изменить выражение XPath на / feed: feed или подобное.

0 голосов
/ 29 января 2014

После некоторых исследований я нашел следующее решение, которое просто работает как запросы пути 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];
}
...