NSXMLParser在遇到特殊字符后停止解析

时间:2012-08-06 16:44:27

标签: iphone ios xml xcode xcode4

我正在从google weather api读取XML文件并使用NSXMLParser解析它。有问题的城市是巴黎。这是我得到的简短的xml输出

           <?xml version="1.0"?>
    <xml_api_reply version="1">
    <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" ><forecast_information>
    <city data="Paris, Île-de-France"/>
    <postal_code data="Paris"/>
    <latitude_e6 data=""/>
    <longitude_e6 data=""/> 
...
...

现在我用来削减这个xml的代码是

NSString *address = @"http://www.google.com/ig/api?weather=Paris";
    NSURL *URL = [NSURL URLWithString:address];

NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
    [parser setDelegate:self];
    [parser parse];
...

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

    NSLog(@"XML Parser 1 ... elementName ... %@", elementName);

}

这是我获得的上述xml

的输出
XML Parser 1 ... elementName ... xml_api_reply
XML Parser 1 ... elementName ... weather
XML Parser 1 ... elementName ... forecast_information

问题在于它解析所有标签,直到达到“城市数据”,因为在巴黎,法兰西岛的名称中有一个非ascii字符然后它就停止了。之后它不像postal_code那样处理标签。纬度,经度等。

所以我的问题是,有没有办法可以从返回的URL XML字符串中删除所有非ascii字符?

4 个答案:

答案 0 :(得分:8)

我知道会发生什么,我只是遇到同样的问题......

在解析器中查看您的foundCharacters方法......

我有这样的事情:

if (!currentElementValue) {
   currentElementValue = [[NSMutableString alloc] initWithString:string];
}

currentElementValue在特殊字符发生时就停止了。

现在我的工作代码是:

if (!currentElementValue) {
    currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
    [currentElementValue appendString:string];
}

请务必在currentElementValue方法结束时将nil设为didEndElement

答案 1 :(得分:2)

确定。我已经解决了这个问题。这就是我开始工作的方式。

首先,我要从URL中获取带有特殊字符的XML。然后我从XML字符串中删除所有特殊字符。然后我将字符串转换为NSdata,然后将该nsdata对象传递给我的NSXMLParser。由于没有更多特殊字符,NSXMLParser很高兴。

以下是可能在将来遇到的任何人的代码。非常感谢为这篇文章做出贡献的每个人!

NSString *address = @"http://www.google.com/ig/api?weather=Paris";
    NSURL *URL = [NSURL URLWithString:address];
    NSError *error;    
    NSString *XML = [NSString stringWithContentsOfURL:URL encoding:NSASCIIStringEncoding error:&error];

    //REMOVE ALL NON-ASCII CHARACTERS
         NSMutableString *asciiCharacters = [NSMutableString string];
         for (NSInteger i = 32; i < 127; i++)  
         {
         [asciiCharacters appendFormat:@"%c", i];
         }

         NSCharacterSet *nonAsciiCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:asciiCharacters] invertedSet];

         XML = [[XML componentsSeparatedByCharactersInSet:nonAsciiCharacterSet] componentsJoinedByString:@""];

    NSData *data = [XML dataUsingEncoding:NSUTF8StringEncoding];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    [parser setDelegate:self];
    [parser parse];

修改

NSXMLParser是一个可怕的工具。我已经在我的所有应用程序中成功使用了RaptureXML。它超级易用,避免了所有这些非ascii字符的感觉。 https://github.com/ZaBlanc/RaptureXML

答案 2 :(得分:0)

您遇到的问题是Google的响应使用的编码与您期望的ASCII或UTF8不同。使用方便的命令行工具curl,很容易看到:

$ curl -I http://www.google.com/ig/api?weather=Paris
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
Content-Type: text/xml; charset=ISO-8859-1
...

如果你查找ISO-8859-1,你会发现它也被称为Latin-1字符集。其中一个内置编码选项是NSISOLatin1StringEncoding,所以这样做:

NSString *XML = [NSString stringWithContentsOfURL:URL encoding:NSISOLatin1StringEncoding error:&error];

使用正确的编码可以让NSString弄清楚如何解释这些字符,并且您将获得可用的数据。或者,您可以修改您的请求,以指定您希望Google提供的字符编码。这可能更合适,因此您不必尝试将您使用的编码与特定请求进行匹配。

编辑:到目前为止,我的答案主要集中在将响应作为可读字符串。我看到你真正的问题涉及使用NSXMLParser进行解析。我认为你至少有两个选择:

  • 修改您收到的XML 以包含字符编码。您获得的XML是Latin-1编码的,但XML标记仅表示:<?xml version="1.0"?>。您可以将其修改为:<?xml version="1.0" encoding="ISO-8859-1"?>。我不知道这是否能解决NSXMLParser的问题,但可能会解决。

  • 如上所述,从Google请求您想要的字符集。在请求中添加Accept-Charset标头应该可以解决问题,但这会使检索数据变得更复杂。

答案 3 :(得分:-2)

坚持使用ISO-8859-1,因此您无需“删除特殊字符”。使用不同的机制获取http数据。

使用NSURLConnection,从长远来看,它的灵活性和异步性都会更加灵活。

NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                            cachePolicy:NSURLRequestUseProtocolCachePolicy
                                        timeoutInterval:15.0];

 NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
        // Create the NSMutableData to hold the received data.
        // receivedData is an instance variable declared elsewhere.
        receivedData = [[NSMutableData data] init];
        return YES;
    } else {
        // Inform the user that the connection failed.
        return NO;
    }
}

#pragma mark - Url connection data delegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [receivedData setLength:0];
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    receivedData = nil;
    [self badLoad];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //inform delegate of completion
    [self.delegate fetchedData:receivedData];

    receivedData = nil;
}