【问题标题】:NSXMLParser doesn't ignore CDATANSXMLParser 不会忽略 CDATA
【发布时间】:2013-03-22 17:24:10
【问题描述】:

我是 ios 开发的新手,我正在尝试解析 RSS 文件(xml)。

这里是 xml:(对不起语言)

<item>
<category> General < / category >
<title> killed in a tractor accident , was critically injured windsurfer </ title>
<description>
< ! [ CDATA [
<div> <a href='http://www.ynet.co.il/articles/0,7340,L-4360016,00.html'> <img src = 'http://www.ynet.co. il/PicServer3/2012/11/28/4302844/YOO_8879_a.jpg ' alt =' photo: Yaron Brener 'title =' Amona 'border = '0' width = '116 'height = '116'> </ a> < / div >
] ] >
Tractor driver in his 50s near Kfar Yuval flipped and trapped underneath . Room was critically injured windsurfer hurled rocks because of strong winds and wind surfer after was moderately injured in Netanya
< / description >
<link>
http://www.ynet.co.il/articles/0 , 7340, L- 4360016 , 00.html
< / link >
<pubDate> Fri, 22 Mar 2013 17:10:15 +0200 </ pubDate>
<guid>
http://www.ynet.co.il/articles/0 , 7340, L- 4360016 , 00.html
< / guid >
<tags> Kill , car accidents , surfing < / tags >
< / item >

这是我的 xmlparser 代码:

    - (void)parserDidStartDocument:(NSXMLParser *)parser
    {
       self.titles = [[NSMutableArray alloc]init];
       self.descriptions = [[NSMutableArray alloc]init];
        self.links = [[NSMutableArray alloc]init];
    }

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"item"]) {
        isItem = YES;
    }

    if ([elementName isEqualToString:@"title"]) {
        isTitle=YES;
        self.titlesString = [[NSMutableString alloc]init];
    }

    if ([elementName isEqualToString:@"description"]) {
        isDesription = YES;
        self.descriptionString = [NSMutableString string];
        self.data = [NSMutableData data];
    }



}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    if(isItem && isTitle){
        [self.titlesString appendString:string];
    }
    if (isItem && isDesription) {
        if (self.descriptionString)
            [self.descriptionString appendString:string];
    }






}

- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
    if (self.data)
        [self.data appendData:CDATABlock];

}


- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"item"]) {
        isItem = NO;
        [self.titles addObject:self.titlesString];

        [self.descriptions addObject:self.descriptionString];


    }

    if ([elementName isEqualToString:@"title"]) {
        isTitle=NO;

    }
    if ([elementName isEqualToString:@"description"]) {

        NSString *result = [self.descriptionString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSLog(@"string=%@", result);


        if ([self.data length] > 0)
        {
            NSString *htmlSnippet = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
            NSString *imageSrc = [self firstImgUrlString:htmlSnippet];
            NSLog(@"img src=%@", imageSrc);
            [self.links addObject:imageSrc];
        }



        self.descriptionString = nil;
        self.data = nil;
    }


}

- (NSString *)firstImgUrlString:(NSString *)string
{
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(<img\\s[\\s\\S]*?src\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>)+?"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];

    NSTextCheckingResult *result = [regex firstMatchInString:string
                                                     options:0
                                                       range:NSMakeRange(0, [string length])];

    if (result)
        return [string substringWithRange:[result rangeAtIndex:2]];

    return nil;
}

@end

就像我说的我对 iPhone 开发很陌生,我花了几个小时寻找解决它的方法,但一无所获。 我决定开个话题,然后几个问题:

一个。解析器不会忽略 CDATA 正在解析的所有内容。 为什么会这样?正如您所看到的,描述本身不在 cdata 中,我只有第一步,但即使我没有使用 foundCDATA,我也会得到其余的:(NSData *) CDATABlock

二。我要拍图片链接,怎么办?我在网上搜索,发现很多指南解释只使用函数foundCDATA:(NSData *)CDATABlock 但它是如何使用的?我在代码中使用的方式?

我需要一个解释,以便我能理解,谢谢!

【问题讨论】:

  • 如何获得该图像源的正则表达式模式

标签: iphone ios xcode xcode4.5 nsxmlparser


【解决方案1】:

回答你的两个问题:

  1. 如果您实现了foundCDATA,解析器将在该方法中解析description CDATA,而不是在foundCharacters 中。另一方面,如果您还没有实现foundCDATA,则CDATA 将被foundCharacters 解析。所以,如果你不想foundCharacters解析CDATA,那么你必须实现foundCDATA

  2. 如果你想提取img URL,你必须以某种方式解析你收到的HTML。你可以使用 Hpple,但我可能只是倾向于使用正则表达式:

    - (NSString *)firstImgUrlString:(NSString *)string
    {
        NSError *error = NULL;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(<img\\s[\\s\\S]*?src\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>)+?"
                                                                               options:NSRegularExpressionCaseInsensitive
                                                                                 error:&error];
    
        NSTextCheckingResult *result = [regex firstMatchInString:string
                                                         options:0
                                                           range:NSMakeRange(0, [string length])];
    
        if (result)
            return [string substringWithRange:[result rangeAtIndex:2]];
    
        return nil;
    }
    

    另请参阅this other Stack Overflow answer,我在其中演示了 Hpple 和正则表达式解决方案:


