我有一個解決方案,涉及使用內置的NSXMLParser和一對NSXMLParserDelegate方法。
我們首先繼承NSObject的子類並創建一個解析器類。這裏是.H:
#import <Foundation/Foundation.h>
@interface XMLParser : NSObject
- (id)initWithData:(NSData *)data;
- (BOOL)parse;
@end
在這裏你可以看到,我們會把這個對象,你想分析的數據和完成後,我們可以告訴它來解析。解析方法僅僅是您將在稍後看到的NSXMLParser解析方法的一個包裝。
類擴展是我們將添加我們將用來管理我們正在解析的數據的私有屬性的地方。它顯示如下:
@interface XMLParser()
<NSXMLParserDelegate>
@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) NSXMLParser *parser;
@property (nonatomic, strong) NSMutableDictionary *objectDict;
@property (nonatomic, strong) NSMutableString *elementDataString;
@property (nonatomic, strong) NSMutableDictionary *wertTwo;
@property (nonatomic, assign, getter = isParsingWertTwo) BOOL parsingWertTwo;
@end
的data
和parser
性質是自解釋的。 objectDict
屬性是我們將用來存儲您希望從此XML解析的數據。 elementDataString將保存解析器在元素標籤之間找到的字符。我們有一個wertTwo
屬性和一個標誌來指示我們何時解析第二個Wert元素。這樣我們就可以確保從第二個Wert元素中獲取屬性。
實施之初出現如下:
@implementation XMLParser
- (id)initWithData:(NSData *)data
{
self = [super init];
if (self) {
self.data = data;
self.parser = [[NSXMLParser alloc] initWithData:data];
self.parser.delegate = self;
self.objectDict = [@{} mutableCopy];
self.wertTwo = [@{} mutableCopy];
}
return self;
}
- (BOOL)parse
{
return [self.parser parse];
}
你可以從初始化看到,我們建立了我們需要隨着數據和解析器做實際的解析的對象。我剛纔提到的解析方法只是簡單地包裝了NSXMLParser類的解析方法。它實際上返回一個BOOL,這就是爲什麼我選擇在這裏返回它。我們將self
設置爲解析器的委託,因此我們必須在委託協議中實現一些方法以獲取必要的數據。委託方法如下所示:
#pragma mark - NSXMLParserDelegate
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:@"MesPar"]) {
// Get the value from the attribute dict of the MesPar element
NSString *value = attributeDict[@"StrNr"];
// Compare whether the value is equal to the desired value
if ([value isEqualToString:@"2416"]) {
// if the value is equal, add the attribute dict to the object dict
[self.objectDict addEntriesFromDictionary:attributeDict];
return;
}
}
// If the element is Wert AND there is an attribute named dt we know this is the second Wert element
if ([elementName isEqualToString:@"Wert"] && attributeDict[@"dt"]) {
// add the attribute element to the wertTwo dict
[self.wertTwo addEntriesFromDictionary:attributeDict];
// Set the parsing flag to YES so we know where we are in the delegate methods
self.parsingWertTwo = YES;
return;
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
// if this is the Name element, set the element data in the object dict
if ([elementName isEqualToString:@"Name"]) {
[self.objectDict setObject:[self.elementDataString copy] forKey:@"name"];
// set the data to nil since it will be reset by a delegate method for the next element
self.elementDataString = nil;
return;
}
if ([elementName isEqualToString:@"Datum"]) {
[self.objectDict setObject:[self.elementDataString copy] forKey:@"datum"];
// set the data to nil since it will be reset by a delegate method for the next element
self.elementDataString = nil;
return;
}
if ([elementName isEqualToString:@"Zeit"]) {
[self.objectDict setObject:[self.elementDataString copy] forKey:@"zeit"];
// set the data to nil since it will be reset by a delegate method for the next element
self.elementDataString = nil;
return;
}
if ([elementName isEqualToString:@"Wert"]) {
// Checks to see if this is the Wert element AND that we are parsing the second element
if (self.isParsingWertTwo) {
[self.wertTwo setObject:[self.elementDataString copy] forKey:@"wertTwoString"];
// set the wertTwo dict for the key wertTwo in the object dict
// this allows us to pull out this info for the key wertTwo and includes the attribute of dt along with the elementDataString
[self.objectDict setObject:[self.wertTwo copy] forKey:@"wertTwo"];
// set the data to nil since it will be reset by a delegate method for the next element
self.elementDataString = nil;
return;
}
else{
[self.objectDict setObject:[self.elementDataString copy] forKey:@"wertOne"];
// set the data to nil since it will be reset by a delegate method for the next element
self.elementDataString = nil;
return;
}
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// You do not have to implement this but if you'd like here you can access `self.objectDict` which should have a representation of your XML you're looking to parse
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Append the foundCharacters (in between the element tags) to the data string
[self.elementDataString appendString:string];
}
的代碼是什麼是實際發生的,但在短期,解析器通知委託,self
在這種情況下,當某些事情正在發生這樣的,當它遇到一個如評論元素或當它找到字符時。有一點要記住的是,elementDataString
屬性需要延遲加載,我們做到這一點,像這樣:
// lazy loads the elementDataString if it is nil
// it will be set to nil after each time it is set in a dict
// this is why we copy it when we add it to the dict
- (NSMutableString *)elementDataString
{
if (!_elementDataString) {
_elementDataString = [NSMutableString string];
}
return _elementDataString;
}
有幾件事情我還沒有解決,如解析錯誤或其他委託方法,您可以感興趣。這是一個使用內置類而不是依賴第三方庫的特殊解決方案。