Je voudrais décoder un document XML en utilisant le nouveau protocole Decodable
introduit dans Swift 4, cependant, il ne semble pas y avoir d'implémentation existante pour un décodeur XML qui est conforme au protocole Decoder
.
Mon plan était d'utiliser la bibliothèque SWXMLHash pour analyser le XML, puis de faire éventuellement de la classe XMLIndexer
dans cette bibliothèque étendre le protocole Decoder
afin que mon modèle puisse être initialisé avec une instance de XMLIndexer
(XMLIndexer
est retourné par SWXMLHash.parse(xmlString)
).
Mon problème est que je n'ai aucune idée de comment implémenter le protocole Decoder
et je n'arrive pas à trouver de ressources en ligne qui expliquent comment cela est fait. Chaque ressource que j'ai trouvée mentionne strictement la classe JSONDecoder
qui est incluse avec la bibliothèque standard Swift et aucune ressource que j'ai trouvée résout le problème de la création de votre propre décodeur personnalisé .
Je n'ai pas encore eu la chance de transformer mon code en framework, mais vous pouvez jeter un œil à mon référentiel Github qui implémente à la fois un décodeur et un encodeur personnalisés pour XML.
Lien: https://github.com/ShawnMoore/XMLParsing
L'encodeur et le décodeur résident dans le dossier XML du dépôt. Il est basé sur JSONEncoder et JSONDecoder d'Apple avec des modifications pour s'adapter à la norme XML.
Différences entre XMLDecoder et JSONDecoder
XMLDecoder.DateDecodingStrategy
a un cas supplémentaire intitulé keyFormatted
. Ce cas prend une fermeture qui vous donne une CodingKey, et c'est à vous de fournir le DateFormatter correct pour la clé fournie. Il s'agit simplement d'un cas pratique sur le DateDecodingStrategy de JSONDecoder.XMLDecoder.DataDecodingStrategy
a un cas supplémentaire intitulé keyFormatted
. Ce cas prend une fermeture qui vous donne une CodingKey, et c'est à vous de fournir les données correctes ou nulles pour la clé fournie. Il s'agit simplement d'un cas pratique sur le DataDecodingStrategy de JSONDecoder.Différences entre XMLEncoder et JSONEncoder
Contient une option appelée StringEncodingStrategy
, cette énumération a deux options, deferredToString
et cdata
. L'option deferredToString est par défaut et encodera les chaînes comme de simples chaînes. Si cdata est sélectionné, toutes les chaînes seront encodées en CData.
La fonction encode
accepte deux paramètres supplémentaires que JSONEncoder. Le premier paramètre supplémentaire dans la fonction est une chaîne RootKey qui aura le XML entier enveloppé dans un élément nommé cette clé. Ce paramètre est obligatoire. Le deuxième paramètre est un XMLHeader, qui est un paramètre facultatif qui peut prendre la version, la stratégie d'encodage et l'état autonome, si vous souhaitez inclure ces informations dans le xml encodé.
Pour une liste complète d'exemples, consultez le dossier Sample XML dans le référentiel.
XML à analyser:
<?xml version="1.0"?>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
Structures rapides:
struct Book: Codable {
var id: String
var author: String
var title: String
var genre: Genre
var price: Double
var publishDate: Date
var description: String
enum CodingKeys: String, CodingKey {
case id, author, title, genre, price, description
case publishDate = "publish_date"
}
}
enum Genre: String, Codable {
case computer = "Computer"
case fantasy = "Fantasy"
case romance = "Romance"
case horror = "Horror"
case sciFi = "Science Fiction"
}
Décodeur XML:
let data = Data(forResource: "book", withExtension: "xml") else { return nil }
let decoder = XMLDecoder()
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
decoder.dateDecodingStrategy = .formatted(formatter)
do {
let book = try decoder.decode(Book.self, from: data)
} catch {
print(error)
}
XMLEncoder:
let encoder = XMLEncoder()
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
encoder.dateEncodingStrategy = .formatted(formatter)
do {
let data = try encoder.encode(self, withRootKey: "book", header: XMLHeader(version: 1.0))
print(String(data: data, encoding: .utf8))
} catch {
print(error)
}