2012-08-06 51 views
2

我正在從谷歌天氣api中讀取XML文件並使用NSXMLParser解析它。有問題的城市是巴黎。下面是一個簡單的XML輸出我得到NSXMLParser在遇到特殊字符後停止解析

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

的問題在於它解析了所有標籤,直到達到「城市數據」爲止,因爲在法國巴黎Île-de-France有一個非ascii字符,然後它就停止。它不像postal_code那樣處理標籤。緯度,經度等

所以我的問題是,有沒有辦法,我可以從返回的URL XML字符串中刪除所有非ASCII字符?

+0

結束設置currentElementValuenil,此對象不會對你做任何事情:'的NSString * XML = [NSString的stringWithContentsOfURL :URL編碼:NSASCIIStringEncoding error:&error];'你根本沒有使用它。 'NSXMLParser'直接從'URL'加載。 – 2012-08-06 16:54:52

+0

您是否收到解析或驗證錯誤? – 2012-08-06 16:56:23

+0

@Justin - 你正確的操縱XML字符串不會做任何事情,因爲我將URL傳遞給XML解析器。有沒有一種方法可以在 - (void)分析器中修改該xml的結果?若要:傑西 - 我沒有得到任何錯誤,會發生什麼是XML停止分析後,它擊中第一個特殊字符。我有更多的標籤,但沒有閱讀 – 2012-08-06 17:14:10

回答

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

+1

如果您需要特殊字符怎麼辦? – Steven 2013-03-07 18:09:07

-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; 
} 
+0

但是,一旦收到數據,您仍然必須將其解釋爲文本,這意味着您必須使用正確的編碼。所返回的數據不是UTF8,因此試圖以這種方式解釋它是不正確的。你關於使用NSURLConnection來避免阻塞的觀點很好,但是OP可能會在後臺線程上發出這個請求,因爲同步調用並不是一件壞事,而且對於單線請求。 – Caleb 2012-08-06 17:14:47

+0

與實際問題無關 – Rakesh 2014-05-30 06:00:44

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頭應該能夠做到這一點,儘管這會使得檢索數據變得更加複雜一些。

+0

謝謝Caleb - 我改變了一下我的問題。問題在這裏。 NSXMLParser * parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];和 - (void)解析器:...我如何修復返回的URL結果中的特殊字符? – 2012-08-06 17:19:04

+0

正確 - 請參閱我對該主題的一些想法的編輯。 – Caleb 2012-08-06 17:31:44

8

我知道可能會發生,我只是有同樣的問題...

看看你的解析器您foundCharacters方法...

我有這樣的事情:

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

currentElementValue剛剛停止時發生特殊字符。

現在我的工作代碼爲:

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

記住你didEndElement方法

+0

什麼是「currentElementValue」 – ram880 2015-06-19 10:59:12