Имам решение, което включва използването на вградения 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;
}
Има няколко неща, които не съм разгледал, като например грешки при синтактичния анализ или допълнителни методи на делегиране, които може да ви интересуват. Това е едно конкретно решение, което използва вградени класове, вместо да разчита на библиотека на трета страна.
person
Brian Palma
schedule
26.11.2013