5

i've got a problem when i'm using libxml with XPath. I want to parse an youtube playlist :

<?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>

when i use the following xpath expression "/feed", the xmlXPathEvalExpression say me that i doesnt find.

if i remove all the xmlns attributes of feed it works. How could i make it work even with xmlns attributes ?

i use libxml with objective-C

ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
Sly33
  • 165
  • 2
  • 7
  • One from many possible duplicates of this FAQ: [libxml2 error with namespaces and xpath](http://stackoverflow.com/questions/3135175/libxml2-error-with-namespaces-and-xpath) –  Apr 22 '11 at 23:50

5 Answers5

3

I am using the XPathQuery wrapper around xmlXPathEvalExpression which makes it harder to go the xmlXpathRegisterNS route.

If you are querying for the fields directly, you probably do not care about the namespaces - it doesn't matter for my app. So, I just modified the XML before I process it.

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

Now you can use modifiedXMLData in xmlXPathEvalExpression or PerformXMLXPathQuery if you use XPathQuery.

pablasso
  • 2,479
  • 2
  • 26
  • 32
Sunil Gowda
  • 2,476
  • 2
  • 17
  • 13
3

I ran into a similar issue when trying to use libxml-ruby to parse through xml. From http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/XPath.html:

To find nodes you must define the atom namespace for libxml. One way to do this is:

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

Alternatively, you can register the default namespace like this:

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

Either way works, but registering makes sense if you're going to be using the methods a lot. Then you can just reference items like 'atom:title'.

alimi
  • 31
  • 4
2

You didn't post your query code, but it sounds like you aren't registering the namespaces with your XpathContext. Here's the API docs for xmlXPathRegisterNS, I believe it will do what you're looking for. It won't let you register a default namespace, so you'll need to change your XPath expression to /feed:feed or the like.

easel
  • 3,982
  • 26
  • 28
  • 2
    ok for xmlXpathRegisterNS function. But why i can't register a default namespace ? why should i use /feed:feed expression if i just want to get ? – Sly33 Aug 31 '09 at 18:48
2

To use a default namespace just register the namespace xlmns= and then use /xmlns:feed in your query.

anton
  • 21
  • 1
1

After some research, I found the following solution that just works like NSXMLDocument path queries:

when xml documents declare a default namespace without a prefix, like xmlns="..."

simple xpaths queries fail, like xpath: /node

that's because xmlXPathEvalExpressionexpects some kind of default namespace prefix but there is none.

One approach is to fix the missing prefix (like GDataXML does) but that requires all xpaths to use this prefix, like xpath: /__def_ns:node

But this is not how xpath's and NSXMLDocument works.

The following solution (based on a DDXMLNode) goes to the root node and scans for a namesepace without a prefix. Then all nodes below are being traversed and if they belong to that namespace, it is being removed. This is just like if there was no namespace in the first place.

- (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];
}
berbie
  • 978
  • 10
  • 13