Раздел 11.0.
11.12. Синтаксический разбор XML с помощью NSXMLParser
Необходимо выполнить синтаксический разбор (парсинг) фрагмента кода на языке XML или XML-документа.
Воспользуйтесь классом NSXMLParser.
Для синтаксического разбора XML-содержимого класс NSXMLParser использует делегат. Создадим простой XML-файл, содержащий следующие данные (сохраните этот файл в вашем проекте как MyXML.xml):
Anthony
Robbins
51
Richard
Branson
61
Теперь определим свойство типа NSXMLParser:
#import «AppDelegate.h»
@interface AppDelegate ()
@property (nonatomic, strong) NSXMLParser *xmlParser;
@end
@implementation AppDelegate
Кроме того, как видите, я определил делегат моего приложения как делегат XML-парсера, который подчиняется протоколу NSXMLParserDelegate. Согласно этому протоколу, объект делегата XML-парсера должен относиться к типу NSXMLParser. Cчитаем с диска файл MyXML.xml и передадим его на обработку в XML-парсер:
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *xmlFilePath = [[NSBundle mainBundle] pathForResource:@"MyXML"
ofType:@"xml"];
NSData *xml = [[NSData alloc] initWithContentsOfFile: xmlFilePath];
self.xmlParser = [[NSXMLParser alloc] initWithData: xml];
self.xmlParser.delegate = self;
if ([self.xmlParser parse]){
NSLog(@"The XML is parsed.");
} else{
NSLog(@"Failed to parse the XML");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Сначала считываем содержимое файла в экземпляр NSData, а потом инициализируем XML-парсер с помощью метода initWithData:, используя данные, считанные из XML-файла. Затем вызываем метод parse XML-парсера, чтобы запустить процесс синтаксического разбора. Этот метод заблокирует актуальный поток до тех пор, пока синтаксический разбор не завершится. Если вам требуется произвести синтаксический разбор больших XML-файлов, используйте для этого глобальную диспетчерскую очередь.
Для синтаксического разбора XML-файла необходимо знать методы делегатов, определенные в протоколе NSXMLParserDelegate, а также понимать, за что они отвечают:
• parserDidStartDocument: — вызывается при запуске синтаксического разбора;
• parserDidEndDocument: — вызывается по окончании синтаксического разбора;
• parser: didStartElement: namespaceURI: qualifiedName: attributes: — вызывается, когда парсер встречает и начинает разбирать новый элемент в XML-документе;
• parser: didEndElement: namespaceURI: qualifiedName: — вызывается, когда парсер завершает синтаксический разбор текущего элемента;
• parser: foundCharacters: — вызывается, когда парсер анализирует строковое содержимое элементов.
С помощью этих методов делегата можно определить объектную модель для XML-объектов. Сначала определим объект, который будет представлять XML-элемент. Сделаем это в классе XMLElement:
#import
@interface XMLElement: NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) NSDictionary *attributes;
@property (nonatomic, strong) NSMutableArray *subElements;
@property (nonatomic, weak) XMLElement *parent;
@end
Теперь реализуем класс XMLElement:
#import «XMLElement.h»
@implementation XMLElement
— (NSMutableArray *) subElements{
if (subElements == nil){
subElements = [[NSMutableArray alloc] init];
}
return subElements;
}
@end
Мы хотим, чтобы изменяемый массив subElements создавался лишь тогда, когда при достижении этой точки в коде мы имеем значение nil. Поэтому код для выделения и инициализации свойства subElements класса XMLElement поместим в его собственном методе-получателе. Если у XML-элемента нет дочерних элементов, то использовать это свойство не придется. Ведь отсутствует точка, в которой можно было бы выделить и инициализировать изменяемый массив для данного элемента. Такая техника называется «ленивое выделение» (Lazy Allocation).
Итак, продолжим. Определим экземпляр XMLElement и назовем его rootElement. Наш план — начать синтаксический разбор и подробно изучить XML-файл по мере разбора его и методов его делегата, пока не рассмотрим весь файл целиком:
#import «AppDelegate.h»
#import «XMLElement.h»
@interface AppDelegate ()
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSXMLParser *xmlParser;
@property (nonatomic, strong) XMLElement *rootElement;
@property (nonatomic, strong) XMLElement *currentElementPointer;
@end
@implementation AppDelegate
currentElementPointer будет соответствовать тому XML-элементу, который мы в данный момент разбираем в XML-структуре. В ходе синтаксического разбора можно будет перемещаться по этой структуре вверх и вниз. В отличие от постоянно изменяющегося указателя currentElementPointer, rootElement всегда будет оставаться корневым элементом XML-файла и его значение не изменится в ходе синтаксического разбора данного файла.
Читать дальше
Конец ознакомительного отрывка
Купить книгу