例如,这里是 NSXMLParserDelegate 方法,它将解析描述,将文本(不包括 CDATA)放在一个字段中,并将 CDATA 中的图像 URL 放在另一个变量中。您必须进行修改以适应您的流程,但希望这可以为您提供基本思路:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"description"])
    {
        self.string = [NSMutableString string];
        self.data = [NSMutableData data];
    }
}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"%s, parseError=%@", __FUNCTION__, parseError);
}

// In my standard NSXMLParser routine, I leave self.string `nil` when not parsing 
// a particular element, and initialize it if I am parsing. I do it this way
// so only my `didStartElement` and `didEndElement` need to worry about the particulars
// and my `foundCharacters` and `foundCDATA` are simplified. But do it however you
// want.

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if (self.string)
        [self.string appendString:string];
}

- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
    if (self.data)
        [self.data appendData:CDATABlock];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"description"])
    {
        // get the text (non-CDATA) portion

        // you might want to get rid of the leading and trailing whitespace

        NSString *result = [self.string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSLog(@"string=%@", result);

        // get the img out of the CDATA

        if ([self.data length] > 0)
        {
            NSString *htmlSnippet = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
            NSString *imageSrc = [self firstImgUrlString:htmlSnippet];
            NSLog(@"img src=%@", imageSrc);
        }

        // once I've saved the data where I want to save it, I `nil` out my
        // `string` and `data` properties:

        self.string = nil;
        self.data = nil;
    }
}

【讨论】:

  • 首先感谢您的回答。但是为什么即使我没有实现foundCDATA,我也会从“描述”中获取所有文本。解析器应该跳过 CDATA,不是吗?我只需要文本,我将使用 Hpple 获取图像 url。希望你能理解我,再次感谢!
  • @user1600694 我不太确定您要实现什么,但是当您解析 XML 时,found... 方法将报告打开和关闭 description 标记之间的所有数据.唯一的问题是您是同时实现foundCharactersfoundCDATA(在这种情况下,description 标记的两个部分将分别返回)还是只实现foundCharacters 标记(在这种情况下,打开和结束标签将由foundCharacters 返回)。你问“为什么我得到所有的文本?”这就是解析器的工作原理。
  • 如果你想丢弃CDATA(或者可能只是解析imgsrc,然后丢弃其余部分),然后实现foundCDATA(在这种情况下foundCharacters将排除 CDATA),然后对 CDATA 做任何你想做的事情。
  • @user1600694 我添加了一个示例,说明如果 (a) 您不想将CDATA 作为description 的一部分返回,您可以通过确保你实现了一个foundCDATA 并且(b)你想从 CDATA 中获取图像 URL。这只是概念的演示(我的示例不解析您的其他元素,不将结果存储在任何模型结构中,等等)。但它应该给你基本的想法。
  • 好的,我只得到foundCharacters 上的文本和foundCDATA 上的cdata。从我读到的解析器应该跳过cdata实际上是他的函数,将文本隐藏在里面。但是根据您所说的(即使我尝试过并且有效),解析器由于某种原因并没有忽略它:|但是现在的问题是如何在 cdata 中获取图像链接?与 hpple?
【解决方案2】:

答案 1: 我会同意 Rob 对这个问题的回答。

答案 2: 试试这个来获取图片链接....

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{   
    if([currentElement isEqualToString:@"img"]) {
        NSLog(@"%@",[attributeDict objectForKey:@"src"]);
    }
}

【讨论】:

  • 在第 2 点上,如果 img 标签是 XML 标签,您将是绝对正确的。可悲的是,它在 CDATA 中,NSXMLParser 不会解析(也不应该解析)。这就是 CDATA 的全部目的,将内容标记为不被解析为 XML。
【解决方案3】:

您要提取的图像链接位于 CDATA 块内,但 rss 解析器会忽略 CDATA 块。

如果你需要从 CDATA 中提取字符串,你可以在 foundCDATA 中使用这个块:

    - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
    {

    NSMutableString *cdstring = [[NSMutableString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
    }

现在可变字符串“cdstring”将包含:

    <div>
    <a href='http://www.ynet.co.il/articles/0,7340,L-4360016,00.html'>
    <img src='http://www.ynet.co. il/PicServer3/2012/11/28/4302844/YOO_8879_a.jpg ' alt=' photo: Yaron Brener ' title=' Amona ' border='0' width='116 ' height='116'>
    </ a>
    </ div>
    ]]>

现在只需使用 stringcontainsstring 搜索 href=' 并提取链接或使用 webview 来显示

 htmlContent = [NSString stringWithFormat:@"%@", cdstring];
    [webView loadHTMLString:htmlContent baseURL:nil];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 2011-01-09
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多