xml swift decoder codable swxmlhash

xml - Implementando un decodificador personalizado en Swift 4



decoder codable (1)

Me gustaría decodificar un documento XML utilizando el nuevo protocolo Decodable introducido en Swift 4, sin embargo, no parece haber una implementación existente para un decodificador XML que se ajuste al protocolo Decoder .

Mi plan era usar la biblioteca SWXMLHash para analizar el XML y luego posiblemente hacer que la clase XMLIndexer en esa biblioteca extienda el protocolo Decoder para que mi modelo pueda inicializarse con una instancia de XMLIndexer ( XMLIndexer es devuelto por SWXMLHash.parse(xmlString) ) .

Mi problema es que no tengo ni idea de cómo implementar el protocolo Decoder y parece que no puedo encontrar ningún recurso en línea que explique cómo se hace. Cada recurso que he encontrado menciona estrictamente la clase JSONDecoder que se incluye con la biblioteca estándar de Swift y ningún recurso que he encontrado aborda el problema de crear su propio decodificador personalizado.


Todavía no he tenido la oportunidad de convertir mi código en un marco, pero puedes echar un vistazo a mi repositorio Github que implementa un decodificador y codificador personalizados para XML.

Enlace: https://github.com/ShawnMoore/XMLParsing

El codificador y el decodificador residen en la carpeta XML del repositorio. Se basa en JSONEncoder y JSONDecoder de Apple con cambios que se ajustan al estándar XML.

Diferencias entre XMLDecoder y JSONDecoder

  1. XMLDecoder.DateDecodingStrategy tiene un caso adicional titulado keyFormatted . Este caso requiere un cierre que le proporciona una CodingKey, y depende de usted proporcionar el DateFormatter correcto para la clave proporcionada. Esto es simplemente un caso de conveniencia en la estrategia DateDecoding de JSONDecoder.
  2. XMLDecoder.DataDecodingStrategy tiene un caso adicional titulado keyFormatted . Este caso requiere un cierre que le proporciona un CodingKey, y depende de usted proporcionar los datos correctos o nula para la clave proporcionada. Este es simplemente un caso de conveniencia en la estrategia de DataDecoding de JSONDecoder.
  3. Si el objeto que cumple con el protocolo Codable tiene una matriz, y el XML que se está analizando no contiene el elemento de la matriz, XMLDecoder asignará una matriz vacía al atributo. Esto se debe a que el estándar XML dice que si el XML no contiene el atributo, eso podría significar que hay cero de esos elementos.

Diferencias entre XMLEncoder y JSONEncoder

  1. Contiene una opción llamada StringEncodingStrategy , esta enumeración tiene dos opciones, deferredToString y cdata . La opción deferredToString es predeterminada y codificará cadenas como cadenas simples. Si se selecciona cdata , todas las cadenas serán codificadas como CData.

  2. La función de encode toma dos parámetros adicionales que JSONEncoder. El primer parámetro adicional en la función es una cadena RootKey que tendrá todo el XML envuelto en un elemento llamado esa clave. Este parámetro es obligatorio. El segundo parámetro es un XMLHeader, que es un parámetro opcional que puede tomar la versión, la estrategia de codificación y el estado independiente, si desea incluir esta información en el código XML codificado.

Ejemplos

Para obtener una lista completa de ejemplos, consulte la carpeta XML de muestra en el repositorio.

XML a analizar:

<?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>

Estructuras Swift:

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" }

XMLDecoder:

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) }