202
Сериализация и транспорты
токол доступа к объектам (Simple Object Access Protocol, SOAP), но мы, чтобы не
усложнять, будем использовать для демонстрации слегка измененную версию
формата JSON, примененного выше. Начнем с такого фрагмента XML:
Mike
Этот фрагмент описывает автора с именем Mike, который оказался челове
-
ком (
type="human"
) и, по случайному совпадению, автором этой книги.
Если вы ожидаете такой же простоты, какую предлагает протокол
Codable
,
реа лизованный в
JSONEncoder
и
JSONDecoder
, то у меня есть плохие новости:
XMLPar ser
в iOS гораздо более многословен.
Возьмем этот фрагмент XML и создадим из него объект, выполнив парсинг:
class SomeObject: NSObject {
func parseSomeXML() {
let xml = "
Mike"
let rawData = xml.data(using: .utf8)!
let parser = XMLParser(data: rawData)
parser.delegate = self;
parser.parse()
}
}
У нас есть класс
SomeObject
, наследующий
NSObj
ect
, который имеет созданный
нами метод
parseSomeXml
. Этот метод определяет строковую переменную с име
-
нем
xml
, содержащую наш фрагмент XML. В следующей строке мы преобразуем
его в объект
Data
в кодировке UTF-8. Затем создаем экземпляр
XMLParser
с объ
-
ектом
rawData
. Назначаем себя в качестве делегата для обработки событий пар
-
синга. И наконец, вызываем
parse()
, запуская парсинг.
Если попытаться запустить этот код прямо сейчас, он завершится с ошибкой,
потому что в настоящее время
SomeObject
не реализует протокол
XMLParserDel
egate
, который должен быть реализован для правильной обработки событий
парсинга. Поэтому давайте подробно рассмотрим каждый метод протокола,
чтобы понять суть происходящего.
Парсинг XML происходит синхронно. Документ сканируется, и из него из
-
влекаются элементы один за другим. В нашем делегате мы будем использовать
четыре метода:
1)
parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)
2)
parser(_:foundCharacters:)
3)
parser(_:didEndElement:namespaceURI:qualifiedName:)
4)
parserDidEndDocument(_:)
Вот первый метод из этого списка:
func parser(_ parser: XMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?,
attributes attributeDict: [String : String] = [:]) {
204
Сериализация и транспорты
Если бы в нашем XMLдокументе было больше элементов, мы продолжили бы
создавать новые экземпляры авторов и сохраняли бы их перед началом парсинга
нового элемента и создания временного объекта.
Вот полный код реализации парсинга, описанной выше:
struct Author {
var name: String?
var type: String?
}
class SomeObject: NSObject {
var author: Author?
var characters: String = ""
func parseSomeXML() {
let xml = "
Mike"
let rawData = xml.data(using: .utf8)!
let parser = XMLParser(data: rawData)
parser.delegate = self;
parser.parse()
}
}
extension SomeObject: XMLParserDelegate {
func parser(_ parser: XMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?,
attributes attributeDict: [String : String] = [:]) {
if elementName == "author" {
author = Author()
if let type = attributeDict["type"] {
author?.type = type
}
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
characters += string
}
func parser(_ parser: XMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "name" {
author?.name = characters
}
characters = ""
}
func parserDidEndDocument(_ parser: XMLParser) {
print(author?.name)
print(author?.type)
}
}