NSXMLParser会跳过具有命名空间的元素

时间:2012-01-26 07:03:58

标签: xml cocoa nsxmlparser

(tl; dr:见底部摘要。)

我正在实施一个应用程序,它从单个站点的RSS源中提取内容。以下是XML的示例:

<item>
<title>Title</title>
<link>http://example.com</link>
<comments>http://example.com/#comments</comments>
<pubDate>Thu, 26 Jan 2012 03:05:11 +0000</pubDate>
<dc:creator>Billy D. Author</dc:creator> 
<category><![CDATA[sample_category]]></category>

<guid isPermaLink="false">http://example.com</guid>
<description><![CDATA[Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ac erat nec odio cursus accumsan. Nam feugiat hendrerit neque, nec tristique nisl ullamcorper vel. Nullam pellentesque augue metus. Vestibulum in lectus orci, eget ornare felis.&#8230;]]></description>
<content:encoded><![CDATA[<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ac erat nec odio cursus accumsan. Nam feugiat hendrerit neque, nec tristique nisl ullamcorper vel. Nullam pellentesque augue metus. Vestibulum in lectus orci, eget ornare felis. Vestibulum nisl lacus, faucibus ac aliquet eu, pellentesque rutrum justo. Nulla fringilla venenatis augue a laoreet. Maecenas metus leo, euismod eget rutrum in, mattis eget nisi. Proin at massa sit amet odio tempor venenatis sit amet sit amet erat. Mauris vitae bibendum arcu. Curabitur a purus vitae ipsum ultricies luctus vel et velit.</p><p>Donec in lacus sit amet mi sagittis auctor eget nec nunc. Pellentesque adipiscing venenatis risus, a faucibus sem pretium quis. Nam fringilla metus eu nulla pellentesque semper. Quisque in lectus nisi. Fusce pretium accumsan purus nec sodales. Donec velit nisi, ullamcorper at faucibus vitae, lacinia quis dui. Duis eu dui leo, eget varius diam. Aliquam imperdiet volutpat tellus quis venenatis. Vivamus laoreet malesuada tincidunt. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris ut purus est. Sed quis mauris ut dolor dapibus vestibulum ut eu dolor. Cras interdum sagittis faucibus. Nulla tortor ligula, molestie at sollicitudin at, hendrerit et lacus. Nunc lorem enim, aliquet id porttitor ultrices, sodales ac sapien.</p>]]></content:encoded>
<wfw:commentRss>http://example.com/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<enclosure url="http://example.com/some/other/stuff/>
</item>

我对以下元素感兴趣:title,link,pubDate,dc:creator,description,content:encoded。

正如您可能猜到的那样,标题,链接,pubDate和描述都很好。但是,而不是dc:creator的任何内容,我得到pubDate的内容,而不是内容:编码,我得到描述。

对于我的解析器对象,我有

[xmlParser setDelegate:self];

[xmlParser setShouldProcessNamespaces: YES];
[xmlParser setShouldReportNamespacePrefixes:YES];
[xmlParser setShouldResolveExternalEntities:YES];

并实施了以下方法:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {

    // NSLog(@"element %@, ns %@, qn %@", elementName, namespaceURI, qName);

    if ( [elementName isEqualToString:@"rss"] ) {
    return;
}

if ( [elementName isEqualToString:@"channel"] ) {
    // begin the set of entries
    if (!allEntries)
        allEntries = [NSMutableArray array];
    return;
}

if ( [elementName isEqualToString:@"item"] ) {
    // item means a new post!
    // currentPost = [[DIDSEntry alloc] init]; 
    return;
}

if ( [elementName isEqualToString:@"title"]) {
    [self setCurrentProperty:@"title"];
    currentPostTitle = [NSString string];
    return;
}

if ( [elementName isEqualToString:@"link"] ) {
    [self setCurrentProperty:@"url"];
    currentPostUrl = [[NSURL alloc] init];
    return;
}

if ( [elementName isEqualToString:@"pubDate"] ) {
    [self setCurrentProperty:@"date"];
    currentPostDate = [[NSDate alloc] init];
    return;
}

if ( [elementName isEqualToString:@"dc:creator"] ) {
    [self setCurrentProperty:@"author"];
    currentPostAuthor = [NSString string];
    return;
}

if ( [elementName isEqualToString:@"description"] ) {
    [self setCurrentProperty:@"preview"];
    currentPostPreview = [NSString string];
    return;
}

if ( [elementName isEqualToString:@"content:encoded"] ) {
    [self setCurrentProperty:@"text"];
    currentPostText = [NSString string];
    return;
}

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentStringValue) {
    // currentStringValue is an NSMutableString instance variable
    currentStringValue = [[NSMutableString alloc] initWithCapacity:50];
}
[currentStringValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

if ( [elementName isEqualToString:@"rss"] ) {
    return;
}
if ( [elementName isEqualToString:@"channel"]) return;

if ( [elementName isEqualToString:@"item"] ) {
    currentPost = [[DIDSEntry alloc] initWithPostTitle:currentPostTitle postAuthor:currentPostAuthor postUrl:currentPostUrl pubDate:currentPostDate postPreview:currentPostPreview postText:currentPostPreview];
    [allEntries addObject:currentPost];
    return;
}
NSString *prop = [self currentProperty];

if ( [prop isEqualToString:@"title"] ) {
    [self setCurrentPostTitle:currentStringValue];
    // return;
}

if ( [prop isEqualToString:@"url"] ) {
    [self setCurrentPostUrl:[NSURL URLWithString:currentStringValue]];
    // return;
}

if ( [prop isEqualToString:@"date"] ) {
    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss ZZZ"];
    [self setCurrentPostDate:[formatter dateFromString:currentStringValue]];
    // NSLog(@"date: %@", currentStringValue);
}

if ( [prop isEqualToString:@"author"] ) {
    [self setCurrentPostAuthor:currentStringValue];
    // return;
}

if ( [prop isEqualToString:@"preview"] ) {
    [self setCurrentPostPreview:currentStringValue];
    // return;
}

if ( [prop isEqualToString:@"text"] ) {
    [self setCurrentPostText:currentStringValue];
    // return;
}
// currentStringValue is an instance variable
currentStringValue = nil;

return;
}

我也有点实施了

- (void)parser:(NSXMLParser *)parser didStartMappingPrefix:(NSString *)prefix toURI:(NSString *)namespaceURI

- (void)parser:(NSXMLParser *)parser didEndMappingPrefix:(NSString *)prefix

但只记录他们被调用(他们是)因为我不知道我甚至应该对他们做什么。

我一直在网上试图找到答案,为什么我的代码表现得像这样,以及我如何解决它,但我完全不知所措。我尝试测试合格的名称而不是元素名称,删除前缀和其他一些东西,但没有快乐。 (我也只是表面上理解XML名称空间,虽然我看到的所有东西都没有真正解决我所追求的问题。)

总结:

尝试使用命名空间解析元素并将其内容存储在实例变量中会导致先前解析的元素存储在这些ivars中。我不知道为什么会这样,以及如何修复它。

1 个答案:

答案 0 :(得分:1)

解决。请原谅我,但显然这篇文章只与名称空间相关。当我检查它时, 从元素名称中删除了名称空间前缀,在每次使用后将currentProperty字符串设置为nil,并注意到我将postText设置为currentPostPreview。抱歉。已经很晚了。