当我使用带有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/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<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/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<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
答案 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
,则可以在xmlXPathEvalExpression
或PerformXMLXPathQuery
中使用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];
}